Requests that arrive as locals.

bytetourist is a proxy and crawling API. Every request leaves through an edge we run (a datacenter machine or a home connection) with a real browser’s fingerprint, at a pace the site will accept.

India-first: datacenter and residential edges for sites that turn foreign or cloud traffic away.

curl -k https://example.com \
  -x http://dev.bytetourist.com:8080 \
  -U "$BT_KEY-cc-in:" \
  -H "X-Proxy-Stealth: safari_ios"
Your API key is the proxy username, and routing options ride along in it: -cc-in picks an Indian IP. The -k is there because the proxy re-signs HTTPS to route each request.

Steer every request

Point any HTTP client at the proxy with your API key as the username. Routing options ride along in the username, so they work the same for HTTP and HTTPS. Per-request options are headers. None of it reaches the site.

Illustration: requests sorted across edges by the country and network you ask for.

In the username, after your key

cc-in
The edge’s country, as an ISO code: in, us, de.
iptype-residential
datacenter or residential.
session-abc
Any token. With strategy-session_affinity, requests that share it stay on the same edge while it’s available.
strict-true
Fail instead of falling back to any edge when none matches.
strategy-goodput_per_second
How the edge is picked. This one, which favours edges by pages delivered per second, is the default.

For example, $BT_KEY-cc-in-iptype-residential

As request headers

X-Proxy-Stealth
The browser identity: chrome_desktop, chrome_android, firefox_desktop, safari_desktop or safari_ios. Leave it out and we choose one per site, skipping identities that site has been refusing.
X-Proxy-Insecure
true skips checking the site’s own certificate, for origins with expired or self-signed ones.
X-Proxy-Reuse
true keeps the connection to the site open between requests; false gives each request a fresh TLS handshake.

Proxy-side failures carry a stable X-Proxy-Error slug, like no_edge or governor_throttle, so your client can tell “retry” from “give up”.

curl -X POST \
  https://dev.bytetourist.com/v1/fetch \
  -H "Authorization: Bearer $BT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com"
  }'
One request, no proxy client needed. You get the status, headers and body back as JSON.

Papers that agree with themselves

Anti-bot systems don’t just read your User-Agent. They compare it with the TLS handshake, the HTTP/2 settings, the client hints and the order of your headers. A Chrome handshake under a Firefox User-Agent is the giveaway.

Each bytetourist identity is one browser, top to bottom, and for Chrome and Firefox every part derives from a single version number, so the parts can’t drift apart.

Browser identity (the X-Proxy-Stealth value)
Type
P
Issued by
bytetourist
Identity
chrome_desktop
Handshake (TLS + HTTP/2)
chrome_146
User-Agent
Chrome 146 on Windows
Client hints
Sent:platform "Windows",mobile ?0
Header order
sec-ch-ua,sec-ch-ua-mobile,sec-ch-ua-platform,Upgrade-Insecure-Requests,User-Agent,…
Accept-Language
en-US,en;q=0.9
P<BTRCHROME<<DESKTOP<<<<<<<<<<<<<<<<<<<<<<<<CHROME146<<BTR<WINDOWS<<<<<<<<<<<<<<<<<<<<<<

Handshake, User-Agent, client hints and header order all describe the same browser.

Hand us a URL. We’ll walk the site.

A crawl starts from one URL and follows the links on that host, breadth-first, up to your page and depth limits, through the same edges. Pages are saved in batches as zstd-compressed JSON lines.

Pause or cancel a running crawl; resume a paused one. Already have a sitemap? Send the URLs and skip discovery.

Render JavaScript
The page as a browser sees it after scripts run. The browser runs on our side, but every request it makes still leaves through an edge.
Screenshot
A full-page PNG alongside the rendered DOM.

Crawl

From
example.com
Pages
up to1,000
Depth
5
Subdomains
no
Render JavaScript
yes
Saved as
zstd JSON lines
curl -X POST \
  https://dev.bytetourist.com/v1/crawls \
  -H "Authorization: Bearer $BT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "maxPages": 1000,
    "renderJs": true
  }'
{
  "crawl_id": "crawl_…",
  "url": "https://example.com/about",
  "status_code": 200,
  "fetched_at": "2026-09-26T09:14:03.512Z",
  "depth": 1,
  "headers": { … },
  "body": "<!doctype html>…"
}
One saved page. In the crawl’s file it’s a single line of JSON; here it’s set out to read.

Transparent Pricing

  • 1 credit: Fetch, or one crawled page

  • 6 credits: A crawled page rendered with JavaScript

  • 6 credits: A full-page screenshot of a crawled page, with its DOM

  • +1 credit: Structured extraction (preview)

  • +1 credit: Each 5 MiB of response body on a proxied request

You’re charged once a response arrives, even if the site answers 404 or 429. If we fail before the site answers (no edge, a timeout, our own throttle), it’s free.

A render counts once, however many scripts and images the page loads.

A crawl retries pages that fail, and each attempt that gets a response is charged.

Plans
PlanCreditsAt once
Basic5,000 a monthup to 10 requests
Pro100,000 a monthup to 200
EnterpriseBy agreementup to 2,000

Unused monthly credits carry over.

Top-up packs
CreditsPrice
5,000$16
100,000$83
500,000$333

Packs never expire.