Skip to content

React and SPAs

Load the queue stub and loader once in your HTML shell. Do not insert a new loader on every component render. Reference the published declarations so the global tiketoChat name is typed.

Register stable action/component handlers in an effect. Registration may happen after init, provided it finishes before the agent calls that contract. The API replaces an action/component registration with the same name. Event handlers use on/off; repeated registration of the same event/function pair is ignored. Make setup idempotent because React Strict Mode intentionally runs development effects twice.

import { useEffect } from "react";
import { createRoot } from "react-dom/client";
export function TiketoIntegration() {
useEffect(() => {
tiketoChat("action", "whereAmI", () => ({
route: window.location.pathname,
}));
tiketoChat("component", "productPreview", (element, payload, { reply }) => {
const root = createRoot(element);
root.render(
<button
type="button"
onClick={() => reply({
requestId: payload.requestId,
productId: payload.productId,
variant: payload.variants[0],
})}
>
Choose {payload.name}
</button>,
);
return () => root.unmount();
});
}, []);
return null;
}

Return cleanup from each component renderer so its React root is unmounted with the chat response. A host component restored from conversation history before this effect registers displays fallback text; it is not re-rendered later.

Launch context is a snapshot read when the widget starts. Do not send route updates through a route-dependent context effect expecting the running agent to change. Instead, read window.location.pathname inside the supplied whereAmI handler so every call sees current SPA state. The reference contract treats the route as path-only; leave query strings and hashes out unless Tiketo explicitly defines and reviews them for your chatbot.

Do not put access tokens, user records, email addresses, or other secrets/PII in context. Await reset at the account boundary, clear your own handler state, and then continue navigation:

async function logout() {
try {
await tiketoChat("reset");
} catch (error) {
hideChatLauncher();
reportChatResetFailure(error);
} finally {
clearHostChatState();
await endApplicationSession();
}
}

hideChatLauncher() and reportChatResetFailure() are host application hooks: hide your chat integration container immediately and send the error code plus diagnostics to your normal reporting path. Default reset clears the widget conversation, its project-scoped persistence, and reply de-duplication state without starting another widget. It is safe before initialization; when no project is known it clears all widget-owned voiceflow-session-* keys. Destruction failure rejects even though storage is cleared, so keep host logout in finally as shown. A page reload after reset is optional if your application already reloads during logout; reload alone is not a clean-session guarantee.

To start chat for a newly signed-in user after logout without reloading the page, first set the new user’s non-sensitive context, then await tiketoChat("reset", { relaunch: true }). The relaunch uses that current context. Call init only once per page; do not call it again for the new user. Do not use an old user’s context for the new launch.