# Gắn Playwright

> Kết nối Playwright, Patchright hoặc Puppeteer vào phiên Browlix đang chạy qua broker có kiểm vé trên máy chạy.

Browlix mở trình duyệt; code của bạn gắn vào qua Chrome DevTools Protocol. Chạy đoạn code gắn kết trên máy đang giữ phiên ([vì sao](https://browlix.com/docs/where-code-runs)).

## Xin vé

```ts tab=TypeScript
import { Browlix } from "@browlix/sdk";

const bx = new Browlix({ apiKey: process.env.BROWLIX_API_KEY! });
const a = await bx.attach(sessionId, { ttlSeconds: 300 });
// a.endpoint = "ws://127.0.0.1:<port>/cdp", a.headers = { Authorization: "Bearer <ticket>" }
```

```bash tab=curl
curl -X POST https://browlix.com/api/public/v1/sessions/$SESSION_ID/attach \
  -H "Authorization: Bearer $BROWLIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ttl_seconds":300}'
```

Phản hồi có `ticket`, `endpoint`, `expires_at`, `session_id` và `scope`. Phiên phải đang `ready`.

## Playwright

```ts tab=TypeScript
import { chromium } from "playwright";

const browser = await chromium.connectOverCDP(a.endpoint, { headers: a.headers });
const context = browser.contexts()[0]!; // context của chính hồ sơ
const page = context.pages()[0] ?? (await context.newPage());
await page.goto("https://example.com");
await browser.close(); // chỉ ngắt kết nối; trình duyệt vẫn chạy
```

```python tab=Python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp(endpoint, headers={"Authorization": f"Bearer {ticket}"})
    context = browser.contexts[0]
    page = context.pages[0] if context.pages else context.new_page()
    page.goto("https://example.com")
    browser.close()
```

Dùng context có sẵn — nó mang cookie, bộ nhớ và thiết lập của hồ sơ. `browser.newContext()` sẽ tạo một context trống khác, không thuộc hồ sơ.

## Patchright và Puppeteer

Patchright là bản Playwright thay thế trực tiếp: import `chromium` từ `patchright` và gọi `connectOverCDP` y như trên. Puppeteer kết nối theo cách tương tự:

```bash
npm i patchright
npm i puppeteer-core
```

```ts
import puppeteer from "puppeteer-core";

const browser = await puppeteer.connect({ browserWSEndpoint: a.endpoint, headers: a.headers });
```

## Quy tắc broker áp dụng

- Chỉ loopback: broker nghe trên `127.0.0.1` của máy giữ phiên.
- Một vé, một phiên, tới `expires_at` (30–900 giây). Hết hạn thì xin vé mới cho kết nối mới.
- Vé hết hiệu lực khi phiên đổi chủ giữ hoặc kết thúc.
- Ngắt kết nối không bao giờ dừng phiên; gọi `sessions.stop` khi xong.

## Những điều nên tránh

- Đừng đóng trình duyệt qua CDP (`Browser.close`); kết thúc phiên bằng `sessions.stop` để dữ liệu hồ sơ được lưu.
- Đừng đổi ngôn ngữ, múi giờ, user agent hay khung nhìn của hồ sơ qua CDP override; hãy đặt trên hồ sơ để cả trình duyệt luôn nhất quán.
