Live showcase demos
The marketing site can host live demos that connect to VoiceThere-owned projects — a landing-page voice chat, a showcase catalog, and a shared-world board where visitors spawn objects other visitors can see. Demos use the same browser client and session API as production embeds; visitors never send a forgeable project header.
Try the live demos
- Showcase catalog — voice agent, shared world, and links to related docs.
- Home — scroll to Live voice demo or use the floating chat launcher.
- Shared world — connect and spawn circles on a multiplayer board.
Deep links and QR codes
Marketing pages use query params to open demos without scrolling to a hash anchor. URLs are built from NEXT_PUBLIC_SITE_URL so QR codes work on phones even when you preview the site on localhost.
/?chat=1opens the floating voice chat panel (visitor taps Connect when ready)./?chat=1&connect=1opens the panel and auto-connects once demo config is loaded. The Live voice demo section shows a QR for this URL./showcase/shared-world?connect=1opens the shared board and auto-connects once. The page includes a QR and an Open in a new window button that launches the same URL in a separate tab for side-by-side testing.
Landing chat
The floating Chat launcher on the home page and showcase routes loads public demo config from GET /api/public/showcase-demos. When voice demo env vars are set, Connect provisions a session with the returned projectId, clientKey, and sessionApiBase — the same pattern as the dashboard project chat panel and embed snippet. Speech and text events appear in the panel log.
When voice env vars are empty, the launcher stays visible and shows Live demo is not configured — CI and local dev stay green without secrets.
Shared world
The shared-world page connects with the world demo target from the same public API. Objects stay synced across browser sessions and tabs. Visitors click Connect, then Spawn to send { "type": "register" } to the agent over the data channel. Click an object on the board to select its id, then use Remove to send { "type": "remove", "objectId": <id> } and drop that object from the live world. The board tracks up to 25 live objects — spawn is disabled when the world is full. Object positions sync via binary messages (game-sync protocol).
Stock template: deploy the game-sync agent bundle on the world demo project. With project Redis enabled, game-sync stores world state in Redis (game-sync:world) so every visitor sees the same objects — even across warm-pool workers. Set these on the world project:
- Enable project Redis (
redis_enabled true) so the agent receivesAGENT_REDIS_URL. Then redeploy. - Set
shared_child_per_session true, then redeploy. With project Redis this is not required for a shared board — Redis already syncs across runner instances — but it is strongly recommended so many sessions share one child and fewer Redis connections. Advanced defaults this to false (voice isolation). - Use data-only mode for the world project so the browser waits on data channels rather than microphone tracks.
- Keep warm pool on (Advanced default). Redis backs the world buffer (cap 25 objects); visitors click an object to select it, then Remove sends
{ "type": "remove", "objectId": <id> }.
On Free, Budget, and Budget+ only one runner instance runs, so there is nothing to sync across instances. Those tiers do not use project Redis — keep shared_child_per_session true so clients on that instance share the in-memory board (those tiers already default it on). Click Spawn or Remove only after the status line shows the session is ready — both talk on the control data channel.
Landing chat (voice-showcase)
The marketing landing chat runs the voice-showcase template: a greeting, optional name, then a text menu (weather, count, recipe, fun fact). The agent speaks a short prompt and sends the menu as a chat_reply on the data channel — the Live voice demo transcript shows it as [agent] lines. See Agent templates.
How demos are configured
Platform runtime env (names only — set in GitHub Environment staging / production, synced to K8s by deploy):
SHOWCASE_VOICE_PROJECT_ID+SHOWCASE_VOICE_CLIENT_KEY— landing chat and voice cardSHOWCASE_WORLD_PROJECT_ID+SHOWCASE_WORLD_CLIENT_KEY— shared-world boardSHOWCASE_SESSION_API_BASE(optional) — overrides the public sessions API base; defaults to the site's normal sessions URL
Each demo is active only when both project id and client key are non-empty. Empty values mean that demo shows unavailable copy — never a crash.
Client key + project
The browser uses the client API key as a Bearer token on startSession. The platform resolves tenant scope from that key — visitors do not send X-Project-Id or pick a project id from the URL. The public API returns the project id that matches the configured client key; the UI passes that id to the client library together with the same key.
Mint a clientAPI key per demo project in the VoiceThere dashboard. Allow browser origins for the marketing hostname on that project's CORS list (dashboard origin is typically already included). Deploy agents before enabling demos:
- Voice demo — voice-showcase template
- World demo — game-sync. On Advanced:
redis_enabled true(sync across workers) andshared_child_per_session true(strongly recommended: fewer Redis connections; not required for correctness). On Free, Budget, and Budget+: no Redis and one runner —shared_child_per_sessionmust stay true so clients share the in-memory board. Alwaysdata_only true; keep warm pool on when the tier allows it. Redeploy after changing settings.
See also Browser client, Agent templates, and Inbound webhooks for related building blocks linked from the showcase catalog.