Skip to main content

Browser, React, embedded, and hosted

Render an assessment using a token scoped to one participant session—never an app or environment credential.
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.

Controller

Pinned consent, next-question or question-page state, answer/unknown/decline, pause/resume, completion, and callbacks.

Embedded renderer

Dependency-free UI mounted in your DOM with your controller and surrounding brand.

Hosted renderer

A hardened iframe handoff using the server-returned hosted URL and a fragment token.

React adapter

An external-store hook that keeps rendering separate from the transport lifecycle.

Embedded journey

Question pages

A custom UI can show up to five questions at once. Set pageSize (1 to 5) and the controller loads server-reserved pages from GET /v1/participant/next-batch instead of one question at a time.
  • snapshot.page holds the current page. It stays null until consent is accepted. snapshot.next mirrors its first question, so code that checks snapshot.next.complete keeps working.
  • submitPage sends the page’s responses in page order, usually in one request with the page’s question_viewed events, then loads the next page. batchSize (events per request, default 20) still applies: a page queues up to twice pageSize events, so a smaller batchSize, or older events queued ahead of the page, can split it across requests.
  • snapshot.submittedPage is the page’s batch_id from the moment its responses are queued until the next page loads or Synapse rejects the page. Show the page read-only while submittedPage === page.batch_id. It is part of the controller state, so it survives UI remounts.
  • Submitting the same page again with the same answers only retries delivery. Different answers reject with an Error and nothing is queued.
  • Offline responses stay queued, and the controller loads the next page once the queue is delivered.
  • If the answers were delivered but the next page failed to load, submitPage still resolves with the same page. snapshot.error says why, and the controller retries the load; a “Try again” button can call loadNextPage().
  • If Synapse rejects page events (409, 422, or nothing accepted), the controller drops every page event from the queue, reloads the current page, sets snapshot.error to a ParticipantPageRejectedError, and calls onError. This also happens during background delivery and for a queue restored after a reload, so show the “page was refreshed” notice whenever snapshot.error is a ParticipantPageRejectedError. submitPage rejects with it when its own delivery was rejected.
  • 401, 403, 404, or 410 mean the link no longer works. The queue is kept, the page is not reloaded, snapshot.status becomes "error", and submitPage rejects with the original ApiError.
  • Pages served by this server version never hold a question that another page question’s response could hide or show, so raw API clients can post a page’s responses in any order.
  • The embedded renderer always shows one question at a time.

Hosted journey

  • 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.