Developers
SDK & API.
Two packages do the work. @onpilot/node mints identity tokens on your server. @onpilot/react renders the widget. Both wrap the same public HTTP contract — you can hit it directly if you don't use Node or React.
@onpilot/react and @onpilot/node packages are published but stabilizing. Talk to us to get set up with your tenant ID and embed secret.@onpilot/react and @onpilot/node v0.3.0+. If your lockfile pinned an older version, run npm i @onpilot/react@latest @onpilot/node@latest. The biggest v0.2 → v0.3 break: the externalOrgId claim and option are now copilotId. See the changelog at the bottom of this page.HTML embed
One script tag
Drop the embed on any page. The widget exchanges the JWT for a session and renders. Works with WordPress, Webflow, Shopify, Rails, Django, Laravel — any framework that can render a script tag.
<script
src="https://chat.onpilot.ai/embed.js"
data-identity-token="<%= identityToken %>"
></script>The widget reads data-identity-token, optional data-position, and a small set of styling attributes.
React
React SDK
Render the agent as a React component. Pass either a static identityToken or an async identityTokenProvider so tokens refresh automatically — never hardcode.
import { CopilotBubble } from "@onpilot/react";
export default function App() {
return (
<CopilotBubble
identityTokenProvider={async () =>
fetch("/api/onpilot/token").then((r) => r.text())
}
/>
);
}Components: CopilotBubble, CopilotSidebar, CopilotInline, and headless CopilotPanel. See the component picker to choose.
Server
Server SDK (Node)
Sign short-lived identity tokens for your signed-in users. The token carries user identity and agent binding, signed HS256 with your tenant Embed Secret. No network call — sign locally.
import { OnPilot } from "@onpilot/node";
const onpilot = new OnPilot({
tenantId: process.env.ONPILOT_TENANT_ID!,
embedSecret: process.env.ONPILOT_EMBED_SECRET!,
});
const identityToken = onpilot.signIdentityToken({
copilotId: process.env.ONPILOT_COPILOT_ID!,
user: {
id: currentUser.id,
name: currentUser.name,
email: currentUser.email,
role: currentUser.isAdmin ? "admin" : "user",
},
expiresIn: "1h",
});Required claims: iss (tenantId), sub (userId), copilot_id. Full claim shape and rotation in Identity tokens.
HTTP contract
No SDK? Sign the JWT yourself
The SDKs wrap a public contract. If your stack isn't Node — Python, Go, Ruby, PHP, Elixir — sign the JWT directly with your embed secret using any HS256 library.
# JWT claims (HS256, signed with your tenant Embed Secret)
{
"iss": "<tenantId>",
"sub": "<userId>",
"copilot_id": "<copilotId>",
"role": "user",
"iat": 1730131200,
"exp": 1730134800
}Pass the resulting JWT to the embed script's data-identity-token attribute. The widget exchanges it for a session at chat.onpilot.ai/api/v1/embed/resolve.
REST
Conversation REST API
Drive conversations from your backend instead of (or in addition to) the embed widget. Useful for batch automations, server-rendered chat surfaces, or custom UI on top of the same agent.
Iframe protocol
postMessage events
The widget renders inside an iframe and exchanges typed postMessage events with the host page — for token rotation, page context, theme sync, and lifecycle. The full event catalog (parent ↔ iframe, payloads, when each fires) lives on its own page.
See postMessage protocol for every onpilot:* event the iframe sends and accepts, including how to reach the iframe from outside the React SDK.
Changelog
SDK changelog
Both packages version together. Breaking changes are called out in the migration notes.
v0.3.0 — current
- Breaking:
externalOrgIdis renamed tocopilotIdacrosssignIdentityToken, the JWT claim (copilot_id), and the embed URL query param. resolve()now returnscopilotIdon the session object.- Identity-token errors are explicit:
copilotId is required.
Migrate: rename every externalOrgId argument to copilotId. If you sign JWTs by hand, change the claim name from external_org_id to copilot_id. If you build the embed URL by hand, swap ?orgId= for ?copilotId=.
v0.2.0
- Initial public preview.
- Used
externalOrgIdto bind an agent — replaced bycopilotIdin v0.3.0.