DEV Community

Devil Scrapes
Devil Scrapes

Posted on

Binance's api.binance.com Blocks Every US IP — Its Own Data Mirror Doesn't

Quick answer

Binance runs two live hosts for the exact same public spot-market data, and only one of them enforces the US jurisdiction block. api.binance.com returns HTTP 451 to a US exit IP — we confirmed this from both a US datacenter proxy and a US residential proxy, so it isn't a datacenter-IP thing. data-api.binance.vision, Binance's own market-data mirror, answered 200 with identical ticker data from the same two blocked US exits, no geoblock at all. Only a German residential exit got api.binance.com to answer 200. All four numbers below came from real requests we ran today, 2026-09-12.

We hit api.binance.com from three real exits, live 🔍

No synthetic test here — three actual proxied requests to GET /api/v3/ticker/24hr?symbol=BTCUSDT, run minutes apart from the same machine, routed through three different Apify Proxy exits:

from curl_cffi import requests

URL = "https://api.binance.com/api/v3/ticker/24hr?symbol=BTCUSDT"
PASSWORD = "<APIFY_PROXY_PASSWORD>"

exits = {
    "US datacenter": f"http://groups-BUYPROXIES94952,country-US:{PASSWORD}@proxy.apify.com:8000",
    "US residential": f"http://groups-RESIDENTIAL,country-US:{PASSWORD}@proxy.apify.com:8000",
    "DE residential": f"http://groups-RESIDENTIAL,country-DE:{PASSWORD}@proxy.apify.com:8000",
}
for label, proxy in exits.items():
    r = requests.get(URL, impersonate="chrome131", proxy=proxy, timeout=25)
    print(label, "->", r.status_code)
Enter fullscreen mode Exit fullscreen mode
US datacenter -> 451
US residential -> 451
DE residential -> 200
Enter fullscreen mode Exit fullscreen mode

The 451 body is the same on both blocked exits, word for word:

{
  "code": 0,
  "msg": "Service unavailable from a restricted location according to 'b. Eligibility' in https://www.binance.com/en/terms. Please contact customer service if you believe you received this message in error."
}
Enter fullscreen mode Exit fullscreen mode

That's a jurisdiction block, not a bot-detection one — Binance is citing its own Terms of Service, not a WAF challenge. Residential vs. datacenter made zero difference from a US exit; only the exit country did.

The part that actually surprised us: the mirror host doesn't check 🪞

Binance publishes data-api.binance.vision as a market-data-only mirror of the same REST surface. We pointed the identical request at it, from the same two US exits that had just been 451'd on api.binance.com:

MIRROR = "https://data-api.binance.vision/api/v3/ticker/24hr?symbol=BTCUSDT"
for label in ("US datacenter", "US residential"):
    r = requests.get(MIRROR, impersonate="chrome131", proxy=exits[label], timeout=25)
    print(label, "->", r.status_code)
Enter fullscreen mode Exit fullscreen mode
US datacenter  -> 200
US residential -> 200
Enter fullscreen mode Exit fullscreen mode

Same trading pair, same data, no restricted-location response — from exits that fail on the primary host every single time we tried. Binance doesn't document .vision as jurisdiction-exempt anywhere we could find; empirically, on the date and exits we tested, it just isn't enforcing the block that api.binance.com enforces. If your code only ever tests against one of these two hosts, you'll ship a bug that only shows up when someone runs it from the other exit.

One more artifact worth knowing about if you're parsing responses yourself: api.binance.com sends an X-MBX-USED-WEIGHT-1M header on every 200 (we saw 2 on a plain ticker call), which is how you're supposed to track your request-weight budget against Binance's rate limits. On the 451 responses, that header is simply absent — the block happens before weight accounting, so there's nothing in the response you can inspect to confirm why you got nothing back. You find out by reading the body, not the headers.

What we handle for you 🛡️

None of the above is a one-time recon finding we then ignore — it's wired into how this Actor runs every request. We pin the proxy to a residential exit outside the blocked jurisdiction by default (verified DE clears it, above), so a customer on the default settings doesn't open a run straight into a wall. We retry 408/429/5xx with exponential backoff and honour Retry-After, but a 418 or 451 gets zero retries and stops the run immediately — hammering a ban only extends it, and a jurisdiction block isn't going away on attempt three. One bad or delisted symbol is skipped and logged, not fatal to the rest of your batch, and every row lands typed and validated — TickerRow or KlineRow, discriminated by rowType, ISO-8601 timestamps, no raw Binance array indices leaking into your dataset.

Output

{
  "rowType": "kline",
  "symbol": "BTCUSDT",
  "interval": "1h",
  "openTime": "2026-09-12T09:00:00Z",
  "open": 77289.73,
  "high": 77351.30,
  "low": 77266.00,
  "close": 77309.99,
  "volume": 590.05,
  "closeTime": "2026-09-12T09:59:59Z",
  "numberOfTrades": 55422,
  "scrapedAt": "2026-09-12T10:03:00Z"
}
Enter fullscreen mode Exit fullscreen mode
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("DevilScrapes/binance-market-data-scraper").call(
    run_input={"symbols": ["BTCUSDT", "ETHUSDT"], "dataTypes": ["ticker", "klines"], "interval": "1h"}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["rowType"], item["symbol"])
Enter fullscreen mode Exit fullscreen mode

Pricing: $0.20 per run, then $0.004 per ticker row ($4.00 / 1,000) and $0.0015 per kline row ($1.50 / 1,000) — split because one /klines call can hand back up to 1,000 candles, and billing all of them at the ticker rate would make a single call cost roughly $4.

Binance Market Data Scraper on Apify

FAQ

Does Binance block scrapers, or is this specific to certain regions?
It's regional, not anti-bot. We confirmed api.binance.com 451s a US datacenter and a US residential exit with the same "restricted location" message citing Binance's own Terms — a WAF challenge would look different and wouldn't quote a ToS clause.

Is data-api.binance.vision a safe permanent workaround?
It's a real, Binance-operated public mirror, and it cleared the block from every US exit we tried on 2026-09-12. We didn't find it documented as jurisdiction-exempt, so treat today's behavior as today's behavior, not a permanent guarantee — which is exactly why this Actor defaults to a proxy-country fix instead of hardcoding a host that could change its own policy tomorrow.

Do I need a Binance account or API key to use this?
No — every endpoint here is public spot-market data. No signature, no account, no rate-limit tier to buy into.

Binance Market Data Scraper on Apify — grab the $5 free trial credit, no card required.


Built by Devil Scrapes. We pin proxies past the jurisdiction wall, retry the transient failures, and stop cold on the ones that aren't — so your dataset doesn't have to guess which is which.

Top comments (0)