[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"blog-post-en-scrape-binance-rest-api-proxies":3},{"success":4,"payload":5,"related":64,"errors":153},true,{"id":6,"slug":7,"title":8,"excerpt":9,"body_html":10,"meta_title":11,"meta_description":12,"canonical_url":13,"canonical_override":14,"og_title":15,"og_description":16,"og_image_url":17,"faq_json":18,"key_takeaways":14,"allow_index":4,"noindex_google_only":31,"allow_follow":4,"published_at":32,"updated_at":32,"content_updated_at":33,"featured_image_url":34,"featured_image_alt":35,"card_image_url":36,"reading_time_minutes":37,"author":38,"categories":42,"tags":49,"alternates":50,"locale_paths":56,"views":63},194,"scrape-binance-rest-api-proxies","Weight-Based Rate Limits on Crypto Exchange APIs: Collecting Market Data with Proxies (Binance Example)","Collect public market data from Binance's REST API at scale using rotating residential proxies. Learn weight-based rate limits, endpoint mapping, and production-ready Python\u002FNode.js code.","\u003Cp>If you need to build historical candlestick datasets, monitor order books across dozens of trading pairs, or track real-time prices for quantitative strategies, you need to know how to scrape the Binance REST API with proxies. Binance exposes rich public market-data endpoints, but its weight-based rate limiting is aggressive: a single IP that hammers \u003Ccode>\u002Fapi\u002Fv3\u002Fdepth\u003C\u002Fcode> can exhaust its per-IP weight budget in minutes and earn a temporary ban. This guide maps every key endpoint, explains the weight system, and gives you runnable Python and Node.js code that rotates residential proxies through \u003Ccode>gate.proxyhat.com\u003C\u002Fcode> to stay under the limit.\u003C\u002Fp>\n\n\u003Cblockquote>\u003Cp>\u003Cstrong>Compliance caveat:\u003C\u002Fstrong> This guide covers \u003Cem>public market data only\u003C\u002Fem> — endpoints that require no authentication and are documented in Binance's official API docs. Always respect Binance's \u003Ca href=\"https:\u002F\u002Fwww.binance.com\u002Fen\u002Flegal\u002Fterms-of-use\" rel=\"noopener noreferrer\">Terms of Use\u003C\u002Fa>, honor rate-limit weights, and prefer the official API access path where terms require it. Do not scrape authenticated or private endpoints without explicit authorization.\u003C\u002Fp>\u003C\u002Fblockquote>\n\n\u003Ch2>Binance API Scraping: Endpoint Map and Weight Costs\u003C\u002Fh2>\n\n\u003Cp>Binance's REST API lives at \u003Ccode>https:\u002F\u002Fapi.binance.com\u003C\u002Fcode>. The public market-data endpoints you'll use most frequently are all under \u003Ccode>\u002Fapi\u002Fv3\u002F\u003C\u002Fcode>. Each endpoint carries a \u003Cstrong>request weight\u003C\u002Fstrong> that counts against your per-IP limit. Binance returns the current weight consumption in the \u003Ccode>X-MBX-USED-WEIGHT-1M\u003C\u002Fcode> response header on every reply.\u003C\u002Fp>\n\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Endpoint\u003C\u002Fth>\n\u003Cth>Purpose\u003C\u002Fth>\n\u003Cth>Default Weight\u003C\u002Fth>\n\u003Cth>Key Parameters\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>\u002Fapi\u002Fv3\u002Fklines\u003C\u002Fcode>\u003C\u002Ftd>\u003Ctd>Candlestick \u002F OHLCV data\u003C\u002Ftd>\u003Ctd>1–2 (varies with limit)\u003C\u002Ftd>\u003Ctd>\u003Ccode>symbol\u003C\u002Fcode>, \u003Ccode>interval\u003C\u002Fcode>, \u003Ccode>limit\u003C\u002Fcode> (max 1000)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>\u002Fapi\u002Fv3\u002Fdepth\u003C\u002Fcode>\u003C\u002Ftd>\u003Ctd>Order book snapshot\u003C\u002Ftd>\u003Ctd>5–20 (varies with limit)\u003C\u002Ftd>\u003Ctd>\u003Ccode>symbol\u003C\u002Fcode>, \u003Ccode>limit\u003C\u002Fcode> (5\u002F10\u002F20\u002F50\u002F100\u002F500\u002F1000)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>\u002Fapi\u002Fv3\u002Fticker\u002F24hr\u003C\u002Fcode>\u003C\u002Ftd>\u003Ctd>24-hour rolling stats\u003C\u002Ftd>\u003Ctd>1–40 (single vs all symbols)\u003C\u002Ftd>\u003Ctd>\u003Ccode>symbol\u003C\u002Fcode> (optional)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>\u002Fapi\u002Fv3\u002Fticker\u002Fprice\u003C\u002Fcode>\u003C\u002Ftd>\u003Ctd>Latest trade price\u003C\u002Ftd>\u003Ctd>1–2 (single vs all)\u003C\u002Ftd>\u003Ctd>\u003Ccode>symbol\u003C\u002Fcode> (optional)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\n\u003Cp>The critical insight: weight is per IP, not per API key. For public market-data endpoints, no API key is required, so the IP address of the requester is the sole identity Binance uses for rate limiting. This is exactly why rotating \u003Ca href=\"\u002Fproxy\u002Fresidential\">residential proxies\u003C\u002Fa> through \u003Ca href=\"\u002Flocations\">ProxyHat's global IP pool\u003C\u002Fa> is so effective — each exit IP gets its own weight budget.\u003C\u002Fp>\n\n\u003Cp>For full details on weights and limits, see Binance's \u003Ca href=\"https:\u002F\u002Fdevelopers.binance.com\u002Fdocs\u002Fbinance-spot-api-docs\u002Frest-api\u002Fgeneral-api-information\" rel=\"noopener noreferrer\">official REST API documentation\u003C\u002Fa>, which is the authoritative source for current weight values.\u003C\u002Fp>\n\n\u003Ch2>Why Binance's Weight-Based Rate Limiting Burns Through IPs\u003C\u002Fh2>\n\n\u003Cp>Binance enforces a per-IP weight budget of approximately \u003Cstrong>6,000 weight units per minute\u003C\u002Fstrong> (the exact figure may vary by endpoint group and can change). Every request consumes weight based on the endpoint and parameters. When your cumulative weight approaches the limit, Binance responds with \u003Cstrong>HTTP 429 (Too Many Requests)\u003C\u002Fstrong>. If you continue sending requests after a 429, Binance escalates to \u003Cstrong>HTTP 418\u003C\u002Fstrong>, which indicates an automatic IP ban — typically lasting 2 to 15 minutes for first offenses, but longer for repeat violators.\u003C\u002Fp>\n\n\u003Cp>The \u003Ccode>Retry-After\u003C\u002Fcode> header on a 429 tells you how many seconds to wait before retrying. The \u003Ccode>X-MBX-USED-WEIGHT-1M\u003C\u002Fcode> header on every successful response tells you how much of your budget you've consumed in the current minute window. A well-behaved scraper reads this header and throttles accordingly.\u003C\u002Fp>\n\n\u003Cp>Here's why a naive \u003Ccode>\u002Fapi\u002Fv3\u002Fdepth\u003C\u002Fcode> poll is dangerous: requesting \u003Ccode>limit=1000\u003C\u002Fcode> for a single symbol costs 20 weight per call. If you poll 10 symbols every second, that's 200 weight\u002Fsecond, or 12,000 weight\u002Fminute — double the budget. You'll hit 429 in under 30 seconds. With \u003Ccode>limit=500\u003C\u002Fcode>, each call costs 10 weight, so the same poll rate consumes 6,000 weight\u002Fminute — right at the ceiling, with zero margin for retries or other endpoints.\u003C\u002Fp>\n\n\u003Ch3>The Binance.com vs Binance.US Geo-Split\u003C\u002Fh3>\n\n\u003Cp>Another gotcha: Binance.com restricts access from US IP addresses, returning HTTP 451 (Unavailable For Legal Reasons) for some endpoints. Conversely, Binance.US (a separate entity at \u003Ccode>api.binance.us\u003C\u002Fcode>) is only accessible from US IPs. If your infrastructure runs in a US datacenter and you need \u003Ccode>api.binance.com\u003C\u002Fcode> data, you'll need a non-US exit IP. ProxyHat's geo-targeting solves this cleanly — you can request \u003Ccode>-country-DE\u003C\u002Fcode> for Binance.com access or \u003Ccode>-country-US\u003C\u002Fcode> for Binance.US.\u003C\u002Fp>\n\n\u003Ch2>ProxyHat Setup: Rotating Residential Proxies for Binance\u003C\u002Fh2>\n\n\u003Cp>ProxyHat provides residential, mobile, and datacenter proxies through a single gateway: \u003Ccode>gate.proxyhat.com\u003C\u002Fcode>. HTTP traffic uses port 8080; SOCKS5 uses port 1080. Geo-targeting and session control are embedded in the username field, not the URL path.\u003C\u002Fp>\n\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Parameter\u003C\u002Fth>\n\u003Cth>Value\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>Gateway hostname\u003C\u002Ftd>\u003Ctd>\u003Ccode>gate.proxyhat.com\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>HTTP port\u003C\u002Ftd>\u003Ctd>\u003Ccode>8080\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>SOCKS5 port\u003C\u002Ftd>\u003Ctd>\u003Ccode>1080\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>HTTP URL format\u003C\u002Ftd>\u003Ctd>\u003Ccode>http:\u002F\u002FUSERNAME:PASSWORD@gate.proxyhat.com:8080\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>SOCKS5 URL format\u003C\u002Ftd>\u003Ctd>\u003Ccode>socks5:\u002F\u002FUSERNAME:PASSWORD@gate.proxyhat.com:1080\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\n\u003Cp>Username flags let you control geo-targeting and session stickiness:\u003C\u002Fp>\n\n\u003Cul>\n\u003Cli>\u003Ccode>user-country-US:pass\u003C\u002Fcode> — US exit IP (for Binance.US)\u003C\u002Fli>\n\u003Cli>\u003Ccode>user-country-DE:pass\u003C\u002Fcode> — German exit IP (for Binance.com)\u003C\u002Fli>\n\u003Cli>\u003Ccode>user-country-DE-region-state_of_berlin-city-berlin:pass\u003C\u002Fcode> — city-level targeting\u003C\u002Fli>\n\u003Cli>\u003Ccode>user-sid-abc123:pass\u003C\u002Fcode> — sticky session (same IP for session ID)\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Cp>For Binance scraping, residential proxies are the best choice because they appear as real ISP-assigned IPs, making them less likely to be flagged by Binance's anti-abuse systems. Datacenter IPs may work but carry higher ban risk. See \u003Ca href=\"\u002Fpricing\">ProxyHat pricing\u003C\u002Fa> for residential proxy plans.\u003C\u002Fp>\n\n\u003Ch2>Code Example 1: Raw Proxy Rotation with Python requests\u003C\u002Fh2>\n\n\u003Cp>This example fetches klines for BTCUSDT using a rotating residential proxy. Each request gets a fresh IP because no session flag is set — ProxyHat rotates automatically.\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>import requests\nimport time\nimport logging\n\nlogging.basicConfig(level=logging.INFO, format=&apos;%(asctime)s %(levelname)s %(message)s&apos;)\n\nPROXY_USER = &quot;user-country-DE&quot;\nPROXY_PASS = &quot;your_password&quot;\nPROXY_URL = f&quot;http:\u002F\u002F{PROXY_USER}:{PROXY_PASS}@gate.proxyhat.com:8080&quot;\n\nBINANCE_BASE = &quot;https:\u002F\u002Fapi.binance.com&quot;\n\nsession = requests.Session()\nsession.proxies = {&quot;http&quot;: PROXY_URL, &quot;https&quot;: PROXY_URL}\n\ndef fetch_klines(symbol: str, interval: str, limit: int = 500) -&gt; list:\n    &quot;&quot;&quot;Fetch candlestick data with weight-aware throttling.&quot;&quot;&quot;\n    url = f&quot;{BINANCE_BASE}\u002Fapi\u002Fv3\u002Fklines&quot;\n    params = {&quot;symbol&quot;: symbol, &quot;interval&quot;: interval, &quot;limit&quot;: limit}\n\n    for attempt in range(5):\n        resp = session.get(url, params=params, timeout=15)\n\n        # Read the weight header on every response\n        used_weight = resp.headers.get(&quot;X-MBX-USED-WEIGHT-1M&quot;, &quot;unknown&quot;)\n        logging.info(f&quot;{symbol} {interval} status={resp.status_code} weight_1m={used_weight}&quot;)\n\n        if resp.status_code == 200:\n            # Back off proactively if we&apos;re near the limit\n            if used_weight != &quot;unknown&quot; and int(used_weight) &gt; 5000:\n                logging.warning(f&quot;Weight {used_weight} near limit, sleeping 10s&quot;)\n                time.sleep(10)\n            return resp.json()\n\n        if resp.status_code == 429:\n            retry_after = int(resp.headers.get(&quot;Retry-After&quot;, 5))\n            logging.warning(f&quot;429 rate limited, waiting {retry_after}s&quot;)\n            time.sleep(retry_after)\n            continue\n\n        if resp.status_code == 418:\n            logging.error(&quot;418 IP banned — backing off 60s&quot;)\n            time.sleep(60)\n            continue\n\n        if resp.status_code == 451:\n            logging.error(&quot;451 geo-restricted — try a different country flag&quot;)\n            raise RuntimeError(&quot;Geo-blocked, change proxy country&quot;)\n\n        resp.raise_for_status()\n\n    raise RuntimeError(f&quot;Failed after 5 attempts for {symbol}&quot;)\n\n# Fetch 500 candles of 1h BTCUSDT\nklines = fetch_klines(&quot;BTCUSDT&quot;, &quot;1h&quot;, limit=500)\nprint(f&quot;Got {len(klines)} candles, first close: {klines[0][4]}&quot;)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>Code Example 2: ProxyHat SDK with Per-Request IP Rotation\u003C\u002Fh2>\n\n\u003Cp>The ProxyHat SDK wraps proxy management, giving you clean per-request rotation without manually constructing proxy URLs. This example fetches \u003Ccode>\u002Fapi\u002Fv3\u002Fticker\u002F24hr\u003C\u002Fcode> for multiple symbols concurrently using \u003Ccode>httpx\u003C\u002Fcode> with async support.\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>import httpx\nimport asyncio\nimport logging\nfrom proxyhat import ProxyHatClient  # ProxyHat SDK\n\nlogging.basicConfig(level=logging.INFO, format=&apos;%(asctime)s %(levelname)s %(message)s&apos;)\n\nBINANCE_BASE = &quot;https:\u002F\u002Fapi.binance.com&quot;\nSYMBOLS = [&quot;BTCUSDT&quot;, &quot;ETHUSDT&quot;, &quot;BNBUSDT&quot;, &quot;SOLUSDT&quot;, &quot;XRPUSDT&quot;]\n\n# Initialize ProxyHat SDK — rotating residential, Germany for Binance.com access\nph = ProxyHatClient(\n    username=&quot;user-country-DE&quot;,\n    password=&quot;your_password&quot;,\n    protocol=&quot;http&quot;,\n    # SDK handles gate.proxyhat.com:8080 internally\n)\n\nasync def fetch_24hr_ticker(client: httpx.AsyncClient, symbol: str) -&gt; dict:\n    url = f&quot;{BINANCE_BASE}\u002Fapi\u002Fv3\u002Fticker\u002F24hr&quot;\n    params = {&quot;symbol&quot;: symbol}\n\n    for attempt in range(5):\n        # Get a fresh rotating proxy URL for each request\n        proxy_url = ph.get_proxy_url()  # returns http:\u002F\u002Fuser-country-DE:pass@gate.proxyhat.com:8080\n\n        async with httpx.AsyncClient(proxy=proxy_url, timeout=15) as proxied_client:\n            try:\n                resp = await proxied_client.get(url, params=params)\n                used_weight = resp.headers.get(&quot;X-MBX-USED-WEIGHT-1M&quot;, &quot;unknown&quot;)\n                logging.info(f&quot;{symbol} status={resp.status_code} weight={used_weight}&quot;)\n\n                if resp.status_code == 200:\n                    data = resp.json()\n                    return {&quot;symbol&quot;: symbol, &quot;price&quot;: data[&quot;lastPrice&quot;], &quot;volume&quot;: data[&quot;volume&quot;]}\n\n                if resp.status_code == 429:\n                    retry_after = int(resp.headers.get(&quot;Retry-After&quot;, 5))\n                    logging.warning(f&quot;{symbol} 429, waiting {retry_after}s&quot;)\n                    await asyncio.sleep(retry_after)\n                    continue\n\n                if resp.status_code == 418:\n                    logging.error(f&quot;{symbol} 418 banned, backing off 60s&quot;)\n                    await asyncio.sleep(60)\n                    continue\n\n                resp.raise_for_status()\n\n            except httpx.ProxyError as e:\n                logging.warning(f&quot;{symbol} proxy error: {e}, retrying&quot;)\n                await asyncio.sleep(2 ** attempt)\n            except httpx.TimeoutException:\n                logging.warning(f&quot;{symbol} timeout, retrying&quot;)\n                await asyncio.sleep(2 ** attempt)\n\n    raise RuntimeError(f&quot;Failed for {symbol}&quot;)\n\nasync def main():\n    # Limit concurrency to 5 to avoid overwhelming any single IP\n    semaphore = asyncio.Semaphore(5)\n\n    async def bounded_fetch(symbol):\n        async with semaphore:\n            return await fetch_24hr_ticker(None, symbol)\n\n    results = await asyncio.gather(*[bounded_fetch(s) for s in SYMBOLS])\n    for r in results:\n        print(f&quot;{r[&apos;symbol&apos;]}: ${r[&apos;price&apos;]} (vol: {r[&apos;volume&apos;]})&quot;)\n\nasyncio.run(main())\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>Code Example 3: Sticky Sessions for Paginated Klines Backfills\u003C\u002Fh2>\n\n\u003Cp>When backfilling historical klines, you'll paginate through thousands of candles. Using a sticky session keeps the same IP for the entire backfill, which means your weight budget is predictable and the \u003Ccode>X-MBX-USED-WEIGHT-1M\u003C\u002Fcode> header accurately reflects your consumption. Rotate to a new session (new IP) when weight gets high.\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>import requests\nimport time\nimport logging\nfrom datetime import datetime, timedelta\n\nlogging.basicConfig(level=logging.INFO, format=&apos;%(asctime)s %(levelname)s %(message)s&apos;)\n\nBINANCE_BASE = &quot;https:\u002F\u002Fapi.binance.com&quot;\nMAX_LIMIT = 1000  # Binance allows max 1000 candles per klines request\nWEIGHT_THRESHOLD = 5000  # Rotate session before hitting 6000\n\nclass KlinesBackfiller:\n    def __init__(self, proxy_pass: str, country: str = &quot;DE&quot;):\n        self.proxy_pass = proxy_pass\n        self.country = country\n        self.session_id = None\n        self.session = requests.Session()\n        self._new_session()\n\n    def _new_session(self):\n        &quot;&quot;&quot;Start a new sticky session with a fresh IP.&quot;&quot;&quot;\n        import uuid\n        self.session_id = f&quot;backfill-{uuid.uuid4().hex[:8]}&quot;\n        proxy_user = f&quot;user-country-{self.country}-sid-{self.session_id}&quot;\n        proxy_url = f&quot;http:\u002F\u002F{proxy_user}:{self.proxy_pass}@gate.proxyhat.com:8080&quot;\n        self.session.proxies = {&quot;http&quot;: proxy_url, &quot;https&quot;: proxy_url}\n        logging.info(f&quot;New sticky session: {self.session_id}&quot;)\n\n    def fetch_klines_page(self, symbol: str, interval: str, start_time: int, limit: int = MAX_LIMIT) -&gt; list:\n        url = f&quot;{BINANCE_BASE}\u002Fapi\u002Fv3\u002Fklines&quot;\n        params = {\n            &quot;symbol&quot;: symbol,\n            &quot;interval&quot;: interval,\n            &quot;startTime&quot;: start_time,\n            &quot;limit&quot;: limit,\n        }\n\n        for attempt in range(5):\n            resp = self.session.get(url, params=params, timeout=20)\n            used_weight = int(resp.headers.get(&quot;X-MBX-USED-WEIGHT-1M&quot;, 0))\n\n            if resp.status_code == 200:\n                logging.info(f&quot;{symbol} weight={used_weight} session={self.session_id}&quot;)\n\n                # Rotate to fresh IP if weight is getting high\n                if used_weight &gt; WEIGHT_THRESHOLD:\n                    logging.info(f&quot;Weight {used_weight} &gt; {WEIGHT_THRESHOLD}, rotating session&quot;)\n                    self._new_session()\n                    time.sleep(1)  # brief cooldown\n\n                return resp.json()\n\n            if resp.status_code == 429:\n                retry_after = int(resp.headers.get(&quot;Retry-After&quot;, 5))\n                logging.warning(f&quot;429, waiting {retry_after}s then rotating&quot;)\n                time.sleep(retry_after)\n                self._new_session()\n                continue\n\n            if resp.status_code == 418:\n                logging.error(&quot;418 banned, rotating IP and waiting 60s&quot;)\n                self._new_session()\n                time.sleep(60)\n                continue\n\n            resp.raise_for_status()\n\n        raise RuntimeError(f&quot;Failed after 5 attempts&quot;)\n\n    def backfill(self, symbol: str, interval: str, start_ms: int, end_ms: int) -&gt; list:\n        &quot;&quot;&quot;Backfill klines from start_ms to end_ms (Unix milliseconds).&quot;&quot;&quot;\n        all_klines = []\n        current_start = start_ms\n\n        while current_start &lt; end_ms:\n            page = self.fetch_klines_page(symbol, interval, current_start)\n            if not page:\n                break\n\n            all_klines.extend(page)\n            # Move start to the close time of the last candle + 1ms\n            current_start = page[-1][6] + 1  # index 6 is closeTime\n            logging.info(f&quot;{symbol} fetched {len(all_klines)} candles so far&quot;)\n\n            # Respect rate limit — klines with limit=1000 costs ~2 weight\n            time.sleep(0.2)  # ~5 req\u002Fs, ~10 weight\u002Fs\n\n        return all_klines\n\n# Backfill 30 days of 1m BTCUSDT candles\nnow_ms = int(time.time() * 1000)\nstart_ms = now_ms - (30 * 24 * 3600 * 1000)  # 30 days ago\n\nbackfiller = KlinesBackfiller(proxy_pass=&quot;your_password&quot;, country=&quot;DE&quot;)\nklines = backfiller.backfill(&quot;BTCUSDT&quot;, &quot;1m&quot;, start_ms, now_ms)\nprint(f&quot;Total candles: {len(klines)}&quot;)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>Code Example 4: Weight-Aware Depth Polling with Exponential Backoff\u003C\u002Fh2>\n\n\u003Cp>Order book polling is the most weight-expensive operation. This example polls \u003Ccode>\u002Fapi\u002Fv3\u002Fdepth\u003C\u002Fcode> for multiple symbols with a weight budget controller that tracks \u003Ccode>X-MBX-USED-WEIGHT-1M\u003C\u002Fcode> and pauses before hitting the limit.\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>import requests\nimport time\nimport logging\nfrom collections import defaultdict\n\nlogging.basicConfig(level=logging.INFO, format=&apos;%(asctime)s %(levelname)s %(message)s&apos;)\n\nBINANCE_BASE = &quot;https:\u002F\u002Fapi.binance.com&quot;\nSYMBOLS = [&quot;BTCUSDT&quot;, &quot;ETHUSDT&quot;, &quot;BNBUSDT&quot;, &quot;SOLUSDT&quot;]\nDEPTH_LIMIT = 100  # weight = 5 per request\nMAX_WEIGHT_PER_MIN = 5500  # leave margin below 6000\n\nPROXY_USER = &quot;user-country-DE&quot;\nPROXY_PASS = &quot;your_password&quot;\nPROXY_URL = f&quot;http:\u002F\u002F{PROXY_USER}:{PROXY_PASS}@gate.proxyhat.com:8080&quot;\n\nclass WeightAwarePoller:\n    def __init__(self):\n        self.session = requests.Session()\n        self.session.proxies = {&quot;http&quot;: PROXY_URL, &quot;https&quot;: PROXY_URL}\n        self.current_weight = 0\n        self.weight_reset_time = time.time() + 60\n        self.consecutive_errors = 0\n\n    def _check_weight(self):\n        &quot;&quot;&quot;Pause if we&apos;re near the weight limit.&quot;&quot;&quot;\n        now = time.time()\n        if now &gt; self.weight_reset_time:\n            self.current_weight = 0\n            self.weight_reset_time = now + 60\n\n        if self.current_weight &gt;= MAX_WEIGHT_PER_MIN:\n            sleep_duration = self.weight_reset_time - now\n            logging.info(f&quot;Weight {self.current_weight} &gt;= {MAX_WEIGHT_PER_MIN}, sleeping {sleep_duration:.1f}s&quot;)\n            time.sleep(max(sleep_duration, 0))\n            self.current_weight = 0\n            self.weight_reset_time = time.time() + 60\n\n    def fetch_depth(self, symbol: str, limit: int = DEPTH_LIMIT) -&gt; dict:\n        url = f&quot;{BINANCE_BASE}\u002Fapi\u002Fv3\u002Fdepth&quot;\n        params = {&quot;symbol&quot;: symbol, &quot;limit&quot;: limit}\n\n        for attempt in range(5):\n            self._check_weight()\n\n            try:\n                resp = self.session.get(url, params=params, timeout=15)\n            except requests.exceptions.ProxyError:\n                backoff = min(2 ** attempt, 30)\n                logging.warning(f&quot;{symbol} proxy error, backing off {backoff}s&quot;)\n                time.sleep(backoff)\n                continue\n\n            used_weight = int(resp.headers.get(&quot;X-MBX-USED-WEIGHT-1M&quot;, self.current_weight + 5))\n            self.current_weight = used_weight\n\n            if resp.status_code == 200:\n                self.consecutive_errors = 0\n                data = resp.json()\n                return {\n                    &quot;symbol&quot;: symbol,\n                    &quot;bids&quot;: data[&quot;bids&quot;][:10],\n                    &quot;asks&quot;: data[&quot;asks&quot;][:10],\n                }\n\n            if resp.status_code == 429:\n                retry_after = int(resp.headers.get(&quot;Retry-After&quot;, 10))\n                logging.warning(f&quot;{symbol} 429, sleeping {retry_after}s&quot;)\n                time.sleep(retry_after)\n                self.current_weight = 0\n                self.weight_reset_time = time.time() + 60\n                continue\n\n            if resp.status_code == 418:\n                logging.error(f&quot;{symbol} 418 banned, sleeping 120s&quot;)\n                time.sleep(120)\n                self.current_weight = 0\n                self.weight_reset_time = time.time() + 60\n                continue\n\n            resp.raise_for_status()\n\n        self.consecutive_errors += 1\n        if self.consecutive_errors &gt;= 10:\n            raise RuntimeError(&quot;Too many consecutive errors, aborting&quot;)\n        return None\n\n    def poll_loop(self, symbols: list, interval_sec: float = 2.0):\n        &quot;&quot;&quot;Poll depth for all symbols every interval_sec.&quot;&quot;&quot;\n        while True:\n            for symbol in symbols:\n                depth = self.fetch_depth(symbol)\n                if depth:\n                    best_bid = float(depth[&quot;bids&quot;][0][0]) if depth[&quot;bids&quot;] else 0\n                    best_ask = float(depth[&quot;asks&quot;][0][0]) if depth[&quot;asks&quot;] else 0\n                    logging.info(f&quot;{symbol} bid={best_bid} ask={best_ask} spread={best_ask - best_bid:.4f}&quot;)\n                time.sleep(0.5)  # stagger requests\n            time.sleep(interval_sec)\n\npoller = WeightAwarePoller()\ntry:\n    poller.poll_loop(SYMBOLS, interval_sec=5.0)\nexcept KeyboardInterrupt:\n    logging.info(&quot;Stopped by user&quot;)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>Code Example 5: Node.js (axios) with Proxy Rotation\u003C\u002Fh2>\n\n\u003Cp>For JavaScript\u002FTypeScript teams, here's an equivalent implementation using \u003Ccode>axios\u003C\u002Fcode> with a proxy agent. This example fetches ticker prices for multiple symbols with retry logic and weight tracking.\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>const axios = require(&apos;axios&apos;);\nconst { HttpsProxyAgent } = require(&apos;https-proxy-agent&apos;);\nconst { SocksProxyAgent } = require(&apos;socks-proxy-agent&apos;);\n\nconst BINANCE_BASE = &apos;https:\u002F\u002Fapi.binance.com&apos;;\nconst PROXY_USER = &apos;user-country-DE&apos;;\nconst PROXY_PASS = &apos;your_password&apos;;\n\n\u002F\u002F HTTP proxy via gate.proxyhat.com:8080\nconst HTTP_PROXY_URL = `http:\u002F\u002F${PROXY_USER}:${PROXY_PASS}@gate.proxyhat.com:8080`;\n\u002F\u002F SOCKS5 alternative via gate.proxyhat.com:1080\nconst SOCKS5_PROXY_URL = `socks5:\u002F\u002F${PROXY_USER}:${PROXY_PASS}@gate.proxyhat.com:1080`;\n\nconst agent = new HttpsProxyAgent(HTTP_PROXY_URL);\n\nconst SYMBOLS = [&apos;BTCUSDT&apos;, &apos;ETHUSDT&apos;, &apos;BNBUSDT&apos;, &apos;SOLUSDT&apos;, &apos;XRPUSDT&apos;,\n                 &apos;ADAUSDT&apos;, &apos;DOGEUSDT&apos;, &apos;AVAXUSDT&apos;, &apos;DOTUSDT&apos;, &apos;LINKUSDT&apos;];\n\nconst MAX_CONCURRENCY = 5;\nconst MAX_WEIGHT_PER_MIN = 5500;\nlet currentWeight = 0;\nlet weightResetTime = Date.now() + 60000;\n\nfunction checkWeight() {\n  const now = Date.now();\n  if (now &gt; weightResetTime) {\n    currentWeight = 0;\n    weightResetTime = now + 60000;\n  }\n  if (currentWeight &gt;= MAX_WEIGHT_PER_MIN) {\n    const sleepMs = weightResetTime - now;\n    console.log(`Weight ${currentWeight} &gt;= ${MAX_WEIGHT_PER_MIN}, sleeping ${sleepMs}ms`);\n    return new Promise(resolve =&gt; setTimeout(resolve, Math.max(sleepMs, 0)));\n  }\n  return Promise.resolve();\n}\n\nasync function fetchTickerPrice(symbol, attempt = 0) {\n  await checkWeight();\n\n  try {\n    const url = `${BINANCE_BASE}\u002Fapi\u002Fv3\u002Fticker\u002Fprice`;\n    const resp = await axios.get(url, {\n      params: { symbol },\n      httpsAgent: agent,\n      timeout: 15000,\n    });\n\n    const usedWeight = parseInt(resp.headers[&apos;x-mbx-used-weight-1m&apos;] || &apos;0&apos;, 10);\n    currentWeight = usedWeight;\n\n    console.log(`${symbol} price=${resp.data.price} weight=${usedWeight}`);\n    return { symbol, price: parseFloat(resp.data.price) };\n\n  } catch (err) {\n    if (err.response) {\n      const status = err.response.status;\n      const usedWeight = parseInt(\n        err.response.headers[&apos;x-mbx-used-weight-1m&apos;] || &apos;0&apos;, 10\n      );\n      currentWeight = usedWeight;\n\n      if (status === 429) {\n        const retryAfter = parseInt(err.response.headers[&apos;retry-after&apos;] || &apos;5&apos;, 10);\n        console.warn(`${symbol} 429, waiting ${retryAfter}s`);\n        await new Promise(r =&gt; setTimeout(r, retryAfter * 1000));\n        currentWeight = 0;\n        weightResetTime = Date.now() + 60000;\n        if (attempt &lt; 5) return fetchTickerPrice(symbol, attempt + 1);\n      }\n\n      if (status === 418) {\n        console.error(`${symbol} 418 banned, waiting 120s`);\n        await new Promise(r =&gt; setTimeout(r, 120000));\n        currentWeight = 0;\n        weightResetTime = Date.now() + 60000;\n        if (attempt &lt; 3) return fetchTickerPrice(symbol, attempt + 1);\n      }\n\n      if (status === 451) {\n        console.error(`${symbol} 451 geo-blocked — switch country flag`);\n        throw new Error(&apos;Geo-blocked&apos;);\n      }\n    }\n\n    const backoff = Math.min(Math.pow(2, attempt) * 1000, 30000);\n    console.warn(`${symbol} error, backing off ${backoff}ms`);\n    await new Promise(r =&gt; setTimeout(r, backoff));\n    if (attempt &lt; 5) return fetchTickerPrice(symbol, attempt + 1);\n    throw err;\n  }\n}\n\nasync function main() {\n  const results = [];\n  \u002F\u002F Process in batches of MAX_CONCURRENCY\n  for (let i = 0; i &lt; SYMBOLS.length; i += MAX_CONCURRENCY) {\n    const batch = SYMBOLS.slice(i, i + MAX_CONCURRENCY);\n    const batchResults = await Promise.all(\n      batch.map(sym =&gt; fetchTickerPrice(sym).catch(e =&gt; ({ symbol: sym, error: e.message })))\n    );\n    results.push(...batchResults);\n  }\n\n  console.log(&apos;\\nResults:&apos;);\n  results.forEach(r =&gt; {\n    if (r.error) console.log(`${r.symbol}: ERROR ${r.error}`);\n    else console.log(`${r.symbol}: $${r.price}`);\n  });\n}\n\nmain().catch(console.error);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>Code Example 6: curl Quick Test\u003C\u002Fh2>\n\n\u003Cp>Before writing any code, verify your proxy setup with a single curl command:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode># Test klines endpoint through ProxyHat residential proxy (Germany exit)\ncurl -x &quot;http:\u002F\u002Fuser-country-DE:your_password@gate.proxyhat.com:8080&quot; \\\n  &quot;https:\u002F\u002Fapi.binance.com\u002Fapi\u002Fv3\u002Fklines?symbol=BTCUSDT&amp;interval=1h&amp;limit=5&quot; \\\n  -H &quot;Accept: application\u002Fjson&quot; \\\n  -D -  # dump headers to see X-MBX-USED-WEIGHT-1M\n\n# Test ticker\u002Fprice through SOCKS5\ncurl -x &quot;socks5:\u002F\u002Fuser-country-DE:your_password@gate.proxyhat.com:1080&quot; \\\n  &quot;https:\u002F\u002Fapi.binance.com\u002Fapi\u002Fv3\u002Fticker\u002Fprice?symbol=ETHUSDT&quot;\n\n# Test Binance.US with US exit IP\ncurl -x &quot;http:\u002F\u002Fuser-country-US:your_password@gate.proxyhat.com:8080&quot; \\\n  &quot;https:\u002F\u002Fapi.binance.us\u002Fapi\u002Fv3\u002Fticker\u002Fprice?symbol=BTCUSD&quot;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>When to Use WebSocket Streams Instead of REST Polling\u003C\u002Fh2>\n\n\u003Cp>Binance offers public WebSocket streams at \u003Ccode>wss:\u002F\u002Fstream.binance.com:9443\u003C\u002Fcode> that push real-time kline and depth updates. For live data, WebSockets are almost always better than REST polling:\u003C\u002Fp>\n\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Use Case\u003C\u002Fth>\n\u003Cth>REST Polling\u003C\u002Fth>\n\u003Cth>WebSocket Streams\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>Historical backfill\u003C\u002Ftd>\u003Ctd>✅ Best (paginated klines)\u003C\u002Ftd>\u003Ctd>❌ Not designed for history\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>Real-time price feed\u003C\u002Ftd>\u003Ctd>⚠️ Latency, weight cost\u003C\u002Ftd>\u003Ctd>✅ Push-based, ~0 weight\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>Live order book\u003C\u002Ftd>\u003Ctd>⚠️ 5–20 weight per poll\u003C\u002Ftd>\u003Ctd>✅ Diff updates, low overhead\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>Multi-symbol snapshot\u003C\u002Ftd>\u003Ctd>✅ One request, all symbols\u003C\u002Ftd>\u003Ctd>❌ Need one stream per symbol\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>Batch processing \u002F ETL\u003C\u002Ftd>\u003Ctd>✅ Natural fit\u003C\u002Ftd>\u003Ctd>❌ Requires stream management\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\n\u003Cp>The rule of thumb: use REST for historical data and batch snapshots, use WebSocket for continuous real-time monitoring. If you're polling \u003Ccode>\u002Fapi\u002Fv3\u002Fdepth\u003C\u002Fcode> more than once per second per symbol, switch to the \u003Ccode>&lt;symbol&gt;@depth\u003C\u002Fcode> WebSocket stream. You'll save enormous weight budget and get lower latency. For more on web scraping strategies at scale, see our \u003Ca href=\"\u002Fuse-cases\u002Fweb-scraping\">web scraping use case guide\u003C\u002Fa>.\u003C\u002Fp>\n\n\u003Ch2>Common Mistakes and Edge Cases\u003C\u002Fh2>\n\n\u003Ch3>1. Ignoring the X-MBX-USED-WEIGHT-1M Header\u003C\u002Fh3>\n\u003Cp>The single most common mistake. This header is your real-time fuel gauge. If you don't read it, you're flying blind and will hit 429s unpredictably. Every code example above reads and logs this header.\u003C\u002Fp>\n\n\u003Ch3>2. Using Datacenter Proxies for High-Frequency Polling\u003C\u002Fh3>\n\u003Cp>Datacenter IP ranges are well-known and more aggressively rate-limited by exchanges. Residential proxies distribute your requests across real ISP IPs, reducing the chance of collective bans. For Binance specifically, residential proxies from non-US countries give the best results for \u003Ccode>api.binance.com\u003C\u002Fcode>.\u003C\u002Fp>\n\n\u003Ch3>3. Not Handling HTTP 451 (Geo-Restriction)\u003C\u002Fh3>\n\u003Cp>If you accidentally route through a US IP to \u003Ccode>api.binance.com\u003C\u002Fcode>, you'll get 451 errors. Always set the country flag explicitly: \u003Ccode>-country-DE\u003C\u002Fcode> for Binance.com, \u003Ccode>-country-US\u003C\u002Fcode> for Binance.US.\u003C\u002Fp>\n\n\u003Ch3>4. No Exponential Backoff on 429\u002F418\u003C\u002Fh3>\n\u003Cp>Retrying immediately after a 429 is the fastest path to a 418 ban. Always respect the \u003Ccode>Retry-After\u003C\u002Fcode> header and add exponential backoff for non-429 errors (timeouts, proxy errors).\u003C\u002Fp>\n\n\u003Ch3>5. Over-Concurrent Requests from a Single IP\u003C\u002Fh3>\n\u003Cp>Even with weight headroom, sending 50 concurrent requests from one IP looks suspicious. Use semaphores or connection pools to limit concurrency to 5–10 per IP. With ProxyHat's rotating proxies, each request naturally gets a different IP, but sticky sessions need explicit concurrency control.\u003C\u002Fp>\n\n\u003Ch2>Key Takeaways\u003C\u002Fh2>\n\n\u003Cblockquote>\n\u003Cul>\n\u003Cli>Weight is per IP — rotating residential proxies through \u003Ccode>gate.proxyhat.com:8080\u003C\u002Fcode> gives each request its own ~6,000\u002Fmin budget.\u003C\u002Fli>\n\u003Cli>Always read \u003Ccode>X-MBX-USED-WEIGHT-1M\u003C\u002Fcode> — it's your real-time rate limit indicator. Throttle or rotate when it exceeds 5,000.\u003C\u002Fli>\n\u003Cli>Handle 429 and 418 distinctly — 429 means slow down (check \u003Ccode>Retry-After\u003C\u002Fcode>); 418 means you're banned (wait longer, rotate IP).\u003C\u002Fli>\n\u003Cli>Use sticky sessions for backfills — the \u003Ccode>-sid-abc123\u003C\u002Fcode> username flag keeps one IP for predictable weight tracking during pagination.\u003C\u002Fli>\n\u003Cli>Prefer WebSocket for real-time data — REST polling \u003Ccode>\u002Fapi\u002Fv3\u002Fdepth\u003C\u002Fcode> at 1Hz is wasteful; use \u003Ccode>&lt;symbol&gt;@depth\u003C\u002Fcode> streams instead.\u003C\u002Fli>\n\u003Cli>Geo-target with country flags — \u003Ccode>-country-DE\u003C\u002Fcode> for Binance.com, \u003Ccode>-country-US\u003C\u002Fcode> for Binance.US to avoid HTTP 451.\u003C\u002Fli>\n\u003Cli>Respect the Terms of Use — only collect public market data, honor weight limits, and check \u003Ca href=\"https:\u002F\u002Fdocs.proxyhat.com\u002F\" rel=\"noopener noreferrer\">ProxyHat docs\u003C\u002Fa> for the latest gateway configuration.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003C\u002Fblockquote>","Crypto API Weight Limits & Proxies (Binance Example) | ProxyHat","Learn how to scrape the Binance REST API with proxies. Map endpoints, handle weight limits, avoid 429\u002F418 bans, and rotate residential IPs through gate.proxyhat.com.","\u002Fblog\u002Fscrape-binance-rest-api-proxies",null,"Crypto Exchange API Rate Limits with Proxies | ProxyHat","Developer guide to scraping Binance REST API market data with rotating residential proxies. Code examples in Python and Node.js, weight-aware throttling, and IP ban avoidance.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fen\u002Fscrape-binance-rest-api-proxies-og.webp",[19,22,25,28],{"question":20,"answer":21},"Why does proxy rotation matter for Binance API scraping?","Binance enforces weight-based rate limits per IP address, not per API key. A single IP polling \u002Fapi\u002Fv3\u002Fdepth with limit=1000 (20 weight per call) at 10 symbols\u002Fsecond burns through the 6,000\u002Fmin budget in 30 seconds, triggering HTTP 429 and then HTTP 418 bans. Rotating residential proxies give each request a fresh IP with its own budget, dramatically increasing sustainable throughput.",{"question":23,"answer":24},"Which proxy type works best for Binance API scraping?","Residential proxies are the best choice for Binance API scraping. They use real ISP-assigned IP addresses, making them less likely to be flagged by Binance's anti-abuse systems compared to datacenter IPs. For Binance.com access, use non-US residential exits (e.g., -country-DE). For Binance.US, use US residential exits (-country-US). SOCKS5 on port 1080 is available if you need protocol-level flexibility.",{"question":26,"answer":27},"How do you avoid IP bans when scraping the Binance REST API?","To avoid bans: (1) always read the X-MBX-USED-WEIGHT-1M header and throttle before reaching 6,000; (2) respect Retry-After on 429 responses; (3) rotate IPs per request using ProxyHat's rotating residential proxies; (4) use sticky sessions for paginated backfills and rotate sessions when weight exceeds ~5,000; (5) limit concurrency to 5-10 per IP; (6) prefer WebSocket streams for real-time data instead of REST polling.",{"question":29,"answer":30},"Can I use the Binance REST API without an API key for market data?","Yes. Public market-data endpoints like \u002Fapi\u002Fv3\u002Fklines, \u002Fapi\u002Fv3\u002Fdepth, \u002Fapi\u002Fv3\u002Fticker\u002F24hr, and \u002Fapi\u002Fv3\u002Fticker\u002Fprice do not require authentication. However, you still consume per-IP weight on every request, so rate limiting applies regardless of whether you use an API key. Always check Binance's official API documentation for the current weight values and terms.",false,"2026-08-03T10:04:04+00:00","2026-10-04T01:29:50+00:00","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fen\u002Fscrape-binance-rest-api-proxies-master.webp","How to Scrape the Binance REST API with Proxies: A Developer Guide","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fen\u002Fscrape-binance-rest-api-proxies-card.webp",12,{"name":39,"slug":40,"bio":41,"avatar_url":14,"website_url":14,"social_links":14},"ProxyHat Team","proxyhat-team","The ProxyHat editorial team covers proxies, web scraping, and data extraction.",[43],{"id":44,"slug":45,"name":46,"description":14,"meta_title":47,"meta_description":48,"parent_id":14},4,"developer-guides","Developer Guides","Developer Guides | ProxyHat Blog","Code tutorials and SDK guides for integrating proxies into your applications.",[],{"fr":51,"pt":52,"ko":53,"ru":54,"en":13,"zh":55,"x-default":13},"\u002Ffr\u002Fblog\u002Fcomment-scraper-api-rest-binance-proxies","\u002Fpt\u002Fblog\u002Fcomo-raspar-api-binance-proxies","\u002Fko\u002Fblog\u002Fbinance-rest-api-proxy-scraping","\u002Fru\u002Fblog\u002Fkak-skrejpit-binance-rest-api-proksi","\u002Fcn\u002Fblog\u002Fbinance-rest-api-proxy-scraping-guide",{"tr":57,"fr":51,"ja":58,"pt":52,"ko":53,"pl":59,"es":60,"ru":54,"en":13,"zh":55,"it":61,"de":62},"\u002Ftr\u002Fblog\u002Fbinance-rest-api-proxy-tarama","\u002Fja\u002Fblog\u002Fbinance-api-scraping-proxy","\u002Fpl\u002Fblog\u002Fjak-scrapowac-rest-api-binance-proxy","\u002Fes\u002Fblog\u002Fscrapear-api-binance-proxies","\u002Fit\u002Fblog\u002Fscraping-binance-rest-api-con-proxy","\u002Fde\u002Fblog\u002Fbinance-rest-api-mit-proxies-scrapen",81,[65,97,123,138],{"id":66,"slug":67,"title":68,"excerpt":69,"featured_image_url":70,"featured_image_alt":68,"card_image_url":71,"og_image_url":72,"published_at":73,"updated_at":74,"content_updated_at":75,"reading_time_minutes":76,"is_featured":31,"indexable":4,"views":76,"author":77,"categories":78,"tags":80},210,"proxy-setup-for-ai-agents","Proxy Setup for AI Agents: browser-use, Crawl4AI and an MCP Server","Agents on cloud VMs exit from datacenter IPs. Here is current, working proxy configuration for browser-use, Crawl4AI and an MCP server, with a sticky-vs-rotating decision table and the cost traps to avoid.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fen\u002Fproxy-setup-for-ai-agents-master.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fen\u002Fproxy-setup-for-ai-agents-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fen\u002Fproxy-setup-for-ai-agents-og.webp","2026-10-24T09:00:00+00:00","2026-10-24T09:00:20+00:00","2026-10-03T09:31:26+00:00",14,{"name":39,"slug":40,"bio":41,"avatar_url":14,"website_url":14,"social_links":14},[79],{"id":44,"slug":45,"name":46,"description":14,"meta_title":47,"meta_description":48,"parent_id":14},[81,85,89,93],{"id":82,"slug":83,"name":84},1,"web-scraping","Web Scraping",{"id":86,"slug":87,"name":88},2,"residential-proxies","Residential Proxies",{"id":90,"slug":91,"name":92},9,"python","Python",{"id":94,"slug":95,"name":96},22,"playwright","Playwright",{"id":98,"slug":99,"title":100,"excerpt":101,"featured_image_url":102,"featured_image_alt":100,"card_image_url":103,"og_image_url":104,"published_at":105,"updated_at":106,"content_updated_at":75,"reading_time_minutes":76,"is_featured":31,"indexable":4,"views":107,"author":108,"categories":109,"tags":111},206,"camoufox-residential-proxies-python-guide","Camoufox with Residential Proxies: A Code-First Python Guide","How to run Camoufox, the C++-patched Firefox, behind residential proxies: current Python API, why geoip needs a sticky session, a fingerprint coherence checklist, and when Patchright or nodriver fits better.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fen\u002Fcamoufox-residential-proxies-python-guide-master.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fen\u002Fcamoufox-residential-proxies-python-guide-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fen\u002Fcamoufox-residential-proxies-python-guide-og.webp","2026-10-13T09:00:00+00:00","2026-10-13T09:00:22+00:00",29,{"name":39,"slug":40,"bio":41,"avatar_url":14,"website_url":14,"social_links":14},[110],{"id":44,"slug":45,"name":46,"description":14,"meta_title":47,"meta_description":48,"parent_id":14},[112,113,114,118,119],{"id":82,"slug":83,"name":84},{"id":86,"slug":87,"name":88},{"id":115,"slug":116,"name":117},6,"anti-detection","Anti-Detection",{"id":90,"slug":91,"name":92},{"id":120,"slug":121,"name":122},21,"headless-browser","Headless Browser",{"id":124,"slug":125,"title":126,"excerpt":127,"featured_image_url":128,"featured_image_alt":126,"card_image_url":129,"og_image_url":130,"published_at":131,"updated_at":131,"content_updated_at":132,"reading_time_minutes":37,"is_featured":31,"indexable":4,"views":133,"author":134,"categories":135,"tags":137},176,"got-scraping-nodejs-residential-proxies","got-scraping in Node.js: A Developer's Guide with Residential Proxies","A practical guide to using Apify's got-scraping HTTP client in Node.js with residential proxies — header generation, proxy rotation, retry hooks, and Crawlee scaling patterns for production scrapers.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fen\u002Fgot-scraping-nodejs-residential-proxies-master.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fen\u002Fgot-scraping-nodejs-residential-proxies-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fen\u002Fgot-scraping-nodejs-residential-proxies-og.webp","2026-08-04T16:05:06+00:00","2026-10-03T08:29:58+00:00",121,{"name":39,"slug":40,"bio":41,"avatar_url":14,"website_url":14,"social_links":14},[136],{"id":44,"slug":45,"name":46,"description":14,"meta_title":47,"meta_description":48,"parent_id":14},[],{"id":139,"slug":140,"title":141,"excerpt":142,"featured_image_url":143,"featured_image_alt":141,"card_image_url":144,"og_image_url":145,"published_at":146,"updated_at":146,"content_updated_at":147,"reading_time_minutes":37,"is_featured":31,"indexable":31,"views":148,"author":149,"categories":150,"tags":152},175,"rotating-proxies-in-colly-golang","Rotating Proxies in Colly: A Framework-Idiomatic Guide for Go Developers","A developer-first guide to implementing rotating proxies in Colly using residential IPs, custom proxy switchers, geo-targeting, and production patterns for high-throughput Go web scraping.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fen\u002Frotating-proxies-in-colly-golang-master.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fen\u002Frotating-proxies-in-colly-golang-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fen\u002Frotating-proxies-in-colly-golang-og.webp","2026-08-04T10:05:34+00:00","2026-10-03T08:29:56+00:00",71,{"name":39,"slug":40,"bio":41,"avatar_url":14,"website_url":14,"social_links":14},[151],{"id":44,"slug":45,"name":46,"description":14,"meta_title":47,"meta_description":48,"parent_id":14},[],[]]