FrankieProvider
Every chat sits inside one provider. It holds the connection to Frankie, so the launcher, a full-page chat and your own components all share one conversation.
<FrankieProvider
publishableKey="pk_live_…"
getUserToken={getUserToken}
context={{ route: "/settings/billing", plan: "trial" }}
>
{children}
</FrankieProvider>
Props
| Prop | Required | What it does |
|---|---|---|
publishableKey | Yes | The agent's public key. Safe in the browser. |
getUserToken | For signed-in users | Returns a short-lived user token from your backend. See below. |
context | Facts about the current page the agent can use. | |
theme | Overrides the theme set in the dashboard. See Styling. | |
persist | Keep an anonymous conversation across reloads (stored in the browser). Defaults to true; set false to start fresh on every load. Signed-in chat uses server history instead. | |
conversationId | Open a specific saved conversation. | |
injectStyles | Set false when you load the stylesheet yourself or compile it with Tailwind. | |
baseUrl | Frankie's API address. Defaults to the hosted cloud; leave it unset. | |
api | Where actions that run in the user's browser are sent. Defaults to the site the user is on, with the page's cookies. See below. | |
approvals | "ask": show each action that changes data on a card with Approve first. "auto": run them at once, without a card; a delete still asks unless the workspace runs those too. Unset (default): the workspace's setting, which asks. Also on ChatPanel (and so FrankieWidget, FrankieInline), where it wins over the provider's. See Running without asking. |
getUserToken
Called before each message. Return a token signed by your backend, or undefined when nobody is signed in. Throw for anything else: the chat shows the error's message instead of quietly treating a broken endpoint as a signed-out visitor.
async function getUserToken() {
const res = await fetch("/api/frankie/token", { method: "POST" });
if (res.status === 401) return undefined; // nobody is signed in
if (!res.ok) throw new Error("Frankie token endpoint returned " + res.status);
return (await res.json()).token;
}
Leave it out on public pages. See Chat as the signed-in user for the server side, and Authentication for the full handshake.
context
Short facts about where the user is, such as the route or their plan. The agent can use them to answer ("you're on the trial plan"), but they're treated as untrusted data, never as instructions, and are capped at 20 keys of 200 characters each.
api
Actions set to run in the user's browser call your API from the page, with the user's own sign-in. By default they go to the connection's API base URL or the spec's absolute servers[0], else the site the user is on (window.location.origin), with the page's cookies. That's right for a Next.js app whose API routes live beside its pages. Set api when your API is elsewhere or expects a token. A baseUrl other than the page's origin wins over the spec's servers, and over the connection's base URL when that one's host isn't trusted (below):
<FrankieProvider
publishableKey="pk_live_…"
api={{
baseUrl: "https://api.acme.com",
credentials: "include", // send cookies cross-origin (your API must allow it with CORS)
headers: async () => ({ Authorization: `Bearer ${await getAccessToken()}` }),
allowedOrigins: ["https://acme-api-123.a.run.app"], // the same API under another hostname
}}
>
headers and credentials only go to trusted origins: the page's, baseUrl's and each of allowedOrigins. A call the workspace sends anywhere else still runs, without them.
Frankie adds no credential of its own: your API checks each call exactly as it would a request from your own frontend.