Core concepts
The interview journey
The whole experience is a state machine. Every UI — styled or custom — is just a switch on the current phase.
The phases
useInterview().phase is one of the following. The core advances them; you render one screen per phase.
| Phase | Meaning |
|---|---|
idle | Provider mounted, nothing opened yet. |
bootstrapping | Authenticating (token exchange). |
ready | Authenticated, study not yet loaded. |
study | Fetching the study + its public config. |
consent | Showing consent; accept() creates the interview. |
creatingInterview | Creating the interview record. |
profile | Collecting participant profile fields. |
screener | Running the screener question flow. |
deviceCheck | Mic/camera preview before connecting. |
connecting | Joining the LiveKit room (may await screen share). |
live | The interview is running with the AI agent. |
ending | Wrapping up the call. |
processing | Server-side processing after the call. |
completed | Done — completionToken on the payload (may be null). |
screenedOut | Not eligible; optional redirect URL. |
studyClosed | Study not active or quota exceeded. |
alreadyCompleted | This participant already finished. |
aborted | Ended early (declined, unload, host abort). |
errored | A non-recoverable error occurred. |
Reading the phase
tsx
const { phase, study, start, end } = useInterview(studyId);
switch (phase) {
case 'consent': return <Consent />;
case 'screener': return <Screener />;
case 'deviceCheck': return <button onClick={start}>Start</button>;
case 'live': return <button onClick={end}>End</button>;
case 'completed': return <Thanks />;
// …
}Passing a
studyId to useInterview(studyId) auto-opens the study on mount. The styled <Interview> does this for you.Driving transitions
Most transitions are triggered by hook actions, not by you setting phase:
useConsent().accept()/decline()— leaveconsent.useParticipantProfile().next()— leaveprofile.useScreener().submit()— advance questions, then leavescreener.useInterview().start()— leavedeviceCheck→connecting.useInterview().end()— leavelive.
Terminal phases
completed, screenedOut, studyClosed, alreadyCompleted, aborted, and errored are terminal. To run the journey again, remount the provider (e.g. bump a React key) for a fresh core. Recoverable errors expose useInterview().retry().