Chapter 9 of 11 · ~2 min

Put it on the website

The prospect never sees Chatterfly. They see a panel on Kettle Co.'s website that asks five questions and, a minute later, shows a quote. That panel is the widget, and it is embedded in two lines: a React component, or a script tag for a site without a build step, given the API origin and an identity.

Two ways to start a run. For a public, single-participant workflow, the widget is given the workflow id and starts a run itself when the visitor clicks; every live experiment in these courses works this way. For the full enquiry workflow, with a rep as the second participant, the deployment is private and the site's backend does two things before the panel appears: it starts the run with a stable workflow key that never reaches the browser, and it mints a short-lived participant token for the prospect role. The widget is given the run id and that token, nothing else. The rep's side works the same way. The company's sales tool can request a token for the rep and show the rep's step in the same embedded panel, or the rep can use the inbox that comes with the platform. Which of these a participant uses is a single setting in the definition.

What the page can do. It can tell the widget to wait for a click, pass in what it already knows about the visitor so the form does not ask again, be told when the run completes so the page can react, and be themed to the site. It can also run in a floating launcher, or be driven headless from the site's own components.

Where the code comes from. The Ship tab's integrate panel generates the snippet for your framework from the workflow's own inputs and roles, together with a short brief a coding agent can paste to wire the widget into the host application. The embedding reference is published in the form agents read, and the MCP server hands it to them on request.

Experiment

Runs in your browser

The React embed of a public slice, then the two backend calls and the widget for the private enquiry workflow, annotated.

The widget on the company's site, two ways. First a public single-participant slice, then the private enquiry workflow, which the site's backend has to start.

// 1. A public workflow: the widget starts the run itself
import "@chatterfly/widget/style.css";
import { ChatterflyWidget } from "@chatterfly/widget";
<ChatterflyWidget
workflowId={process.env.NEXT_PUBLIC_QUOTE_ASSESSMENT_ID}
apiBase="https://<your-api-origin>"
clickToStart={{ label: "Get an assessment", description: "About a minute" }}
initialInput={{ company: knownCompanyName }}
onCompleted={(output) => showThanks(output)}
/>
// 2. The private enquiry workflow: two calls on the server, never in the browser
// app/api/enquiry/route.ts
const start = await fetch(`${apiBase}/api/v1/runs`, {
method: "POST",
headers: { Authorization: `Bearer ${process.env.CHATTERFLY_WORKFLOW_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ input: {} }),
});
const { run_id } = await start.json();
const mint = await fetch(`${apiBase}/api/v1/runs/${run_id}/tokens`, {
method: "POST",
headers: { Authorization: `Bearer ${process.env.CHATTERFLY_WORKFLOW_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ role: "prospect" }),
});
const { participant_token } = await mint.json();
return Response.json({ run_id, participant_token });
// 3. The page renders the widget with the run and the prospect's token, nothing else
<ChatterflyWidget runId={run_id} participantToken={participant_token} apiBase="https://<your-api-origin>" />
// No build step? The same thing as a script tag and a custom element:
<script src="https://cdn.jsdelivr.net/npm/@chatterfly/widget/dist/embed.global.js"></script>
<chatterfly-widget workflow-id="…" api-base="https://<your-api-origin>"></chatterfly-widget>
  1. 1A workflow id, not a deployment id: the widget follows the latest live deployment after every redeploy.
  2. 2What the page already knows is passed in, so the form does not ask again.
  3. 3A stable workflow key, held by the server. It never reaches the browser, which is why a multi-participant workflow must be started this way.
  4. 4One token per participant role per run, short-lived, re-mintable. The rep's side is reached through the inbox, not through the site.
  5. 5Three props: the run, the token, the API origin. The widget renders the prospect's steps of that run and nothing of the rep's.
  6. 6The custom element for sites without a build step. The Ship tab generates either form, and a brief a coding agent can use to wire it in.

Big question

On which page of your site should the prospect's side of this process live, and what does that page already know about them?