Skip to main content
Every Theo Browser session response includes an embed_url that renders the full Theo-branded browser chrome (URL bar, live indicator, auto-reconnect UI) in a third-party iframe. No SDK wiring, no manual CDP handling — point an <iframe> at the URL and ship.

Quick start

  1. Create a session from your backend (never expose your THEO_API_KEY to the browser):
  1. Drop the URL into an iframe on your frontend:
That’s it. The embed page handles:
  • Fetching the correct live view URL on first paint (no about:blank flash)
  • Listening for browserbase-disconnected postMessages
  • Auto-refetching and rekeying the iframe when the CDP target changes
  • Tight 10 s polling while disconnected, relaxed 30 s while healthy
  • A Theo-branded URL bar + live indicator + reconnect overlay

How the token works

embed_url is a signed, short-lived URL bound to (sessionId, userId):
  • Format: {APP_ORIGIN}/embed/browser/{sessionId}?token=<hmac>
  • Scope: the token is tied to a specific session AND the user who created it
  • Lifetime: 60 minutes (Theo Browser sessions hard-cap at 20 min, so this leaves headroom for keep_alive sessions)
  • Secret: signed with BROWSER_EMBED_TOKEN_SECRET on the server; never exposed to the client
  • Rotation: every GET /api/v1/browser/sessions/:id call mints a fresh token, so long-running dashboards can refresh the iframe on demand
A third party cannot forge a token for a session they don’t own — even if they guess the session id, HMAC validation fails.

Disconnect handling

The embed page already implements the full recovery protocol, but if you’re building a custom iframe wrapper, here is the exact contract:
Internally, the embed page force-refetches its live URL the moment this event fires. The server-side session manager bumps a monotonic live_view_version counter every time it resolves a fresh debugger URL — the iframe rekeys on version change, not URL equality, because BrowserBase can return the same URL string while silently swapping the underlying CDP page target.

Security posture

  • Iframe sandbox: allow-scripts allow-same-origin is the minimal set that keeps the DevTools frontend + CDP WebSocket alive. Adding allow-forms / allow-popups has no functional benefit and can trigger stray navigations that retarget the iframe out of the live view.
  • frame-ancestors *: the embed page sets Content-Security-Policy: frame-ancestors * so any origin can iframe it. If you want to restrict which origins can load the embed, terminate the iframe at your own CDN layer and apply your own header.
  • No credentials in the iframe: the embed page never sees your API key. It talks to a companion token-authenticated /embed/browser/:id/live route.

End the session

Always end the session from your backend when the user closes the iframe, otherwise you’re billed for the remaining wall-clock time: