REST API ↗
Get started

Quickstart

Render a branded interview in a React app in four steps.

Before you begin

Three values come from the Dialogue dashboard (or your Dialogue contact). If you just want to see it run first, skip to degraded anonymous mode — it needs none of them.

ValueWhere it livesWhere you get it
studyIdA UUID for the study to runDashboard → the study you created
Secret key (sk_…)Server-side only — never ships to the browserDashboard → API keys
publishableKey (pk_…)Public; passed to the provider (reserved today)Dashboard → API keys
environment'production' (default) or 'staging'Pick per Dialogue env
The secret key never touches the browser. It lives only in your backend and is used to mint bootstrap tokens (step 2). The browser only ever sees the short-lived bootstrap token your endpoint returns.
  1. Install the packages

    The styled drop-in needs @dialogueai/react-ui and its peer @dialogueai/react. react 18 is a peer dependency.

    bash
    pnpm add @dialogueai/react @dialogueai/react-ui
  2. Expose a bootstrap-token endpoint

    Your backend exchanges your secret key for a Dialogue-signed bootstrap token. The SDK calls a function you provide; it never sees your secret. (See Authentication.)

    app/api/dialogue-token/route.tsts
    export async function POST() {
      const res = await fetch('https://api.dialogueai.com/sdk/bootstrap-tokens', {
        method: 'POST',
        headers: { Authorization: `Bearer ${process.env.DIALOGUE_SECRET_KEY}` },
      });
      // { bootstrapToken, expiresAt }
      return Response.json(await res.json());
    }
  3. Mount the interview

    Wrap your tree in <DialogueProvider> and drop in <Interview>. Import the stylesheet once.

    InterviewWidget.tsxtsx
    'use client';
    import { DialogueProvider } from '@dialogueai/react';
    import { Interview } from '@dialogueai/react-ui';
    import '@dialogueai/react-ui/styles.css';
    
    export function InterviewWidget() {
      return (
        <DialogueProvider
          publishableKey="pk_live_…"
          bootstrapTokenProvider={async () => {
            const res = await fetch('/api/dialogue-token', { method: 'POST' });
            return res.json(); // { bootstrapToken, expiresAt }
          }}
        >
          <Interview
            studyId="019e16c4-ce3f-7388-b236-24455b07e857"
            appearance={{ layout: 'floating' }}
          />
        </DialogueProvider>
      );
    }
  4. Handle completion

    onCompleted fires when the interview itself finishes (payload { interviewId, durationSeconds, completionToken }). onFinish fires later, when the participant clicks Finish to dismiss the widget. They are distinct: a participant can complete and then sit on the thank-you screen before dismissing.

    tsx
    <Interview
      studyId={studyId}
      onCompleted={({ interviewId, completionToken }) => {
        // completionToken may be null today (end-tokens not minted yet).
        // When present, send it to YOUR backend to verify — never trust the
        // client that an interview finished.
        void fetch('/api/dialogue-complete', {
          method: 'POST',
          body: JSON.stringify({ interviewId, completionToken }),
        });
      }}
      onFinish={() => router.push('/thank-you')}  // router: your app's router
    />
Server-side, the source of truth for whether someone completed is the Dialogue REST API (queried with your secret key), not the browser callback. Treat onCompleted as a UX signal; treat completionToken (once it ships) as something to verify on your backend, like a webhook signature.
That’s it. <Interview> renders exactly one screen per journey phase and drives every transition itself. You never manage phase state.

Running without a backend

Omit bootstrapTokenProvider and the SDK runs in degraded anonymous mode: it mints an anonymous session directly. Useful for local development and demos before publishable keys are wired up. Identity is not carried across studies in this mode.

tsx
<DialogueProvider baseUrl="/dlg" debug>
  <Interview studyId={studyId} />
</DialogueProvider>