$npx -y skills add vercel-labs/agent-browser --skill derive-clientReverse-engineer a website's internal API by recording browser traffic into a HAR file, then generate a standalone client or CLI that calls the endpoints directly, with no browser needed after the first recording. Use when asked to "derive a client", "build a CLI for <site>", "re
| 1 | # Derive an API client from a recorded session |
| 2 | |
| 3 | Driving a browser is the right tool for the first visit and the wrong tool for the hundredth. This skill records a site's network traffic once while you use it, then turns the captured requests into a standalone client (script, CLI, or library) that talks to the site's internal API directly. |
| 4 | |
| 5 | The recording alone contains everything needed: agent-browser embeds text response bodies (JSON/HTML/JS) in the HAR by default, so endpoint shapes can be studied offline after the browser is closed. |
| 6 | |
| 7 | ## Workflow |
| 8 | |
| 9 | ``` |
| 10 | 1. Record Start HAR capture, drive the flows you want in the client |
| 11 | 2. Identify Find the real API endpoints among the noise |
| 12 | 3. Extract Pull request shapes, response schemas, and auth material |
| 13 | 4. Generate Write the client, one function per flow |
| 14 | 5. Verify Call every endpoint for real before declaring done |
| 15 | ``` |
| 16 | |
| 17 | ## 1. Record |
| 18 | |
| 19 | ```bash |
| 20 | agent-browser network har start # embeds text response bodies by default |
| 21 | # ... drive the site: search, open a detail page, paginate, etc. ... |
| 22 | agent-browser network har stop /tmp/site.har |
| 23 | ``` |
| 24 | |
| 25 | - Exercise **every flow the client should support**, and run each one at least twice with different inputs (two search terms, two detail pages). Diffing the recorded URLs reveals which parts are parameters. |
| 26 | - If the site needs login, log in **before** starting the HAR so credentials don't land in the recording unnecessarily. The session cookies are exported separately in step 3. |
| 27 | - `--content all` embeds binary bodies too (base64); `--content none` disables embedding. Per-body cap is 2 MB. |
| 28 | |
| 29 | While the session is still open, `agent-browser network requests` and `network request <id>` give the same data interactively — but only the HAR survives navigation and browser close, so prefer it for anything multi-page. |
| 30 | |
| 31 | ## 2. Identify endpoints |
| 32 | |
| 33 | Query the HAR with `jq`: |
| 34 | |
| 35 | ```bash |
| 36 | # All JSON API calls: method, URL, status |
| 37 | jq -r '.log.entries[] |
| 38 | | select(.response.content.mimeType | test("json")) |
| 39 | | "\(.request.method) \(.response.status) \(.request.url)"' /tmp/site.har |
| 40 | ``` |
| 41 | |
| 42 | Ignore analytics and infrastructure noise: telemetry endpoints (`/collect`, `/track`, `/beacon`, `/log`), third-party domains (google-analytics, segment, sentry, datadog, intercom, hotjar), and static assets. The real API is usually first-party, JSON, and correlates with the actions you performed. |
| 43 | |
| 44 | ## 3. Extract shapes and auth |
| 45 | |
| 46 | ```bash |
| 47 | # Full detail for one endpoint: request headers, POST body, response body |
| 48 | jq '.log.entries[] | select(.request.url | test("api/search")) |
| 49 | | {request: {method: .request.method, headers: .request.headers, |
| 50 | postData: .request.postData.text}, |
| 51 | response: .response.content.text}' /tmp/site.har |
| 52 | ``` |
| 53 | |
| 54 | - **Response schema**: read `.response.content.text` — this is the real payload, use it to derive types. |
| 55 | - **Auth**: compare request headers across endpoints. Look for `authorization`, `cookie`, `x-csrf-token`, `x-api-key`, and site-specific `x-*` headers. Replay only the ones that matter — test by omission in step 5. |
| 56 | - **Cookies**: export the live session with `agent-browser cookies get --json > cookies.json` for the client to load at runtime. Never hardcode cookie values into generated source. |
| 57 | |
| 58 | ## 4. Generate the client |
| 59 | |
| 60 | - One function per recorded flow (`search(query)`, `getItem(id)`), typed from the observed response bodies. |
| 61 | - Auth material (cookies, bearer tokens) loads from a file or environment variable, with a clear error telling the user to re-run the browser login when it expires. |
| 62 | - Reproduce the headers the API actually requires — some sites 403 without a matching `user-agent`, `referer`, or `x-requested-with`. |
| 63 | - Keep pagination, sort, and filter parameters that appeared in the recorded query strings as function options. |
| 64 | |
| 65 | ## 5. Verify |
| 66 | |
| 67 | Call every generated function against the live API and compare the response shape with the recording. Common failures: |
| 68 | |
| 69 | | Symptom | Cause | Fix | |
| 70 | |---------|-------|-----| |
| 71 | | 401/403 | Expired or missing session | Re-login via agent-browser, re-export cookies | |
| 72 | | 403/419 on writes | CSRF token is per-session or per-form | Fetch the token endpoint first, or keep that flow browser-driven | |
| 73 | | Works then breaks | Signed/expiring request params | Fall back to the browser for that step; derive the rest | |
| 74 | | Different shape than HAR | A/B tests or geo-dependent responses | Re-record and treat the union as optional fields |