REST API ↗
API reference

Hooks

The headless surface from @dialogueai/react. Hooks are thin reactive views onto the core; they hold no state of their own.

A styled drop-in only needs useInterview(). The rest exist to drive custom UIs. For the exact shape of every referenced type (Study, ParticipantUpdate, ScreenerQuestion, TranscriptSegment, …) see the Types reference — the hook signatures here are abbreviated for readability.

Lifecycle

useInterview(studyId?)

The top-level lifecycle hook, the only one a drop-in needs. Passing studyId auto-opens the study on mount.

ts
{
  phase: Phase;
  study: Study | null;
  // The error EVENT payload — not the DialogueError class. No `status`/`raw`.
  error: { code: ErrorCode; message: string; recoverable: boolean } | undefined;
  completionToken: string | null;   // null even on `completed` until end-tokens ship
  start(): void;        // deviceCheck → connecting
  end(): void;          // end a live interview
  retry(): void;        // retry a recoverable error
  on: <K>(event: K, cb) => Unsubscribe;
}

useDialogue()

Coarse provider/SDK status plus the authenticated userId and the underlying core.

ts
{ status: 'loading' | 'ready' | 'error'; userId: string | null; error; core }

useStudy()

The loaded study, its public config, and the media requirements (camera/mic/screen).

ts
{ study; studyPublic; requirements; isLoading: boolean; error }

Journey steps

useConsent()

Drives the consent phase. accept() creates the interview record and loads the screener.

ts
{
  accepted: boolean;
  accept(consentId?: string): void;  // creates the interview + fetches screener
  decline(): void;
  showCompany: boolean;
  company: Company | null;
  hasScreener: boolean;
}

useParticipantProfile()

Collects profile fields with an immediate per-step PATCH. Fields include firstName, lastInitial (a single char, not a last name), email, gender, dob, and location.

ts
{
  profile: ParticipantUpdate;
  update(fields: ParticipantUpdate): Promise<void>;  // immediate PATCH
  next(): void;                                       // advance past profile
  isSaving: boolean;
  error: unknown;
}

useScreener()

The screener question flow with eligibility. submit() advances through questions and, on the last one, submits all responses.

ts
{
  hasScreener: boolean;
  questions; currentIndex; question;
  answer: string[];
  setAnswer(optionId: string): void;
  setInput(optionId: string, text: string): void;   // custom "other" text
  canContinue: boolean;
  canGoBack: boolean; back(): void;
  submit(): Promise<void>;   // advances; on last question, submits responses
  screenedOut: boolean;
  redirectUrl: string | null;
}

useAnonymousNames(locale)

Up to 10 locale-appropriate pseudonyms for the anonymous name picker. The argument is AnonymousNamesLocale — a lowercase code ('en', 'es', 'ja', …), not the uppercase DialogueLocale. Passing 'EN' will not match.

ts
(locale: AnonymousNamesLocale) => { names: string[]; isLoading: boolean; error: unknown }

Media & connection

useConnection()

LiveKit connection state and link quality. LiveKit auto-reconnects, so reconnect() is a no-op placeholder. Host code reaches the connection only through this hook.

ts
{ state: 'idle' | 'connecting' | 'connected'; quality: ConnectionQuality; reconnect() }

useMediaControls()

In-call mic / camera toggles. Camera state is derived from the published local track.

ts
{
  cameraOn: boolean; micMuted: boolean;
  setCameraEnabled(enabled: boolean): Promise<void>;
  setMicEnabled(enabled: boolean): Promise<void>;
  toggleCamera(): void; toggleMic(): void;
}

useScreenShare()

Per-gesture screen sharing. When a study requires it, connecting holds until confirm() publishes the share.

ts
{
  active; supported; usable; required; awaiting;
  confirm(): Promise<void>;   // satisfies a required-share gate, then goes live
  start(audio?: boolean): Promise<void>;
  stop(): Promise<void>;
}

useRecording()

Read-only recording state (recording is server-side) with a live elapsed timer.

ts
{ recording: boolean; durationSecs: number }

useDeviceCheck()

Live mic VU meter, camera preview track, and device enumeration for the device-check screen.

ts
{ vuLevel: number; videoTrack; devices: MediaDeviceInfo[]; selectedDeviceId; selectDevice }

Locale, agent, feedback

useLocale()

The active locale (undefined until resolved). Locks at interview creation; set() is a no-op after that. See the 17 locale codes and the default-resolution rule.

ts
{ locale: DialogueLocale | undefined; available: DialogueLocale[]; locked: boolean; set(l: DialogueLocale): void }

useAgent()

Advanced: AI-agent speaking state, live transcript, and the current study section.

ts
{ speaking: boolean; transcript: TranscriptSegment[]; sectionIndex: number; on }

useFeedback()

Submit post-interview feedback.

ts
{ submit({ title, description, currentUrl? }): Promise<void>; isSubmitting; error }

useTelemetry()

Emit a lifecycle telemetry event (recorded as a breadcrumb).

ts
(event: { type: string; [k]: unknown }) => void

Browser capability

useDevicePermissions()

Camera + microphone permission state and a request trigger (not screen share). Seeds from the Permissions API where supported.

ts
{
  camera: 'prompt' | 'granted' | 'denied';
  microphone: 'prompt' | 'granted' | 'denied';
  request(opts?: { audio?: boolean; video?: boolean }): Promise<void>;
}

usePreflight()

One-shot capability check before consent. A non-empty blocking array means the browser can’t run the interview (no getUserMedia, no WebRTC, or a nested iframe without allow=).

ts
{ capabilities: { hasUserMedia; hasDisplayMedia; hasRTC }; blocking: string[] }

Low-level access

For advanced cases, the store and context are exposed directly:

ts
import { useCoreState, useMediaState, useDialogueContext } from '@dialogueai/react';

const core  = useCoreState();   // full CoreState snapshot (re-renders on change)
const media = useMediaState();  // MediaState: quality, speaking, transcript, tracks…
const { core, controller, media, reporter } = useDialogueContext();
splitName(name, anonymous?) is exported to build { firstName, lastInitial } from a display name the normative way.