> ## Documentation Index
> Fetch the complete documentation index at: https://synapse-docs.apart.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Browser and React SDK

> Render participant journeys with short-lived, evaluation-scoped tokens.

# Browser, React, embedded, and hosted

Render an assessment using a token scoped to one participant session—never an
app or environment credential.

<Warning>
  The only Synapse credential allowed in browser JavaScript is a short-lived
  `spt_` participant token. Keep environment keys server-side, and handle
  `shr_` report-share tokens only in the separate controlled report-view flow.
</Warning>

<CardGroup cols={2}>
  <Card title="Controller" icon="sliders">
    Pinned consent, next-question state, answer/unknown/decline, pause/resume,
    completion, and callbacks.
  </Card>

  <Card title="Embedded renderer" icon="code">
    Dependency-free UI mounted in your DOM with your controller and surrounding
    brand.
  </Card>

  <Card title="Hosted renderer" icon="window-maximize">
    A hardened iframe handoff using the server-returned hosted URL and a
    fragment token.
  </Card>

  <Card title="React adapter" icon="atom">
    An external-store hook that keeps rendering separate from the transport
    lifecycle.
  </Card>
</CardGroup>

## Embedded journey

```typescript theme={null}
import {
  createParticipantClient,
  createParticipantSessionController,
  MemoryParticipantQueueStorage,
} from "@apart-ai/synapse/participant";
import { mountEmbeddedParticipant } from "@apart-ai/synapse/participant/embedded";

const client = createParticipantClient({
  baseUrl: SYNAPSE_API_URL,
  participantToken,
});
const controller = createParticipantSessionController({
  client,
  queueKey: `evaluation:${opaqueEvaluationRef}`,
  storage: new MemoryParticipantQueueStorage(),
  consent: {
    beforeStart: async (session) => showConsent(session.consent.notice_text),
  },
  onComplete: (report) => renderResult(report),
});

const mounted = mountEmbeddedParticipant(
  document.querySelector("#synapse")!,
  { controller },
);

mounted.destroy();
controller.dispose();
```

## Hosted journey

```typescript theme={null}
import { mountHostedParticipant } from "@apart-ai/synapse/participant/hosted";

const hosted = mountHostedParticipant(container, {
  hostedUrl: session.hosted_url!,
  baseUrl: PUBLIC_SYNAPSE_WEB_ORIGIN,
  onComplete: (evaluationId) => showCompletion(evaluationId),
  onReport: (report) => renderReport(report),
});

hosted.destroy();
```

## Consent and queue safety

* The controller sends the server-pinned `consent_accepted` event before any
  restored or new participant traffic.
* `mountEmbeddedParticipant` starts the controller. Do not call `start()` a
  second time after mounting.
* Use `MemoryParticipantQueueStorage` by default. Local storage can retain
  assessment content in clear text and needs an explicit privacy review.
* Use an opaque evaluation reference as the queue key—never the participant
  token, an external ID, or a report token.
* `skip` records unknown; `decline` records an explicit refusal. Neither is
  imputed as a negative answer.
* Call `dispose()` and destroy the renderer when the host view unmounts.
