Adapter
An OnboardAdapter is how BYO mode talks to your store. Helper: createLocalAdapter (demo). Hosted mode is used internally when you pass flowId + publishableKey and omit adapter.
Resolve order
- If
adapteris passed, use it for progress. Published config is still fetched whenflowIdandpublishableKeyare set (Path C). - Else if
flowIdandpublishableKeyare set, use Hosted progress. - Else fall back to
createLocalAdapter.
Required methods
getProgress(input) completeStep(input) skipStep(input) snooze(input) dismiss(input) resume(input) resetPersonal(input) reportOutcome(input)
Optional methods
unskipStep(input) deletes a skipped progress row so that optional step is incomplete again. The widget shows Undo only when this method exists. It uses the skip permission and does not uncomplete a complete row. Omit it and current BYO adapters keep compiling.
Pinned input
Mutations include revision, personalGeneration, workspaceGeneration, and requestId. Return AdapterResult with changed and acceptedTransitions. See progress.
reportOutcome
Called after evaluation with applicable required keys, item states, and requirementsSatisfied. Attach integration-reported summary metadata on your backend. See summaries.
BYO example
<Onboard
flowId="flw_..."
publishableKey={process.env.NEXT_PUBLIC_BSW_ONBOARD_PUBLISHABLE_KEY}
user={currentUser}
workspaceKey={workspace.id}
onEvent={(event, payload) => { /* analytics */ }}
adapter={{
getProgress: async (input) =>
fetch(`/api/onboard/progress?${new URLSearchParams(input as Record<string, string>)}`).then((r) => r.json()),
completeStep: async (input) =>
fetch("/api/onboard/progress", { method: "POST", body: JSON.stringify({ action: "complete", ...input }) }).then((r) => r.json()),
skipStep: async (input) =>
fetch("/api/onboard/progress", { method: "POST", body: JSON.stringify({ action: "skip", ...input }) }).then((r) => r.json()),
unskipStep: async (input) =>
fetch("/api/onboard/progress", { method: "POST", body: JSON.stringify({ action: "unskip", ...input }) }).then((r) => r.json()),
snooze: async (input) =>
fetch("/api/onboard/progress", { method: "POST", body: JSON.stringify({ action: "snooze", ...input }) }).then((r) => r.json()),
dismiss: async (input) =>
fetch("/api/onboard/progress", { method: "POST", body: JSON.stringify({ action: "dismiss", ...input }) }).then((r) => r.json()),
resume: async (input) =>
fetch("/api/onboard/progress", { method: "POST", body: JSON.stringify({ action: "resume", ...input }) }).then((r) => r.json()),
resetPersonal: async (input) =>
fetch("/api/onboard/progress", { method: "POST", body: JSON.stringify({ action: "resetPersonal", ...input }) }).then((r) => r.json()),
reportOutcome: async (input) =>
fetch("/api/onboard/outcomes", { method: "POST", body: JSON.stringify(input) }).then((r) => r.json()),
}}
/>