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

# 嵌入 Theo Browser

> 只需一個 iframe，即可將實時 Theo Browser 會話嵌入到你自己的產品中。

每個 Theo Browser 會話響應都包含一個 `embed_url`，它會在第三方 iframe 中渲染完整的 Theo 品牌瀏覽器外殼（地址欄、實時狀態指示器、自動重連界面）。無需 SDK 接線，無需手動處理 CDP —— 只要把 `<iframe>` 指向該 URL 即可上線。

## 快速開始

1. 在你的後端創建會話（切勿將 `THEO_API_KEY` 暴露給瀏覽器）：

```typescript theme={null}
import { Theo } from "@hitheo/sdk";
const theo = new Theo({ apiKey: process.env.THEO_API_KEY! });

const session = await theo.browser.create({
  url: "https://example.com",
  region: "us-west-2",
});
return Response.json({ embed_url: session.embed_url });
```

2. 將該 URL 放入前端的 iframe 中：

```html theme={null}
<iframe
  src="{embed_url}"
  width="100%"
  height="600"
  allow="clipboard-read; clipboard-write"
  sandbox="allow-scripts allow-same-origin"
></iframe>
```

就這麼簡單。嵌入頁面會自動處理：

* 首次渲染時獲取正確的實時視圖 URL（不會出現 `about:blank` 閃屏）
* 監聽 `browserbase-disconnected` 的 postMessage 消息
* 在 CDP 目標發生變化時自動重新獲取併為 iframe 重新賦 key
* 斷開連接時以 10 秒為間隔緊密輪詢，連接正常時放寬為 30 秒
* 帶有 Theo 品牌的地址欄 + 實時狀態指示器 + 重連遮罩層

## 令牌的工作原理

`embed_url` 是一個簽名、短時效的 URL，綁定到 `(sessionId, userId)`：

* **格式：** `{APP_ORIGIN}/embed/browser/{sessionId}?token=<hmac>`
* **作用範圍：** 該令牌與特定會話以及創建該會話的用戶綁定
* **有效期：** 60 分鐘（Theo Browser 會話硬性上限為 20 分鐘，因此這為 `keep_alive` 會話留出了餘量）
* **密鑰：** 由服務器端使用 `BROWSER_EMBED_TOKEN_SECRET` 簽名，永不暴露給客戶端
* **輪換：** 每次調用 `GET /api/v1/browser/sessions/:id` 都會生成一個新令牌，因此長時間運行的儀表盤可以按需刷新 iframe

第三方無法為自己不擁有的會話偽造令牌 —— 即使猜中了會話 id，HMAC 校驗也會失敗。

## 斷線處理

嵌入頁面已經實現了完整的恢復協議，但如果你要構建自定義的 iframe 包裝層，以下是確切的約定：

```javascript theme={null}
// Listen on the parent window for the iframe's disconnect event.
window.addEventListener("message", (ev) => {
  if (ev.data === "browserbase-disconnected") {
    // Option A: let Theo handle it — refetch /live?force=1 and rekey.
    // Option B: surface a "reconnecting…" UI to your user.
  }
});
```

在內部，一旦觸發該事件，嵌入頁面就會強制重新獲取其實時 URL。服務器端的會話管理器每次解析出新的調試器 URL 時都會遞增一個單調的 `live_view_version` 計數器 —— iframe 會在版本號變化時重新賦 key，而不是在 URL 相等性變化時，因為 BrowserBase 可能返回相同的 URL 字符串，卻在背後悄悄更換了底層的 CDP 頁面目標。

## 安全姿態

* **Iframe 沙箱：** `allow-scripts allow-same-origin` 是保持 DevTools 前端與 CDP WebSocket 存活所需的最小權限集合。添加 `allow-forms` / `allow-popups` 沒有任何功能上的好處，反而可能觸發意外的導航，把 iframe 帶離實時視圖。
* **`frame-ancestors *`：** 嵌入頁面設置了 `Content-Security-Policy: frame-ancestors *`，因此任何來源都可以將其加載到 iframe 中。如果你想限制哪些來源可以加載該嵌入頁面，請在你自己的 CDN 層終止該 iframe 請求並應用你自己的響應頭。
* **iframe 中不含任何憑據：** 嵌入頁面永遠不會接觸到你的 API 密鑰。它通過一個使用令牌鑑權的配套路由 `/embed/browser/:id/live` 進行通信。

## 結束會話

當用戶關閉 iframe 時，務必從你的後端結束該會話，否則你將按剩餘的時鐘時間被計費：

```typescript theme={null}
await theo.browser.end(session.session_id);
```

## 相關內容

* [Browser Sessions API](/api-reference/browser/sessions) —— 完整的 `/api/v1/browser/sessions` 接口
* [Theo Browser SDK](/sdk-reference/browser) —— 適用於 Node/Deno/edge 的類型化輔助工具


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