Skip to main content

Co-browse API

Co-browse is the real-time twin of session replay. When a customer is stuck on your site, they start a co-browse session from the native chat widget; a support agent then joins from the inbox to watch the customer’s live page and, when the customer grants control, highlight elements, scroll, and assist with form fields. The page DOM is mirrored over a data channel — it is not a screen share, so off-screen content the agent was never shown is never transmitted, and the visitor can revoke at any time. This page documents the operator half: reading the session state, joining the live session, ending it, configuring the capture-time privacy policy, and sending guided-control packets. The visitor starts and ends co-browse from the widget runtime — those calls are authenticated with the visitor’s widget token and are not part of this API key surface. Base path: /api/v1/cobrowse Authentication: API key (X-API-Key) or session JWT. Scopes & roles:
  • Reads (GET) require the conversations:read scope.
  • Writes — joining a session, ending it, updating the privacy policy, and sending a control packet — require the conversations:write scope and an owner, admin, or developer role.
A session is keyed by its conversationId — the conversation it belongs to. Sessions are tenant-scoped: you only ever see sessions on your own account’s conversations.

Using the SDKs

Prefer the typed client, but this page’s endpoint has no helper yet — the generic request() keeps auth/retries and the { data, meta } envelope identical:
Python (same call via the SDK’s escape hatch):
The Python SDK is core-scope — it wraps the 8 core resources (messaging, voice, contacts, campaigns, verify, numbers) and reaches everything else through the generic client.request() escape hatch above. See the Python SDK. Raw curl in the body of this page works identically. Full SDK index at SDK quickstart.

The session object

Every endpoint returns the current session under cobrowse, or null when the conversation has never started one.

Read the session state

Returns the current co-browse session stamped on the conversation, or null when no session has been started. The inbox detail panel polls this to decide whether to show the “Co-browse available” or “Co-browse live” affordance.
cobrowse is null when the conversation exists but carries no session. Requesting a conversation that isn’t in your account returns 404 NOT_FOUND. A malformed conversationId returns 422 VALIDATION_ERROR.

Join the session

Mints a data-channel join token for the agent so they can view — and, when the visitor granted control, guide — the customer’s live browser session. The call flips the session to active and stamps the agent and start time. Pass control: true to request guided control. The effective grant is the AND of your request and the visitor’s stored consent: if the visitor joined observe-only, the session can never be escalated to guided control, regardless of this flag. The grant is enforced when the token is minted, not just in the UI.
The body is optional; control defaults to false (observe-only).
Use token and ws_url to connect to the room with the orbit-media client SDK. The token expires after expires_in seconds (30 minutes); the SDK re-mints on reconnect by calling this endpoint again, which is idempotent on an already-active session — it re-stamps the agent without resetting started_at. control in the response is the effective grant after the visitor’s consent ceiling is applied.

End the session

Ends the co-browse session from the agent side: status becomes ended, with ended_at and ended_by: "agent" stamped. The call is idempotent — ending an already-ended session is a no-op and returns the same record. The visitor can independently end from the widget; either side ending stops the data room. To start co-browsing again, the visitor must re-initiate from the widget so consent is re-confirmed.
Returns 404 NOT_FOUND when the conversation — or its session — isn’t in your account.

Get/update the capture-time privacy policy

Co-browse mirrors the visitor’s live DOM to the agent’s browser over a data channel. The privacy policy decides what the capture client masks in the visitor’s page before it publishes a DOM packet, and doubles as the server-side guard on the control endpoint below — a selector or input type the policy blocks can never be captured or remotely controlled. The policy is default-deny: with nothing configured, every input is masked and tel, email, and cc input types are blocked. input[type="password"] and a small set of built-in payment/card selectors are always blocked and cannot be relaxed by this endpoint, regardless of what you send.
To update the policy:
The response echoes the merged policy under data.privacy. Selectors round-trip verbatim; omitted fields fall back to their default-deny values, not to whatever was previously stored. The change takes effect on the next co-browse session bootstrap for both the visitor and the joining agent — it does not retroactively change a session already in progress. PUT requires the conversations:write scope and an owner, admin, or developer role, same as joining or ending a session. A malformed body returns 422 VALIDATION_ERROR.

Send a guided-control packet

Broadcasts an agent-initiated highlight, scroll, or form_fill action into the co-browse data room so the visitor’s browser can render it. The target selector (and, for form_fill, the input_type) is checked against the tenant’s privacy policy above before anything is sent — a packet aimed at a blocked selector, an always-blocked region, or a password field is rejected and never reaches the visitor. Sending control requires the visitor to have granted control on this session; requesting it does not escalate an observe-only session.
A successful call returns 204 No Content — the packet was broadcast to the room. Every accepted form_fill is audit-logged; highlight and scroll are not, to keep the audit trail focused on packets that write a value into the visitor’s page.

See also