Docs

Run from your own IP

Send a run's requests to the website yourself, from your own IP, while Unbrowse still decides every request and reads every response. Useful when a site must see your address (your region, your allowlisted IP, your network), or when you would rather no third party connects to it on your behalf.

How it works

Start a run as usual and add "egress": "client". Instead of calling the site, Unbrowse answers with the next request to send:

curl -X POST https://api.unbrowse.ai/api/v1/runs \
  -H "Authorization: Bearer $UNBROWSE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"capability":"hn.top_stories","input":{"limit":3},"egress":"client"}'
{
  "status": "egress_required",
  "egressId": "eg_mB1s…",
  "requests": [
    {
      "id": "rq_1",
      "method": "GET",
      "url": "https://hn.algolia.com/api/v1/search?tags=front_page&hitsPerPage=12",
      "headers": { "accept": "application/json", "user-agent": "…" },
      "redirect": "manual",
      "curl": "curl -sS -i -X GET 'https://hn.algolia.com/api/v1/search?tags=front_page&hitsPerPage=12' -H 'accept: application/json' …"
    }
  ]
}

Send that request from your machine, then post the site's raw response back:

curl -X POST https://api.unbrowse.ai/api/v1/egress/eg_mB1s… \
  -H "Authorization: Bearer $UNBROWSE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"requestId":"rq_1","response":{"status":200,"headers":[["content-type","application/json"]],"body":"{\"hits\":[…]}"}}'

Unbrowse reads it and answers with the next request (egress_required again), or with the finished run — the same verified result a normal run returns:

{ "runId": "run_…", "status": "succeeded", "capabilityId": "hn.top_stories", "result": { "stories": [ … ] } }

A multi-step flow (sign in, then search, then read a detail) is one request at a time: you only ever hold the request in front of you.

With the SDK

runOnClient does the loop: it sends each request with your fetch and posts the response back.

import { Unbrowse } from "@unbrowse/sdk";

const unbrowse = new Unbrowse({ apiKey: process.env.UNBROWSE_API_KEY });
const run = await unbrowse.runOnClient({ capability: "hn.top_stories", input: { limit: 3 } });
console.log(run.result);

Pass fetch to send through your own proxy or network stack, and onRequest to see or veto each request before it goes out.

Answering

FieldWhat to send
requestIdThe id of the request you sent.
response.statusThe HTTP status the site returned.
response.headers[name, value] pairs (keeps repeated headers such as set-cookie) or an object.
response.bodyThe body, decoded (after gzip/brotli). Text, or base64 with "bodyEncoding": "base64". Up to 10 MB.
response.urlThe final URL, if you followed redirects.
errorInstead of response, when the request could not be sent at all (DNS, TLS, refused). The run treats it as a network error.

When redirect is manual, do not follow redirects: return the 3xx as it came (Unbrowse follows it itself and asks you for the next hop). You have 120 seconds to answer each request; an abandoned run can be closed with DELETE /api/v1/egress/{egressId}. GET /api/v1/egress/{egressId} shows what the run is waiting for.

What stays where