> ## Documentation Index
> Fetch the complete documentation index at: https://developer.suki.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Headless Web SDK Quickstart

> Install `@suki-sdk/platform-react`, authenticate with `useAuth`, and run your first ambient recording in a React app

This guide walks you through setting up the Suki Headless Web SDK in your React application, from installation to creating your first ambient recording session.

**What you will do**

1. **Install** `@suki-sdk/platform-react` in your React project.
2. **Wrap** your app with **`PlatformClient`** and **`PlatformClientProvider`** at the root so all SDK hooks share one client.
3. **Authenticate** with **`useAuth`** inside that tree so users are signed in and tokens are available.
4. **Create** an ambient session with `useAmbient`, then **control recording** with `useAmbientSession` (start, pause, resume, submit, and optional context).
5. **Wire up** a minimal end-to-end flow using the complete example as a reference.

<Tip>
  **Using an AI coding tool?**

  Copy the prompt below to point your agent at the Ambient skill and [Documentation MCP](/documentation/references/mcp). For every task skill, refer to [AI coding tools](/documentation/references/ai-coding-tools).

  <Prompt description="Fetch the Ambient skill and connect the documentation MCP." icon="gear" iconType="regular" actions={["copy", "cursor"]}>
    Build ambient clinical documentation with Suki for Partners.
    Fetch the Ambient build skill:
    [https://developer.suki.ai/.well-known/agent-skills/suki-ambient/SKILL.md](https://developer.suki.ai/.well-known/agent-skills/suki-ambient/SKILL.md)
    Connect the documentation MCP for page search:
    [https://developer.suki.ai/documentation/references/mcp](https://developer.suki.ai/documentation/references/mcp)
  </Prompt>
</Tip>

## Prerequisites

For the rest of this documentation, we assume the following setup is complete:

* You run a **React 18+** app with a standard bundler (Vite, Webpack, or Next.js).
* You have received your `partnerId` from Suki.
* Your host URLs are on the Suki allowlist.
* Your partner configuration in the Suki Platform points to your correct JWKS endpoint.
* Your JWT token contains the key that you specified as your **User identifier field**.
* You can request microphone access over **HTTPS** in production (and set iframe `allow` attributes if your app is embedded).

Refer to the [Prerequisites](/headless-web-sdk/prerequisites) guide for the full checklist.

## Create your first Headless Web SDK Ambient session

<Steps>
  <Step title="Install the Package">
    Install the Suki Headless Web SDK package in your React project.

    <CodeGroup title="Install the @suki-sdk/platform-react Package">
      ```shell pnpm theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
      pnpm add @suki-sdk/platform-react
      ```

      ```shell npm theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
      npm install @suki-sdk/platform-react
      ```

      ```shell yarn theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
      yarn add @suki-sdk/platform-react
      ```
    </CodeGroup>

    For detailed setup instructions, refer to the [Installation guide](/headless-web-sdk/installation).
  </Step>

  <Step title="Configure the Platform Client">
    Create a single **`PlatformClient`** instance and wrap your entire application with **`PlatformClientProvider`**. Hooks such as `useAuth`, `useAmbient`, and `useAmbientSession` must run under this provider.

    ```tsx React expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
    import { PlatformClient, PlatformClientProvider } from '@suki-sdk/platform-react';

    const client = new PlatformClient({
      env: "staging",
      enableDebug: true,
      logLevel: "error"
    });

    function App() {
      return (
        <PlatformClientProvider client={client}>
          <YourApp />
        </PlatformClientProvider>
      );
    }
    ```
  </Step>

  <Step title="Authenticate with useAuth">
    After the provider wraps your app, use **`useAuth`** in a child component (for example **`YourApp`**). This hook manages user identity and provides access tokens needed for all SDK operations.

    ```tsx React expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
    import { useAuth } from '@suki-sdk/platform-react';

    function YourApp() {
      const {
        isLoggedIn,
        isPending,
        error,
        login
      } = useAuth({
        partnerId: 'your-partner-id', // Required: Replace with your actual partner ID
        partnerToken: 'your-partner-token', // Required: Replace with your actual partner token
        autoRegister: true, // Optional: Automatically register users if they don't exist
        loginOnMount: true, // Optional: Sign in automatically when component mounts
        providerName: 'Dr. John Doe', // Required for auto-registration
        providerOrgId: 'org-123', // Required for auto-registration
        providerSpecialty: 'FAMILY_MEDICINE' // Required for auto-registration
      });

      if (isPending) {
        return <div>Signing in...</div>;
      }

      if (error) {
        return <div>Error: {error.message}</div>;
      }

      if (!isLoggedIn) {
        return <button onClick={login}>Sign In</button>;
      }

      return <div>Ready to use Suki Headless Web SDK</div>;
    }
    ```

    <Note>
      If you set `autoRegister: true`, you must provide `providerName`, `providerOrgId`, and `providerSpecialty`. If you prefer manual registration, set `autoRegister: false` and use the `registerUser` method. See the [Authentication hook guide](/headless-web-sdk/guides/hooks/auth-hook) for more details.
    </Note>
  </Step>

  <Step title="Create an Ambient Session">
    Once authenticated, create an ambient session using the `useAmbient` hook. This creates a session container that you'll use for recording.

    ```tsx React expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
    import { useEffect } from 'react';
    import { useAmbient } from '@suki-sdk/platform-react';

    function SessionCreator({ onSessionReady }) {
      const {
        ambientSessionId,
        session: { create, isPending, isSuccess, error }
      } = useAmbient();

      // Create session when component mounts
      useEffect(() => {
        create({ encounterId: 'your-encounter-id' });
      }, [create]);

      // Pass session ID to parent when ready
      useEffect(() => {
        if (isSuccess && ambientSessionId) {
          onSessionReady(ambientSessionId);
        }
      }, [isSuccess, ambientSessionId, onSessionReady]);

      if (isPending) {
        return <div>Creating session...</div>;
      }

      if (error) {
        return <div>Error: {error.message}</div>;
      }

      return null;
    }
    ```

    <Note>
      You must wait for `isSuccess` to be `true` before attempting to use the `ambientSessionId`. Passing an undefined ID to the recording hooks will cause errors.
    </Note>
  </Step>

  <Step title="Manage Recording">
    Use the `useAmbientSession` hook to control recording. This hook provides methods to start, pause, resume, and submit recordings, along with session status.

    ```tsx React expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
    import { useState } from 'react';
    import { useAmbientSession } from '@suki-sdk/platform-react';

    function Recorder({ sessionId }) {
      const {
        start,
        pause,
        resume,
        submit,
        sessionStatus,
        sessionType, // [!code ++] New in v0.2.2
        setSessionContext
      } = useAmbientSession({
        ambientSessionId: sessionId,
        onAudioChunkAvailable: (chunk) => {
          // Optional: Use audio chunks for visualization
          console.log('Audio chunk received:', chunk);
        }
      });

      // sessionStatus is only "created" | "submitted" | "completed" | "cancelled".
      // Track recording vs paused locally.
      const [phase, setPhase] = useState('idle'); // 'idle' | 'recording' | 'paused'

      const handleStart = async () => {
        await start();
        setPhase('recording');
        await setSessionContext({
          patient: {
            dob: '1980-01-15',
            sex: 'M'
          },
          provider: {
            specialty: 'FAMILY_MEDICINE',
            role: 'Attending Physician'
          },
          visit: {
            visit_type: 'Follow-up',
            encounter_type: 'Office Visit',
            reason_for_visit: 'Chest pain evaluation',
            chief_complaint: 'Chest pain'
          }
        });
      };

      const handlePause = async () => {
        await pause();
        setPhase('paused');
      };

      const handleResume = async () => {
        await resume();
        setPhase('recording');
      };

      return (
        <div>
          <h3>Status: {sessionStatus}</h3>
          {sessionType === 'offline' && ( // [!code ++:2] added in v0.2.2
            <p>Session will sync when online</p>
          )}

          {sessionStatus === 'created' && phase === 'idle' && (
            <button type="button" onClick={handleStart}>Start Recording</button>
          )}

          {sessionStatus === 'created' && phase === 'recording' && (
            <>
              <button type="button" onClick={handlePause}>Pause</button>
              <button type="button" onClick={submit}>Finish & Submit</button>
            </>
          )}

          {sessionStatus === 'created' && phase === 'paused' && (
            <>
              <button type="button" onClick={handleResume}>Resume</button>
              <button type="button" onClick={submit}>Finish & Submit</button>
            </>
          )}
        </div>
      );
    }
    ```

    <Tip>
      Always use `setSessionContext` to provide relevant patient or encounter details. This context acts as a hint for the AI, resulting in significantly higher quality clinical notes.
    </Tip>
  </Step>

  <Step title="Complete Example">
    Here's a complete example that brings everything together:

    ```tsx React expandable theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
    import { useState, useEffect } from 'react';
    import {
      PlatformClient,
      PlatformClientProvider,
      useAuth,
      useAmbient,
      useAmbientSession
    } from '@suki-sdk/platform-react';

    const client = new PlatformClient({
      env: 'staging',
      enableDebug: true,
      logLevel: 'error'
    });

    function App() {
      return (
        <PlatformClientProvider client={client}>
          <SukiRecorder />
        </PlatformClientProvider>
      );
    }

    function SukiRecorder() {
      const [sessionId, setSessionId] = useState(null);

      // Step 1: Authenticate (under PlatformClientProvider)
      const { isLoggedIn, isPending: authPending } = useAuth({
        partnerId: 'your-partner-id', // Required: Replace with your actual partner ID
        partnerToken: 'your-partner-token', // Required: Replace with your actual partner token
        autoRegister: true, // Optional: Automatically register users if they don't exist
        loginOnMount: true, // Optional: Sign in automatically when component mounts
        providerName: 'Dr. John Doe', // Required for auto-registration
        providerOrgId: 'org-123', // Required for auto-registration
        providerSpecialty: 'FAMILY_MEDICINE' // Required for auto-registration
      });

      // Step 2: Create session
      const {
        ambientSessionId,
        session: { create, isSuccess: sessionCreated }
      } = useAmbient();

      useEffect(() => {
        if (isLoggedIn && !sessionCreated) {
          create({ encounterId: 'your-encounter-id' });
        }
      }, [isLoggedIn, sessionCreated, create]);

      useEffect(() => {
        if (ambientSessionId) {
          setSessionId(ambientSessionId);
        }
      }, [ambientSessionId]);

      // Step 3: Manage recording
      // sessionStatus is only "created" | "submitted" | "completed" | "cancelled".
      // Track recording vs paused in local state (see AmbientSessionStatus type).
      const {
        start,
        pause,
        resume,
        submit,
        sessionStatus,
        sessionType, // New in v0.2.2
        setSessionContext
      } = useAmbientSession({
        ambientSessionId: sessionId
      });
      const [phase, setPhase] = useState('idle'); // 'idle' | 'recording' | 'paused'

      async function handleStart() {
        await start();
        setPhase('recording');
        await setSessionContext({
          patient: { dob: '1980-01-15', sex: 'M' },
          provider: { specialty: 'FAMILY_MEDICINE', role: 'Attending Physician' },
          visit: {
            visit_type: 'Follow-up',
            encounter_type: 'Office Visit',
            reason_for_visit: 'Medication review'
          }
        });
      }

      async function handlePause() {
        await pause();
        setPhase('paused');
      }

      async function handleResume() {
        await resume();
        setPhase('recording');
      }

      if (authPending) {
        return <div>Authenticating...</div>;
      }

      if (!isLoggedIn) {
        return <div>Please sign in</div>;
      }

      if (!sessionId) {
        return <div>Creating session...</div>;
      }

      return (
        <div>
          <h2>Recording Status: {sessionStatus}</h2>
          {sessionType === 'offline' && ( // added in v0.2.2
            <p>Session will sync when online</p>
          )}

          {sessionStatus === 'created' && phase === 'idle' && (
            <button type="button" onClick={handleStart}>Start Recording</button>
          )}

          {sessionStatus === 'created' && phase === 'recording' && (
            <>
              <button type="button" onClick={handlePause}>Pause</button>
              <button type="button" onClick={submit}>Submit</button>
            </>
          )}

          {sessionStatus === 'created' && phase === 'paused' && (
            <>
              <button type="button" onClick={handleResume}>Resume</button>
              <button type="button" onClick={submit}>Submit</button>
            </>
          )}
        </div>
      );
    }
    ```
  </Step>
</Steps>

## Available tutorials

<div className="hp-io-method-grid tut-hub-card-grid">
  <a className="hp-io-method-card tut-hub-method-card" href="/documentation/tutorials/headless-ambient-hooks">
    <div className="tut-hub-card-media" aria-hidden="true" />

    <div className="hp-io-method-card-body">
      <span className="hp-wn-badge hp-wn-badge-new">Headless Web SDK</span>
      <h3 className="hp-io-method-card-title">Build a Headless Ambient Recorder</h3>

      <p className="hp-io-method-card-desc">
        Use Headless hooks to sign in, create an ambient session, and control recording in a custom React UI.
      </p>

      <div className="hp-io-method-card-meta tut-hub-card-foot" aria-label="20 min, Intermediate">
        <div className="tut-hub-card-foot-meta">
          <span className="hp-io-method-card-meta-time">20 min</span>
          <span className="tut-hub-level">Intermediate</span>
        </div>
      </div>
    </div>
  </a>
</div>

## Next steps

Refer to the following guides to learn more:

<Icon icon="file-lines" iconType="solid" /> [Platform client and provider](/headless-web-sdk/api-reference/platform-client) - Understand how to use `PlatformClient` and `PlatformClientProvider`

<Icon icon="file-lines" iconType="solid" /> [Authentication hook](/headless-web-sdk/guides/hooks/auth-hook) - Learn more about authentication options and token management

<Icon icon="file-lines" iconType="solid" /> [Create ambient session](/headless-web-sdk/guides/hooks/ambient-hook) - Understand session creation in detail

<Icon icon="file-lines" iconType="solid" /> [Manage ambient session](/headless-web-sdk/guides/hooks/ambient-session-hook) - Explore all recording controls and session context

<Icon icon="file-lines" iconType="solid" /> [Error handling](/headless-web-sdk/guides/error-handling) - Learn how to handle errors gracefully

<Icon icon="file-lines" iconType="solid" /> [Offline mode](/headless-web-sdk/guides/offline-mode) - Understand how the SDK handles network interruptions
