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

# Observe-only co-browse in 15 minutes

> The shortest path from widget install to an agent watching a visitor's live page: keep the default masking, let the visitor start the session, and join from the Inbox. No guided control, no custom code.

# Observe-only co-browse in 15 minutes

Observe-only co-browse is the pattern most teams want first: the agent sees what the customer sees, in real time, and nothing the agent types or clicks can reach the visitor's page. This guide stands up exactly that posture, end to end, in about 15 minutes.

It is the laser-focused counterpart to [From support widget to resolution](/guides/support-widget-to-resolution). That guide assumes your web-chat stack is already embedded and runs the full support loop around it; this one assumes nothing beyond a public page and gets one observe-only session live. When you later want the agent to highlight, scroll, or fill fields, the consent model and guided-control packets are covered in [Co-browse: live screen assistance](/guides/cobrowse-live-assist).

| Step | What you do | Time |
| - | - | - |
| 1 | Decide when observe is enough | 1 min |
| 2 | Pick the session shape (defaults are fine) | 2 min |
| 3 | Put the widget on the page and let the visitor consent | 5 min |
| 4 | Confirm the security controls | 5 min |
| 5 | Join from the Inbox and run the session | 2 min |

## When to co-browse vs observe

Reach for observe-only when the diagnostic value is in what the visitor sees right now: a checkout that renders differently than your staging env, a form abandoned midway, an error message the visitor can't describe. Because the capture is the page's DOM (not a pixel stream), an observe-only session on a public page is low-risk by construction: the visitor's own browser redacts inputs before anything is published, off-screen content is never transmitted, and the agent has no input path into the page at all.

Observe-first is a viable default posture, not just a fallback:

* **It is the platform default.** A session starts observe-only unless the visitor explicitly grants more; `control` defaults to `false` on the start call, and an agent request can never exceed the visitor's grant.
* **It never escalates silently.** An observe-only session cannot be upgraded to guided control mid-session. If the agent needs to fill a field, the visitor re-starts the session with `control: true` and consent is re-confirmed.
* **It works on any public page the widget is on.** No authenticated area, no screen-share plugin, no share link.

When the value of the session depends on the agent *doing* something on the page (form coaching, walking a multi-step setup), that is the guided-control posture; read the [live-assist guide](/guides/cobrowse-live-assist) for that loop. Start observe-only anyway: it proves the pipe, and the visitor can grant control on the next session.

## Pick the session shape

Three dials define a session, and the defaults are the right first answer:

* **Duration.** Join tokens expire after 30 minutes (`expires_in` on the join response); a reconnecting agent re-mints by calling join again, which is idempotent on a live session. The session itself stays open until either side ends it, so a long troubleshooting conversation doesn't drop the mirror at the token boundary.
* **Capture granularity.** The visitor's browser publishes DOM snapshots of the page they are on, plus incremental mutations between snapshots. There is no pixel stream and no off-screen capture: the agent's mirror is exactly the visible DOM of the current page.
* **Input masking.** The default policy masks every `<input>`, `<textarea>`, and `<select>` value, blocks `tel`, `email`, and `cc` fields by type, and always blocks password and card-number/CVC fields no matter what you configure. For an observe-first rollout, keep the defaults: the agent sees layout, labels, and validation states, which is what "see what the customer sees" actually needs.

Relax masking only per-selector and only when a specific support flow demands it; the policy fields are documented in [Co-browse: live screen assistance](/guides/cobrowse-live-assist#set-the-capture-time-privacy-policy-first) and editable without an API client in the dashboard panel below.

## Wire the widget callback

A session can only exist on a page that carries the widget, and consent is collected synchronously by the widget at start time: the visitor taps the co-browse action inside the conversation, and that same request starts the session. There is no separate consent handshake to build.

Put the widget on the pages your visitors use (if [support-widget-to-resolution](/guides/support-widget-to-resolution) is your roadmap, this snippet is the piece of it you need today):

```html theme={null}
<script
  async
  src="https://api.orbit.devotel.io/widget/v1/orbit-chat.js"
  data-public-key="pk_live_your_widget_key"
></script>

<orbit-chat></orbit-chat>
```

The practical consent choreography is one chat exchange:

1. The agent asks in the open conversation: "Can I see what you're looking at?"
2. The visitor taps the co-browse action in the widget. That tap is the consent capture and the session start in one synchronous step; the widget calls the start endpoint with its own visitor token and the chosen consent ceiling (`control` omitted, i.e. observe-only, unless the visitor grants more).
3. The session is stamped on the conversation and fans out to your Inbox in real time.

Keep the start in the widget. The visitor-side call authenticates with the visitor's session token; your API key is for the operator verbs only (join, end, privacy policy), as listed in the [Co-browse API reference](/api-reference/cobrowse). If the visitor closes the widget or ends the session, the mirror stops; a re-start is a fresh consent capture, never a revival of the old room.

If you embed the SDK programmatically instead of the hosted bootstrap, the same widget surface ships as the `./widget` subpath of the web SDK (`@devotel-orbit/web`).

## Security controls

Everything below is enforced at capture time, in the visitor's browser, before a packet is published; the server never sees an un-redacted DOM.

* **Snapshot masking.** Every DOM snapshot and every mutation packet passes through your privacy policy before upload. Masked values travel as mask placeholders, so the interval at which snapshots upload only controls how fresh the mirror is, never what it contains. Tighten content with masking, not cadence.
* **Regions that are never mirrored.** Password fields and card-number/CVC fields are always excluded, and you can add regions two ways: `block_selectors` in the privacy policy (via `PUT /api/v1/cobrowse/privacy` or the dashboard panel), or the `data-cobrowse-block` attribute on any element. A blocked subtree is neither published nor targetable.
* **Origins.** A session can only start from an origin where your widget is installed and enabled; the same allowed-origins list that governs the chat widget governs co-browse, because the widget is the only entry point. Review it in the [native chat widget channel config](/guides/native-chat-widget-channel-config) (see its Privacy & GDPR section) and in **Settings → Channels → Native chat** ([dashboard reference](/guides/settings-channels-native-chat)).
* **Scoped tokens.** The agent's join token is bound to exactly one {organization, conversation, session} room and expires after 30 minutes; it cannot be replayed against another tenant, thread, or session.
* **Revocation.** The visitor can end the session at any time from the widget; the mirror stops immediately. Ending from either side is terminal: the visitor re-initiates if the agent needs back in, which re-confirms consent.

The policy is tenant-owned: you set the masking posture, your DPO signs off on the blocked-region list, and the platform enforces the hard floor (passwords and card fields) beneath whatever you configure.

## The workflow

With the widget live and the policy confirmed, a session is two moves:

1. **Visitor starts.** The visitor taps co-browse in the widget while the conversation is open. The Inbox conversation is flagged **Co-browse available**.
2. **Agent joins.** Open the conversation in the Inbox and join. The flag flips to **Co-browse live** with the per-session consent indicator, and the agent's browser renders the visitor's page mirror, observe-only.

```bash theme={null}
# Agent joins (observe) — receives token, ws_url, room_name
curl -X POST https://api.orbit.devotel.io/api/v1/cobrowse/conv_abc123/join \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "control": false }'
```

The Inbox **End session** button ends the session and stamps who ended it; the visitor's widget shows the same outcome. End sessions on resolution rather than leaving them open: an ended session can never be re-joined, so the next start is always a fresh consent capture. Co-browse runs only on web-chat conversations; SMS, WhatsApp, voice, and email threads never carry a session.

If a session won't start or stalls, work the ladder in [Troubleshooting: co-browse session stuck](/troubleshooting/cobrowse-stuck); the usual first check is simply whether the page the visitor is on carries the widget script.

## See also

* [Co-browse: live screen assistance](/guides/cobrowse-live-assist) — the full consent model, guided-control packets, and the privacy policy reference
* [From support widget to resolution](/guides/support-widget-to-resolution) — the full-stack web-chat install this guide borrows the widget snippet from
* [Native chat widget channel config](/guides/native-chat-widget-channel-config) — allowed origins and the Privacy & GDPR section
* [Settings → Channels → Native chat](/guides/settings-channels-native-chat) — the dashboard panel for widget and masking settings
* [Co-browse API reference](/api-reference/cobrowse) — session, privacy, and control record shapes and error codes
* Web SDK `./widget` subpath (`@devotel-orbit/web`) — programmatic widget embed


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.