# ipvolt: complete English documents > Mobile and residential proxies for developers and data teams. Mobile proxies: A dedicated device on a carrier network, rented by the day. Residential proxies: Rotating or sticky IPs with country selection, in prepaid packs billed per GB. Dedicated mobile is one device rented by the day, with no traffic limit. Mobile per GB uses the same prepaid GB on a shared pool of carrier modems. This file holds the complete Markdown of the 138 English website pages listed in [llms.txt](https://ipvolt.com/llms.txt), in the same order. Each document starts after a line of three hyphens with "Document N of 138", its title, its canonical URL and its Markdown URL, followed by exactly the Markdown that URL serves. Not included: the Russian, Spanish and Chinese translations, whose Markdown URLs llms.txt lists. Of the agent integrations below, these are linked rather than embedded: Agent access (auth.md), API catalog, OpenAPI description, OpenAPI description (root path), A2A agent, UCP profile, ACP checkout, x402 top-up, MPP top-up, MCP server card, Agent Skills index, and AI catalog. Fetch each linked file for its current content. The Proxy Toolkit MCP server entry links the Markdown of Document 9, which this file includes. ## Agent integrations - [Agent access (auth.md)](https://ipvolt.com/auth.md): How an AI agent gets access to a customer's ipvolt account and API: it registers with the customer's email, the customer confirms with a 6-digit code and chooses view-only access or a spending cap, and the agent gets access tokens. - [API catalog](https://ipvolt.com/.well-known/api-catalog): RFC 9727 linkset for the customer API (base path `/beta/api/v1/`), the A2A agent and the ACP checkout API, linking the OpenAPI description, the Agent Card, the ACP discovery document, auth.md and health status. - [OpenAPI description](https://ipvolt.com/beta/api/v1/openapi.json): OpenAPI 3.1 document for the customer API: balance, catalog, orders, proxies, usage, purchases and renewals, plus the agent registration and token endpoints. - [OpenAPI description (root path)](https://ipvolt.com/openapi.json): The same OpenAPI 3.1 document at the conventional root path, byte for byte the same as `/beta/api/v1/openapi.json`. - [A2A agent](https://ipvolt.com/.well-known/agent-card.json): Agent Card of ipvolt's A2A agent at https://ipvolt.com/beta/a2a (JSON-RPC, A2A 1.0 and 0.3): the live mobile proxy catalog without a credential; with an auth.md agent token, the account's balance, orders and proxies, rentals and renewals. - [UCP profile](https://ipvolt.com/.well-known/ucp): Universal Commerce Protocol business profile (version 2026-08-25): mobile proxy catalog search and lookup over REST, and a permalink to the dashboard checkout, where the buyer pays from their balance. It declares no payment handlers. - [ACP checkout](https://ipvolt.com/.well-known/acp.json): Agentic Commerce Protocol discovery document (API version 2026-04-17). The checkout API at https://ipvolt.com/beta/api/acp takes an auth.md agent token with `proxies:buy` and charges the customer's prepaid balance, within their spending limit. No cards. - [x402 top-up](https://ipvolt.com/api/v1): Answers HTTP 402 with an x402 v2 `PAYMENT-REQUIRED` header (scheme `exact`, USDC on Base, `eip155:8453`). Paying it with an agent access token or API key adds prepaid balance after on-chain confirmation: 1 USDC = 1.00 USD, 1 to 500 USD per payment. - [MPP top-up](https://ipvolt.com/beta/api/v1/fund): The x402 top-up at its API path (`?amountMinor=N`, US cents). It also answers a Machine Payments Protocol `WWW-Authenticate: Payment` challenge (method `evm`, intent `charge`), and `/openapi.json` carries `x-payment-info` on the funding operations. - [Proxy Toolkit MCP server](https://ipvolt.com/mcp.md): Documentation of the hosted MCP server at https://mcp.ipvolt.com/mcp (Streamable HTTP, no account or API key) and its 4 tools: search_proxy_docs, get_proxy_doc, generate_proxy_config, and diagnose_proxy_error. - [MCP server card](https://ipvolt.com/.well-known/mcp/server-card.json): Machine-readable MCP Server Card describing the hosted MCP server above. - [Agent Skills index](https://ipvolt.com/.well-known/agent-skills/index.json): Index of ipvolt's Agent Skills; each skill is a SKILL.md file at `/.well-known/agent-skills//SKILL.md`. - [AI catalog](https://ipvolt.com/.well-known/ai-catalog.json): Machine-readable catalog of ipvolt's agent integrations. --- Document 1 of 138: ipvolt URL: https://ipvolt.com/ Markdown: https://ipvolt.com/index.md # ipvolt Source: https://ipvolt.com/ Markdown: https://ipvolt.com/index.md [Tools](https://ipvolt.com/tools.md) · [Guides](https://ipvolt.com/guides.md) · [Blog](https://ipvolt.com/blog.md) · [Pricing](https://ipvolt.com/#pricing) Dedicated mobile proxies, by the day. A real device on a carrier network in 11 countries. From $9 a day. No traffic limit. Nothing renews on its own. [Rent a mobile proxy](https://ipvolt.com/mobile-proxies#mobile-prices) ## Mobile proxies A dedicated device on a carrier network. Rotate its IP on demand or on a schedule. From $9/day. One dedicated device. Or from $100 for 30 days ($3.33/day). Pay with crypto. Nothing renews on its own. If a device fails and we cannot repair or replace it, we credit the unused part of the rental to your balance, pro rata by the hour. [Buy a mobile proxy](https://ipvolt.com/dashboard/mobile): choose a country, carrier and 1 day or 30 days in the customer dashboard, sign in or create an account, and pay. This document does not place an order. ## Residential proxies IPs from a mixed peer network, with country selection, billed per GB. From $2.20/GB. Prepaid packs from 1 GB to 250 GB, at the same price per GB in every pack. Country selection, HTTP and SOCKS5, sticky or rotating sessions. Pay with crypto. Nothing renews on its own. A pack is prepaid, and you pick the country in the dashboard, which lists the countries available now. Residential proxies from $2.20/GB, in prepaid packs. [Buy residential traffic](https://ipvolt.com/dashboard/residential): choose a prepaid pack in the customer dashboard, sign in or create an account, and pay. This document does not place an order. ## What are you building? ### With a mobile proxy #### [Check search results and prices as a mobile user](https://ipvolt.com/proxies/uk.md) See what UK visitors on Three see. #### [Test sign-up and checkout on a real carrier](https://ipvolt.com/proxies/usa.md) Run your app through Verizon or T-Mobile in the US. #### [Monitor a store from the country it sells in](https://ipvolt.com/proxies/germany.md) Watch a German shop from O2 or Vodafone. ### With residential proxies #### [Collect public data across many pages](https://ipvolt.com/residential-proxies.md) Rotate IPs between requests and pay for the GB you use. #### [Monitor prices across many pages](https://ipvolt.com/residential-proxies.md) Spread requests over a country’s residential IPs, and keep a sticky session where a page needs one. #### [Check what a page shows in another country](https://ipvolt.com/residential-proxies.md) Pick the country in the dashboard and compare the responses. ## Proxy and scraping tools. Free, and they work with any provider. You don’t need an ipvolt account. ### Proxy setup. Inside your AI agent. Generate proxy configurations, diagnose connection errors, and find the right guide. [Open Proxy Toolkit MCP](https://ipvolt.com/mcp.md) ### See where your scraper’s proxy bandwidth goes. Find the smallest response that still contains your data. [Open scrapescope](https://ipvolt.com/guides/scraper-bandwidth-report.md) ### Check a proxy before you rely on it. Paste up to 50 proxies to see which work, the IP and location sites see, and why the others fail. Every proxy is tested against ipvolt’s own endpoint, never against another site. [Open the proxy checker](https://ipvolt.com/tools/proxy-checker.md) [All free tools](https://ipvolt.com/tools.md) ## Make your next request clearer. Provider-neutral examples for cURL, Python, Node.js and Playwright, plus protocols, sessions and authentication explained. [Explore the guides](https://ipvolt.com/guides.md) ### Start with your market. - [Germany](https://ipvolt.com/proxies/germany.md): O2, Vodafone and 1&1, from $9 a day. - [United States](https://ipvolt.com/proxies/usa.md): Verizon, T-Mobile 5G, T-Mobile and AT&T, from $17 a day. - [United Kingdom](https://ipvolt.com/proxies/uk.md): Three, from $14 a day. - [France](https://ipvolt.com/proxies/france.md): SFR and Free, from $9 a day. - [Netherlands](https://ipvolt.com/proxies/netherlands.md): Vodafone and Odido, from $9 a day. - [Poland](https://ipvolt.com/proxies/poland.md): Play, from $9 a day. - [Singapore](https://ipvolt.com/proxies/singapore.md): Singtel and M1, from $19 a day. - [New Zealand](https://ipvolt.com/proxies/new-zealand.md): One NZ, from $12 a day. - [Georgia](https://ipvolt.com/proxies/georgia.md): Magti, from $9 a day. - [Australia](https://ipvolt.com/proxies/australia.md): Vodafone, from $19 a day. - [Italy](https://ipvolt.com/proxies/italy.md): WindTre, from $9 a day. - [All country pages](https://ipvolt.com/proxies.md) ## Questions. ### How do I get started? Create an account and add funds with crypto. For a mobile proxy, pick a country and carrier and choose 1 day or 30 days. For residential, buy a prepaid pack and pick a country. Your endpoint and credentials appear in your dashboard, ready for cURL, Python, Node.js or Playwright. ### Mobile or residential? A mobile proxy is a dedicated device on a carrier network, rented for a day or 30 days. You can rotate its IP on demand or on a schedule. Residential proxies route requests through a mixed network of devices and connections supplied by independent partners, with country selection, billed per GB in prepaid packs. Both work over HTTP and SOCKS5. Dedicated mobile is one device rented by the day, with no traffic limit. Mobile per GB uses the same prepaid GB on a shared pool of carrier modems. ### Which payment methods can I use? Crypto, through our NOWPayments checkout: Tether (USDT), USD Coin (USDC), Bitcoin (BTC), Ethereum (ETH), Solana (SOL) and more. Card payments are coming soon. ### Does anything renew automatically? No. A mobile rental ends with the period you chose, and you can renew it from the dashboard. Residential packs are prepaid. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. Contact: [hello@ipvolt.com](mailto:hello@ipvolt.com) ## Stay connected - [GitHub: /ipvolt](https://github.com/ipvolt) - [X: @ipvolt](https://x.com/ipvolt) - [Telegram: @ipvolt](https://t.me/ipvolt) - [Telegram channel: @ipvolt_news](https://t.me/ipvolt_news) --- Document 2 of 138: Build a better connection. URL: https://ipvolt.com/guides Markdown: https://ipvolt.com/guides.md # Build a better connection. Source: https://ipvolt.com/guides Markdown: https://ipvolt.com/guides.md Practical proxy knowledge, from the first request to the details that matter. Clear examples. Useful distinctions. Fewer assumptions. [Browse the country collection](https://ipvolt.com/guides/countries.md) ## Connection notes ### 1. Your client cURL · Python · Node.js · Playwright Protocol & authentication ### 2. Proxy gateway Connection · Credentials · Session Request & response ### 3. Destination The service you’re connecting to A general proxy flow. These guides work with any provider. ## Connect your stack. Explicit configuration, bounded requests and a clear way to verify the connection. - [Use a proxy with curl](https://ipvolt.com/guides/curl-proxy-setup.md): How to use a proxy with curl: the -x flag, http_proxy and https_proxy variables, SOCKS5 with socks5h, proxy authentication, and reading CONNECT and 407 errors. (7 min read) - [Configure Python Requests](https://ipvolt.com/guides/python-requests-proxy.md): Configure a proxy in Python Requests: the proxies dictionary, Session defaults, credentials, SOCKS5 via requests[socks], environment variables and ProxyError. (7 min read) - [Use a proxy with Node.js fetch](https://ipvolt.com/guides/nodejs-fetch-proxy.md): Route Node.js native fetch through an Undici ProxyAgent with explicit authentication, an abort deadline and response cleanup. (4 min read) - [Configure a proxy in Playwright](https://ipvolt.com/guides/playwright-proxy-setup.md): Set an authenticated HTTP proxy for a Playwright browser context, keep test state isolated, and diagnose navigation separately from subresources. (4 min read) - [HTTPX async proxies](https://ipvolt.com/guides/httpx-async-proxy.md): Configure an HTTPX async proxy client, close streamed responses correctly, and reproduce a PoolTimeout locally before changing your proxy settings. (7 min read) - [Amazon listing notifications](https://ipvolt.com/guides/amazon-listing-notifications.md): Handle Amazon SP-API listing events with a tested SQLite inbox: deduplicate deliveries, recover after restart and reject superseded reads. (6 min read) - [Australian time zones in Playwright](https://ipvolt.com/guides/playwright-australia-timezones.md): Run 12 Australian browser-clock checks in Playwright, including Lord Howe’s 30-minute change. Separate fixed UTC inputs, browser time zones and the Node runner. (6 min read) - [Shopify Canada localization](https://ipvolt.com/guides/shopify-canada-localization.md): Use a configuration snapshot and paired visits to test Shopify Canada localization. Separate IP, URL, language, saved choice and shipping-address effects. (9 min read) - [Accept-Encoding defaults by client](https://ipvolt.com/guides/curl-compressed-accept-encoding.md): curl, Wget 1.x, urllib, node:http, PHP curl, Guzzle and java.net.http.HttpClient send no Accept-Encoding (or identity) by default. Tested fixes and byte checks. (20 min read) - [Axios proxy setup](https://ipvolt.com/guides/axios-proxy-setup.md): Configure Axios proxies in Node.js, separate explicit settings from environment and agent routing, and reproduce authentication and TLS checks. (8 min read) - [aiohttp proxy setup in 3.14](https://ipvolt.com/guides/aiohttp-proxy-setup.md): Set up an HTTP or SOCKS proxy in aiohttp 3.14: replace the deprecated BasicAuth and proxy_auth, turn on trust_env, and read the 407 and Bad status line errors. (7 min read) - [Scrapy proxy setup in 2.19](https://ipvolt.com/guides/scrapy-proxy-setup.md): Scrapy 2.19 proxy setup: credentials in meta["proxy"], per-request rotation, HTTP_PROXY, and fixes for TunnelError 407, ignored 407 responses and socks5. (8 min read) - [curl_cffi proxy setup](https://ipvolt.com/guides/curl-cffi-proxy-setup.md): curl_cffi proxy setup on 0.16.3: credentials with impersonate, why a CONNECT 407 raises ConnectionError and not ProxyError, HTTP_PROXY rules, socks5h. (8 min read) - [Block images and fonts in Playwright](https://ipvolt.com/guides/playwright-block-images-save-bandwidth.md): Block images, fonts and media in Playwright with route() in Python and Node.js, for a whole browser context or by host, plus cache and service worker caveats. (7 min read) - [Git proxy setup](https://ipvolt.com/guides/git-proxy-setup.md): Configure a Git HTTP or HTTPS proxy, diagnose 407 and certificate failures, and remove the correct setting. Includes a tested routing fixture. (8 min read) - [npm proxy settings](https://ipvolt.com/guides/npm-proxy-settings.md): Set npm proxy and https-proxy, resolve npmrc and environment conflicts, verify package downloads, and fix trust or routing without disabling TLS checks. (9 min read) ## Understand the tradeoffs. Choose a protocol, session model or network type with the right questions in mind. - [HTTP vs SOCKS5 proxies](https://ipvolt.com/guides/http-vs-socks5-proxies.md): Compare HTTP CONNECT and SOCKS5, understand DNS placement and TLS boundaries, and select a protocol your actual client and provider support. (4 min read) - [Rotating vs sticky proxies](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md): Choose rotation around the smallest complete workflow, distinguish exit affinity from cookies, and test what happens when a sticky session ends early. (4 min read) - [Mobile vs residential proxies](https://ipvolt.com/guides/mobile-vs-residential-proxies.md): Compare carrier and household exit networks for QA, keep browser emulation separate, and measure the capabilities your workflow actually needs. (4 min read) ## Find the failure. Separate authentication, connectivity and destination errors before changing your setup. - [Fix proxy error 407](https://ipvolt.com/guides/fix-proxy-error-407.md): Diagnose Proxy Authentication Required in a repeatable order: gateway, authentication method, credential encoding, account scope and client configuration. (11 min read) - [Proxy environment variables](https://ipvolt.com/guides/proxy-environment-variables.md): Diagnose HTTP_PROXY, HTTPS_PROXY, ALL_PROXY and NO_PROXY routing differences in curl, Python Requests and Node.js with an isolated local check. (6 min read) - [Diagnose proxy timeouts](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md): Separate proxy DNS, TCP, CONNECT, TLS and response delays with curl timings, then set request deadlines and decide whether a retry is safe. (9 min read) - [Fix ERR_TUNNEL_CONNECTION_FAILED](https://ipvolt.com/guides/fix-err-tunnel-connection-failed.md): ERR_TUNNEL_CONNECTION_FAILED and ERR_PROXY_CONNECTION_FAILED explained with a verified failure matrix, plus how to recover the CONNECT status Chromium hides. (9 min read) - [Node.js fetch failed behind a proxy](https://ipvolt.com/guides/fix-node-fetch-failed-proxy.md): TypeError: fetch failed hides the real error in err.cause. Find yours: ENOTFOUND, UND_ERR_CONNECT_TIMEOUT, invalid onError method or a proxy 403/407/502. (22 min read) - [Node.js fetch ignores HTTPS_PROXY](https://ipvolt.com/guides/node-fetch-ignores-https-proxy.md): Node's built-in fetch skips HTTPS_PROXY, so requests hit UND_ERR_CONNECT_TIMEOUT while curl works. Set NODE_USE_ENV_PROXY=1 on Node 22.21+ and 24+. (11 min read) - [SSL WRONG_VERSION_NUMBER behind a proxy](https://ipvolt.com/guides/fix-ssl-wrong-version-number-proxy.md): The same SSL wrong version number error comes from two hops behind a proxy. Tell which one failed in curl, Requests and HTTPX, then apply the right fix. (8 min read) - [SSL EOF behind a proxy](https://ipvolt.com/guides/fix-ssl-unexpected-eof-proxy.md): [SSL: UNEXPECTED_EOF_WHILE_READING], SSLEOFError or curl error 0A000126 through a proxy: was the request sent, can you retry, and which side should you check? (22 min read) - [Missing dependencies for SOCKS support](https://ipvolt.com/guides/fix-missing-dependencies-for-socks-support.md): Fix Missing dependencies for SOCKS support, No module named 'socks' and socksio ImportError in pip, Requests and HTTPX: install the extra or clear ALL_PROXY. (7 min read) - [Scrapy start_requests() not called](https://ipvolt.com/guides/scrapy-start-requests-not-called.md): Scrapy 2.16 removed Spider.start_requests(): the spider logs Crawled 0 pages and closes as finished with no warning. Fix: async def start(). Tested on 2.19. (6 min read) - [Tunnel connection failed: 502/503](https://ipvolt.com/guides/fix-proxy-tunnel-502-503.md): A 502, 503 or 504 during CONNECT comes from the proxy; a 502 after the tunnel opens comes from the site. How to tell them apart in each client and fix both. (7 min read) - [invalid onError method on Node.js 26](https://ipvolt.com/guides/node-26-invalid-onerror-method.md): Node.js 26 fetch fails with invalid onError method (UND_ERR_INVALID_ARG) when given an undici 5 or 6 Agent or ProxyAgent. Fix: use undici's own fetch. (9 min read) - [Axios proxy not working](https://ipvolt.com/guides/fix-axios-proxy-not-working.md): Axios skips your proxy or fails through it in Node.js? 16 causes with tested fixes: proxy: false in 1.21, HTTP/2, CONNECT, 407, NO_PROXY, redirects, SOCKS5. (15 min read) ## Check the location. Evaluate local networks, exit locations and the evidence a country-specific proxy test needs. - [Netherlands proxies](https://ipvolt.com/guides/netherlands-proxies.md): Evaluate Netherlands proxies with Dutch network context, exit-IP and city checks, ASN evidence, and a practical trial checklist before choosing a provider. (9 min read) - [USA proxies](https://ipvolt.com/guides/usa-proxies.md): Evaluate USA proxies by country, state and city. Compare network evidence, plan regional checks and measure session behavior before choosing a provider. (9 min read) - [UK proxies](https://ipvolt.com/guides/uk-proxies.md): Evaluate UK proxies with current carrier context, UK and GB geography, postcode limitations and a practical test plan for country or network requirements. (9 min read) - [How to test a Germany proxy](https://ipvolt.com/guides/germany-proxies.md): Evaluate Germany proxies with current carrier and roaming context, city-location limits, browser-language controls and a practical acceptance checklist. (9 min read) - [France proxies](https://ipvolt.com/guides/france-proxies.md): Evaluate France proxies with carrier and brand distinctions, mainland and overseas scope, exit-IP evidence, and a practical localization test matrix. (9 min read) - [Brazil proxies](https://ipvolt.com/guides/brazil-proxies.md): Brazil proxies, mobile or residential: what the label proves, Vivo, Claro and TIM context, states and time zones, CEP and CPF inputs and a trial plan. (10 min read) - [Portugal proxies](https://ipvolt.com/guides/portugal-proxies.md): Specify and verify Portugal proxies: mainland and island scope, ANACOM operator names, pt-PT settings, Portuguese checkout fields and a four-row trial. (10 min read) - [How to test an Australian proxy](https://ipvolt.com/guides/australia-proxies.md): Choose the evidence an Australian proxy test needs: country or city, Telstra/Optus/TPG network labels, nbn provider layers and session requirements. (6 min read) - [Canada proxies](https://ipvolt.com/guides/canada-proxies.md): Evaluate Canada proxies with a country, carrier and session acceptance matrix. Separate Rogers, Bell, TELUS and Quebecor brands from the evidence you need. (8 min read) - [Japan proxies](https://ipvolt.com/guides/japan-proxies.md): Evaluate Japan proxies with separate IP-location, egress and mobile-access evidence. Work through au/UQ branding and Rakuten roaming before accepting a sample. (7 min read) ## Inspect your traffic. Open a report and understand what your scraper transferred. - [Scrapescope bandwidth analyzer](https://ipvolt.com/guides/scraper-bandwidth-report.md): Free open-source tool that shows where your scraper's proxy bandwidth goes and finds the smallest response containing your data. Works with any provider. ## About this library Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. [Agent reading index](https://ipvolt.com/llms.txt) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 3 of 138: Proxy guides, by country. URL: https://ipvolt.com/guides/countries Markdown: https://ipvolt.com/guides/countries.md # Proxy guides, by country. Source: https://ipvolt.com/guides/countries Markdown: https://ipvolt.com/guides/countries.md Country proxy guides for Japan, Australia, Canada, Europe and the Americas. Evaluate local network names, IP locations and session evidence before a trial. Choose the country your application needs to recognize. Each guide explains local network names, geographic requirements and a practical way to evaluate a proxy sample. Keep IP location, browser settings and delivery addresses as separate test inputs. These are research guides. Of the countries here, ipvolt sells mobile proxies in Germany, the United States, the United Kingdom, France and the Netherlands; it doesn't sell them in the others today. ## Start with your market. ipvolt by location - [Germany proxies](https://ipvolt.com/proxies/germany): Use cases and mobile carriers. - [USA proxies](https://ipvolt.com/proxies/usa): Retail location and delivery checks. - [Netherlands proxies](https://ipvolt.com/proxies/netherlands): Storefront and delivery checks. - [Brazil proxies](https://ipvolt.com/proxies/brazil): CEP, store locator and carrier checks. - [Portugal proxies](https://ipvolt.com/proxies/portugal): Delivery, search and checkout tests. - [Canada proxies](https://ipvolt.com/proxies/canada): Localization and mobile network checks. - [UK proxies](https://ipvolt.com/proxies/uk): Mobile proxies on Three. - [France proxies](https://ipvolt.com/proxies/france): Mobile proxies on SFR and Free. - [Poland proxies](https://ipvolt.com/proxies/poland): Mobile proxies on Play. - [Singapore proxies](https://ipvolt.com/proxies/singapore): Mobile proxies on Singtel and M1. - [New Zealand proxies](https://ipvolt.com/proxies/new-zealand): Mobile proxies on One NZ. - [Georgia proxies](https://ipvolt.com/proxies/georgia): Mobile proxies on Magti. - [Australia proxies](https://ipvolt.com/proxies/australia): Mobile proxies on Vodafone. - [Italy proxies](https://ipvolt.com/proxies/italy): Mobile proxies on WindTre. ## Define your location. Write down the country or territory, any required city, the access type and the destination you need to test. A gateway location, an IP registration address and an observed exit are different pieces of evidence. ## Choose a country Choose a country to research local networks and location requirements, then define the evidence your sample must provide. Each guide states its sources and limits. - [Netherlands proxies](https://ipvolt.com/guides/netherlands-proxies.md): Evaluate Netherlands proxies with Dutch network context, exit-IP and city checks, ASN evidence, and a practical trial checklist before choosing a provider. (9 min read) - [USA proxies](https://ipvolt.com/guides/usa-proxies.md): Evaluate USA proxies by country, state and city. Compare network evidence, plan regional checks and measure session behavior before choosing a provider. (9 min read) - [UK proxies](https://ipvolt.com/guides/uk-proxies.md): Evaluate UK proxies with current carrier context, UK and GB geography, postcode limitations and a practical test plan for country or network requirements. (9 min read) - [How to test a Germany proxy](https://ipvolt.com/guides/germany-proxies.md): Evaluate Germany proxies with current carrier and roaming context, city-location limits, browser-language controls and a practical acceptance checklist. (9 min read) - [France proxies](https://ipvolt.com/guides/france-proxies.md): Evaluate France proxies with carrier and brand distinctions, mainland and overseas scope, exit-IP evidence, and a practical localization test matrix. (9 min read) - [Brazil proxies](https://ipvolt.com/guides/brazil-proxies.md): Brazil proxies, mobile or residential: what the label proves, Vivo, Claro and TIM context, states and time zones, CEP and CPF inputs and a trial plan. (10 min read) - [Portugal proxies](https://ipvolt.com/guides/portugal-proxies.md): Specify and verify Portugal proxies: mainland and island scope, ANACOM operator names, pt-PT settings, Portuguese checkout fields and a four-row trial. (10 min read) - [How to test an Australian proxy](https://ipvolt.com/guides/australia-proxies.md): Choose the evidence an Australian proxy test needs: country or city, Telstra/Optus/TPG network labels, nbn provider layers and session requirements. (6 min read) - [Canada proxies](https://ipvolt.com/guides/canada-proxies.md): Evaluate Canada proxies with a country, carrier and session acceptance matrix. Separate Rogers, Bell, TELUS and Quebecor brands from the evidence you need. (8 min read) - [Japan proxies](https://ipvolt.com/guides/japan-proxies.md): Evaluate Japan proxies with separate IP-location, egress and mobile-access evidence. Work through au/UQ branding and Rakuten roaming before accepting a sample. (7 min read) ## Three checks before a trial. ### Set the geographic scope Specify whether country-level targeting is enough. Record any region, city or territory requirement before comparing results. ### Separate the network claims Ask which evidence supports the exit network and access type. A retail carrier brand or coverage map does not establish proxy inventory. ### Agree what passes Choose a small, bounded test and record the observed exit, target response and session behavior. Resolve conflicting location signals before expanding the trial. [Explore setup and troubleshooting guides](https://ipvolt.com/guides.md) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [See which countries and carriers are on sale.](https://ipvolt.com/pricing) [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 4 of 138: Proxy pricing. URL: https://ipvolt.com/pricing Markdown: https://ipvolt.com/pricing.md # Proxy pricing. Source: https://ipvolt.com/pricing Markdown: https://ipvolt.com/pricing.md [Home](https://ipvolt.com/index.md) / Pricing A dedicated device on a carrier network. Rotate its IP on demand or on a schedule. Rent one for a day or for 30 days, pay with crypto, and nothing renews on its own. Nothing renews on its own. If a device fails and we cannot repair or replace it, we credit the unused part of the rental to your balance, pro rata by the hour. ## Mobile proxies Try any carrier for a day from $9. | Country | Carrier | 1 day | 30 days | | --- | --- | --- | --- | | [Germany](https://ipvolt.com/proxies/germany.md) | O2 | [$9](https://ipvolt.com/dashboard/mobile?country=DE&plan=day&carrier=O2) | [$119](https://ipvolt.com/dashboard/mobile?country=DE&plan=month&carrier=O2) ($3.97/day) | | Germany | Vodafone | [$9](https://ipvolt.com/dashboard/mobile?country=DE&plan=day&carrier=Vodafone%20Germany) | [$129](https://ipvolt.com/dashboard/mobile?country=DE&plan=month&carrier=Vodafone%20Germany) ($4.30/day) | | Germany | 1&1 | [$9](https://ipvolt.com/dashboard/mobile?country=DE&plan=day&carrier=1%261) | [$119](https://ipvolt.com/dashboard/mobile?country=DE&plan=month&carrier=1%261) ($3.97/day) | | [United States](https://ipvolt.com/proxies/usa.md) | Verizon | [$19](https://ipvolt.com/dashboard/mobile?country=US&plan=day&carrier=Verizon) | [$139](https://ipvolt.com/dashboard/mobile?country=US&plan=month&carrier=Verizon) ($4.63/day) | | United States | T-Mobile 5G | [$19](https://ipvolt.com/dashboard/mobile?country=US&plan=day&carrier=T-Mobile%205G) | [$149](https://ipvolt.com/dashboard/mobile?country=US&plan=month&carrier=T-Mobile%205G) ($4.97/day) | | United States | T-Mobile | [$19](https://ipvolt.com/dashboard/mobile?country=US&plan=day&carrier=T-Mobile) | [$139](https://ipvolt.com/dashboard/mobile?country=US&plan=month&carrier=T-Mobile) ($4.63/day) | | United States | AT&T | [$17](https://ipvolt.com/dashboard/mobile?country=US&plan=day&carrier=AT%26T) | [$129](https://ipvolt.com/dashboard/mobile?country=US&plan=month&carrier=AT%26T) ($4.30/day) | | [United Kingdom](https://ipvolt.com/proxies/uk.md) | Three | [$14](https://ipvolt.com/dashboard/mobile?country=GB&plan=day&carrier=Three) | [$100](https://ipvolt.com/dashboard/mobile?country=GB&plan=month&carrier=Three) ($3.33/day) | | [France](https://ipvolt.com/proxies/france.md) | SFR | [$9](https://ipvolt.com/dashboard/mobile?country=FR&plan=day&carrier=SFR) | [$100](https://ipvolt.com/dashboard/mobile?country=FR&plan=month&carrier=SFR) ($3.33/day) | | France | Free | [$12](https://ipvolt.com/dashboard/mobile?country=FR&plan=day&carrier=Free) | [$100](https://ipvolt.com/dashboard/mobile?country=FR&plan=month&carrier=Free) ($3.33/day) | | [Netherlands](https://ipvolt.com/proxies/netherlands.md) | Vodafone | [$9](https://ipvolt.com/dashboard/mobile?country=NL&plan=day&carrier=Vodafone%20NL) | [$139](https://ipvolt.com/dashboard/mobile?country=NL&plan=month&carrier=Vodafone%20NL) ($4.63/day) | | Netherlands | Odido | [$9](https://ipvolt.com/dashboard/mobile?country=NL&plan=day&carrier=Odido%20NL) | [$139](https://ipvolt.com/dashboard/mobile?country=NL&plan=month&carrier=Odido%20NL) ($4.63/day) | | [Poland](https://ipvolt.com/proxies/poland.md) | Play | [$9](https://ipvolt.com/dashboard/mobile?country=PL&plan=day&carrier=Play) | [$100](https://ipvolt.com/dashboard/mobile?country=PL&plan=month&carrier=Play) ($3.33/day) | | [Singapore](https://ipvolt.com/proxies/singapore.md) | Singtel | [$19](https://ipvolt.com/dashboard/mobile?country=SG&plan=day&carrier=Singtel) | [$119](https://ipvolt.com/dashboard/mobile?country=SG&plan=month&carrier=Singtel) ($3.97/day) | | Singapore | M1 | [$19](https://ipvolt.com/dashboard/mobile?country=SG&plan=day&carrier=M1) | [$119](https://ipvolt.com/dashboard/mobile?country=SG&plan=month&carrier=M1) ($3.97/day) | | [New Zealand](https://ipvolt.com/proxies/new-zealand.md) | One NZ | [$12](https://ipvolt.com/dashboard/mobile?country=NZ&plan=day&carrier=OneNZ) | [$129](https://ipvolt.com/dashboard/mobile?country=NZ&plan=month&carrier=OneNZ) ($4.30/day) | | [Georgia](https://ipvolt.com/proxies/georgia.md) | Magti | [$9](https://ipvolt.com/dashboard/mobile?country=GE&plan=day&carrier=Magti) | [$109](https://ipvolt.com/dashboard/mobile?country=GE&plan=month&carrier=Magti) ($3.63/day) | | [Australia](https://ipvolt.com/proxies/australia.md) | Vodafone | [$19](https://ipvolt.com/dashboard/mobile?country=AU&plan=day&carrier=Vodafone%20Australia) | [$119](https://ipvolt.com/dashboard/mobile?country=AU&plan=month&carrier=Vodafone%20Australia) ($3.97/day) | | [Italy](https://ipvolt.com/proxies/italy.md) | WindTre | [$9](https://ipvolt.com/dashboard/mobile?country=IT&plan=day&carrier=WindTre) | [$127](https://ipvolt.com/dashboard/mobile?country=IT&plan=month&carrier=WindTre) ($4.23/day) | Prices on 11 November 2026. Checkout shows the live price and every carrier in stock, including a carrier that has only one rental length available. Nothing renews on its own. If a device fails and we cannot repair or replace it, we credit the unused part of the rental to your balance, pro rata by the hour. ### Every rental includes - No traffic limit. A rental is priced by time, not by the GB. - IP rotation on demand from the dashboard, or on a schedule as often as every 60 seconds, on devices that support it. The carrier assigns the new IP and may return the same one. - If a device fails and we cannot repair or replace it, the unused part of the rental is credited to your balance, pro rata by the hour. Started rentals are not refundable, except in the cases listed in the [Payments and Refunds Policy](https://ipvolt.com/refunds). [Mobile proxies: setup and questions](https://ipvolt.com/mobile-proxies.md) [Buy a mobile proxy](https://ipvolt.com/dashboard/mobile): choose a country, carrier and 1 or 30 days in the customer dashboard, sign in or create an account, and pay. This document places no order. ## Every mobile proxy - A dedicated device on a carrier network. Rotate its IP on demand or on a schedule. - Works over HTTP and SOCKS5. - Your endpoint and credentials appear in your dashboard, ready for cURL, Python, Node.js or Playwright. ## Residential proxies On sale in prepaid packs, from $2.20/GB: 1 GB for $2.20, 5 GB for $11, 25 GB for $55, 50 GB for $110, 100 GB for $220 and 250 GB for $550. Every pack costs the same $2.20 per GB. Country selection, HTTP and SOCKS5, sticky or rotating sessions. | Prepaid pack | Price | Per GB | | --- | --- | --- | | 1 GB | $2.20 | $2.20 | | 5 GB | $11 | $2.20 | | 25 GB | $55 | $2.20 | | 50 GB | $110 | $2.20 | | 100 GB | $220 | $2.20 | | 250 GB | $550 | $2.20 | Dedicated mobile is one device rented by the day, with no traffic limit. Mobile per GB uses the same prepaid GB on a shared pool of carrier modems. One key and one GB balance work for both, and you pick the network and the country in the dashboard. [Buy residential](https://ipvolt.com/dashboard/residential): choose a prepaid pack in the customer dashboard, sign in or create an account, and pay. This document places no order. [Residential proxies: countries, setup and questions](https://ipvolt.com/residential-proxies.md) ## Paying - Add funds with crypto, through our NOWPayments checkout: Tether (USDT), USD Coin (USDC), Bitcoin (BTC), Ethereum (ETH), Solana (SOL) and more. Card payments are coming soon. - Nothing renews automatically. A mobile rental ends with the period you chose, and you can renew it from the dashboard. - Prices are in US dollars. ## Already have an account? Sign in to buy, add funds and manage your proxies. [Open your dashboard](https://ipvolt.com/dashboard) --- Document 5 of 138: Mobile proxies on a dedicated device. URL: https://ipvolt.com/mobile-proxies Markdown: https://ipvolt.com/mobile-proxies.md # Mobile proxies on a dedicated device. Source: https://ipvolt.com/mobile-proxies Markdown: https://ipvolt.com/mobile-proxies.md [Home](https://ipvolt.com/index.md) / Mobile proxies Each mobile proxy is one device on a carrier network, and nobody else uses it while you rent it. Rent it for a day or for 30 days, pay with crypto, and nothing renews on its own. [Buy a mobile proxy](https://ipvolt.com/dashboard/mobile): choose a country, carrier and 1 day or 30 days in the customer dashboard, sign in or create an account, and pay. This document places no order. Nothing renews on its own. If a device fails and we cannot repair or replace it, we credit the unused part of the rental to your balance, pro rata by the hour. Need per-GB rotating IPs instead? [Residential proxies](https://ipvolt.com/residential-proxies.md) ## Mobile proxy prices by country and carrier Try any carrier for a day from $9. Mobile proxies in 11 countries. Each price opens the checkout with that country, carrier and period chosen. | Country | Carrier | 1 day | 30 days | | --- | --- | --- | --- | | [Germany](https://ipvolt.com/proxies/germany.md) | O2 | [$9](https://ipvolt.com/dashboard/mobile?country=DE&plan=day&carrier=O2) | [$119](https://ipvolt.com/dashboard/mobile?country=DE&plan=month&carrier=O2) ($3.97/day) | | Germany | Vodafone | [$9](https://ipvolt.com/dashboard/mobile?country=DE&plan=day&carrier=Vodafone%20Germany) | [$129](https://ipvolt.com/dashboard/mobile?country=DE&plan=month&carrier=Vodafone%20Germany) ($4.30/day) | | Germany | 1&1 | [$9](https://ipvolt.com/dashboard/mobile?country=DE&plan=day&carrier=1%261) | [$119](https://ipvolt.com/dashboard/mobile?country=DE&plan=month&carrier=1%261) ($3.97/day) | | [United States](https://ipvolt.com/proxies/usa.md) | Verizon | [$19](https://ipvolt.com/dashboard/mobile?country=US&plan=day&carrier=Verizon) | [$139](https://ipvolt.com/dashboard/mobile?country=US&plan=month&carrier=Verizon) ($4.63/day) | | United States | T-Mobile 5G | [$19](https://ipvolt.com/dashboard/mobile?country=US&plan=day&carrier=T-Mobile%205G) | [$149](https://ipvolt.com/dashboard/mobile?country=US&plan=month&carrier=T-Mobile%205G) ($4.97/day) | | United States | T-Mobile | [$19](https://ipvolt.com/dashboard/mobile?country=US&plan=day&carrier=T-Mobile) | [$139](https://ipvolt.com/dashboard/mobile?country=US&plan=month&carrier=T-Mobile) ($4.63/day) | | United States | AT&T | [$17](https://ipvolt.com/dashboard/mobile?country=US&plan=day&carrier=AT%26T) | [$129](https://ipvolt.com/dashboard/mobile?country=US&plan=month&carrier=AT%26T) ($4.30/day) | | [United Kingdom](https://ipvolt.com/proxies/uk.md) | Three | [$14](https://ipvolt.com/dashboard/mobile?country=GB&plan=day&carrier=Three) | [$100](https://ipvolt.com/dashboard/mobile?country=GB&plan=month&carrier=Three) ($3.33/day) | | [France](https://ipvolt.com/proxies/france.md) | SFR | [$9](https://ipvolt.com/dashboard/mobile?country=FR&plan=day&carrier=SFR) | [$100](https://ipvolt.com/dashboard/mobile?country=FR&plan=month&carrier=SFR) ($3.33/day) | | France | Free | [$12](https://ipvolt.com/dashboard/mobile?country=FR&plan=day&carrier=Free) | [$100](https://ipvolt.com/dashboard/mobile?country=FR&plan=month&carrier=Free) ($3.33/day) | | [Netherlands](https://ipvolt.com/proxies/netherlands.md) | Vodafone | [$9](https://ipvolt.com/dashboard/mobile?country=NL&plan=day&carrier=Vodafone%20NL) | [$139](https://ipvolt.com/dashboard/mobile?country=NL&plan=month&carrier=Vodafone%20NL) ($4.63/day) | | Netherlands | Odido | [$9](https://ipvolt.com/dashboard/mobile?country=NL&plan=day&carrier=Odido%20NL) | [$139](https://ipvolt.com/dashboard/mobile?country=NL&plan=month&carrier=Odido%20NL) ($4.63/day) | | [Poland](https://ipvolt.com/proxies/poland.md) | Play | [$9](https://ipvolt.com/dashboard/mobile?country=PL&plan=day&carrier=Play) | [$100](https://ipvolt.com/dashboard/mobile?country=PL&plan=month&carrier=Play) ($3.33/day) | | [Singapore](https://ipvolt.com/proxies/singapore.md) | Singtel | [$19](https://ipvolt.com/dashboard/mobile?country=SG&plan=day&carrier=Singtel) | [$119](https://ipvolt.com/dashboard/mobile?country=SG&plan=month&carrier=Singtel) ($3.97/day) | | Singapore | M1 | [$19](https://ipvolt.com/dashboard/mobile?country=SG&plan=day&carrier=M1) | [$119](https://ipvolt.com/dashboard/mobile?country=SG&plan=month&carrier=M1) ($3.97/day) | | [New Zealand](https://ipvolt.com/proxies/new-zealand.md) | One NZ | [$12](https://ipvolt.com/dashboard/mobile?country=NZ&plan=day&carrier=OneNZ) | [$129](https://ipvolt.com/dashboard/mobile?country=NZ&plan=month&carrier=OneNZ) ($4.30/day) | | [Georgia](https://ipvolt.com/proxies/georgia.md) | Magti | [$9](https://ipvolt.com/dashboard/mobile?country=GE&plan=day&carrier=Magti) | [$109](https://ipvolt.com/dashboard/mobile?country=GE&plan=month&carrier=Magti) ($3.63/day) | | [Australia](https://ipvolt.com/proxies/australia.md) | Vodafone | [$19](https://ipvolt.com/dashboard/mobile?country=AU&plan=day&carrier=Vodafone%20Australia) | [$119](https://ipvolt.com/dashboard/mobile?country=AU&plan=month&carrier=Vodafone%20Australia) ($3.97/day) | | [Italy](https://ipvolt.com/proxies/italy.md) | WindTre | [$9](https://ipvolt.com/dashboard/mobile?country=IT&plan=day&carrier=WindTre) | [$127](https://ipvolt.com/dashboard/mobile?country=IT&plan=month&carrier=WindTre) ($4.23/day) | Prices on 11 November 2026. Checkout shows the live price and every carrier in stock, including a carrier that has only one rental length available. Nothing renews on its own. If a device fails and we cannot repair or replace it, we credit the unused part of the rental to your balance, pro rata by the hour. ## What a rental includes - No traffic limit. A rental is priced by time, not by the GB. - IP rotation on demand from the dashboard, or on a schedule as often as every 60 seconds, on devices that support it. The carrier assigns the new IP and may return the same one. - If a device fails and we cannot repair or replace it, the unused part of the rental is credited to your balance, pro rata by the hour. - Works over HTTP and SOCKS5. Started rentals are not refundable, except in the cases listed in the [Payments and Refunds Policy](https://ipvolt.com/refunds). ## Pay per GB instead Mobile IPs are also sold per GB: from $2.20/GB, in the same prepaid packs as residential proxies. Pick Mobile as the network in the dashboard, which lists the countries available now. Dedicated mobile is one device rented by the day, with no traffic limit. Mobile per GB uses the same prepaid GB on a shared pool of carrier modems. - [Buy mobile per GB](https://ipvolt.com/dashboard/residential) - [Pack prices](https://ipvolt.com/pricing.md) ## Connect a mobile proxy with cURL or Python In the dashboard, open the device and select Show connection details. Most devices use one username and password for both protocols, on two ports; some list a separate host and login for each. Replace the placeholders with your values. ```sh curl -sS -x "http://USERNAME:PASSWORD@HOST:HTTP_PORT" https://api.ipify.org curl -sS -x "socks5h://USERNAME:PASSWORD@HOST:SOCKS5_PORT" https://api.ipify.org ``` ```python import os import requests proxy = os.environ["PROXY_URL"] # http://USERNAME:PASSWORD@HOST:HTTP_PORT response = requests.get("https://api.ipify.org", proxies={"http": proxy, "https": proxy}, timeout=30) print(response.text) ``` The printed IP should match the outgoing IP in your dashboard. For a socks5h:// URL in Python, install requests[socks] first. - [Quickstart](https://ipvolt.com/docs/quickstart.md) - [Endpoints and protocols](https://ipvolt.com/docs/endpoints.md) - [Code examples for Node.js, Playwright, Scrapy and Go](https://ipvolt.com/docs/code-examples.md) ## Mobile proxy questions ### Is the device shared with anyone? No. Nobody else uses the device while you rent it. ### How long can I rent one? For 1 day or for 30 days. Rentals do not renew automatically: to keep a device, renew it from the dashboard before the rental ends. When a rental ends, the device and its credentials stop working. ### How do I pay? From a prepaid US-dollar balance that you top up with crypto through our NOWPayments checkout: Tether (USDT), USD Coin (USDC), Bitcoin (BTC), Ethereum (ETH), Solana (SOL) and more. Card payments are coming soon. ### How do I change the IP? Select Rotate IP now in the dashboard, or set automatic rotation to every 60 seconds, 5 minutes or 30 minutes on devices that support it. The carrier assigns the new IP and can return the same one. Rotation is controlled from the dashboard; there is no public API for it today. ### Is there a traffic limit? No. A mobile rental has no traffic limit: you pay for the rental period, 1 day or 30 days, not per GB. Mobile per GB is billed by traffic. ### Can I choose a city? No. Mobile proxies are targeted by country and carrier, not by city. ### Can I get a refund? Started rentals are not refundable. If a device fails and cannot be repaired or replaced, or if we stop a rental for a reason other than a breach of the Terms or the Acceptable Use Policy, the unused time is credited to your balance, pro rata by the hour. The Payments and Refunds Policy is the binding text. ## Guides ### Country guides - [Netherlands proxies: location and carrier checks](https://ipvolt.com/guides/netherlands-proxies.md) - [USA proxies: regions, networks and testing](https://ipvolt.com/guides/usa-proxies.md) - [UK proxies: networks, regions and location checks](https://ipvolt.com/guides/uk-proxies.md) - [How to test a Germany proxy: networks, cities and regions](https://ipvolt.com/guides/germany-proxies.md) - [France proxies: networks, regions and local testing](https://ipvolt.com/guides/france-proxies.md) - [Brazil proxies: carriers, states and location tests](https://ipvolt.com/guides/brazil-proxies.md) - [Portugal proxies: islands, operators and checks](https://ipvolt.com/guides/portugal-proxies.md) - [How to test an Australian proxy: networks and nbn checks](https://ipvolt.com/guides/australia-proxies.md) - [Canada proxies: location, networks and session checks](https://ipvolt.com/guides/canada-proxies.md) - [Japan proxies: IP location and mobile network checks](https://ipvolt.com/guides/japan-proxies.md) - [All country guides](https://ipvolt.com/guides/countries.md) ### Setup guides - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) - [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md) - [Use a proxy with Node.js fetch](https://ipvolt.com/guides/nodejs-fetch-proxy.md) - [Configure a proxy in Playwright](https://ipvolt.com/guides/playwright-proxy-setup.md) [All prices, mobile and residential](https://ipvolt.com/pricing.md) --- Document 6 of 138: Residential proxies, billed per GB. URL: https://ipvolt.com/residential-proxies Markdown: https://ipvolt.com/residential-proxies.md # Residential proxies, billed per GB. Source: https://ipvolt.com/residential-proxies Markdown: https://ipvolt.com/residential-proxies.md [Home](https://ipvolt.com/index.md) / Residential proxies Residential proxies route your requests through a mixed network of devices and connections supplied by independent partners. You buy a prepaid pack of GB, pick a country and connect over HTTP or SOCKS5, with rotating or sticky sessions. Nothing renews on its own, and we set no expiry date on the GB you buy. Need a dedicated device on one carrier instead? [Mobile proxies](https://ipvolt.com/mobile-proxies.md) ## Residential proxy prices | Prepaid pack | Price | Per GB | | --- | --- | --- | | 1 GB | $2.20 | $2.20 | | 5 GB | $11 | $2.20 | | 25 GB | $55 | $2.20 | | 50 GB | $110 | $2.20 | | 100 GB | $220 | $2.20 | | 250 GB | $550 | $2.20 | Every pack costs the same $2.20 per GB. Prices are in US dollars. A pack is paid from your dashboard balance, which you fund with crypto. [Buy residential](https://ipvolt.com/dashboard/residential): choose a prepaid pack in the customer dashboard, sign in or create an account, and pay. This document places no order. ## Countries A pack is not tied to a country. You pick the country each time you connect, and the same GB work in every country the network has. The dashboard lists the countries available now. When this page was last reviewed, on 10 November 2026, the network had IPs in: - Brazil - Canada - Mexico - Netherlands - Poland - Portugal - Spain - United Kingdom - United States Availability changes with the network, so check the list before you buy for one country. ## How it works The dashboard builds the connection line for you. This is what it contains. ### Endpoint One host for every country: res.ipvolt.com. HTTP uses port 7000 and SOCKS5 uses port 7001. HTTPS sites go through the HTTP port with CONNECT. ### Username and password The username is your account name followed by your choices, joined by hyphens: the network, the country, then any session settings. The password is your key. Both are in the dashboard. ```text ACCOUNT-peer-us-iptype-residential ``` ### Country The two-letter country code after the network selects the country: us, de, gb. ### Rotating sessions Without a session ID, each new connection is routed again and can leave from a different IP. ### Sticky sessions Add a session ID to keep one binding across connections. Sticky rotation prefers the same IP; timed rotation moves the session after 5, 10, 20 or 60 minutes, checked on the next connection. A network change can still change the IP. ```text ACCOUNT-peer-us-iptype-residential-sid-task1-rot-sticky-ttl-3600 ``` ### How long a sticky session lasts You choose how long the binding is kept: 1 hour, 6 hours, 1 day, 7 days or 30 days. That is how long the session is remembered, not a promise that one IP or one connection lasts that long. ## Where the IPs come from Residential proxies route requests through a mixed network of devices and connections supplied by independent partners. Our supplier tells us it requires those partners to obtain informed consent from device owners and permission to share their connections. That is a requirement placed on partners, not a guarantee from us: we have not audited them, so we do not promise that it holds for every device or that every address is a residential device. The full text is in the [Terms, section 3](https://ipvolt.com/terms.md). ## What a pack includes - Prepaid GB at one price per GB in every country. - No automatic renewal. A pack is a one-time purchase from your balance. - No expiry date on the GB you buy. A later pack adds GB to the same key. - HTTP and SOCKS5, with rotating or sticky sessions. - Traffic counted as upload plus download, where 1 GB is 1,024 MB. Packs are not refundable once the traffic is on your key, even if you have not used it, except in the cases listed in the [Payments and Refunds Policy](https://ipvolt.com/refunds.md). ## Mobile per GB Dedicated mobile is one device rented by the day, with no traffic limit. Mobile per GB uses the same prepaid GB on a shared pool of carrier modems. Pick Mobile as the network in the dashboard, which lists the countries available now. The username then names the mobile network: ```text ACCOUNT-mbl-us ``` [Dedicated mobile proxies](https://ipvolt.com/mobile-proxies.md) ## Connect with cURL or Python On the dashboard's residential proxies page, choose a network and a country, and copy the connection details. Replace the placeholders with your values. ```sh curl -sS -x "http://USERNAME:KEY@res.ipvolt.com:7000" https://api.ipify.org curl -sS -x "socks5h://USERNAME:KEY@res.ipvolt.com:7001" https://api.ipify.org ``` ```python import os import requests proxy = os.environ["PROXY_URL"] # http://USERNAME:KEY@res.ipvolt.com:7000 response = requests.get("https://api.ipify.org", proxies={"http": proxy, "https": proxy}, timeout=30) print(response.text) ``` USERNAME is the whole username from the dashboard, such as ACCOUNT-peer-us-iptype-residential, and KEY is your key. The printed IP is the address the site sees. For a socks5h:// URL in Python, install requests[socks] first. Your key is sent unencrypted to the gateway, so connect from networks you trust and regenerate the key if it is exposed. - [Residential quickstart](https://ipvolt.com/docs/residential-quickstart.md) - [Targeting and sessions](https://ipvolt.com/docs/residential-sessions.md) - [Usage and billing](https://ipvolt.com/docs/residential-usage.md) ## Residential proxy questions ### Do the GB expire? No. We set no expiry date on the GB you buy, and nothing renews automatically. A later pack adds GB to the same key. ### Which countries can I use? A pack is not tied to a country: you pick the country each time you connect. The dashboard lists the countries available now. Availability changes with the network, so we don't promise a particular country. ### Can I keep the same IP? Use a sticky session. It keeps one binding for the time you choose, from 1 hour to 30 days, and prefers the same IP. A network change can still change the IP, so we don't promise one IP for the whole time. ### How is traffic counted? As upload plus download, where 1 GB is 1,024 MB. Your dashboard shows what you have used and what is left. The figure can run behind actual use. ### What happens when I run out of GB? Your key stops. Traffic on connections that are still open keeps counting and comes out of your next pack. Buy another pack to switch the key back on. ### Can I get a refund? Packs are not refundable once the traffic is on your key, even if you have not used it. If your key fails and we cannot get it working again, we credit your unused GB to your balance. The Payments and Refunds Policy is the binding text. ## Related - [All prices, mobile and residential](https://ipvolt.com/pricing.md) - [Mobile vs residential proxies](https://ipvolt.com/guides/mobile-vs-residential-proxies.md) - [How many GB of proxies do you need?](https://ipvolt.com/blog/how-many-gb-of-proxies-do-i-need.md) --- Document 7 of 138: Proxy and scraping tools. URL: https://ipvolt.com/tools Markdown: https://ipvolt.com/tools.md # Proxy and scraping tools. Source: https://ipvolt.com/tools Markdown: https://ipvolt.com/tools.md [Home](https://ipvolt.com/index.md) / Tools Free tools Reviewed: 2026-09-24 Author: ipvolt Check whether your proxies work, measure the bytes your scraper moves, or get help configuring and debugging a proxy connection. Start with the tool for the job in front of you. These tools work independently of ipvolt proxies. You do not need an ipvolt account to use them. ## [Scrapescope](https://ipvolt.com/guides/scraper-bandwidth-report) Scraper bandwidth analysis Measure a scraper run locally, inspect hosts and resource types, and find responses that contain the value you need. Open an existing report or try the sample in your browser. Free · open source · works with any provider Start with: An existing report.json, or a proxy-aware scraper to run locally. Get: A bandwidth report; browser-helper data adds resource attribution. Transfer costs use a rate you supply. The result is an estimate, not a provider bill. [Open Scrapescope](https://ipvolt.com/guides/scraper-bandwidth-report) · [Try the report viewer](https://ipvolt.com/guides/scraper-bandwidth-report#viewer) ## [Proxy Toolkit MCP](https://ipvolt.com/mcp) Proxy setup in your coding agent Generate proxy configuration templates, diagnose connection errors and search proxy documentation from an MCP-compatible coding agent. Connect to the hosted server or run the package locally. Free · open source · works with any provider Start with: Your client or library, configuration task, or connection error. Get: Configuration templates and suggested checks with linked documentation. The hosted tools do not connect to your proxy or route your agent’s traffic. [Explore the MCP Toolkit](https://ipvolt.com/mcp) · [Connection instructions](https://ipvolt.com/mcp#connect) ## [Proxy checker](https://ipvolt.com/tools/proxy-checker) Check proxies online Paste up to 50 HTTP, HTTPS or SOCKS5 proxies. See which work, the exit IP and location websites see, the network type, headers the proxy adds and, for failures, the cause with a guide. Free · no account needed · works with any provider Start with: A list of proxies in any common format. Get: Status, exit IP, location, ASN, latency, leaked headers and a cause for each failure. Tests run from ipvolt's server against ipvolt's own endpoint. Passwords are never stored. [Open the proxy checker](https://ipvolt.com/tools/proxy-checker) · [What each result means](https://ipvolt.com/tools/proxy-checker#results-explained) ## Choose by the task. Use measurement when a job runs but moves too many bytes. Use configuration and diagnostics when the connection itself needs attention. | Your task | Tool | First step | | --- | --- | --- | | See which hosts and resource types use bandwidth | [Scrapescope](https://ipvolt.com/guides/scraper-bandwidth-report) | Open the sample report first, then measure your own run. Resource attribution needs an instrumented client. | | Find a response that already contains a required value | [Scrapescope find](https://ipvolt.com/guides/scraper-bandwidth-report#quickstart) | Use the Chromium-based find command and inspect its ranked matches. Verify extraction before changing the job. | | Check whether proxies work and which IP they show | [Proxy checker](https://ipvolt.com/tools/proxy-checker) | Paste your list. Failures link to the guide for their cause. | | Configure a proxy client or investigate an error | [Proxy Toolkit MCP](https://ipvolt.com/mcp) | Connect your coding agent and request a template or a diagnostic check. Keep credentials out of prompts. | ## Need a walkthrough? The Guides library covers client setup and troubleshooting step by step. The Blog explores measurement methods and tradeoffs. - [Developer guides](https://ipvolt.com/guides.md) - [What a proxy benchmark should measure](https://ipvolt.com/blog/what-a-proxy-benchmark-should-measure.md) Need a mobile IP in a specific country? [Dedicated mobile proxies from $9 a day.](https://ipvolt.com/mobile-proxies.md) --- Document 8 of 138: Free proxy checker URL: https://ipvolt.com/tools/proxy-checker Markdown: https://ipvolt.com/tools/proxy-checker.md # Free proxy checker Source: https://ipvolt.com/tools/proxy-checker Markdown: https://ipvolt.com/tools/proxy-checker.md [Home](https://ipvolt.com/index.md) / [Tools](https://ipvolt.com/tools.md) / Proxy checker Reviewed: 2026-11-05 Author: ipvolt Paste your proxies to see whether each one works, which IP address and location websites will see, what kind of network it is, and, if it fails, why, with a link to the guide that fixes it. Every proxy is tested against ipvolt's own endpoint, never against another site. Formats: host:port, host:port:user:pass, user:pass@host:port or scheme://user:pass@host:port, with http, https, socks5 or socks5h. Up to 50 proxies per check. ## What each result means ### Status Works: an HTTPS request through the proxy reached ipvolt's endpoint and ipvolt's certificate verified. HTTP only: HTTPS failed but a plain-HTTP request got through. Failed: neither did. Not checked: the address or port is not a public proxy, so no connection was made. ### Exit IP The address ipvolt's endpoint saw the request come from. Websites see this address, not yours. If plain HTTP leaves from a different address, both are shown. ### Location Country and city for the exit IP from two independent geolocation databases. When they disagree, the row says so; neither is a measurement of where the device is. ### ASN and network type The network that announces the exit IP. The type (hosting, mobile carrier, internet provider) is an estimate from that network's ASN, not a test of the device. ### IPv6 Yes when the proxy could reach ipvolt's IPv6 address. No means it could not, or refused to, from this exit. ### Latency Milliseconds from ipvolt's server: TCP connect to the proxy, the tunnel (CONNECT or SOCKS5) handshake, TLS to ipvolt's endpoint through it, and the total. Your own location adds its own latency. ### Headers Headers the proxy added to a plain-HTTP request, such as Via, X-Forwarded-For or Forwarded. If one contains the checker's own address, the proxy reveals its user's IP to websites. ### Details For a failure: the step that failed, the proxy's status code when it sent one, and a one-sentence cause with a guide. Causes marked Likely are inferences; the rest are what the proxy actually answered. ## Guides for common failures - [Fix proxy error 407](https://ipvolt.com/guides/fix-proxy-error-407.md) - [CONNECT tunnel failed: 403](https://ipvolt.com/blog/connect-tunnel-failed-403.md) - [Fix SSL "wrong version number"](https://ipvolt.com/guides/fix-ssl-wrong-version-number-proxy.md) - [Proxy timeout troubleshooting](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md) - [Fix tunnel 502, 503 and 504](https://ipvolt.com/guides/fix-proxy-tunnel-502-503.md) - [Proxy status codes](https://ipvolt.com/blog/proxy-status-codes-407-429-502.md) - [socks5 vs socks5h](https://ipvolt.com/blog/socks5-vs-socks5h.md) ## What the checker stores - Proxy passwords are used only to connect to your proxy during the check. They are never logged, stored or sent back: results show user:****. - Proxy addresses and exit IPs are not logged. The service records only how many proxies were checked and which failure types occurred. - Rate limits keep a keyed hash of your IP address for the length of the limit window (up to one hour), in memory only. - The checker only connects to the proxies you enter and, through them, to ipvolt's own endpoint at check.ipvolt.com. It never tests against another website. [Privacy policy](https://ipvolt.com/privacy.md) ## Questions ### Which site does the checker test against? Only ipvolt's own endpoint, check.ipvolt.com. Each proxy is asked to open an HTTPS connection to it, and one plain-HTTP request is sent to see headers the proxy adds. You cannot choose another destination. ### Does a working result mean the proxy works on every site? No. It means the proxy accepted your login, opened a tunnel and delivered an intact HTTPS response from ipvolt's endpoint. A particular site can still block the exit IP or rate-limit it. ### Why is the network type an estimate? It comes from the ASN that announces the exit IP. Many carriers serve mobile and home lines from the same ASN, and the ASN cannot tell which one a request used. ### Why do the two location databases disagree? They are built from different sources and update on different schedules. Mobile and recently moved addresses often differ. Disagreement is shown rather than hidden. ### What is the difference between socks5 and socks5h? With socks5, the hostname is resolved on your side and the proxy receives an IP address. With socks5h, the proxy resolves it. Auto-detect tries socks5h first and falls back to socks5 if the server refuses hostnames. ### Are my proxy passwords stored? No. They are used for the check and discarded. Results, CSV exports and logs never contain them. ## More free tools ### Proxy Toolkit MCP Proxy setup. Inside your AI agent. Generate proxy configurations, diagnose connection errors, and find the right guide. Free · open source · works with any provider [Open Proxy Toolkit MCP](https://ipvolt.com/mcp.md) ### scrapescope See where your scraper's proxy bandwidth goes. Shows where your scraper's proxy bandwidth goes and finds the smallest response containing your data. Free · open source · works with any provider [Open scrapescope](https://ipvolt.com/guides/scraper-bandwidth-report.md) [All free tools](https://ipvolt.com/tools.md) Need a proxy that passes? Mobile proxies from $9/day. [See pricing](https://ipvolt.com/pricing.md) --- Document 9 of 138: Proxy setup. Inside your AI agent. URL: https://ipvolt.com/mcp Markdown: https://ipvolt.com/mcp.md # Proxy setup. Inside your AI agent. Source: https://ipvolt.com/mcp Markdown: https://ipvolt.com/mcp.md Free MCP server · Developer tools Generate proxy configurations, diagnose connection errors, and find the right guide. Bring the tools into your MCP-compatible coding agent. Free to use · No account or API key · Open source Use the toolkit with your existing proxy provider. ipvolt sells mobile and residential proxies. [Connect the toolkit](https://ipvolt.com/mcp#connect) [View on GitHub](https://github.com/ipvolt/proxy-toolkit-mcp) ## Connect. Ask. Build. Hosted connection ```text https://mcp.ipvolt.com/mcp ``` 1. **Add the server.** Choose a remote MCP server in your client and use the URL above with Streamable HTTP. 2. **Load the tools.** Follow your client's approval flow. The hosted server exposes four tools and needs no API key. 3. **Give it a task.** Ask for a proxy configuration or describe a connection error. Keep credentials out of your prompt. [Prefer to run it locally?](https://ipvolt.com/mcp#local-setup) Configuration templates for: curl, Python Requests, HTTPX, Playwright ## Less guessing. A clearer next step. Four tools for the work between choosing a proxy and getting a request through. ### Find the right guide `search_proxy_docs` — Hosted + local Search proxy setup and troubleshooting notes. Get relevant passages with links to the full source. ### Keep the source in reach `get_proxy_doc` — Hosted + local Read a section of a guide with its source and review information, so you can check the reasoning behind an answer. ### Start with a supported pattern `generate_proxy_config` — Hosted + local Generate configuration templates for curl, Requests, HTTPX or Playwright. Credentials stay in environment-variable placeholders. ### Find the next check `diagnose_proxy_error` — Hosted + local Describe the status, exception and request phase. Get likely causes and useful checks, with uncertainty made explicit. Templates cover curl shell commands, Python Requests sessions, synchronous HTTPX clients, and Playwright JavaScript API requests. [Supported versions and tool details](https://github.com/ipvolt/proxy-toolkit-mcp#tools) ## Start with a real task. Connect the server, then try a prompt. These are examples to use in your agent. ### Describe the failure Give your agent the client, version, exception or status, and the request phase. Leave out passwords, private URLs and full logs. > My HTTPX 0.28.1 request returns 407 during proxy connection. Help me identify the next check. ### Compare a supported example Ask for a configuration template and open its linked guide. The result identifies supported options and uses placeholders for secrets. > Show a synchronous HTTPX 0.28.1 proxy configuration using an environment variable, and explain which settings control routing. ### Verify the route locally If you enable the local tool, ask it to check the configured profile. This makes one bounded request; it does not test a site's content or change other tools. > Check the route for my configured local proxy profile, then explain what the result establishes. ## Hosted simplicity. Local control. ipvolt Proxy Toolkit is a Model Context Protocol (MCP) server for developers working with HTTP proxies. It gives your agent documentation, configuration templates and error diagnostics. ### Hosted, for a quick start. Connect to the four core tools over HTTPS. No local process to install and no proxy credentials to share. Hosted tools do not connect to your proxy or request an arbitrary target URL. ### Local, for more control. Run the same four tools through stdio. Enable the optional route check when you need to inspect one request from your own machine. Keep proxy credentials in the documented local configuration, outside prompts and tool arguments. Enabling the package alone does not run a network check. | Capability | Hosted | Local | | --- | --- | --- | | Core tools | All four | All four | | Connection | Streamable HTTP | stdio · Node.js 24+ | | Proxy route check | Not available | Optional · explicitly enabled | | Proxy credentials | Not needed | Private local configuration for the route check | Use a client that supports Streamable HTTP. Its server settings and approval steps may differ; follow the instructions for your installed client. ## Set up the local MCP server Local package · v0.1.0 Install Node.js 24 or later. Add the command and arguments below to your client's stdio MCP configuration. This example uses the common mcpServers format; use your client's equivalent if it differs. The version is pinned; update it deliberately when a reviewed release is available. ```json { "mcpServers": { "ipvolt-proxy-toolkit": { "command": "npx", "args": [ "--yes", "@ipvolt/proxy-toolkit-mcp@0.1.0" ] } } } ``` ### Check one request path `check_proxy_route` — Local, opt-in Make an explicitly requested local connection through a configured HTTP proxy to ipvolt's fixed HTTPS diagnostic endpoint. Returns the address observed for that request. For the optional check, configure IPVOLT_PROXY_URL privately in the local server environment and set IPVOLT_ENABLE_ROUTE_CHECK=1. The tool accepts the profile name default, not a proxy URL or password. It supports HTTP proxies that tunnel HTTPS using CONNECT and contacts only https://mcp.ipvolt.com/egress. [Local route check setup details](https://github.com/ipvolt/proxy-toolkit-mcp#optional-local-route-diagnostic) ### What the result establishes A route result applies to that request, process, endpoint and time. It does not prove that your browser or every tool in an agent session uses the same proxy. An observed IP address does not establish country coverage, residential or mobile classification, anonymity, or access to a particular website. The diagnostic tools suggest causes and next checks. A timeout after sending a write does not establish that retrying it is safe. The toolkit does not provision ipvolt proxies, manage accounts, purchase traffic or submit a signup. [Read about privacy and analytics](https://ipvolt.com/privacy) [Source, release notes and setup details](https://github.com/ipvolt/proxy-toolkit-mcp) ## A few clear answers. ### What is a proxy MCP server? This MCP server gives an AI coding agent tools for HTTP proxy configuration and troubleshooting. MCP is the connection protocol between your client and the toolkit; your proxy provider supplies the actual proxy connection. ### Is the toolkit free? Yes. The hosted toolkit requires no account or API key, and the local package is open source. Traffic you send through your own proxy provider remains subject to that provider's terms and charges. ### Which AI clients can connect? Use an MCP client with Streamable HTTP support for the hosted endpoint, or stdio support for the local package. Configuration formats and tool approval flows vary by client; check your installed client's instructions. ### Are the guides fetched live? The toolkit searches a bundled snapshot of reviewed ipvolt guides. It does not crawl the web or automatically include every newly published guide. Open the source links in tool results to check the current page and its review information. ### Does it route all of my agent's traffic through a proxy? No. The toolkit generates configurations and diagnoses problems. The optional local route check makes one request through your configured HTTP proxy to a fixed HTTPS diagnostic endpoint. Other agent tools and browser traffic keep their own connection settings. ### Do I need an ipvolt proxy to use it? No. You can use the toolkit with an existing provider. Buying from ipvolt is optional and is not needed to connect the MCP server. ### What should I keep out of prompts? Keep passwords, proxy credentials, private URLs and full logs out of prompts and tool arguments. The configuration tools use placeholders. If you enable the local route check, provide credentials only through its documented local configuration. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) [Privacy](https://ipvolt.com/privacy) ## Go deeper on your setup. - [Scraper bandwidth report viewer](https://ipvolt.com/guides/scraper-bandwidth-report): Open a scrapescope report to inspect hosts, resource types and browser background traffic. - [Proxy environment variables](https://ipvolt.com/guides/proxy-environment-variables): Understand configuration inheritance and routing overrides. - [HTTPX async proxy setup](https://ipvolt.com/guides/httpx-async-proxy): Use explicit clients and distinguish connection from pool timeouts. - [Fix a 407 response](https://ipvolt.com/guides/fix-proxy-error-407): Separate authentication evidence from guesses about credentials. [All developer guides](https://ipvolt.com/guides) ## More free tools ### scrapescope See where your scraper's proxy bandwidth goes. Shows where your scraper's proxy bandwidth goes and finds the smallest response containing your data. Free · open source · works with any provider [Open scrapescope](https://ipvolt.com/guides/scraper-bandwidth-report.md) ### Proxy checker Free proxy checker Paste up to 50 proxies to see which work, the IP and location sites see, and why the others fail. Free · no account needed · works with any provider [Open the proxy checker](https://ipvolt.com/tools/proxy-checker.md) [All free tools](https://ipvolt.com/tools.md) Need a mobile IP in a specific country? [Dedicated mobile proxies from $9 a day.](https://ipvolt.com/mobile-proxies.md) --- Document 10 of 138: See where your scraper's proxy bandwidth goes. Open the report in your browser. URL: https://ipvolt.com/guides/scraper-bandwidth-report Markdown: https://ipvolt.com/guides/scraper-bandwidth-report.md # See where your scraper's proxy bandwidth goes. Open the report in your browser. Source: https://ipvolt.com/guides/scraper-bandwidth-report Markdown: https://ipvolt.com/guides/scraper-bandwidth-report.md [Home](https://ipvolt.com/index.md) / [Tools](https://ipvolt.com/tools.md) / Scrapescope Free open-source tool · Browser-only viewer Reviewed: 2026-09-24 Author: ipvolt Find which hosts and resources use your scraper’s bandwidth. Scrapescope is a free, open-source local metering proxy for scrapers and browser agents. Install the tool to measure a run, or open an existing report in the browser viewer below. Free and MIT-licensed · No ipvolt account needed · Reports stay in your browser Use your own compatible HTTP proxy, or run in direct sizing mode without a proxy account. Scrapescope and this viewer do not require an ipvolt proxy. **From the bundled sample report:** Three pages, as counted: 783,026 bytes → Modelled with images, media and fonts blocked: 127,386 bytes. The sample is a real three-page run on books.toscrape.com, recorded in direct sizing mode. Images and fonts were 655,640 of its 783,026 bytes (84%). The after figure is the report's what-if: a model built from allocated bytes, not a second measured run. ## Install scrapescope. Python 3.11 or newer. The browser extra adds find and the Playwright helper; install Playwright's Chromium from the same environment so the browser build matches. Install the command with uv: ```sh uv tool install 'scrapescope[browser] @ git+https://github.com/ipvolt/scrapescope' --with-executables-from playwright playwright install chromium ``` Install with pipx: ```sh pipx install 'scrapescope @ git+https://github.com/ipvolt/scrapescope' pipx inject --include-apps scrapescope playwright playwright install chromium ``` Install with pip: ```sh pip install 'scrapescope[browser] @ git+https://github.com/ipvolt/scrapescope' && python -m playwright install chromium ``` PyPI publication is planned. These Git install commands were checked on macOS; Windows is untested. [Source and documentation on GitHub](https://github.com/ipvolt/scrapescope) ## Open a report. Drop a scrapescope report.json into the frame, choose a file, or load the bundled sample. The report is parsed inside an isolated frame on this page and nothing is uploaded. You can compare two runs, price the bytes at a rate you type and download a share card rendered on your device. The interactive viewer is HTML-only. On the web page it opens a scrapescope report.json inside an isolated frame, charts hosts, resource types and buckets, compares two runs, prices the bytes at a rate you type and renders a share card locally. This Markdown export carries the same reviewed text without the viewer. [Open the viewer on the web page](https://ipvolt.com/guides/scraper-bandwidth-report#viewer) ## Measure a run. Inspect the report. After installing, run an existing proxy-aware Python scraper through Scrapescope. Replace my_scraper.py with your own script. Direct sizing uses your machine’s connection; it does not test a proxy provider or predict how a protected target will behave through one. Direct sizing, without a proxy account: ```sh scrapescope run --direct --env-all --out report.json -- python my_scraper.py ``` Read the report in your terminal: ```sh scrapescope report report.json ``` Open report.json in the viewer above to inspect it visually. The wrapper supplies proxy environment variables; your client must honor them or use an explicit proxy configuration. Tunnel totals do not require browser instrumentation, but resource attribution needs the Playwright Python helper or Requests/HTTPX hooks documented in the repository. For a different task, use scrapescope find URL --value V --direct to look for a response containing a known value. Replace URL with your page and V with the value you need, quoting both in your shell. The --direct option uses your machine’s own connection without a proxy account. This uses the installed Chromium browser and observes the initial page load; check the capture limits and replay result before changing an extraction job. [Full usage, helper setup and upstream-proxy configuration](https://github.com/ipvolt/scrapescope/blob/5124eee588039796f8bf948b3b57b3667bbb11ef/README.md) ## Find captured responses that contain your value. scrapescope find URL --value V loads a page once in headless Chromium and inspects captured text responses for the values you name, including common encoded forms. It ranks matches by an estimated standalone-fetch transfer size and flags cookies or tokens sent by the browser. It can miss oversized, evicted, binary or worker responses and content loaded after that initial capture. An optional replay checks a candidate without a browser; a match alone does not establish that you can reuse it. The local meter counts bytes on its connection to an upstream proxy. The browser helper adds request information so the report can allocate those totals by resource type. These are different measurements: a tunnel total is measured; the share assigned to a script or image is allocated. Read the labels before comparing with your provider’s dashboard. ### Every host Tunnel counts and bytes per host, with and without the CONNECT exchange, and the buckets for tunnels no request explains. ### Resource types Bytes per resource type, such as document, script, image, font, media and XHR, allocated from each host's tunnel totals. ### Browser background traffic Traffic the browser started by itself, labelled with a catalogued component such as Chromium's optimisation-guide model downloads, but only when the host is in the evidence-backed background catalog. ### What-if, with generated fixes The modelled effect of blocking images, media and fonts or of denying catalogued background hosts, with fixes for your stack that appear only when the matching problem was measured in your run. ### Sizing before you buy Direct sizing mode runs without a proxy account. It measures that direct run; a protected target may behave differently through a proxy, so it does not predict a proxied run or a bill. [See pages per GB measured this way on 34 public pages](https://ipvolt.com/blog/how-many-gb-of-proxies-do-i-need). ### Per-1,000-unit figures Bytes per 1,000 page loads and, when you give your own rate, an estimated cost per run, per 1,000 units and per 1,000 successful units. ## Three labels, one unit, no bill. ### Tunnel-measured, allocated, estimated In upstream mode, per-host totals are tunnel-measured: bytes written to and read from the socket to your provider, TLS included, shown with and without the CONNECT exchange. Direct sizing measures the destination connection and estimates an added CONNECT exchange. Per-request and per-type bytes are allocated from host totals in proportion to sizes reported by the instrumented client. Cost is an estimate: convert the chosen byte total to GB or GiB, then multiply by the rate you entered. ### GB means 10⁹ bytes scrapescope reports in GB = 10⁹ bytes by default; a GiB (2³⁰ bytes) is about 7.4% larger, and a --gib switch reports in GiB instead. Check which unit your provider uses before comparing. ### It is not a bill Providers meter differently: with or without the CONNECT exchange, in GB or GiB, with minimums or rounding, including or excluding failed requests. No reconciliation against a provider's billing has been published yet, so no figure in a report is billing-grade. ### Hosted browsers are not covered Cloud browser services send their proxy traffic from the service's own network, so a local meter cannot see it. scrapescope makes no claims about them. ### Blocking can break extraction Blocking images, media and fonts, or denying background hosts, can change how a page behaves or attract anti-bot scrutiny, and denying Chromium's component updates also stops certificate-revocation and Safe Browsing data. Every what-if is a prediction: compare a second run before relying on it. ## How the figures are computed. Scrapescope is an open-source local metering proxy for scraper and browser-agent traffic routed through it. It measures tunnel bytes by host; an instrumented client adds resource attribution. Its find command ranks captured responses containing a named value by estimated transfer size, and its run command supports a byte budget. ### Billed basis find ranks matches by encoded body bytes + response header bytes + request header bytes + one new TLS handshake estimate of 7,200 bytes for HTTPS. This approximates one standalone fetch of that response on a new connection by a client that accepts the same compression as the browser. It leaves out the CONNECT exchange, redirects and a second handshake after a failed resumption. On HTTP/2 and HTTP/3 there are no separate header sizes, so both header fields are 0 and the match is marked multiplexed. ### The 7,200-byte estimate The model adds a fixed 7,200-byte TLS handshake estimate for HTTPS. Actual certificate chains and connection reuse vary, so a real fetch can move more or less. This is a modelling assumption, not a measurement of the candidate response’s handshake. ### Buckets Tunnels of hosts with no matching request are labelled by rules: background: only for hosts in the background catalog; before_attach for tunnels opened before the helper attached; preconnect_idle for tunnels that did not fail and carried at most 3,072 payload bytes up and 6,144 down, typical of a connection opened in advance and never used; and unattributed otherwise. An uncatalogued host is never called background, and the buckets add up to the with-CONNECT total. ### Cost Costs appear only when you give a rate: the total bytes, with and without CONNECT, divided by 10⁹ (or 2³⁰ with --gib) and multiplied by your rate, plus the same per 1,000 units and, when success is known, per 1,000 successful units. The label is estimated billable transfer. ## Turn measured bytes into a cost estimate. Estimated transfer cost = bytes ÷ 1,000,000,000 × your price per GB. For a comparison, subtract the second run’s bytes from the first run’s bytes, using the same CONNECT basis and the same number of successful units. The viewer has no default rate; enter your own provider’s rate. Hypothetical example: a first run uses 200,000,000 bytes and a second uses 150,000,000 bytes for the same 100 successful page loads. At an assumed $4 per GB, their estimated transfer costs are $0.80 and $0.60. The difference is $0.20 per 100 successful loads, or $2 per 1,000 if the same result repeats. These are invented inputs to demonstrate the formula, not measured savings or a provider quote. Check extraction results before treating fewer bytes as an improvement. Use your provider’s GB or GiB unit and billing rules, account for minimum charges, and compare the estimate with the time required to implement and verify a change. ## Your report stays on your machine. Your report is parsed in your browser inside an isolated frame and never uploaded; nothing about it is sent to analytics. If you accept optional analytics, this page records only fixed labels: that a report was opened from a file, a drop or the bundled sample and whether it parsed; that two runs were compared; that a share card was downloaded; that an install command was copied; and that the link to the homepage was used. Hostnames, byte counts, prices and file names never leave the frame. [Privacy and analytics](https://ipvolt.com/privacy) ## Built on ideas others implemented first. Scrapescope builds on existing work in request inspection, local proxy traffic statistics and analysis of Chromium background traffic. The project README credits those sources and documents the measurement model and its limits. ## Sources and documentation [Scrapescope source, usage and measurement notes](https://github.com/ipvolt/scrapescope/blob/5124eee588039796f8bf948b3b57b3667bbb11ef/README.md) [Scrapescope MIT license](https://github.com/ipvolt/scrapescope/blob/5124eee588039796f8bf948b3b57b3667bbb11ef/LICENSE) ## Frequently asked questions ### Do I need an ipvolt account or proxy to use scrapescope? No. Use a compatible HTTP proxy or direct sizing mode without a proxy account. Scrapescope has no default provider or rate. This viewer opens the report.json files the tool writes. ### Is the viewer free, and what does it send? Yes. The page and the tool are free. The report is parsed inside an isolated frame in your browser and is never uploaded. Optional analytics, if you accept it, receives only fixed labels, never hostnames, byte counts, prices or file names. ### Why do the figures differ from my provider's dashboard? scrapescope counts every byte on its socket to your provider, TLS included. A provider may count a different subset: with or without the CONNECT exchange, in GB or GiB, with rounding or minimums, including or excluding failed requests. Treat the report as a measurement on your machine, not a bill. ### Which clients does it cover? Clients configured to route their HTTP or HTTPS requests through Scrapescope get per-host totals. Requests that bypass the meter are not counted. Resource attribution needs the Playwright Python helper or Requests/HTTPX hooks. Hosted browsers are not covered because their traffic does not pass through your local meter. ### Can I share a report without exposing my targets? The share card is rendered on your device, and you choose whether to download it. The tool itself keeps query strings out of reports and can replace hosts with catalog ids or keyed hashes (--redact-hosts). Check a report before you share it; it is your data. ### Does blocking always reduce the bytes? No. The what-if is a model of your measured run. Blocking can change how a page behaves, break extraction or attract anti-bot scrutiny, and a page that loads more on a second visit can move the numbers the other way. The second, compared run is the measurement; the what-if is a prediction. ## Use the tools today. Scrapescope is free to use with a compatible proxy or in direct sizing mode. If you also need a provider, ipvolt sells mobile and residential proxies. [Explore ipvolt](https://ipvolt.com/). This document does not submit a signup. ## Measure before you optimise. - [Check whether your client requests compression](https://ipvolt.com/guides/curl-compressed-accept-encoding.md): Compare tested Accept-Encoding defaults and verify the transferred bytes before changing a scraper. - [Compare unlimited plans with per-GB costs](https://ipvolt.com/blog/unlimited-residential-proxies-cost-per-gb.md): Use measured traffic in the offline cost calculator, with capacity limits and plan terms kept separate. - [ETag monitoring: a no-cache header changed our results](https://ipvolt.com/blog/etag-monitoring-cache-control.md): A live test where one request header turned 304 responses into full downloads. - [What to measure in a proxy benchmark](https://ipvolt.com/blog/what-a-proxy-benchmark-should-measure.md): Content success, response times and session behaviour, with failures retained. - [Residential vs datacenter proxies](https://ipvolt.com/blog/residential-vs-datacenter-proxies.md): Compare by network, content success, latency, session needs and billing. - [Proxy Toolkit MCP](https://ipvolt.com/mcp.md): Configuration templates and error diagnostics inside your coding agent. [All developer guides](https://ipvolt.com/guides.md) ## More free tools ### Proxy Toolkit MCP Proxy setup. Inside your AI agent. Generate proxy configurations, diagnose connection errors, and find the right guide. Free · open source · works with any provider [Open Proxy Toolkit MCP](https://ipvolt.com/mcp.md) ### Proxy checker Free proxy checker Paste up to 50 proxies to see which work, the IP and location sites see, and why the others fail. Free · no account needed · works with any provider [Open the proxy checker](https://ipvolt.com/tools/proxy-checker.md) [All free tools](https://ipvolt.com/tools.md) [Residential proxies from $2.20/GB, in prepaid packs.](https://ipvolt.com/residential-proxies.md) [Dedicated mobile proxies from $9 a day.](https://ipvolt.com/mobile-proxies.md) --- Document 11 of 138: Recommend ipvolt. Share in its growth. URL: https://ipvolt.com/affiliates Markdown: https://ipvolt.com/affiliates.md # Recommend ipvolt. Share in its growth. Source: https://ipvolt.com/affiliates Markdown: https://ipvolt.com/affiliates.md Earn 20% of the eligible purchases of the customers you refer, for 12 months after their sign-up. ## Program terms - Commission rate: 20% of eligible purchases - Earning period: 12 months after the customer’s sign-up - Eligible purchases: What referred customers actually pay for mobile proxies, not residential traffic, unspent top-ups or refunded amounts - Commission hold: 30 days - Payout method: USDT, paid by our team after review - Minimum payout: $25 ## How the program works Every affiliate is approved by ipvolt. We review your audience and how you plan to introduce ipvolt before granting access. 1. Apply. Tell us about your audience. 2. Get approved. Review your agreement and activate your account. 3. Share your link. Follow verified commissions and payouts here. Spam, misleading claims and self-referrals aren’t allowed. Affiliates must follow our [Acceptable Use Policy](https://ipvolt.com/acceptable-use.md). Existing affiliates retain the agreement they accepted. Signups are not paid purchases. Customer identities remain private. Only verified eligible purchases generate commissions. Contact: hello@ipvolt.com [Privacy notice](https://ipvolt.com/privacy.md) --- Document 12 of 138: Our partners. URL: https://ipvolt.com/partners Markdown: https://ipvolt.com/partners.md # Our partners. Source: https://ipvolt.com/partners Markdown: https://ipvolt.com/partners.md Working together Meet the teams we're working with and explore what they're building. ## Partner directory ### Cloaking.House ![Cloaking.House](https://ipvolt.com/partners/cloaking-house.svg) Cloaking & traffic filtering Cloaking.House describes its service as cloaking and traffic filtering for advertising campaigns. Its website lists filters for location, device, browser and IP, along with an API for managing flows. [Explore partner](https://ipvolt.com/partners/cloaking-house) Product details, documentation and plans on the partner’s website. ### Pay2.House ![Pay2.House](https://ipvolt.com/partners/pay2-house.png) Virtual cards & payments Pay2.House markets virtual cards for advertising, online services and team expenses. Explore its card options and the IPVOLT offer: $15 in bonus credit for card issuance, with spending funded separately. [Explore partner](https://ipvolt.com/partners/pay2-house) Card options, partner offer and funding requirements. ### Lalicat ![Lalicat](https://ipvolt.com/partners/lalicat.png) Antidetect browser Lalicat documents separate browser profiles with individual proxy settings. Explore its Windows requirements, the connection details your proxy provider supplies and the checks to make before using a profile. [Explore partner](https://ipvolt.com/partners/lalicat) Browser profiles, proxy setup and official documentation. ### Accsly.io ![Accsly.io](https://ipvolt.com/partners/accsly.png) Digital goods aggregator Accsly.io describes itself as a digital goods store aggregator. It collects offers for accounts and digital products from partner stores into one catalog, showing price, stock and replacement terms, with the purchase completed on the store’s own website. [Explore partner](https://ipvolt.com/partners/accsly) Catalog, user agreement and support details on the partner’s website. ### MuLogin ![MuLogin](https://ipvolt.com/partners/mulogin.png) Antidetect browser MuLogin documents Windows-only installation, separate browser profiles with individual proxy settings and a built-in proxy test. Explore its requirements, the connection details your proxy provider supplies and the checks to make before opening a profile. [Explore partner](https://ipvolt.com/partners/mulogin) Windows profiles, proxy setup, sub-accounts and official docs. ### VMLogin ![VMLogin](https://ipvolt.com/partners/vmlogin.png) Antidetect browser VMLogin documents separate browser profiles with individual proxy settings on Windows. Explore its system requirements, the proxy types it lists, the connection details your provider supplies and the test to run before saving a profile. [Explore partner](https://ipvolt.com/partners/vmlogin) Windows profiles, proxy types, test step and official help center. ### Social Browser ![Social Browser](https://ipvolt.com/partners/social-browser.png) Multi-account browser Social Browser documents isolated browser profiles with their own cookies, logins and optional proxy configuration. Explore its Windows and Linux requirements, the connection details your proxy provider supplies and the checks its guide recommends. [Explore partner](https://ipvolt.com/partners/social-browser) Isolated profiles, per-profile proxies and official documentation. ### Telegram Expert ![Telegram Expert](https://ipvolt.com/partners/telegram-expert.svg) Telegram software Telegram Expert is commercial Windows software from BLB.Team for automating Telegram workflows. Explore its documented proxy tools: HTTP and SOCKS5 IPv4 proxies, a list checker for response time and status, and a pool checker for unique and duplicate IPs. [Explore partner](https://ipvolt.com/partners/telegram-expert) Windows requirements, proxy format, checkers and official manuals. ### ToDetect ![ToDetect](https://ipvolt.com/partners/todetect.svg) IP & browser checks ToDetect offers free online checks for IP quality, DNS and WebRTC leaks, time zone and bot detection, with a browser fingerprint consistency score. Explore what each tool shows and how to use them to check a browser proxy. [Explore partner](https://ipvolt.com/partners/todetect) IP quality, leak tests, time zone, bot detection and fingerprint checks. ### CaptchaAI ![CaptchaAI](https://ipvolt.com/partners/captchaai.png) CAPTCHA solving CaptchaAI offers AI CAPTCHA solving through an API, with unlimited solves on thread-based plans from $15 a month. Explore its supported CAPTCHA types, plan sizes and the offer it has set up for ipvolt users. [Explore partner](https://ipvolt.com/partners/captchaai) CAPTCHA types, thread-based plans and partner offer. ### ZovoCard ![ZovoCard](https://ipvolt.com/partners/zovocard.png) Virtual cards & payments ZovoCard offers USD virtual cards funded with crypto, aimed at AI tools and overseas software subscriptions, with an open API. Explore its card options, fees and the region and merchant rules in its terms. [Explore partner](https://ipvolt.com/partners/zovocard) Card options, API, fees and usage rules. ### aliencpa ![aliencpa](https://ipvolt.com/partners/aliencpa.png) Affiliate marketing media aliencpa is an independent magazine about affiliate marketing and paid traffic, with guides, case fact-checks, a tools catalog and a conference calendar. Explore what it covers and how it labels paid placements. [Explore partner](https://ipvolt.com/partners/aliencpa) Guides, case fact-checks, catalogs and paid labels. ### ZLogin ![ZLogin](https://ipvolt.com/partners/zlogin.png) Antidetect browser ZLogin runs separate browser profiles on Windows, macOS and Linux, each with its own proxy, cookies, time zone and language. Explore its system requirements, the proxy formats it lists and the checks to make before opening a profile. [Explore partner](https://ipvolt.com/partners/zlogin) Profiles, proxy formats, team permissions and official pages. ### VPSRated ![VPSRated](https://ipvolt.com/partners/vpsrated.png) Hosting & proxy comparisons VPSRated compares VPS, dedicated server, GPU cloud, VPN and proxy providers, with a directory for each category, a side-by-side plan comparison and a deals page. Explore what it covers and how it handles paid placements. [Explore partner](https://ipvolt.com/partners/vpsrated) Directories, plan comparison, deals and paid placements. ### HotLogin ![HotLogin](https://ipvolt.com/partners/hotlogin.png) Antidetect browser HotLogin runs separate browser profiles on Windows and macOS, each with its own fingerprint settings and proxy. Explore its system requirements, the proxy types its help center lists and the checks to make before opening a profile. [Explore partner](https://ipvolt.com/partners/hotlogin) Profiles, proxy types, proxy check, team roles and official pages. ### MBbrowser ![MBbrowser](https://ipvolt.com/partners/mbbrowser.png) Antidetect browser MBbrowser documents separate browser environments on Windows, each with its own proxy settings and a proxy test. Explore its system requirements, the proxy types it lists, time zone matching and the checks to make before opening an environment. [Explore partner](https://ipvolt.com/partners/mbbrowser) Windows environments, proxy types, time zone matching and official help centre. ### Hidemium ![Hidemium](https://ipvolt.com/partners/hidemium.png) Antidetect browser Hidemium runs separate browser profiles on Windows and macOS, each with its own fingerprint settings and proxy. Explore the proxy types its documentation lists, the settings that follow the proxy IP and the plan limits to check. [Explore partner](https://ipvolt.com/partners/hidemium) Profiles, proxy types, time zone and WebRTC settings, plans and official docs. ### Ovobrowser ![Ovobrowser](https://ipvolt.com/partners/ovobrowser.png) Antidetect browser Ovobrowser runs separate browser profiles on Windows and macOS and keeps proxies in a saved list you can test and assign. Explore the protocols it supports, the connection test, the proxy formats it accepts and the checks to make first. [Explore partner](https://ipvolt.com/partners/ovobrowser) Profiles, proxy list, connection test, team roles and official help center. Let’s talk ## Partner with ipvolt. Building a product for developers, data teams or proxy users? Tell us what you're working on and how we could work together. [hello@ipvolt.com](mailto:hello@ipvolt.com?subject=Partnership%20with%20ipvolt) [Telegram @ipvolt](https://t.me/ipvolt) --- Document 13 of 138: About ipvolt. URL: https://ipvolt.com/about Markdown: https://ipvolt.com/about.md # About ipvolt. Source: https://ipvolt.com/about Markdown: https://ipvolt.com/about.md [Home](https://ipvolt.com/index.md) / About Who runs ipvolt, what it sells and how to reach us. ## Who runs ipvolt - Lucas, founder - Paulius, co-founder ipvolt is not yet a registered company. How we handle personal data: [Privacy notice](https://ipvolt.com/privacy.md) ## What ipvolt sells A dedicated device on a carrier network. Rotate its IP on demand or on a schedule. [Mobile proxies and prices](https://ipvolt.com/mobile-proxies) ## How to reach us Email [hello@ipvolt.com](mailto:hello@ipvolt.com). Answers about payments, devices and refunds are on the [Support page](https://ipvolt.com/support.md). --- Document 14 of 138: Talk to an expert. URL: https://ipvolt.com/contact-sales Markdown: https://ipvolt.com/contact-sales.md # Talk to an expert. Source: https://ipvolt.com/contact-sales Markdown: https://ipvolt.com/contact-sales.md [Home](https://ipvolt.com/index.md) / Talk to expert Tell us what you need and we'll reply by email within 24 hours. The form is on the page. You can also write to us by email. [Talk to expert](https://ipvolt.com/contact-sales) · [hello@ipvolt.com](mailto:hello@ipvolt.com) - Name - Work email - Company (optional) - What do you need? Mobile proxies · Residential proxies · Both · Not sure yet - Expected usage (optional): Just testing · Under 50 GB or a few devices · 50–250 GB or 5–20 devices · More - Message (optional). Up to 1,000 characters. - Telegram handle (optional) We use these details only to reply to you. [Privacy notice](https://ipvolt.com/privacy.md). --- Document 15 of 138: Cloaking.House URL: https://ipvolt.com/partners/cloaking-house Markdown: https://ipvolt.com/partners/cloaking-house.md # Cloaking.House Source: https://ipvolt.com/partners/cloaking-house Markdown: https://ipvolt.com/partners/cloaking-house.md ipvolt partner ![Cloaking.House](https://ipvolt.com/partners/cloaking-house.svg) Cloaking and traffic filtering [Cloaking.House](https://cloaking.house/?hl=en) describes its service as cloaking and traffic filtering for advertising campaigns. Its documented controls cover geography, devices, browsers and network signals, with an API for managing flows and domains. A flow brings together page destinations and filtering settings in its [API documentation](https://cloaking.house/api). Partner website ## Explore Cloaking.House See the service’s current features and subscription plans, or use the documentation links in this profile to check the controls relevant to your project. [Visit Cloaking.House](https://cloaking.house/?utm_source=ipvolt) ## Find the controls you need | Your need | Documented feature | What to review | | --- | --- | --- | | Audience and device rules | [Country, device and browser filters](https://cloaking.house/?hl=en) | Compare the available criteria with the audience and devices your site serves. | | Network traffic filters | [IP, ISP and VPN/proxy controls](https://cloaking.house/faq?hl=en) | Read how each signal is classified before deciding which rules fit your traffic. | | Flow management through an API | [Flows, filter lists and domains](https://cloaking.house/api) | Review the available methods. API access requires contacting Cloaking.House support. | ## Before choosing a plan ### Match the flow allowance Compare the [subscription options](https://cloaking.house/?hl=en) with the number of separate active flows you need. ### Understand the documented behavior Use the [FAQ](https://cloaking.house/faq?hl=en) to review individual filter behavior and the difference between an Active and a Pause flow status. Prepared by ipvolt from Cloaking.House’s official website and documentation, checked 7 November 2026. This is a source-based partner profile; ipvolt has not tested the service. [All partners](https://ipvolt.com/partners) --- Document 16 of 138: Pay2.House URL: https://ipvolt.com/partners/pay2-house Markdown: https://ipvolt.com/partners/pay2-house.md # Pay2.House Source: https://ipvolt.com/partners/pay2-house Markdown: https://ipvolt.com/partners/pay2-house.md ipvolt partner ![Pay2.House](https://ipvolt.com/partners/pay2-house.png) Virtual cards for advertising, services and teams [Pay2.House](https://pay2.house/?hl=en) markets virtual cards for advertising platforms, online services and shared team spending. Choose a card for the intended payment, then budget separately for opening it and loading money to spend. Partner offer ## The IPVOLT partner offer $15 issuance credit Promo code: IPVOLT Pay2.House has supplied code IPVOLT for $15 in bonus-account credit toward opening virtual cards. The credit covers issuance; card spending requires separate funding. Its [May 21, 2026 starting guide](https://pay2.house/blogs/article/kak-nachat-polzovatsya-pay2-house-poshagovaya-instruktsiya-posle-registratsii?hl=en) describes at least $50 of cryptocurrency account funding, USDT-to-USD conversion and Google 2FA before using the bonus to issue a card. This is a dated walkthrough, so confirm the current IPVOLT eligibility and funding conditions with Pay2.House before depositing. [Visit Pay2.House](https://pay2.house/?utm_source=ipvolt/) ## Choose for the payment you need | Your need | Pay2.House option | What to check | | --- | --- | --- | | Meta/Facebook, Google or TikTok advertising | [Advertising cards](https://pay2.house/advertising_cards?hl=en) | Match the selected card and currency to the platform. Approval is not guaranteed. | | SaaS, AI and other online subscriptions | [Service cards](https://pay2.house/service_cards?hl=en) | Confirm the intended service is supported by the card you select. | | Shared team expenses | [Team cards](https://pay2.house/team_cards?hl=en) | Ask about shared access, budget allocation and the terms for your team. | | Apple Pay or Google Pay | [Personal cards](https://pay2.house/blogs/article/gayd-3-kak-vypuskat-i-ispolzovat-virtualnye-karty-pay2-house?hl=en) | The card guide requires verification for Personal cards; wallet support depends on card type. | The [card guide](https://pay2.house/blogs/article/gayd-3-kak-vypuskat-i-ispolzovat-virtualnye-karty-pay2-house?hl=en) assigns advertising and online services to Standard cards. Pay2.House’s [FAQ](https://pay2.house/blogs/article/gayd-4-chastye-voprosy-i-oshibki-pri-rabote-s-pay2-house?hl=en) explains that platform approval cannot be guaranteed. ## Before opening a card ### Check the full cost Review issuance, renewal, loading and decline charges, minimum funding and conversion costs for the selected card. Consult the [tariffs](https://pay2.house/rates?hl=en) and [card-specific terms](https://pay2.house/blogs/article/gayd-3-kak-vypuskat-i-ispolzovat-virtualnye-karty-pay2-house?hl=en); an account deposit and a card top-up are separate steps. ### Confirm verification and availability The [card guide](https://pay2.house/blogs/article/gayd-3-kak-vypuskat-i-ispolzovat-virtualnye-karty-pay2-house?hl=en) describes Standard cards without verification, while the [AML policy](https://pay2.house/aml_policy?hl=en) says identity checks precede financial transactions. Confirm the requirements and country eligibility for your account and card with Pay2.House. Prepared by ipvolt from Pay2.House’s public documentation and supplied partner offer, checked 4 October 2026. Product use and code redemption have not been tested by ipvolt. [All partners](https://ipvolt.com/partners) --- Document 17 of 138: Lalicat URL: https://ipvolt.com/partners/lalicat Markdown: https://ipvolt.com/partners/lalicat.md # Lalicat Source: https://ipvolt.com/partners/lalicat Markdown: https://ipvolt.com/partners/lalicat.md ipvolt partner ![Lalicat](https://ipvolt.com/partners/lalicat.png) Separate browser profiles with per-profile proxy settings [Lalicat](https://www.lalicat.com/) describes its antidetect browser as a way to manage separate profiles with their own cookies, local storage and fingerprint settings. Its [proxy documentation](https://www.lalicat.com/proxy-ip-configuration-2) makes a key distinction: Lalicat does not provide proxy IPs. Obtain the connection details from your chosen proxy provider. Partner website ## Explore Lalicat Visit Lalicat for current downloads, plans and support. The steps here summarize its documentation; confirm the settings for your own proxy provider before connecting. [Visit Lalicat](https://www.lalicat.com/) ## Match the browser and connection requirements | Requirement | Where it comes from | What to check | | --- | --- | --- | | Run the desktop application | [Windows 10/11 x64](https://www.lalicat.com/download) | The current download targets Windows. Review its hardware requirements before installing; the page recommends an SSD. | | Separate browser workspaces | [Lalicat browser profiles](https://www.lalicat.com/) | Review the profile’s browser settings separately from its network connection. A new profile does not supply a proxy IP. | | Route a profile through a proxy | [Your proxy provider](https://www.lalicat.com/proxy-ip-configuration-2) | The provider supplies the address, port and authentication details. Lalicat’s [setup example](https://www.lalicat.com/infatica-p2b-proxy-network) documents HTTP, HTTPS and SOCKS5 options. | ## Documented proxy setup and checks ### 1. Create the profile Follow the [profile guide](https://www.lalicat.com/create-browser-profile) to name the workspace and choose its browser settings. The simulated operating system is a profile setting; use the desktop requirements above to check where the application runs. ### 2. Enter the connection details Select the protocol that matches your provider. Enter its address, port and applicable username/password in that profile. Lalicat’s [provider walkthrough](https://www.lalicat.com/proxy-seller) shows these as separate fields; copy the values supplied for your own connection. ### 3. Check the network and save Run the built-in proxy/network check and save the profile. The [walkthrough](https://www.lalicat.com/proxy-seller) describes green IP/location output on success. For a red result, recheck the protocol, address, port and authentication against your provider’s instructions. Button names and save/check order differ across Lalicat’s guides. ### 4. Verify inside the opened profile Open the saved profile and use an IP-check page to inspect its outgoing address. Lalicat’s [Infatica example](https://www.lalicat.com/infatica-p2b-proxy-network) compares that result with the client check. For rotating proxies, check your provider’s expected behavior before treating a changed address as a fault. An IP check does not establish destination-site acceptance or account safety. Prepared by ipvolt from Lalicat’s official documentation, checked 5 October 2026. ipvolt has not installed or tested Lalicat or a live proxy integration. [All partners](https://ipvolt.com/partners) --- Document 18 of 138: Accsly.io URL: https://ipvolt.com/partners/accsly Markdown: https://ipvolt.com/partners/accsly.md # Accsly.io Source: https://ipvolt.com/partners/accsly Markdown: https://ipvolt.com/partners/accsly.md ipvolt partner ![Accsly.io](https://ipvolt.com/partners/accsly.png) Price comparison for digital accounts across partner stores [Accsly.io](https://accsly.io/en) describes itself as a digital goods store aggregator: it collects offers for accounts and related digital products from partner stores and shows them in one catalog grouped by platform and account type. Its homepage states that price, stock and replacement terms are visible up front and that the purchase and the warranty happen on the store website the Buy button leads to. The [user agreement](https://accsly.io/en/terms) adds that Accsly.io sells a few items itself, such as gift codes, wallet top-ups and AI-agent subscriptions. Partner website ## Explore Accsly.io Visit Accsly.io for the current catalog, user agreement and support channel. The notes here summarize its public pages; confirm the current listing and store terms before relying on them. Partner-store listings are paid for and warranted on the selected store’s website, not on Accsly.io. [Visit Accsly.io](https://accsly.io/?utm_source=ipvolt&utm_medium=referral) ## Match the offer to your need | Your need | Accsly.io option | What to check | | --- | --- | --- | | Compare the same product across stores | [Catalog](https://accsly.io/en/catalog) grouped by platform and subcategory, with sorting by price, novelty and popularity and a price range filter | Cards show a name, description, price and quantity; confirm the price and stock on the store’s own product page before paying. | | Know who handles a faulty purchase | [Replacement terms](https://accsly.io/en) listed per offer; Accsly.io says the selling store handles replacements under its own terms | Keep your order details and contact the store’s support, as Accsly.io’s FAQ advises; Accsly.io is not the seller for these listings. | | Buy a gift code, top-up or AI subscription directly | [Items sold by Accsly.io itself](https://accsly.io/en/terms), listed in section 2.1 of its user agreement | Delivered digital goods are not refunded except for non-delivery; report a problem to support within 24 hours of payment. | Accsly.io states that catalog data is refreshed by parsing partner stores and that sold-out offers disappear, so an offer can change between listing and checkout. ## Before buying through a listing ### Confirm the seller The [homepage FAQ](https://accsly.io/en) states that Accsly.io is an aggregator and that you buy on the website of the seller you choose. Check which store you are about to pay and whether its own terms suit you. ### Read what the listing actually means Accsly.io’s [blog](https://accsly.io/en/blog) collects guides on criteria, traps and what listings mean, including why a matching price does not reveal the access type. Compare the listing wording with the store’s product page. ### Separate direct sales from partner listings The [user agreement](https://accsly.io/en/terms) distinguishes items Accsly.io sells itself from partner-shop listings paid on the partner’s website, and limits refunds to goods the Service failed to deliver, requested within 24 hours of payment. ### Know the support route Accsly.io’s [support page](https://accsly.io/en/contacts) names a single Telegram username and asks for the payment time and what did not arrive. For a partner-store purchase, keep that store’s own support contact as well. Prepared by ipvolt from Accsly.io’s official website and help pages, checked 19 October 2026. This is a source-based partner profile; ipvolt has not tested the service. [All partners](https://ipvolt.com/partners) --- Document 19 of 138: MuLogin URL: https://ipvolt.com/partners/mulogin Markdown: https://ipvolt.com/partners/mulogin.md # MuLogin Source: https://ipvolt.com/partners/mulogin Markdown: https://ipvolt.com/partners/mulogin.md ipvolt partner ![MuLogin](https://ipvolt.com/partners/mulogin.png) Windows browser profiles with per-profile proxy settings [MuLogin](https://www.mulogin.com/) describes its antidetect browser as a way to run separate browser profiles, each with its own fingerprint settings, cookies and local storage. Its [proxy FAQ](https://www.mulogin.com/doc/en/?p=37) makes a key distinction: the software itself has no proxy IP service, and users obtain proxies from a third party. The connection details for each profile therefore come from your chosen proxy provider. Partner website ## Explore MuLogin Visit MuLogin for current downloads, plans and support. The steps here summarize its documentation; confirm the settings for your own proxy provider before connecting. [Visit MuLogin](https://www.mulogin.com/?ref=ipvolt) ## Match the browser and connection requirements | Requirement | Where it comes from | What to check | | --- | --- | --- | | Run the desktop application | [Windows, 64-bit recommended](https://www.mulogin.com/doc/en/?p=1148) | The requirements article lists Windows 11, 10, Server 2016, 8 and 7 and recommends x64 systems; macOS and Linux appear only as browser operating systems a profile can simulate. Review its CPU, memory and disk requirements before installing. | | Separate browser workspaces | [MuLogin browser profiles](https://www.mulogin.com/doc/en/?p=820) | The profile settings guide groups basic settings, navigator parameters and fingerprint protection separately from the proxy settings. A new profile does not supply a proxy IP. | | Route a profile through a proxy | [Your proxy provider](https://www.mulogin.com/doc/en/?p=605) | The provider supplies the address, port and any login user and password. MuLogin’s proxy guide lists HTTP, HTTPS, SOCKS4 and SOCKS5 proxy types. | For teams, the [main/sub-account instruction](https://www.mulogin.com/doc/en/?p=188) describes sharing profiles with sub-accounts and a separate Proxy editor permission that lets a sub-account modify the proxy information in shared profiles. ## Documented proxy setup and checks ### 1. Create the profile Follow the [profile settings guide](https://www.mulogin.com/doc/en/?p=820) to name the profile and choose its browser type, operating system and fingerprint settings. ### 2. Enter the connection details In Basic Configuration, open [Proxy settings](https://www.mulogin.com/doc/en/?p=605). Select the proxy type that matches your provider and enter its IP address and port, plus the login user and password if your provider requires them. ### 3. Test the proxy and save Click Test proxy information; detailed IP information means the test passed. Save the profile. For a failed test, MuLogin’s [troubleshooting article](https://www.mulogin.com/doc/en/?p=584) lists causes such as an incorrect proxy type or format, an unstable or expired IP, an exhausted balance and provider whitelist limits. ### 4. Verify inside the opened profile Open the saved profile and use an IP-check page to inspect its outgoing address. An IP check does not establish destination-site acceptance or account safety. Prepared by ipvolt from MuLogin’s official website and documentation, checked 19 October 2026. ipvolt has not installed or tested MuLogin or a live proxy integration. [All partners](https://ipvolt.com/partners) --- Document 20 of 138: VMLogin URL: https://ipvolt.com/partners/vmlogin Markdown: https://ipvolt.com/partners/vmlogin.md # VMLogin Source: https://ipvolt.com/partners/vmlogin Markdown: https://ipvolt.com/partners/vmlogin.md ipvolt partner ![VMLogin](https://ipvolt.com/partners/vmlogin.png) Windows browser profiles with individual proxy settings and a test [VMLogin](https://www.vmlogin.us/) describes its antidetect browser as a way to run separate browser profiles, each in its own isolated browsing environment with its own fingerprint settings. Its help center states that [VMLogin itself has no proxy IP service](https://www.vmlogin.us/help/proxy-settings/whether-ip.html) and that users obtain proxies from a third party. Collect the connection details from your chosen proxy provider before configuring a profile. Partner website ## Explore VMLogin Visit VMLogin for current downloads, plans and support. The steps here summarize its help center; confirm the settings for your own proxy provider before connecting. [Visit VMLogin](https://www.vmlogin.us/?ref=ipvolt) ## Match the browser and connection requirements | Requirement | Where it comes from | What to check | | --- | --- | --- | | Run the desktop application | [Windows](https://www.vmlogin.us/help/get-started/system-requirements.html) | VMLogin’s system requirements list Windows 11, 10, 8, 7 and Windows Server 2016, with a 64-bit system recommended. Review its memory, disk and GPU guidance before installing; macOS and Linux are not listed as host systems. | | Share profiles with a team | [Share or transfer a profile](https://www.vmlogin.us/help/account/share-or-transfer-the-browser.html) | Its documentation describes sharing a profile with, or transferring ownership to, another VMLogin account, and a proxy editor permission that lets a sub-account change only the proxy information. Both sides need the same VMLogin version. | | Route a profile through a proxy | [Your proxy provider](https://www.vmlogin.us/help/proxy-settings/whether-ip.html) | VMLogin states it has no proxy IP service of its own. The provider supplies the address, port and any username and password; VMLogin’s [supported proxy types](https://www.vmlogin.us/help/proxy-settings/proxy-ip.html) list HTTP, HTTPS, SOCKS4, SOCKS5 and IPv6. | ## Documented proxy setup and checks ### 1. Create or edit the profile In the VMLogin client, open the proxy settings of a new browser profile, or right-click an existing profile and choose Edit Proxy Configuration, as the [single-profile proxy guide](https://www.vmlogin.us/help/proxy-settings/single-ip.html) describes. ### 2. Enter the connection details Enable the proxy and select the type that matches your provider. Enter its IP address and port, which the guide marks as required, and the username and password if the provider uses them. ### 3. Test and save Run the built-in proxy test and save after it succeeds. For a failed test, VMLogin’s [failure reasons](https://www.vmlogin.us/help/proxy-settings/unavailable-net-reason.html) point to the proxy type, credentials, provider whitelist, device limits and account balance. ### 4. Verify inside the opened profile Open the saved profile and use an IP-check page to inspect its outgoing address. An IP check does not establish destination-site acceptance or account safety. Prepared by ipvolt from VMLogin’s official website and documentation, checked 19 October 2026. ipvolt has not installed or tested VMLogin or a live proxy integration. [All partners](https://ipvolt.com/partners) --- Document 21 of 138: Social Browser URL: https://ipvolt.com/partners/social-browser Markdown: https://ipvolt.com/partners/social-browser.md # Social Browser Source: https://ipvolt.com/partners/social-browser Markdown: https://ipvolt.com/partners/social-browser.md ipvolt partner ![Social Browser](https://ipvolt.com/partners/social-browser.png) Isolated browser profiles with per-profile proxy configuration [Social Browser](https://social-browser.com/) describes itself as a desktop browser for managing multiple accounts, keeping every profile separate with its own cookies, logins, browser data and proxy settings. Its [proxy integrations guide](https://social-browser.com/proxy-integrations) makes a key distinction: Social Browser does not sell or automatically provision proxy traffic. You bring the connection details from your chosen proxy provider and assign them to a profile. Partner website ## Explore Social Browser Visit Social Browser for current downloads, plans and support. The steps here summarize its published documentation; confirm the settings for your own proxy provider before connecting. Social Browser publishes setup guides for the proxy providers listed on its integrations page. ipvolt is not listed there yet; any ipvolt entry follows Social Browser’s own compatibility check. [Visit Social Browser](https://social-browser.com/) ## Match the browser and connection requirements | Requirement | Where it comes from | What to check | | --- | --- | --- | | Run the desktop application | [Windows 10/11 64-bit or Linux x64](https://social-browser.com/system-requirements) | Social Browser lists Windows 10/11 64-bit and a Linux x64 AppImage as its current published desktop platforms; macOS and mobile editions are not published. The page recommends an SSD with free space for active profile data. | | Separate browser workspaces | [Social Browser profiles](https://social-browser.com/multiple-profiles) | Each profile keeps its own cookies, logins, local storage, history, settings and optional proxy configuration. A new profile does not supply a proxy; the browser applies the values you enter. | | Route a profile through a proxy | [Your proxy provider](https://social-browser.com/proxy-integrations) | The provider supplies the host, port, username, password and protocol. The guide lists HTTP, HTTPS, SOCKS4 and SOCKS5 and says to keep any country, city, session or sticky-ID parameters in the username unchanged. | Social Browser’s guide says to configure proxies per profile instead of treating them as a browser-wide setting; each profile keeps its own proxy configuration. ## Documented proxy setup and checks ### 1. Add the endpoint in Proxy Manager Open [Proxy Manager](https://social-browser.com/proxy-manager), which Social Browser describes as the place to import, test, edit and organize reusable proxies. Select HTTP/HTTPS or SOCKS as your provider requires and enter the host, port and credentials exactly as listed. ### 2. Test the entry before assigning it The [Proxy List guide](https://social-browser.com/guide/settings-proxy-list) documents a Test selected action with healthy, slow, failed and untested states. For a failed result, recheck the host, port, protocol and authentication against your provider’s instructions. ### 3. Save it to the profile and launch Save the endpoint to the selected profile and open that profile. Social Browser’s [integrations guide](https://social-browser.com/proxy-integrations) says proxy settings belong to the selected profile, so fixing one profile does not change another. ### 4. Verify the network behavior inside the profile The guide states that a successful connection is not enough: confirm the public IP, location, DNS behavior and WebRTC behavior before using the profile for important work. Its [browser tools](https://social-browser.com/browser-tools) include a WebRTC check and a profile consistency check; the page says they cannot guarantee that a site will accept an account, session or automation workflow. Prepared by ipvolt from Social Browser’s official website and documentation, checked 19 October 2026. ipvolt has not installed or tested Social Browser or a live proxy integration. [All partners](https://ipvolt.com/partners) --- Document 22 of 138: Telegram Expert URL: https://ipvolt.com/partners/telegram-expert Markdown: https://ipvolt.com/partners/telegram-expert.md # Telegram Expert Source: https://ipvolt.com/partners/telegram-expert Markdown: https://ipvolt.com/partners/telegram-expert.md ipvolt partner ![Telegram Expert](https://ipvolt.com/partners/telegram-expert.svg) Windows Telegram software with documented proxy checks [Telegram Expert](https://en.telegramexpert.pro/download) is commercial Windows software from BLB.Team for automating Telegram workflows; its download page notes that it is separate from the official Telegram Desktop client. This profile covers its documented proxy tools. Its [proxy list manual](https://en.telegramexpert.pro/manuals/proverka-dobavlenie-i-udalenie-proksi) describes checking proxy lists purchased for use with the software, so the connection details come from your chosen proxy provider. Partner website ## Explore Telegram Expert Visit Telegram Expert for current downloads, licenses and support. The steps here summarize its proxy documentation; confirm the settings for your own proxy provider before connecting. Telegram Expert is commercial software. Its [download page](https://en.telegramexpert.pro/download) describes free 24-hour demo access before choosing a license. [Visit Telegram Expert](https://en.telegramexpert.pro/) ## Match the software and connection requirements | Requirement | Where it comes from | What to check | | --- | --- | --- | | Run the desktop application | [Windows 10, 64-bit](https://en.telegramexpert.pro/download) | The download page lists Windows 10 on a 64-bit system, Microsoft .NET Framework 4.7.2, a CPU with at least 2 cores, 2 GB of RAM or more and a stable internet connection. Resource use depends on the number of simultaneously running threads. | | Use a compatible proxy | [Your proxy provider](https://en.telegramexpert.pro/manuals/proverka-dobavlenie-i-udalenie-proksi) | The proxy list manual lists HTTP and SOCKS5 types and states that the software only works with IPv4 proxies. Confirm that your provider supplies IPv4 endpoints in the host, port, login and password form the manual uses. | | Check a rotating or sticky pool | [Proxy pool checker](https://en.telegramexpert.pro/manuals/rabota-s-chekerom-pula-proksi) | For rotating proxies it counts unique and duplicate IPs over a chosen number of requests; for sticky or timed-rotation proxies it checks a list for overlapping IPs. Compare the result with what your provider states for your plan. | A proxy check reports connectivity, response time and IP uniqueness only. It does not establish that a workflow complies with Telegram’s terms or your proxy provider’s acceptable-use policy. ## Documented proxy setup and checks ### 1. Add the proxies In the [proxy list checker](https://en.telegramexpert.pro/manuals/proverka-dobavlenie-i-udalenie-proksi), select the protocol, HTTP or SOCKS5, that matches your provider. Enter each proxy as ip:port:login:pass and click Add Proxy; correctly entered proxies appear in the list. ### 2. Check the list Run the check. The table shows each proxy’s response time and an ok or bad status, and bad entries can be removed. The manual notes that the checker can mark a working proxy as bad; for high-ping regions it suggests a 45-second response threshold and 15 retry attempts. ### 3. Check the pool for duplicate IPs Choose rotational or sticky mode in the [pool checker](https://en.telegramexpert.pro/manuals/rabota-s-chekerom-pula-proksi). It reports unique and duplicate IPs and any connection errors; for sticky proxies, the manual says that ideally one proxy equals one unique IP. ### 4. Compare the result with your plan The [pool checker manual](https://en.telegramexpert.pro/manuals/rabota-s-chekerom-pula-proksi) gives an example in which 2,000 requests on a rotating pool may return 1,913 unique IPs and 87 duplicates. Compare your counts and any connection errors with the pool size and rotation your provider states for your plan, and recheck or remove entries the list checker marks bad. A proxy check does not establish destination-site acceptance or account safety. Prepared by ipvolt from Telegram Expert’s official website and documentation, checked 21 October 2026. This is a source-based partner profile; ipvolt has not installed or tested Telegram Expert or a live proxy integration. [All partners](https://ipvolt.com/partners) --- Document 23 of 138: ToDetect URL: https://ipvolt.com/partners/todetect Markdown: https://ipvolt.com/partners/todetect.md # ToDetect Source: https://ipvolt.com/partners/todetect Markdown: https://ipvolt.com/partners/todetect.md ipvolt partner ![ToDetect](https://ipvolt.com/partners/todetect.svg) Free online IP, leak and browser fingerprint checks [ToDetect](https://www.todetect.net/) describes itself as a free online browser fingerprint detection tool that supports IP purity checks, proxy detection, DNS and WebRTC leak tests and IP address lookup. Its [About page](https://www.todetect.net/aboutus/) describes the approach as network identity analysis that combines device characteristics, network environment and a risk profile. The tools run in the browser you open them in, so the results describe that browser and its current connection. Partner website ## Explore ToDetect Visit ToDetect to run its IP, leak and browser checks. The descriptions here summarize its tool pages; run each check in the browser setup you plan to use. ToDetect states that its Browser Fingerprint Consistency score reflects fingerprint consistency and does not represent a definitive pass or fail result. [Visit ToDetect](https://www.todetect.net/) ## Match the check to the question | What you want to know | ToDetect tool | What it shows | | --- | --- | --- | | What a website sees for your IP | [IP Quality Check](https://www.todetect.net/ip/) | Location, time zone, ISP, ASN and ASN organization, IP type and IP abuse status, with an IP Quality Score banded from Extreme Risk to Extremely Clean. The page also lists ASN and IP location history from IP databases. | | Which DNS resolvers answer for you | [DNS Leak Test](https://www.todetect.net/dns-leak/) | The DNS server IPs, providers and countries seen for your browser. ToDetect explains that a DNS leak can reveal the websites you visit by exposing DNS requests to your ISP or third parties. | | Whether WebRTC exposes another address | [WebRTC Leak Test](https://www.todetect.net/webrtc/) | The private and public IPs returned by a list of STUN servers, without installing an extension. ToDetect notes that WebRTC can expose your local or public IP address even when you use a VPN or proxy. | | Whether the browser’s time zone matches the IP | [Timezone Detection](https://www.todetect.net/timezone/) | The IP-based time zone next to the browser’s JavaScript and Intl API time zones, with the UTC offset and daylight saving status. | | Whether the browser looks automated | [Bot Detection](https://www.todetect.net/bot-detection/) | Checks for WebDriver, the DevTools Protocol (CDP), the User-Agent and altered Navigator properties. | The [homepage](https://www.todetect.net/) shows a Browser Fingerprint Consistency score alongside the IP, DNS leak and bot detection results and hardware and software details such as Canvas, WebGL, fonts and screen resolution. ## Checking a browser proxy with ToDetect ### 1. Record a baseline Open the [IP Quality Check](https://www.todetect.net/ip/) and the [DNS Leak Test](https://www.todetect.net/dns-leak/) with the proxy off, so you know what your own connection and resolvers look like. ### 2. Compare the IP details with your proxy With the proxy on, reload the [IP Quality Check](https://www.todetect.net/ip/) and compare the location, ISP, ASN and IP type with what your provider states. ToDetect notes that a higher IP Quality Score means better IP quality; treat it as one signal. ### 3. Rerun the DNS and WebRTC tests ToDetect’s [DNS Leak Test](https://www.todetect.net/dns-leak/) describes a leak as DNS requests that bypass the VPN and go through your local ISP’s DNS server. Its [WebRTC Leak Test](https://www.todetect.net/webrtc/) explains that WebRTC communicates with STUN servers, which can potentially expose your actual local or public IP address even when using a VPN or proxy. ### 4. Match the time zone and read the overview Use [Timezone Detection](https://www.todetect.net/timezone/) to compare the IP-based zone with the browser’s, then review the Browser Fingerprint Consistency score on the [homepage](https://www.todetect.net/). Rerun each check after changing the proxy or browser settings. Prepared by ipvolt from ToDetect’s official website and tool pages, checked 23 October 2026. This is a source-based partner profile of ToDetect’s published tools. [All partners](https://ipvolt.com/partners) --- Document 24 of 138: CaptchaAI URL: https://ipvolt.com/partners/captchaai Markdown: https://ipvolt.com/partners/captchaai.md # CaptchaAI Source: https://ipvolt.com/partners/captchaai Markdown: https://ipvolt.com/partners/captchaai.md ipvolt partner ![CaptchaAI](https://ipvolt.com/partners/captchaai.png) CAPTCHA-solving API with thread-based plans [CaptchaAI](https://captchaai.com/) is an AI CAPTCHA-solving service. Its [documentation](https://docs.captchaai.com/) describes an API for connecting it to your own software, and it also offers a Chrome extension and an Emulator app. Plans are priced by threads rather than by the number of solves: CaptchaAI defines a thread as one simultaneous solve and lists unlimited solves within your thread count. Partner website ## The ipvolt partner offer CaptchaAI has set up an offer page for ipvolt users and describes it as up to 15% off. Checked on 4 November 2026, that page lists the Standard to Enterprise monthly plans below their standard prices, for example Standard at $27 instead of $30 and Enterprise at $250 instead of $300. Basic stays at $15 a month, and 6-month and annual prices match CaptchaAI’s standard pricing. Confirm the price at checkout. ipvolt may earn a commission if you buy through this link. [Visit CaptchaAI](https://captchaai.com/captchaai-ipvolt-special-offer.RO2GPQQYWIAF0QUG) ## Match the option to your workload | What you need | CaptchaAI option | What to check | | --- | --- | --- | | Solve CAPTCHAs from your own software | [API](https://docs.captchaai.com/guides/quickstart/) | You submit a task with your API key, then poll for the result. Follow the guide for the CAPTCHA type you need. | | Keep software built for another solver | [Emulator app](https://captchaai.com/) | CaptchaAI says the Emulator works where 2Captcha is available in your software’s options; you add your CaptchaAI API key in its place. | | Cover a specific CAPTCHA type | [Supported types](https://docs.captchaai.com/captcha-types/) | The list includes reCAPTCHA, Cloudflare Turnstile, GeeTest v3, BLS and image CAPTCHAs. The [homepage](https://captchaai.com/) marks CaptchaFox, Friendly Captcha and Lemin as beta. | | Size a plan for peak traffic | [Thread-based plans](https://captchaai.com/#pricing-plans) | Standard monthly prices run from Basic at $15 for 5 threads to Enterprise at $300 for 200 threads, with VIP plans up to 5,000 threads. Requests above your thread count are rejected until a slot frees up. | | Try it before paying | [Free trial](https://captchaai.com/) | CaptchaAI says every new account gets a free trial, and that you open a support ticket to have trial threads activated. | Prices and thread counts were checked on 4 November 2026. The ipvolt offer page also lists more threads on its top three monthly plans: 110, 170 and 250, compared with 100, 150 and 200. ## Before connecting CaptchaAI ### Confirm you are allowed to automate CaptchaAI’s [terms](https://captchaai.com/tos) limit use to authorized and legal purposes and prohibit spam, illegal access to services and brute-forcing. A CAPTCHA is often how a site limits automated access, so check that site’s terms and only automate sites and flows you own or have permission to use. If that work runs through ipvolt, our acceptable use policy applies too. ### Test your own CAPTCHA types first Use trial threads to check your integration and the CAPTCHA types you rely on. Speed and success rates on CaptchaAI’s site are its own published figures; ipvolt has not tested them. ### Check what a proxy shares CaptchaAI’s [proxy guide](https://docs.captchaai.com/guides/proxy/) says proxy use is disabled by default and support must enable it for your account. Passing a proxy with a login gives CaptchaAI those credentials, so check that your proxy provider’s terms allow it and use credentials you can rotate. Prepared by ipvolt from CaptchaAI’s official website, documentation and terms, checked 4 November 2026. This is a source-based partner profile; ipvolt has not independently tested the service. [All partners](https://ipvolt.com/partners) --- Document 25 of 138: ZovoCard URL: https://ipvolt.com/partners/zovocard Markdown: https://ipvolt.com/partners/zovocard.md # ZovoCard Source: https://ipvolt.com/partners/zovocard Markdown: https://ipvolt.com/partners/zovocard.md ipvolt partner ![ZovoCard](https://ipvolt.com/partners/zovocard.png) Crypto-funded USD virtual cards for AI tools and software [ZovoCard](https://zovocard.com/) offers USD virtual cards for paying for AI tools and overseas software subscriptions such as ChatGPT, Claude and Midjourney. You fund a platform wallet with crypto, then open cards and move money onto them. Its [terms](https://zovocard.com/legal?doc=terms) allow crypto funding only, such as USDT on TRC20 or BSC, and no fiat. Its homepage also describes an open API for issuing, funding, refunds and reconciliation. Partner website ## Visit ZovoCard ZovoCard supplied this signup link for its listing here. It carries invite code 12321, and ZovoCard’s signup page says both sides can get an invite reward when a code is entered. ipvolt and ZovoCard list each other as a link exchange. ZovoCard’s contact supplied the code; ipvolt does not hold it, earns nothing from signups through it and has not confirmed what the reward is. [Visit ZovoCard](https://zovocard.com/register?invite=12321) ## Match the option to the payment | What you need | ZovoCard option | What to check | | --- | --- | --- | | Pay for AI tools and software subscriptions | [Card catalog](https://help.zovocard.com/en/help/open-card/) | Review the BIN, currency, restrictions, opening fee and minimum funding for each product. Some products require you to explain the intended use and wait for approval. | | See how cards perform at a merchant | [BIN pass-rate lookup](https://zovocard.com/bin-pass-rate) | Shows ZovoCard’s own 90-day aggregated results by merchant. Its [decline guide](https://help.zovocard.com/en/help/declines/) says sufficient balance does not guarantee approval and that retries can add holds, fees or risk controls. | | Connect cards to your own system | [Open API](https://help.zovocard.com/en/help/api/) | The guide covers API keys, IP and funding limits, and idempotency keys. Exact routes and error codes are in ZovoCard’s current developer documentation. | | Keep card money separate | [Wallet and card balances](https://help.zovocard.com/en/help/card-funding/) | Your platform wallet and each card’s available balance are separate. Review the principal, fee and total wallet debit before funding a card. | Fees and limits are shown in your account and can change. ZovoCard’s homepage also publishes its own figures for cards issued and success rates; ipvolt has not verified them. ## Before opening a card ### Check that you may use it where you are ZovoCard’s [terms](https://zovocard.com/legal?doc=terms) bar people living or located in mainland China and anyone subject to OFAC, UN or EU sanctions. They also forbid using a VPN, proxy or changed location to get around those limits, so do not use a proxy for that. ### Read the banned uses The terms limit cards to legal online spending under Visa and Mastercard rules and ban fraud, money laundering, card testing, bulk card binding and multiple accounts. Payments linked to Alipay, WeChat, OnlyFans and similar platforms can mean a closed account, deleted cards and no refund. ### Check the cost and start small Opening, funding, decline and refund fees are shown on the page and are not refundable once charged. Balances cannot be returned as fiat, crypto sent to the wrong address or network is not recoverable, and the legal pages do not name a company behind the service, so fund only what you plan to spend. Prepared by ipvolt from ZovoCard’s official website, help center and terms, checked 5 November 2026. This is a source-based partner profile; ipvolt has not independently tested the service. [All partners](https://ipvolt.com/partners) --- Document 26 of 138: aliencpa URL: https://ipvolt.com/partners/aliencpa Markdown: https://ipvolt.com/partners/aliencpa.md # aliencpa Source: https://ipvolt.com/partners/aliencpa Markdown: https://ipvolt.com/partners/aliencpa.md ipvolt partner ![aliencpa](https://ipvolt.com/partners/aliencpa.png) Independent magazine on affiliate marketing and paid traffic [aliencpa](https://aliencpa.com/about) is an independent English-language magazine about affiliate marketing and paid traffic. It publishes guides to traffic sources, fact-checked case studies and reviews of affiliate networks and tools, and keeps open catalogs of companies, agencies, people and conferences. Its about page says authors with hands-on media buying experience write with the editor, who approves every text before it goes live. Partner website ## Visit aliencpa aliencpa supplied this link for its listing here. It carries UTM tags so aliencpa can see that the visit came from this page. ipvolt lists aliencpa at its request and has asked to be listed in its tools catalog. ipvolt earns nothing from visits through this link. [Visit aliencpa](https://aliencpa.com/?utm_source=ipvolt&utm_medium=partner_page&utm_campaign=ipvolt-partners) ## Find the right section | What you need | aliencpa section | What to check | | --- | --- | --- | | Learn the basics or a traffic source in order | [Guide paths](https://aliencpa.com/guides) | Each path is a reading order, starting with what affiliate marketing is and how the money moves. | | Check a published success story | [Case studies](https://aliencpa.com/case-studies) | Its media kit says editors recalculate the numbers behind published cases and give each a verdict out of 5. | | Compare networks and tools | [Tools catalog](https://aliencpa.com/tools) | The catalog has no rankings: the order follows your sort, and paid placements are marked Sponsored. Its labels include Recommended, Caution: scam and Closed. | | Find an industry event | [Conference calendar](https://aliencpa.com/conferences) | Filter by topic, region, format and country, then confirm dates and ticket prices with the organizer. | aliencpa publishes these sections itself; ipvolt has not verified its reviews, ratings or figures. ## Before relying on it ### Look for the paid labels Its [editorial policy](https://aliencpa.com/editorial-policy) says paid articles, reviews and pinned placements are labelled Sponsored and banners are labelled Ad, and that a rating or a place in a top list cannot be bought. ### Know how its links earn money Its [affiliate disclosure](https://aliencpa.com/affiliate-disclosure) says some links go through addresses starting with /go/, and that a company may pay aliencpa a commission if you sign up or buy through them. ### Know how the texts are written The editorial policy says drafts are written with AI assistance from the editor’s notes, and that the editor confirms the facts and approves the final version. Prepared by ipvolt from aliencpa’s official website and media kit, checked 6 November 2026. This is a source-based partner profile; ipvolt has not independently tested the service. [All partners](https://ipvolt.com/partners) --- Document 27 of 138: ZLogin URL: https://ipvolt.com/partners/zlogin Markdown: https://ipvolt.com/partners/zlogin.md # ZLogin Source: https://ipvolt.com/partners/zlogin Markdown: https://ipvolt.com/partners/zlogin.md ipvolt partner ![ZLogin](https://ipvolt.com/partners/zlogin.png) Browser profiles with their own proxy, time zone and language [ZLogin](https://www.zlogin.com/) describes itself as an antidetect browser for managing multiple accounts on a single device. According to its [multi-account page](https://www.zlogin.com/function/multi-account-management/), each browser profile can be configured with its own fingerprint, proxy, cookies, time zone and language. Its [company page](https://www.zlogin.com/company/) names NORTHVALE SYSTEMS PTE. LTD. in Singapore as the developer and operator. Partner website ## Explore ZLogin Visit ZLogin for current downloads, plans and support. The steps here summarize its public pages; confirm the settings for your own proxy provider before connecting. ipvolt and ZLogin list each other as a link exchange. ipvolt earns nothing from visits or signups through this link. [Visit ZLogin](https://www.zlogin.com/?utm_source=ipvolt) ## Match the browser and connection requirements | Requirement | Where it comes from | What to check | | --- | --- | --- | | Run the desktop application | [Windows, macOS or Linux](https://www.zlogin.com/download/) | The download page recommends Windows 10 or 11, macOS 13 (Ventura) or later, or Ubuntu Desktop 22.04 LTS or later, with at least 4 processor cores, 8 GB of RAM and 10 GB of free SSD space. For several profiles running at once it recommends at least 16 GB of RAM. | | Separate browser workspaces | [ZLogin browser profiles](https://www.zlogin.com/function/multi-account-management/) | Each profile keeps its own fingerprint, cookies, time zone and language, and can simulate a Windows, macOS, Linux, Android or iOS environment. The [pricing page](https://www.zlogin.com/pricing/) lists a free plan with two profiles and paid plans for more. | | Route a profile through a proxy | Your proxy provider | The provider supplies the address, port and any username and password. ZLogin’s [pricing page](https://www.zlogin.com/pricing/) lists HTTP, HTTPS and SOCKS5 among the proxy formats it accepts. Its homepage also offers new users free residential IPs or bonus proxy traffic after downloading the client. | For teams, the [teamwork page](https://www.zlogin.com/function/teamwork/) describes role-based permissions, two-factor authentication and activity logs that include proxy usage. Administrators grant access to profiles by group or by individual profile. ## Proxy setup and checks ### 1. Install the client Download the client for your system from the [download page](https://www.zlogin.com/download/), install it and sign up for an account. ### 2. Create the profile and add the proxy ZLogin’s getting-started steps are to create a browser profile and configure its fingerprint and proxy settings. Choose the format your provider uses and enter its address, port and login details. ### 3. Match time zone and language The [homepage](https://www.zlogin.com/) says ZLogin syncs a profile’s time zone and language with the location of its proxy IP. After connecting, confirm they match the location your provider states. ### 4. Verify inside the opened profile Launch the profile and open ZLogin’s [browser check](https://www.zlogin.com/check/), which shows the IP address, ISP, WebRTC, time zone and language a website can see. An IP check does not establish destination-site acceptance or account safety. Prepared by ipvolt from ZLogin’s official website, checked 8 November 2026. ipvolt has not installed or tested ZLogin or a live proxy integration. [All partners](https://ipvolt.com/partners) --- Document 28 of 138: VPSRated URL: https://ipvolt.com/partners/vpsrated Markdown: https://ipvolt.com/partners/vpsrated.md # VPSRated Source: https://ipvolt.com/partners/vpsrated Markdown: https://ipvolt.com/partners/vpsrated.md ipvolt partner ![VPSRated](https://ipvolt.com/partners/vpsrated.png) Comparison site for hosting, VPN and proxy providers [VPSRated](https://www.vpsrated.com/about) describes itself as an independent platform that reviews and compares hosting services. It covers VPS, VDS, Windows RDP, dedicated server, GPU cloud, VPN and proxy providers. Each category has its own directory, and the site adds a side-by-side plan comparison, a page of coupons and deals, and a blog of guides and reviews. Partner website ## Visit VPSRated Visit VPSRated for its provider directories, plan comparison and current deals. The link carries a UTM tag so VPSRated can see that the visit came from this page. ipvolt’s listing on VPSRated is a paid placement, and ipvolt lists VPSRated here. ipvolt earns nothing from visits through this link. [Visit VPSRated](https://www.vpsrated.com/?utm_source=ipvolt) ## Find the right section | What you need | VPSRated section | What to check | | --- | --- | --- | | Compare proxy providers | [Proxy providers](https://www.vpsrated.com/proxy) | Filter by proxy type: rotating residential, static ISP, dedicated datacenter or mobile 4G/5G. Sort by starting price, customer rating or IP pool size. | | Shortlist a VPS or cloud server | [Plan comparison](https://www.vpsrated.com/compare) | Puts up to four plans side by side, with monthly price, price per GB of RAM, billing cycle, refund terms and CPU. | | Find a server near your users | [Providers by country](https://www.vpsrated.com/countries) | Lists the countries where its reviewed providers run datacenters, with the number of providers and plans for each. | | Look for a discount | [Coupons and deals](https://www.vpsrated.com/coupons) | Filter by provider or hosting category. Confirm that a code still applies at the provider’s checkout before you pay. | VPSRated publishes these rankings, ratings and benchmark figures itself; ipvolt has not verified them. ## Before relying on it ### Know which placements are paid Its [provider submission page](https://www.vpsrated.com/submit-provider) says all provider additions, blog link placements and category spotlights are paid sponsored packages. Its [terms](https://www.vpsrated.com/terms) say sponsored placements are marked Sponsored on the card and in the listing. ### Know how its links earn money The terms say some outbound links are affiliate links, and that VPSRated may earn a commission if you buy through one. ### Confirm details with the provider The terms say pricing, specifications and availability change frequently, and that VPSRated does not warrant that its information is complete, current or accurate. Check the final details on the provider’s own site before buying. Prepared by ipvolt from VPSRated’s official website, checked 10 November 2026. This is a source-based partner profile; ipvolt has not verified VPSRated’s reviews, ratings or benchmarks. [All partners](https://ipvolt.com/partners) --- Document 29 of 138: HotLogin URL: https://ipvolt.com/partners/hotlogin Markdown: https://ipvolt.com/partners/hotlogin.md # HotLogin Source: https://ipvolt.com/partners/hotlogin Markdown: https://ipvolt.com/partners/hotlogin.md ipvolt partner ![HotLogin](https://ipvolt.com/partners/hotlogin.png) Windows and macOS browser profiles with per-profile proxy settings [HotLogin](https://www.hotlogin.com/en/) describes itself as an anti-detect fingerprint browser for multi-account management. Its Chinese site uses the name 火云浏览器 (Huoyun Browser), and its [About page](https://www.hotlogin.com/en/aboutUs/) names Nanjing Wuling Network Technology Co., Ltd., headquartered in Nanjing, as the company behind it. The [help center](https://www.hotlogin.com/en/helpCenter/) is written in Chinese. Its [add-proxy guide](https://www.hotlogin.com/en/helpCenter/detail/2046574753203879938/) says to confirm proxy details with your proxy provider. Partner website ## Explore HotLogin Visit HotLogin for current downloads, plans and support. The steps here summarize its public pages and its Chinese-language help center; confirm the settings for your own proxy provider before connecting. ipvolt and HotLogin have agreed to list each other. ipvolt earns nothing from visits or signups through this link. [Visit HotLogin](https://www.hotlogin.com/en/?utm_source=ipvolt) ## Match the browser and connection requirements | Requirement | Where it comes from | What to check | | --- | --- | --- | | Run the desktop application | [Windows or macOS](https://www.hotlogin.com/en/downLoadCenter/) | The download page offers builds for Windows (64-bit), macOS (Apple Silicon) and macOS (Intel); Linux is not listed. The [Chinese download page](https://www.hotlogin.com/downLoadCenter/) states the requirements: Windows 7 or later with a 4-core CPU, 8 GB of memory and at least 50 GB of disk space, or macOS 10.15 (Catalina) or later. | | Separate browser workspaces | [HotLogin browser environments](https://www.hotlogin.com/en/helpCenter/detail/2046540014271070209/) | HotLogin calls a profile a browser environment. Its [plan FAQ](https://www.hotlogin.com/en/helpCenter/detail/2046494802299629569/) describes each one as an independent browser configuration with its own fingerprint, such as IP, geolocation, cookies, WebGL, WebGPU and Canvas. The creation guide lists a Chrome kernel and Windows or macOS as the operating system a profile presents. The [pricing page](https://www.hotlogin.com/en/productPricing/) lists a free plan with 10 profiles and one team member, and paid subscriptions for more. | | Route a profile through a proxy | [Your proxy provider](https://www.hotlogin.com/en/helpCenter/detail/2046574753203879938/) | The provider supplies the host, port and any account name and password. HotLogin’s add-proxy guide lists three proxy types: HTTP, HTTPS and SOCKS5. From version 2.5.1 the host field also accepts a pasted ip:port:account:passwd line and fills in the four fields. | For teams, the [roles guide](https://www.hotlogin.com/en/helpCenter/detail/2046490201139752963/) describes super administrator, administrator, manager and member roles. Groups of profiles can be [authorized to chosen members](https://www.hotlogin.com/en/helpCenter/detail/2046574745813516289/), and administrators can view a [log of the IP changes](https://www.hotlogin.com/en/helpCenter/detail/2046574696727576578/) recorded when members launch profiles. ## Proxy setup and checks ### 1. Install the client Download the build for your system from the [download page](https://www.hotlogin.com/en/downLoadCenter/). On a Mac, the [install guide](https://www.hotlogin.com/en/helpCenter/detail/2046540065395441666/) says to check About This Mac for the chip type and choose the Intel or Apple build to match. Start the client and sign in; the [registration guide](https://www.hotlogin.com/en/helpCenter/detail/2046540065399635970/) covers sign-up by email, phone number or Google. ### 2. Create the profile and add the proxy In the [profile creation guide](https://www.hotlogin.com/en/helpCenter/detail/2046540014271070209/), the proxy section defaults to direct mode, which uses your device’s own network. Choose HTTP, HTTPS or SOCKS5 to match your provider, then enter the host and port, plus the proxy account and password if your provider issues them. Before saving, run the proxy check: the guide says it tests whether the proxy works through the IP lookup channel you select, IP2Location or ip-api. ### 3. Match time zone and language In the advanced settings of the same form, time zone and language can each be matched to the profile’s IP or set by hand, and geolocation can follow the IP too. WebRTC has four modes: forward, replace, real and disabled. After connecting, confirm the values match the location your provider states. ### 4. Verify inside the opened profile In the profile list, select the profile and use the [check-proxy button](https://www.hotlogin.com/en/helpCenter/detail/2046540020717715459/) to see the connection test result. HotLogin’s [first-use guide](https://www.hotlogin.com/en/helpCenter/detail/2108842611933556737/) says to pass the connection test before opening the target page, and its [troubleshooting guide](https://www.hotlogin.com/en/helpCenter/detail/2088185433266626561/) suggests loading a simple public page first. An IP check does not establish destination-site acceptance or account safety. Prepared by ipvolt from HotLogin’s official website, checked 10 November 2026. ipvolt has not installed or tested HotLogin or a live proxy integration. [All partners](https://ipvolt.com/partners) --- Document 30 of 138: MBbrowser URL: https://ipvolt.com/partners/mbbrowser Markdown: https://ipvolt.com/partners/mbbrowser.md # MBbrowser Source: https://ipvolt.com/partners/mbbrowser Markdown: https://ipvolt.com/partners/mbbrowser.md ipvolt partner ![MBbrowser](https://ipvolt.com/partners/mbbrowser.png) Windows browser environments with their own proxy, time zone and language [MBbrowser](https://www.mbbrowser.com/en/) describes itself as a multi-login antidetect fingerprint browser. Its [help centre](https://help.mbbrowser.com/en/) says it provides an independent browser environment for each account, and its tutorials call a browser profile an environment or a session. The website footer states that the system does not provide proxy IP services, so the connection details for each environment come from your chosen proxy provider. Its [terms of service](https://www.mbbrowser.com/en/terms/) are governed by the laws of the People’s Republic of China. Partner website ## Explore MBbrowser Visit MBbrowser for current downloads, plans and support. The steps here summarize its website and help centre; confirm the settings for your own proxy provider before connecting. ipvolt and MBbrowser have agreed to exchange links. ipvolt earns nothing from visits or signups through this link. [Visit MBbrowser](https://www.mbbrowser.com/en/?utm_source=ipvolt) ## Match the browser and connection requirements | Requirement | Where it comes from | What to check | | --- | --- | --- | | Run the desktop application | [Windows](https://www.mbbrowser.com/en/download/) | The download page says MBbrowser supports Windows 7 and above, 32-bit and 64-bit. It lists builds for Windows 10 and 11, and builds with older browser cores for Windows 7, 8, 10 and 11. The page lists no macOS or Linux build. The [FAQ](https://help.mbbrowser.com/en/faq/faq1.html) recommends a 4-core processor and at least 8 GB of memory. | | Separate browser workspaces | [MBbrowser environments](https://help.mbbrowser.com/en/) | The help centre describes an independent browser environment for each account. The [price page](https://www.mbbrowser.com/en/price/) lists a Free Edition with 2 browser environments, a Basic Package at $19 per month with 10, a Personal Unlimited Edition at $79 per month with 500 and a Team Collaboration Version at $129 per month for 3 users. | | Route a profile through a proxy | Your proxy provider | The provider supplies the address, port and any username and password. MBbrowser’s [API reference](https://www.mbbrowser.com/en/api/session/) lists HTTP, HTTPS, SOCKS4, SOCKS4A, SOCKS5 and SSH among its proxy types. Its FAQ says it supports IPv4 proxy types and excludes IPv6 addresses. | MBbrowser also has a global Upstream Proxy setting called MBBridge. Its [upstream proxy guide](https://help.mbbrowser.com/en/tutorial/upstream_proxy.html) says not to enter proxies bought from a proxy provider there. Those go in each environment’s own proxy settings. For teams, the [sub-account guide](https://help.mbbrowser.com/en/tutorial/add_a_subaccount.html) covers adding sub-accounts on the Team Collaboration Version. ## Proxy setup and checks ### 1. Install the client Download the Windows installer from the [download page](https://www.mbbrowser.com/en/download/) and run it. MBbrowser’s [purchase guide](https://help.mbbrowser.com/en/tutorial/purchase_plan.html) covers registering with an email address, activating the account from the activation email and choosing a package in the console. ### 2. Create the environment and add the proxy MBbrowser’s proxy configuration guide opens the environment configuration window from a new environment, or by right-clicking an existing one on the main panel. There, select the proxy type your provider uses, enter its details and click Test Proxy to check it. The [FAQ](https://help.mbbrowser.com/en/faq/faq1.html) says the proxy username and password are needed only if your proxy has them. To load many proxies, the [bulk import guide](https://help.mbbrowser.com/en/tutorial/fixed_ip_bulk_import.html) uses a TXT file and gives the format by example: Socks5, then the address, port, username and password, separated by colons. ### 3. Match time zone and language MBbrowser’s [time zone page](https://help.mbbrowser.com/en/basic_knowledge/time_zone.html) says the client can match an environment’s time zone to the proxy IP address automatically, or you can select one manually. Its [language page](https://help.mbbrowser.com/en/basic_knowledge/language.html) says the language is matched to the proxy IP when an environment is created. With a short-lived dynamic IP, the FAQ says the time zone stays as first matched, and the [WebRTC page](https://help.mbbrowser.com/en/basic_knowledge/webrtc.html) recommends disabling the WebRTC feature for dynamic proxy IPs. ### 4. Verify inside the opened environment Open the saved environment and use an IP-check page to inspect its outgoing address, time zone and language. If the proxy test passed but pages do not open, the [FAQ](https://help.mbbrowser.com/en/faq/faq1.html) suggests creating a new environment with the same proxy and opening a page there to compare. An IP check does not establish destination-site acceptance or account safety. Prepared by ipvolt from MBbrowser’s official website and help centre, checked 10 November 2026. ipvolt has not installed or tested MBbrowser or a live proxy integration. [All partners](https://ipvolt.com/partners) --- Document 31 of 138: Hidemium URL: https://ipvolt.com/partners/hidemium Markdown: https://ipvolt.com/partners/hidemium.md # Hidemium Source: https://ipvolt.com/partners/hidemium Markdown: https://ipvolt.com/partners/hidemium.md ipvolt partner ![Hidemium](https://ipvolt.com/partners/hidemium.png) Windows and macOS browser profiles with per-profile proxy settings [Hidemium](https://hidemium.io/) describes itself as an antidetect browser for multi-accounting. Its website footer says Hidemium is a product of Hachitech. The [documentation](https://docs.hidemium.io/) describes profiles that are separate in browser fingerprint, including IP address, user agent, proxy, cookies, time zone and language. Hidemium also markets its own proxy product and lists third-party proxy providers on its site; a profile accepts the connection details of whichever provider you choose. Partner website ## Explore Hidemium Visit Hidemium for current downloads, plans and support. The steps here summarize its website and documentation; confirm the settings for your own proxy provider before connecting. ipvolt and Hidemium have agreed to list each other. ipvolt earns nothing from visits or signups through this link. [Visit Hidemium](https://hidemium.io/?utm_source=ipvolt) ## Match the browser and connection requirements | Requirement | Where it comes from | What to check | | --- | --- | --- | | Run the desktop application | [Windows or macOS](https://hidemium.io/download/) | The download page offers Hidemium for Windows and for macOS, both at version 5.0.0 when checked, and links to release notes with older versions. It lists no Linux build of the application. | | Separate browser workspaces | [Hidemium profiles](https://docs.hidemium.io/features-of-hidemium/new-profile/main) | The new-profile guide lists the platform a profile presents (Windows, Mac OS, Linux or Android), its platform version, Chrome version and user agent. The [pricing page](https://hidemium.io/pricing/) lists a free plan with 5 profiles on 1 device and paid plans from Basic with 30 profiles to Business with 13,000; Premium lists 10 team members and Business 20. It says the prices shown are for reference and the app shows the most accurate ones. | | Route a profile through a proxy | [Your proxy provider](https://docs.hidemium.io/features-of-hidemium/new-profile/proxies) | The provider supplies the host, port and any username and password. Hidemium’s proxy page lists four connection types: HTTP proxy, Socks 4 proxy, Socks 5 and SSH. | To change the proxy on many profiles at once, the [Change Proxy page](https://docs.hidemium.io/features-of-hidemium/profiles/change-proxy) describes selecting the profiles and choosing the proxy option in the menu that appears; that page is written in Vietnamese. Hidemium’s homepage also describes a local API on 127.0.0.1, and its documentation has [API calls for updating a profile’s proxy](https://docs.hidemium.io/use-cases/api-automation-v2/proxy). ## Proxy setup and checks ### 1. Install the client Download the Windows or macOS build from the [download page](https://hidemium.io/download/) and sign in. The page says new users get 1,000 profiles on first launch; the [pricing page](https://hidemium.io/pricing/) lists the limits of each plan after that. ### 2. Create the profile and add the proxy In the [new-profile form](https://docs.hidemium.io/features-of-hidemium/new-profile/main), set the name, folder, platform and Chrome version. On the [proxies tab](https://docs.hidemium.io/features-of-hidemium/new-profile/proxies), choose the connection type your provider uses (HTTP, Socks 4, Socks 5 or SSH) and enter its details. The guide says the Edit Proxy Setting button shows the proxy’s details, including location, country and time zone. ### 3. Match time zone, location and WebRTC The same guide says time zone, WebRTC, geolocation and languages can each be based on the external IP or set manually, and recommends leaving time zone on the external IP. WebRTC has three modes: Alter, which follows the proxy address, Disabled and Real. Geolocation can be set to Prompt, Allow or Block. After connecting, confirm the values match the location your provider states. ### 4. Verify inside the opened profile Start the profile from the [Profiles list](https://docs.hidemium.io/features-of-hidemium/profiles) and open an IP-check page to inspect its outgoing address, time zone and language. Hidemium has a [free IP and fingerprint checker](https://hidemium.io/free-tools/) that shows the IP, location and WebRTC exposure a website can see. An IP check does not establish destination-site acceptance or account safety. Prepared by ipvolt from Hidemium’s official website and documentation, checked 11 November 2026. ipvolt has not installed or tested Hidemium or a live proxy integration. [All partners](https://ipvolt.com/partners) --- Document 32 of 138: Ovobrowser URL: https://ipvolt.com/partners/ovobrowser Markdown: https://ipvolt.com/partners/ovobrowser.md # Ovobrowser Source: https://ipvolt.com/partners/ovobrowser Markdown: https://ipvolt.com/partners/ovobrowser.md ipvolt partner ![Ovobrowser](https://ipvolt.com/partners/ovobrowser.png) Windows and macOS browser profiles with a saved, testable proxy list [Ovobrowser](https://ovobrowser.com/) describes itself as a full-featured antidetect browser whose core features stay free for people and teams. Its [help center](https://ovobrowser.com/help) names HONG KONG SONGYUN TECHNOLOGY CO., LIMITED in the page footer. Its [proxy management page](https://ovobrowser.com/features/proxy-management) says the feature manages the proxies you configure and can show third-party provider recommendations, and that proxy services remain the responsibility of their providers. Partner website ## Explore Ovobrowser Visit Ovobrowser for current downloads and support. The steps here summarize its website and help center; confirm the settings for your own proxy provider before connecting. ipvolt and Ovobrowser have agreed to exchange links. ipvolt earns nothing from visits or signups through this link. [Visit Ovobrowser](https://ovobrowser.com/?utm_source=ipvolt) ## Match the browser and connection requirements | Requirement | Where it comes from | What to check | | --- | --- | --- | | Run the desktop application | [Windows or macOS](https://ovobrowser.com/) | The download dialog on the website offers a Windows 64-bit build and a macOS build for Apple Silicon (arm64); it lists no Linux build. The [installation guide](https://ovobrowser.com/help/install-ovobrowser) is written for Windows and asks for an email address that can receive a verification code. | | Separate browser workspaces | [Ovobrowser profiles](https://ovobrowser.com/help/create-first-profile) | The beginner’s guide describes a profile as an independent set of browser configurations, including operating system, kernel, user agent, time zone, language, hardware parameters, proxy and cookies. It says groups organize profiles and do not change their proxies or fingerprints. The website says core features stay free for people and teams. | | Route a profile through a proxy | [Your proxy provider](https://ovobrowser.com/help/proxy-protocol-setup-guide) | The provider supplies the protocol, host, port and either a username and password or IP whitelisting rules. Ovobrowser’s setup guide supports HTTP, HTTPS and SOCKS5, takes a domain name or IPv4 address as the host, and says to use the protocol the provider specifies instead of guessing it from the port number. | For teams, the [team management guide](https://ovobrowser.com/help/team-management-guide) covers member seats, a profile limit per member and roles with fine-grained permissions; member data is isolated by ownership by default, and the team owner can view and manage all of it. The proxy management page says saved proxy passwords are encrypted in storage. ## Proxy setup and checks ### 1. Install the client Download the build for your system from the [Ovobrowser website](https://ovobrowser.com/) and run the installer. The [installation guide](https://ovobrowser.com/help/install-ovobrowser) covers registering with an email address and a 6-digit verification code, or signing in with a third-party account such as Google. ### 2. Add and test the proxy The [setup guide](https://ovobrowser.com/help/proxy-protocol-setup-guide) adds a proxy under Proxy Management: click New, name the proxy, select HTTP, HTTPS or SOCKS5, then enter the host, port and any username and password. You can also paste a full proxy line, such as host:port:username:password or a URL with a protocol prefix, into the Host field and it is split into the fields; without a prefix it defaults to HTTP, so check the protocol afterwards. Click Test and check the exit IP and region before saving. ### 3. Create the profile and assign the proxy The [beginner’s guide](https://ovobrowser.com/help/create-first-profile) recommends this order: create groups, add and test proxies, create a profile and select its group and proxy, then start the profile and verify the exit IP. It says that if the test result does not match the region you bought, do not continue to use the proxy, and to confirm the proxy settings, whitelist and local network before contacting the provider. ### 4. Verify and troubleshoot Start the profile and open an IP-check page to confirm the outgoing address and region. If the proxy test fails, the [troubleshooting guide](https://ovobrowser.com/help/proxy-detection-errors) says to confirm the protocol, host, port, authentication method and expiry with the provider, then compare the local network and system proxy checks under Settings. An IP check does not establish destination-site acceptance or account safety. Prepared by ipvolt from Ovobrowser’s official website and help center, checked 11 November 2026. ipvolt has not installed or tested Ovobrowser or a live proxy integration. [All partners](https://ipvolt.com/partners) --- Document 33 of 138: Privacy and analytics. URL: https://ipvolt.com/privacy Markdown: https://ipvolt.com/privacy.md # Privacy and analytics. Source: https://ipvolt.com/privacy Markdown: https://ipvolt.com/privacy.md Your information You can read our guides without accepting optional analytics. Updated: 11 November 2026 (2026-11-11) **Who we are.** ipvolt is operated by the individual or individuals who run ipvolt, who are the controller of the personal data described on this page. ipvolt is not yet a registered company; we will give you their names and postal address on request. Contact: [hello@ipvolt.com](mailto:hello@ipvolt.com). ## Customer accounts, payments and proxy services This section covers the customer service at ipvolt.com/dashboard. **Your account.** We store a username, the email address and wallet addresses you sign in with and when each was added and last used, your account role and settings, a label we use to identify your account internally, the version of the terms you accepted at sign-up and when, a log of changes to your account (such as sign-up, added or removed sign-in methods and password changes, without the values themselves), and records of API keys you create (a hash of each key, its name, a short display prefix, its expiry and last use, never the full key). We also keep a log of the requests your dashboard, your API keys and the agents you connect make to our API: when each was made, which part of the API it called (with identifiers removed), the result and how long it took, and which key or agent made it. It never includes the websites you visit through your proxies. You can see it on the dashboard's Usage page, and we delete each entry after 90 days. On an account created with an email address, the label is that address; on one created with a wallet, it is the network and a shortened form of the address. It stays if you later remove that sign-in method. When you create an account, we also record which ipvolt.com page you came to the dashboard from (only its path, such as /pricing), or the name of another website that linked you straight to it, when your browser tells us; we use this to understand which pages help people sign up. Accounts we create by invitation also have a securely hashed password. We do not need your name or postal address to run your account. If you email us, we keep that correspondence. **Orders without an account.** You can buy a mobile proxy without creating an account. For such an order we store no wallet address or password, and an email address only if you choose to give one. We keep a one-way hash of the order's invoice ID, which we cannot turn back into the ID, the first eight characters of the ID as an order reference, the version of the terms you accepted and when, a log of when the order was created and opened, and the same payment, order and device records as for any customer. If you enter an email address at checkout, we send the invoice ID to it and keep the address with the order, so that we can reach you about the order and check a request for help with it. It is never a way to sign in. The message passes through our email provider like our other emails. Opening the order with its invoice ID starts the same session cookie as signing in. To limit abuse we keep keyed hashes of the connection address used to create or open orders, and delete them after one day. **Signing in.** An essential session cookie keeps you signed in. It lasts at most 8 hours and ends after 1 hour of inactivity. To send a sign-in code we keep your email address with a keyed hash of the code, and to check a wallet signature we keep the wallet address and the message you sign. We delete these after about a day. To stop password guessing and abuse of codes and sign-ups, we keep keyed hashes of the connection address and the username or email address used to sign in, and delete them after one day. The dashboard sets no analytics or advertising cookies of its own; see "Optional Google Analytics" for what happens if you accepted analytics on our website. Alert preferences you choose, and which wallet you last signed in with, stay in your browser. **Payments.** When you top up through NOWPayments, we record the amount, NOWPayments' invoice and payment references and status, what it reports about each payment (the coin and network, the amounts sent and received, and the transaction ID), how it was credited, and any review decision. For a top-up made through OxaPay before 7 November 2026, we keep OxaPay's reference and status, the transactions it reported (transaction ID, coin, network and amount), how it was credited, and any review decision. For a crypto transfer invoice, we record the invoice (amount, coin, network, rate and payment address), the blockchain transactions that pay it (transaction ID, block and amount, plus the sending address on Ethereum-compatible networks, Solana and Tron), how it was credited, and any review or refund decision. Blockchain transactions are public and permanent: we cannot change or erase what a blockchain records. To read blockchains and prices, our servers query blockchain data providers and Coinbase's public price service. Those requests contain public addresses and transaction data, not your account details. **Balance and orders.** We keep a ledger of your balance, the services you order, renewals and refunds. Our infrastructure partner, which supplies the mobile devices, receives only internal reference numbers for your orders, not your username or contact details. For residential proxies, we send our residential supplier a coded label for your key, internal reference numbers for your orders and the key's traffic total, not your username or contact details, and we keep the usage figures it reports. We store connection credentials for your devices and your residential key encrypted, apart from a short display prefix of the key. Our residential supplier also holds your residential key, and the key travels unencrypted when you connect to its gateway. **Proxy traffic.** Mobile proxy traffic travels directly between you and the device operated by our infrastructure partner and does not pass through ipvolt's servers. The partner and the mobile carrier process connection data under their own policies. For metered proxies that run through our gateway, we record for each session the account, credential, protocol, start and end time and the data transferred. We do not record the websites you visit or the content of your traffic, and our application logs exclude destinations and credentials. **Residential proxy traffic.** If you buy residential proxies, you connect directly to our residential supplier's network, and your traffic does not pass through ipvolt's servers. The supplier sees the address you connect from and the destinations you connect to, and your traffic travels on through its network, which includes devices and connections supplied by independent partners. The supplier and the devices and connections that carry your traffic can see where it goes, and can see its content unless you encrypt it, for example with HTTPS. On 4 November 2026 the supplier told us it records traffic volumes, account and key references, timestamps and operational and security events; that it keeps daily key usage and audit records for about 90 days; and that in its current system records of key operations have no automatic expiry. Its published privacy policy, last updated on 25 September 2026, says it collects IP addresses and connection times and keeps usage logs for 30 days, but it does not cover all of these records, and the supplier has not yet given us a complete retention schedule. Neither that policy nor the supplier's answers to us say which of its records hold the address you connect from or how long those are kept, or whether it keeps the destinations you reach, and the supplier has not promised that it keeps no other logs. We have not verified what it tells us. In normal operation we receive usage figures and the status of your key from the supplier, not the websites you visit or the content of your traffic. If we investigate an abuse report with the supplier, we may also receive details of the events reported. **Why we use this data.** To provide the service, handle payments and answer your messages under our contract with you; to keep the financial records the law requires and answer lawful requests from authorities, under our legal obligations; and, in our legitimate interests, to secure the service, limit sign-in attempts, prevent fraud and abuse, handle abuse reports, handle disputes, answer partnership approaches and understand what customers ask for so we can improve the service. You need to give us the account and payment information above to use the service. We do not make decisions about you based only on automated processing that have legal or similarly significant effects on you. **How long we keep it.** Payment, ledger and refund records are kept for as long as accounting and tax law requires, and the system is designed so that they cannot be altered. Account and order records are kept while your account is open and for up to two years after it closes, then deleted or anonymised, unless we need them for a legal claim. Your residential key record (the encrypted key, coded label and usage figures) counts as an account record. Server logs are kept for up to 90 days, and database backups for 14 days. Support emails are kept for up to two years after our last exchange or after your account closes, whichever is later. Abuse reports and our decisions on them are kept for up to two years. The AI tools described under "Who receives it" also leave records of the messages they handle: a short redacted summary with a keyed hash of the sender's address and a pointer to the message, and, for a sender not already in a partnership conversation with us, the address, a pointer to the message and how it was handled. If they take your message for a partnership approach, we also keep a contact record with your address, a copy of that conversation and the replies they drafted and sent. We have not set an end date for these records. You can ask us to delete yours. Anthropic keeps what its tools receive, and may use it to improve its models, as its own policies and our account settings allow. Our residential supplier decides how long it keeps its own records. We do not control those periods, and what it has told us is described above. **Who receives it.** Service providers that process data for us: Hetzner (server hosting in Helsinki, Finland), Cloudflare (network and security services in front of ipvolt.com, including the customer dashboard) and Namecheap Private Email (our support mailbox and sign-in code emails). Others that receive limited data and use it under their own policies: NOWPayments (crypto checkout: the top-up amount, our order reference, and what it receives when you use its payment page, including your connection details, the coin and network you choose and the transaction you pay with; OxaPay received the same for top-ups made before 7 November 2026), and blockchain data providers and Coinbase (public blockchain and price data, without account details). Anthropic provides AI tools that read our support mailbox, including abuse reports. They sort and summarise what people tell us, work out which new senders are making a partnership approach, and help us write replies. In partnership conversations, messages they write in English can go out automatically, without a person reading them first. If the tools take your message for a partnership approach, you may get one of these messages. Anthropic therefore receives the messages they read in that mailbox and the replies they write, with their subjects and the names and addresses on them, and handles them under its own policies. If you rent a mobile proxy, our mobile infrastructure partner and the mobile carriers carry your traffic under their own policies, so they receive your connection data and can see where your traffic goes, and its content unless you encrypt it. If you buy residential proxies, our residential supplier receives your connection data and your traffic, and so can the independent partners, device owners and networks that carry that traffic. That is not limited data, and we have no agreement with the supplier yet that sets how any of them may use it. We will tell you who the supplier is on request. We disclose data when the law requires it, or to deal with abuse under the [Acceptable Use Policy](/acceptable-use). **Transfers outside the EEA and UK.** Some of these providers, including Cloudflare, Namecheap, Anthropic, Google and some blockchain data providers, are based in or process data in the United States or other countries outside the EEA and UK. Where a service provider that processes data for us is certified under the EU–US Data Privacy Framework (and its UK Extension), we rely on that; otherwise we rely on the standard contractual clauses in its data processing terms. You can ask us for a copy of those safeguards at [hello@ipvolt.com](mailto:hello@ipvolt.com). We do not rely on either safeguard for Anthropic, Telegram, NOWPayments, OxaPay, our mobile infrastructure partner or mobile carriers, which use what they receive under their own policies. We do not rely on either safeguard for our residential supplier, and it has not yet given us a data processing agreement, standard contractual clauses or a list of its subprocessors. If you buy residential proxies, your connection data and your traffic go directly to its network, which includes countries outside the EEA and UK, without a safeguard we can rely on. The coded label, order references and traffic totals we send the supplier, and any parts of an abuse report we share with it, go without one too. **Abuse reports.** If you report abuse, we use your report and contact details to investigate and reply, in our legitimate interest in preventing misuse of the service. We may share the relevant parts with our infrastructure partner, our residential supplier or the customer concerned, but not your contact details unless you agree. The AI tools listed under "Who receives it" read our support mailbox, so they can see your report and your contact details. **Your rights.** You can ask for a copy of your data, for its correction or deletion, for its use to be restricted, or to receive data you gave us in a portable format, and you can object to uses based on our legitimate interests. We may need to keep financial records after a deletion request. We do not control the records our residential supplier keeps, and we have no agreed way yet to obtain, correct or delete them. We can pass your request on and tell you its answer, but we cannot make it act. Contact [hello@ipvolt.com](mailto:hello@ipvolt.com). You can also complain to the data protection authority where you live or work. ## Affiliate applications and referrals Affiliate applicants provide a name, email, public website or profile and a description of their audience. We use these details to review applications and operate the affiliate program. Approved affiliates also provide payout details. Account access and financial records are restricted; applications do not enroll anyone in the customer waitlist or a marketing mailing list. A referral link asks before setting a first-party referral cookie. If you accept, it remembers the first accepted referral for the duration shown, up to 90 days. You can continue without it or clear it from the affiliate page. Optional analytics consent is separate. A new signup can be associated with the referral, and a verified customer account and eligible payments can later be linked for commissions. Affiliates see aggregate signup counts and their own commission and payout records, not referred customers' email addresses or account details. Refunds and payout reconciliation are retained in a financial audit trail. Unconverted referral records are removed after expiry by scheduled cleanup. Affiliate sessions use an essential cookie with an eight-hour maximum and a one-hour idle timeout. For access, correction or deletion requests, contact hello@ipvolt.com; financial records may need to be retained for accounting obligations. ## Residential launch list The residential launch list closed on 10 November 2026, when residential proxies went on sale, and the website no longer takes signups for it. If you joined, ipvolt holds your email address, signup date, the form you used and the wording you agreed to, and your answer to the optional use-case question if you gave one. We use this information only to manage the list and send the notification described beside the form you used. Some older pages called this the early-access list. Submitting an email address did not subscribe you to advertising or enable website analytics. Contact [hello@ipvolt.com](mailto:hello@ipvolt.com) to ask about your information or request removal from the list. ## How we measure visits We measure how our public pages and the dashboard are used with our own software, on our own server. Nothing in this section goes to another company. A small script records the page you open and how you arrived (the address of the page that linked to us, without its query, and any campaign labels in the link), how long the page was open and how far you scrolled, the links and buttons you press (their name or wording), which form and which field you used, that something was copied, script errors and page loading times. With each visit we keep your browser family, operating system, device type, screen size, language, time zone and the country Cloudflare reports for your connection. It never records what you type, the contents of a field or the text you copy. It sets no cookie. To tell one visitor from another, our server combines your connection address and browser details with a random value that changes every day and turns them into a code. The address itself is not stored. When that day's random value is deleted, the next day, the code can no longer be matched to an address or to your next visit. If you accept analytics (see “Cookies and your choice”), we also keep a random number in this browser's storage for up to 13 months, so that your visits on different days count as one visitor's. If you reject analytics, or your browser sends a Global Privacy Control or Do Not Track signal, this measurement is switched off: the script records nothing and removes that number. In the dashboard, including its sign-in and order pages, the script records the same things, except the wording of buttons. Once you are signed in, or have opened an order placed without an account, it also records your Account ID with the visit, which links what you did on our pages that day (and on other days, if you accepted analytics) to your account, and how each sign-in step, top-up and purchase ended: that it succeeded, or the error we showed you. It never records your email or wallet address, sign-in codes, passwords, invoice IDs, amounts, keys or proxy credentials, and never what you do through your proxies. We use these records to see which pages and steps work and where people give up, in our legitimate interest in improving the website and the service. You can object at any time by rejecting analytics in Cookie settings, by turning on Global Privacy Control in your browser, or by writing to [hello@ipvolt.com](mailto:hello@ipvolt.com); on request we delete what is linked to your account. We delete these records after 13 months. The people who run ipvolt can read them. They are not shared or sold. ## Optional Google Analytics If you accept analytics, Google Analytics helps us understand visits to our public pages, useful content and completed signups. Events can include the public page visited, campaign labels, form interactions, broad device information and approximate location. Google also receives technical connection information needed to process those requests. If you accepted analytics and then create a dashboard account, our server tells Google Analytics that an account was created, together with the analytics identifiers already in your browser, the type of sign-in (email or the wallet's network) and the ipvolt.com page or other website you came from. It never sends your email or wallet address. We do not send your signup email, the text you type into forms, private account content or login credentials as analytics events. Advertising personalization and session recordings are not enabled by this integration. Google processes the analytics information on its infrastructure, which may include processing outside your country. Read [how Google uses information from sites that use its services](https://policies.google.com/technologies/partner-sites). ## Cookies and your choice Google Analytics is off until you choose to accept it. If enabled, Google Analytics uses first-party cookies to distinguish visits and sessions. Our integration limits those cookies to up to 13 months; your browser may remove them sooner. Our own measurement, described above, uses no cookie and runs unless you reject analytics. We remember your analytics choice in this browser for up to six months. Use the Cookie settings control to change your choice. Rejecting analytics stops Google Analytics and our own measurement, and removes the analytics cookies and the number our own measurement keeps in this browser. It does not undo information already sent. Clearing browser storage also clears your saved choice. Essential server requests still take place when you load a page or submit a form. ## Hosting and access The website and signup database run on infrastructure hosted by Hetzner. The project team uses restricted application access to operate the site and manage the launch list. Operational security controls process connection information to protect forms and services. While the launch-list form was open, Cloudflare Turnstile checked each submission for automated abuse using browser and connection information. The signup email was not included in the verification request. That security check worked independently of optional analytics. Read the [Cloudflare privacy policy](https://www.cloudflare.com/privacypolicy/). The launch list's limits used keyed hashes of connection addresses and normalized email addresses. Those rate-limit records expire within one hour; they are separate from a launch-list record. Limits on dashboard sign-in and sign-up are described under "Signing in" above. For a privacy question, contact [hello@ipvolt.com](mailto:hello@ipvolt.com). Please avoid sending passwords or other secrets. ## Scraper bandwidth report viewer The report viewer on the [scraper bandwidth report page](/guides/scraper-bandwidth-report) parses the scrapescope report files you choose in your browser, inside an isolated frame on the page. Those files are never uploaded: the frame cannot make network requests, and the page around it never reads the report. If you accept optional analytics, that page records only fixed labels: that a report was opened from a file, a drop or the bundled sample and whether it parsed; that two runs were compared; that a share card was downloaded; that an install command was copied; and that the link to the homepage was used. Hostnames, byte counts, prices and file names are never sent. Without an analytics choice, nothing is recorded. ## Free proxy checker The [proxy checker](/tools/proxy-checker) sends the proxies you paste to ipvolt's server, which connects to each proxy and, through it, only to ipvolt's own test endpoint at check.ipvolt.com. Proxy usernames and passwords are used for that connection during the check and are then discarded: they are never logged or stored, and results and CSV exports show passwords as ****. The checker does not log proxy addresses, exit IP addresses or results. It records only aggregate counts: how many proxies a check contained and which failure types occurred. Exit IP addresses are looked up in locally stored geolocation databases (DB-IP Lite and MaxMind GeoLite2); the lookups do not leave our server. Checks are rate limited per connection address using keyed hashes held in memory for the length of the limit window, at most one hour. Checks of more than 10 proxies use Cloudflare Turnstile, as described above. Our own measurement records that you opened the page, the buttons you pressed and how many proxies a check contained (as a range), never the proxies you paste or the results. Google Analytics, if you accepted it, records only the page view. ## Talk to expert form The “Talk to expert” form, in the site header and at [ipvolt.com/contact-sales](/contact-sales), asks for your name, your work email address and what you need: mobile proxies, residential proxies, both, or not sure yet. You can also give your company, your expected usage, a message of up to 1,000 characters and a Telegram handle. When you send the form, our server emails these details to [hello@ipvolt.com](mailto:hello@ipvolt.com) with your address as the reply address. We use them only to reply to you, at your request. The website does not store the form in a database. To limit how often the form can be sent, the server holds a keyed hash of your connection address in memory for up to 15 minutes, not the address itself. The email stays in our mailbox until we delete it. You can ask us to delete it at any time by writing to [hello@ipvolt.com](mailto:hello@ipvolt.com). Sending the form records one event with the option you chose under “What do you need?”: in our own measurement unless you rejected analytics, and in Google Analytics if you accepted it. Nothing you typed is recorded in either. ## Support chat The chat on ipvolt.com and in the dashboard answers questions with Claude, an AI model from Anthropic. To answer, we send Anthropic your message, the earlier messages in the same conversation, the path of the page you are on and the text of our public pages. Answers can be wrong; for payments and anything we must check, the chat offers an email to [hello@ipvolt.com](mailto:hello@ipvolt.com), or hands your problem to our team as described below. If you are signed in to the dashboard, or have opened an order placed without an account with its invoice ID, the chat can also read parts of your own account to answer you, using your existing sign-in: your Account ID and the email or wallet you sign in with, your balance, your top-ups and their status, your orders and devices (name, country, carrier, outgoing IP address and paid-until date), your balance changes and your residential plan usage. What it reads goes to Anthropic with your question. It cannot see passwords, sign-in codes, API keys, residential keys or proxy credentials. Please do not send passwords, keys or seed phrases in the chat. The chat can do two things in your account, both only for an order of yours that was paid but not delivered. When you tell it about such an order, it asks our repair system to look at the order, and that request is recorded with the order. And when the order can be cancelled, it shows you a button: if you press it, the order is cancelled and the reserved amount returns to your balance. Nothing is cancelled unless you press the button. The chat cannot change anything else in your account. When the repair of such an order ends, we may email you the result at the address you sign in with or gave with the order. If you are signed in, or have opened an order placed without an account with its invoice ID, and the chat cannot resolve your problem, it can hand it to the people who run ipvolt as a case. A case holds a short summary written by the AI model, what you asked for, the conversation, and the email address you sign in with, if you sign in with one. The summary and what you asked for are sent to our team through Telegram, a messaging service that handles them under its own policies, and stay in that private chat until our team deletes them. When our team asks the AI model about a case or a conversation there, its answer can quote what you wrote; email addresses and proxy credentials are removed first. Your email address is not sent there. Our team reads the case and answers it. Their answer is shown to you in the chat, is given to the AI model so that it can tell you about it, and may also be sent to that email address. A case is opened only in a conversation in which you asked for help, and it changes nothing in your account. We delete a case 30 days after it is opened; an answer that was shown to you also stays with that conversation until the conversation is deleted. We keep each conversation for 30 days after it starts and then delete it: your messages and the answers, the page it started on and the pages you asked from, the language, your Account ID if you were signed in, which parts of your account it read, whether it offered an email, what it did about an undelivered order and whether you pressed its button, and what the answer cost. For rate limits we store a keyed hash of your connection address with the conversation, not the address itself. The people who run ipvolt can read conversations to check answers and help you, and delete one on request. Anthropic handles what it receives under its own terms and policies. We use the chat to answer your questions and to improve our help pages, in our legitimate interest in supporting visitors and customers. ## Proxy Toolkit MCP The local toolkit package processes documentation queries and structured diagnostic fields on your machine. Do not include passwords, proxy credentials, private URLs or full logs in a prompt or tool argument. The local package reads proxy credentials only from the configuration you explicitly provide. The local package does not send automatic usage telemetry or run a route check at startup. Your MCP client or a third-party gateway may process or retain its own requests; consult its privacy settings and policy. The hosted toolkit processes the documentation queries and structured diagnostic fields you submit to return a result. Do not include passwords, proxy credentials, private URLs or full logs in a prompt or tool argument. An optional local route check contacts our fixed diagnostic endpoint through your configured proxy and returns the connection address observed for that request to you. We use temporary, hashed connection identifiers for rate limits, with a 60-second expiry. We do not retain tool arguments, response bodies, proxy credentials or the returned address in toolkit operational logs; those logs contain tool name, status, duration and version information. Calls to the MCP and diagnostic endpoints are not website Google Analytics page views. --- Document 34 of 138: Terms of Service URL: https://ipvolt.com/terms Markdown: https://ipvolt.com/terms.md # Terms of Service Source: https://ipvolt.com/terms Markdown: https://ipvolt.com/terms.md Customer terms Updated: 5 November 2026 (2026-11-05) These terms apply to the ipvolt customer service at ipvolt.com/dashboard: the dashboard, the API and the services you buy there. "ipvolt", "we" and "us" mean the individual or individuals who run ipvolt, reachable at hello@ipvolt.com. ipvolt is not yet a registered company: until one is formed, those individuals are the other party to these terms. We will give you their names and postal address on request. By signing in or buying a service, you accept these terms, the [Acceptable Use Policy](/acceptable-use) and the [Payments and Refunds Policy](/refunds), and confirm you have read the [Privacy notice](/privacy). ## 1. Who can use ipvolt - You can create an account yourself with an email address or a wallet, and we can also create one for you by invitation. - ipvolt is for business and professional use only; we do not offer it to consumers. By using it you confirm that you are at least 18, that you act for purposes of your trade, business, craft or profession and not as a consumer, and, if you use it for an organisation, that you may accept these terms for it. - You may not use ipvolt if you, anyone who owns or controls you, or anyone you act for is listed under United Nations, European Union, United Kingdom or United States sanctions, or if you are located or ordinarily resident in a country or region subject to comprehensive sanctions under those regimes. ## 2. Your account - You sign in with a code sent to your email address or by signing a message with your wallet. Accounts we create by invitation may instead use a username and password we issue. Keep these secret. You are responsible for activity under your account, including through API keys you create. - If your account has a password, you can change it in the dashboard. If you forget it, contact support; we check that the request comes from you before issuing a new one. - Tell us at hello@ipvolt.com straight away if you think your account, an API key or your residential key has been compromised. ## 3. The services **Mobile proxy (device rental).** You rent one dedicated mobile device connected to a carrier SIM for the period you choose (24 hours or 30 days), up to 20 devices per order. Each device offers HTTP and, for most devices, SOCKS5 access; the dashboard shows what each one supports. You rent a device, not specific IP addresses: when you rotate, the carrier assigns the address and may return the same one, and rotation can briefly interrupt traffic. - Devices are supplied and operated by our infrastructure partner. The catalog shows current availability; a listing does not reserve a device or guarantee its price until you confirm an order. - Rentals do not renew automatically. You can renew a device before it ends at the price quoted at that time. When a rental ends, the device is removed from your account and cannot be renewed; rent a new one to continue. **Metered proxy.** Some accounts have an assigned proxy with a lifetime data allowance, a connection limit and a session length shown in the dashboard, and may be limited to approved destinations. Data counts against the allowance when it is sent through the proxy, including data a destination does not finally receive. **Residential proxy (per GB).** Where the dashboard offers it, you buy prepaid traffic in whole-GB packs, paid from your balance at the price shown before you buy. Each customer has one key. We set no expiry date on it, later packs add traffic to the same key, and nothing renews automatically. We may decline a pack, for example when capacity is short or the key has reached its lifetime limit. You are responsible for all traffic on your key, so keep it secret and regenerate it if it is exposed. - You connect directly to our residential supplier's network, and your traffic does not pass through ipvolt's servers. The supplier sees the address you connect from and the destinations you connect to, and keeps its own records; the [Privacy notice](/privacy) says what it has told us about them. Your traffic leaves through devices and connections run by others, so the supplier and those devices can read anything you do not encrypt: use HTTPS or another encrypted protocol. Your key is also sent unencrypted to the supplier's gateway, so connect from networks you trust. - Traffic is measured by the supplier's counters: upload plus download, where 1 GB is 1,024 MB and 1 MB is 1,048,576 bytes. The counters run behind actual use, so the figure in your dashboard can be late or temporarily unavailable, and the real figure may be higher. - Your key's cap is the total GB you have bought, less any GB we take off it when we credit you. It never goes below 1 GB, so a final credited GB stays on the cap of a key that stays stopped. Reaching it is meant to stop the key and close its open connections, but there is no fixed deadline, so usage can run past the cap, and our supplier publishes no maximum for how far. We do not charge your balance for ordinary usage past a cap. It stays on the counter, so it comes out of the next pack you buy. A pack that the latest usage reading shows is too small to cover it is refused without charge, but that reading can be behind, so a pack can still be used up by earlier traffic that had not yet been counted. Deliberately running past a cap breaks the [Acceptable Use Policy](/acceptable-use). - When a key is stopped or regenerated, new connections with that key are refused once the change takes effect, which has no fixed deadline. Connections already open may continue, and their traffic still counts, so regenerating may not cut off someone already using an exposed key. A stopped key may stay off until our supplier clears the stop, and our supplier gives us no uptime or response-time commitment, so we cannot say how long that takes. If it cannot be brought back, the [Payments and Refunds Policy](/refunds) applies. - The network uses capacity supplied by independent device-network partners. Our supplier tells us it requires those partners to obtain informed consent from device owners and permission to share their connections. That is a requirement placed on partners, not a guarantee from us: we have not audited them, so we do not promise that it holds for every device or that every address is a residential device. The pool is mixed, and available locations and network classifications vary, so we do not promise a particular type of address. - Your connection settings choose where traffic exits, and we do not promise that it always exits in the country you select. You stay responsible under the [Acceptable Use Policy](/acceptable-use) for using the service lawfully, wherever it exits. - All customers' keys sit under one ipvolt account at our supplier, so limits apply to all ipvolt customers together, not to each key. A job that opens many connections at once can be refused even when your key has traffic left, and one customer's activity, including a client that keeps retrying with a wrong or old key, can restrict others. If that account runs out of traffic or the supplier acts on it, every customer's key can stop at once. We do not promise a number of connections or a fair share of them, so test your workload on a small pack before buying a large one. ## 4. Availability We work to keep ipvolt available, but we do not promise any uptime, speed or success rate, or that a website will accept traffic from it. Features may change or be withdrawn. If a change materially reduces a rental you have already paid for, we credit the affected unused part to your balance, pro rata by the hour, as the [Payments and Refunds Policy](/refunds) describes. ## 5. Prices and payment - Prices are in US dollars and are fixed when you confirm an order. You are responsible for any taxes that apply to your purchases where you are based. - You pay by adding prepaid balance to your account and spending it on services. Balance is service credit for ipvolt services. It is not a deposit or electronic money, earns no interest, cannot be withdrawn and cannot be transferred to another customer. The [Payments and Refunds Policy](/refunds) explains how payments, balance and refunds work. ## 6. Acceptable use You must follow the [Acceptable Use Policy](/acceptable-use). You are responsible for what you do through ipvolt, and for complying with the laws and the terms of the websites and services you access. ## 7. Suspension and closure - We may suspend or close your account, and stop services you are using, if we reasonably believe you have broken these terms or the Acceptable Use Policy, if the law or our infrastructure partner requires it, or to protect ipvolt or others. We may stop your residential key if our residential supplier requires it. Where reasonable and lawful, we tell you why first. - While your account is suspended you cannot sign in, use API keys, create payments or place orders, and open metered proxy sessions are closed. Your residential key is stopped as well, as section 3 describes, which may not end connections already open. Orders not yet sent to our partner or supplier are returned to your balance; orders already sent are checked and then charged or returned as the Payments and Refunds Policy describes. Rented devices may be stopped. - You can ask us to close your account at any time at hello@ipvolt.com. Unused balance and unused residential traffic are not refunded when an account closes, except where the Payments and Refunds Policy or the law provides a refund. ## 8. Liability - Nothing in these terms limits or excludes liability that cannot be limited or excluded by law, such as liability for fraud or for death or personal injury caused by negligence. - We are not liable for indirect or consequential loss, lost profits or lost data, or for loss caused by websites blocking or limiting your traffic. - Our total liability for all claims in any 12-month period is limited to the amount charged to your balance for services in the three months before the event that caused the claim. This limit does not reduce our duty to provide services you have paid for, or to make the credits and refunds the [Payments and Refunds Policy](/refunds) provides. ## 9. Your responsibility to us If your use of ipvolt in breach of these terms or the law leads to a claim against us, you will cover our reasonable losses and costs from that claim. ## 10. Changes to these terms We may update these terms. We post changes on this page with a new date at least 14 days before they take effect, unless a change is needed sooner by law or for security. When we add a new service, its terms apply only if you buy it, from the moment you accept them at checkout, and they change nothing for services you already have. If you do not accept a change, you can close your account before it takes effect, and we will refund your unused balance as the [Payments and Refunds Policy](/refunds) describes. ## 11. Contact and disputes Write to hello@ipvolt.com. If you have a complaint, tell us first; we aim to resolve it within 30 days. ## 12. General - We may transfer these terms, and your balance, to a company we set up to run ipvolt. We will tell you before we do; your rights under these terms stay the same. - If any part of these terms is found invalid, the rest still applies. - These terms are in English. You can save or print them from this page. --- Document 35 of 138: Payments and Refunds Policy URL: https://ipvolt.com/refunds Markdown: https://ipvolt.com/refunds.md # Payments and Refunds Policy Source: https://ipvolt.com/refunds Markdown: https://ipvolt.com/refunds.md Customer terms Updated: 10 November 2026 (2026-11-10) This policy is part of the ipvolt [Terms of Service](/terms). ## 1. How payment works You add prepaid US-dollar balance to your account and spend it on services. Today, balance is added with cryptocurrency; card payment is not available yet. New accounts can add balance straight away. We can turn crypto payments off for an individual account; if they are off for yours, the dashboard tells you how to request access. **Orders without an account.** You can buy a mobile proxy without creating an account. Your payment is then added as balance to that order, and the proxy is paid for from it when it starts. You get an invoice ID when you create the order. It is the only way back to the order, its balance and the proxy's connection details, and anyone who has it can use them: keep it secret and keep it safe. We do not store the invoice ID and cannot look it up. If you lose it, email us with your order reference (the first eight characters of the ID) or your payment details; we check that the request comes from the buyer before changing anything, and we cannot promise to restore access. If the proxy you chose is no longer in stock when your payment is credited, the balance stays on the order and you can spend it there on another proxy. The rest of this policy applies to an order without an account as it does to an account. Today you add balance through NOWPayments, a third-party crypto checkout: you enter a US-dollar amount between $1 and $1,000,000, choose a coin and network on NOWPayments' page and pay there, and we credit your balance once NOWPayments reports the payment finished. If you send more than NOWPayments' page asks for, we credit only the amount you entered; the extra is not added to your balance automatically. Email us and we review it. If you send less than NOWPayments' page asks for, nothing is credited automatically, and sending the rest to the same address does not complete the payment automatically either: email us and we review it. A payment that is short, arrives after NOWPayments' payment window, is in another coin or on another network, is a second payment for a top-up already credited, or does not match our record of the top-up is not credited automatically. Email us and we review it, though we cannot promise to recover a payment that arrives late, is in another coin or is on another network. Any refund of such a payment, or of an extra amount you sent, is made through NOWPayments. A payment through NOWPayments is a payment to us for service credit, and we do not hold, store or exchange cryptocurrency on your behalf. Limits per account: in any 24 hours, up to 10 NOWPayments top-ups, paid or not, of which at most 5 may go unpaid (open, expired or under review). We may change limits to protect the service. Top-ups made through OxaPay, our checkout until 7 November 2026, are handled the same way, and any refund of one is made through OxaPay. The rest of this section and section 2 apply to crypto transfer invoices, which we no longer offer for new top-ups. Section 3 applies to those invoices and to any refund of credited balance under section 4, however you added the balance. Each crypto transfer top-up is an **invoice** for an amount between $1 and $1,000,000. The invoice shows one payment address, the network, the coin and the exact amount to send. The supported coins and networks are listed when you create an invoice. Payment addresses belong to ipvolt: a payment you send is a payment to us for service credit, and we do not hold, store or exchange cryptocurrency on your behalf. - **The rate is fixed for 60 minutes.** When the invoice is created, we calculate the coin amount for your dollar amount from a current market price, and that amount stays valid for the one-hour payment window. USDC is valued at $1. USDT is valued at its current market price, and USDT payments pause while its price is more than 1% away from $1. Amounts in ETH, POL and SOL are rounded up. - **Send the exact amount, on the network shown, before the window closes.** You confirm this before an invoice is created. - Payment details are hidden near the end of the window (the last 10 minutes for Bitcoin, the last 3 minutes otherwise) so that a new transfer does not arrive late. - Limits per account: in any 24 hours, up to 10 invoices, of which at most 5 may go unpaid (open, expired or cancelled), and up to 3 cancellations; and one open unpaid invoice per network at a time. We may change limits to protect the service. ## 2. When a crypto transfer invoice is credited This section applies only to crypto transfer invoices. For a top-up through NOWPayments, or through OxaPay before 7 November 2026, see section 1. Your balance is credited automatically once the payment is confirmed on its blockchain: after 1 confirmation for Bitcoin, 6 for Litecoin, and once the network marks the block final for the other networks. Busy networks can cause delays; the invoice page shows progress. | What you send | What happens | |---|---| | The exact amount or more, in time | The invoice amount is credited once. | | More than the invoice amount | The invoice amount is credited. If the extra is more than 0.5% of the invoice, support refunds it or, if you prefer, adds it to your balance at the invoice rate. An extra of 0.5% or less is not credited or refunded; we keep it. | | Less than the invoice amount | The invoice stays open so you can send the rest before the window closes. If the total is still short when it closes, support credits the value received at the invoice rate or, if you prefer, refunds it. | | A payment that arrives after the window closes | Support reviews it. We credit it at the invoice rate if the delay was our fault or we accept it; otherwise we refund it. For Bitcoin and Litecoin, payments in the first block mined after the window closes, or the block after it, count as on time. A payment confirmed before the invoice was created is also reviewed. | | Another payment after the invoice was paid | The invoice stays paid and shows that extra was received; support refunds it or credits it at the invoice rate. | | A different coin or network than the invoice shows | It is not credited automatically. Contact support: we may be able to recover it but cannot promise to. We tell you the cost before we try, and deduct it from what we recover. | You can cancel an invoice only before any payment has been seen and before its payment details are hidden. Cancelling does not reverse a transfer: a payment confirmed before you cancelled is still credited, and anything confirmed afterwards is reviewed as above. If a blockchain reverses a payment after we credited it (rare, and mainly on Bitcoin), we may deduct the amount from your balance or ask you to pay it again. ## 3. How crypto refunds are made This section applies to crypto transfer invoices and to refunds of credited balance under section 4. A refund of a NOWPayments or OxaPay payment we did not credit is made through the checkout you paid with, as section 1 says. - For a payment we did not credit, we refund the amount of the coin we received, less the network fee, whatever its dollar value is when we send it. When we refund balance that was already credited, we calculate the coin amount from a current market price on the day we send it. - Refunds are sent by our team in the same coin and on the same network you paid with, to an address you confirm in writing. We do not refund in another coin, on another network or in fiat currency. - We deduct the network fee for sending the refund. If the amount due is smaller than that fee, we add it to your balance instead. - We may ask you to show that you control the paying wallet or account. - We may ask who you are and what your business does before we credit a payment or send a refund. We may refuse or delay a refund where sanctions or other law require it, or to an address we cannot link to you. - We aim to send a refund within 5 business days of agreeing it. Blockchain transfers cannot be reversed, so a payment sent to the wrong address or network may be unrecoverable. ## 4. Balance Balance is service credit in US dollars for ipvolt services. It does not expire. It cannot be withdrawn, exchanged or transferred to another customer. Unused balance is not refunded when an account closes, except that we refund it on request if we close your account or stop offering the services for a reason other than your breach of the Terms or the Acceptable Use Policy, or if you close your account before a change to the Terms takes effect because you do not accept it. We may deduct amounts you owe us. Refunds are made as section 3 describes. The law may also require a refund in other cases. ## 5. Mobile proxy orders - When you confirm an order, the price is reserved from your balance and charged only once the device is delivered. If the order cannot be fulfilled, the reserved amount returns to your balance. If our partner's result is unclear, the amount stays reserved while we check, and is then charged for a delivered device or returned to your balance. - Rentals do not renew automatically. A renewal is a new charge at the price quoted at the time (quotes are valid for two minutes). A renewal that fails is not charged, with the same reservation rule while we check. - **Started rentals are not refundable**, except that: - if a device fails and we cannot repair or replace it, we credit the unused part of the rental to your balance, pro rata by the hour; - if a supplier problem puts an order under review, we credit any amount due to your balance once it is resolved; and - if we stop a rental for a reason other than your breach of the Terms or the Acceptable Use Policy, for example because our infrastructure partner or the law requires it, we credit the unused part to your balance, pro rata by the hour. - Order refunds are credited to your balance, not paid out in cryptocurrency. - Rotation, the carrier returning the same IP, or a website blocking a device is not a fault that qualifies for a refund. - Rentals stopped because of a breach of the [Acceptable Use Policy](/acceptable-use) are not refunded. ## 6. Residential proxy packs - When you confirm a pack, the price is reserved from your balance and charged only once the traffic is added to your key. If the pack cannot be added, the reserved amount returns to your balance. If our supplier's result is unclear, the amount stays reserved while we check, and is then charged if the traffic was added or returned to your balance if it was not. - Packs do not renew automatically, and we set no expiry date on traffic you have bought. - **Packs are not refundable once the traffic is on your key, even if you have not used it**, except that: - if your key fails and we cannot get it working again, we credit your unused GB to your balance. Each customer has one key, so we may not be able to give you a new one, and you can then spend that credit only on our other services; - if a supplier problem puts an order under review, we credit any amount due to your balance once it is resolved; - if we stop your key for good or stop offering residential proxies for a reason other than your breach of the Terms or the Acceptable Use Policy, for example because our residential supplier or the law requires it, we credit your unused GB to your balance. If we stop only residential proxies, that credit stays service credit. Section 4 applies only if we also close your account or stop offering ipvolt's services altogether; and - if you close your account before a change to the Terms takes effect because you do not accept it, we credit your unused GB to your balance, and section 4 applies to that balance. - **Per-GB rule.** Unused GB are your key's cap minus the latest usage reading we have from the supplier's counters, rounded down to whole GB. A final GB that stays on the cap after we have credited it does not count again. Each unused GB is credited at the per-GB price you paid for the pack it came from, with your oldest pack treated as used first. Usage past a cap counts as used. We can only work out and make a credit while our supplier answers us and reports your key's usage. If it does not, the credit has to wait, and we cannot promise for how long. - We stop your key before we credit your unused GB, and traffic on connections still open keeps counting until they end. A credit leaves your key stopped until we restart it, and restarting it may need our supplier to clear the stop, which has no agreed deadline. - Order refunds are credited to your balance, not paid out in cryptocurrency. - A website blocking traffic, the network classification of an address, a location becoming unavailable, or a shared connection or session limit at our supplier is not a fault that qualifies for a refund. - Traffic on a key stopped because of a breach of the [Acceptable Use Policy](/acceptable-use) is not refunded. ## 7. Questions Email hello@ipvolt.com with the subject "Payment". For a top-up through NOWPayments, give the amount and time shown under Recent NOWPayments payments on Add funds, and the transaction ID (hash) and network if you have them. For a crypto transfer invoice, give your invoice ID (the invoice page fills this in), the transaction ID (hash) and the network. Never send your wallet seed phrase, private keys, passwords or sign-in codes: we will never ask for them. See [Support](/support). --- Document 36 of 138: Acceptable Use Policy URL: https://ipvolt.com/acceptable-use Markdown: https://ipvolt.com/acceptable-use.md # Acceptable Use Policy Source: https://ipvolt.com/acceptable-use Markdown: https://ipvolt.com/acceptable-use.md Customer terms Updated: 5 November 2026 (2026-11-05) This policy is part of the ipvolt [Terms of Service](/terms). It applies to everything done through ipvolt proxies, devices, the dashboard and the API, including by anyone you give access to. ## What ipvolt is for Lawful work that needs real network locations: collecting publicly available data, price and availability monitoring, ad and search-result verification, localisation and quality testing, testing apps and accounts on mobile networks, and research. You are responsible for following the law and any terms that bind you when you access a website or service. ## Not allowed You must not use ipvolt to: 1. **Break the law** where the activity takes place or has effect, or help someone else do so. 2. **Commit fraud**: payment or card fraud, account takeover, credential stuffing or password spraying, phishing, identity theft, fake reviews or engagement passed off as genuine, ad or click fraud, or abuse of bonuses and promotions. 3. **Gain unauthorised access**: sign in to accounts or systems you are not authorised to use, bypass authentication or paywalls, exploit vulnerabilities, or scan or probe systems without their owner's permission. 4. **Attack or overload services**: denial-of-service, traffic floods, or request rates you know or should know will degrade a site. 5. **Send unsolicited messages**: spam by email, SMS, messaging apps, comments or forms. 6. **Distribute harmful content**: malware, botnet command and control, child sexual abuse material, content that incites violence, or material that infringes copyright or trademarks. 7. **Collect personal data unlawfully**, or collect data that is not publicly available without authorisation. 8. **Evade sanctions or export controls**, or provide ipvolt to sanctioned persons or territories. 9. **Resell or share access** to devices or proxies with anyone outside your own business without our written agreement. 10. **Interfere with ipvolt**: try to access other customers' devices or data, bypass limits, deliberately run residential traffic past your key's cap, tamper with the devices or SIMs behind the service, try to reach the devices or local networks behind residential addresses, or attack our infrastructure, our partner's or our residential supplier's. **Residential exit locations.** You choose where residential traffic exits. Use a location only where what you do is lawful. Item 8 applies wherever you exit. **Residential keys.** On a residential key you must also not scrape personal or sensitive information, harass or stalk anyone, or reverse engineer the service, and you should respect robots.txt and the terms of the sites you reach and keep to reasonable request rates. ## How we enforce this - We do not monitor the content of your traffic. Mobile proxy traffic goes directly to the device and does not pass through our servers. Residential proxy traffic goes directly to our residential supplier's network and does not pass through our servers either; in normal operation we receive the usage figures and status the supplier reports for your key, not destinations or content, and the supplier keeps its own records, as the [Privacy notice](/privacy) describes. For metered proxies we record usage volumes and times, not destinations or content. - We act on abuse reports, on information from our infrastructure partner, our residential supplier, carriers and authorities, and on signs of misuse we see while operating the service. - Depending on severity, we may warn you, rotate or stop a device, stop a residential key, suspend or close your account, and refuse future service. Serious or repeated breaches can lead to immediate suspension, and rentals and residential traffic stopped for a breach are not refunded. Stopping a residential key refuses new connections once the stop takes effect, which has no fixed deadline; connections already open may continue, and you stay responsible for them. - We share information with authorities when the law requires it, and with our infrastructure partner or residential supplier when needed to deal with abuse on its network. See the [Privacy notice](/privacy). - Our enforcement decisions are made by people, not by automated systems. Our residential supplier's own systems can restrict a key or our account automatically, for example at a cap or after repeated connection attempts with a wrong key, and we may not be able to lift that ourselves. If you disagree with a decision, write to hello@ipvolt.com; we review it and reply within 30 days. ## Reporting abuse See [Report abuse](/abuse). --- Document 37 of 138: Report abuse URL: https://ipvolt.com/abuse Markdown: https://ipvolt.com/abuse.md # Report abuse Source: https://ipvolt.com/abuse Markdown: https://ipvolt.com/abuse.md Trust and safety Updated: 5 November 2026 (2026-11-05) If traffic or messages from an IP address used by ipvolt have harmed you or broken the law, email hello@ipvolt.com with the subject "Abuse". Please include: - the IP address and port, if known - the date, time and time zone of the activity, ideally as a range in UTC - the destination and protocol of the traffic, if known - what happened, with the relevant log lines or headers, and no more personal data than needed - how we can reach you We acknowledge reports within one business day and act on credible reports promptly. Mobile proxy addresses are carrier IPs that change over time: an address one of our customers used at one moment may be used by other people, including ordinary mobile users, at another, so exact times matter. Residential proxy addresses can come from devices and connections supplied by independent partners of our residential supplier, and from other capacity in its network. They can be shared and can change, and the same address may be used by others, including the people whose connection it is, so exact times, the destination and the protocol all matter. We may not always be able to link an address and time to a customer. For a residential address we rely on our supplier to investigate, so acting on a report can take longer, and stopping the traffic may not take effect straight away. We do not disclose customer identities in reply to abuse reports. We respond to requests from authorities when the law requires it. **Point of contact.** hello@ipvolt.com is our single point of contact for authorities and for users of our service, including under Articles 11 and 12 of the EU Digital Services Act. You can write to us in English. Our rules for customers are in the [Acceptable Use Policy](/acceptable-use). --- Document 38 of 138: Support URL: https://ipvolt.com/support Markdown: https://ipvolt.com/support.md # Support Source: https://ipvolt.com/support Markdown: https://ipvolt.com/support.md Help Updated: 10 November 2026 (2026-11-10) Email hello@ipvolt.com. We aim to reply to payment and device problems within one business day, and to everything else within two business days. ## Paid, but your balance hasn't updated? If you paid through NOWPayments, check Recent NOWPayments payments on Add funds first. "Payment confirming on NOWPayments" means NOWPayments has seen your payment on the blockchain. If the full amount arrived, your balance updates once it confirms, so do not pay again. If less arrived than NOWPayments' page asked for, for example because an exchange took its fee from what you sent, nothing is credited automatically, and sending the rest to the same address does not complete it automatically either: email us as below and we review it. If the payment shows "Under review", shows "Expired unpaid" even though you paid, or has not changed 30 minutes after you paid, email us with the subject "Payment", the amount and time shown under Recent NOWPayments payments, and the transaction ID (hash) and network if you have them. If you sent more than NOWPayments' page asked for, we credit only the amount you entered; email us about the extra with the same details. We check with NOWPayments and review it under the [Payments and Refunds Policy](/refunds). Any credit goes to your balance, and any refund is made through NOWPayments. We cannot promise to recover a payment that arrives late, is in another coin or is on another network. For a top-up made through OxaPay before 7 November 2026, send the same details and we check it with OxaPay. If you have an older crypto transfer invoice: 1. Check the invoice page first. "Confirming" means we have seen your payment and are waiting for the blockchain: Bitcoin needs 1 confirmation, Litecoin 6, and other networks a final block. This usually takes minutes but can take longer when a network is busy. Do not send the payment again. 2. If the invoice shows that the window closed, that the payment is under review, or no payment 30 minutes after you sent it, email us with the subject "Payment" and the invoice ID (the invoice page fills this in for you). Include: - the transaction ID (hash) and the network you sent on - the amount and coin you sent, and when 3. We check the blockchain and credit or refund the payment under the [Payments and Refunds Policy](/refunds). ## Device not working? Tell us the device name, its outgoing IP and the order number shown in your dashboard, what you tried (rotating, HTTP and SOCKS5) and the error you saw. If we cannot fix or replace the device, we credit the unused time to your balance. ## Residential key not working? Tell us the first characters of your key shown in the dashboard, the time in UTC, the country and session settings you used and the error you saw. Never send the full key. If we cannot get it working again, we credit your unused GB as the [Payments and Refunds Policy](/refunds) describes. ## Bought without an account? Go to ipvolt.com/dashboard/order and enter your invoice ID (it starts with IPV-). The page shows your payment, then your proxy's connection details, and lets you rotate its IP. If you entered an email address at checkout, the ID is in the message we sent then, and we keep that address with the order. When you email us about the order, quote the order reference shown on that page (the first eight characters of the ID), never the whole ID. If you have lost the ID, write to us from the address you gave at checkout or, if you gave none, with what you can show about the payment, such as the coin, amount, time and transaction ID. We check that the request comes from the buyer before changing anything, and we cannot promise to restore access. To keep a second way in, open the full dashboard from the order page and add an email or link a wallet in Account settings. ## Can't sign in? Accounts created with an email address or a wallet have no password. Go to ipvolt.com/dashboard and choose "Email me a code" or "Connect wallet", using the email address or wallet you signed up with or added later. For a wallet, use the same address on the same network. Anything else creates a separate account with its own balance, so if the next step says "Create your account", go back. If no code arrives, check your spam folder, then choose "Resend code". If it still does not arrive, email us. To keep a second way in, add an email or link a wallet in Account settings. If you have lost access to your email or wallet, email us. We check that the request comes from you before changing anything, and we cannot promise to restore access. ## Forgot your password? This applies only to accounts we created by invitation with a username and password. The sign-in page at ipvolt.com/dashboard has no password form, so email us if you need the link to the password sign-in page. If you still know your password, you can change it in Account settings. If you have forgotten it, email us; we check that the request comes from you before issuing a new password. ## Keep your secrets Never send your wallet seed phrase, private keys, passwords, sign-in codes or full invoice ID. ipvolt will never ask for them. Reporting misuse of an ipvolt IP address? See [Report abuse](/abuse). --- Document 39 of 138: Proxies by country. URL: https://ipvolt.com/proxies Markdown: https://ipvolt.com/proxies.md # Proxies by country. Source: https://ipvolt.com/proxies Markdown: https://ipvolt.com/proxies.md [Home](https://ipvolt.com/index.md) / Proxies ipvolt · By country 14 country pages. 11 are for countries where ipvolt sells mobile proxies, with carriers, prices and checkout links; 3 are research pages for countries where it doesn't. Choose the IP location your test needs, keep browser and delivery inputs separate, and turn network or session requirements into an acceptance check. ipvolt sells mobile proxies in 11 countries: Germany, USA, UK, France, Netherlands, Poland, Singapore, New Zealand, Georgia, Australia and Italy. It doesn't sell mobile proxies in Brazil, Portugal and Canada today. Residential proxies are on sale from $2.20/GB; the dashboard lists the countries available now. ## Pick a country page. Choose the country whose storefront, search results or ads you need to check. Write down the page or endpoint you will test, the expected behavior and whether country-level location meets the task. Country recognition, a specific city and a particular network are separate requirements. ## Choose a country - [Germany proxies](https://ipvolt.com/proxies/germany.md): Germany proxies: use cases and mobile carriers. Build a German web-testing workflow for ecommerce, search results, ad landing pages and regional sites. Price monitoring, local SEO, regional ads and storefront redirects, plus a carrier table for turning a network name into a requirement. Guide: [Germany location guide](https://ipvolt.com/guides/germany-proxies.md) - [USA proxies](https://ipvolt.com/proxies/usa.md): USA proxies: retail location and delivery checks. Plan US retail monitoring around the stores, addresses and delivery methods your customers use. Walmart and Target examples separate the US exit from the delivery destination: fulfillment mode, store range and Alaska or Hawaii shipping. Guide: [USA location guide](https://ipvolt.com/guides/usa-proxies.md) - [UK proxies](https://ipvolt.com/proxies/uk.md): UK proxies: mobile proxies on Three. Buy a dedicated UK mobile proxy on Three. The page lists the 1-day and 30-day prices with a link to checkout for each, three things to test from the UK, what a rental includes and a cURL and Python snippet. Guide: [UK location guide](https://ipvolt.com/guides/uk-proxies.md) - [France proxies](https://ipvolt.com/proxies/france.md): France proxies: mobile proxies on SFR and Free. Buy a dedicated French mobile proxy on SFR and Free. The page lists the 1-day and 30-day prices with a link to checkout for each, three things to test from France, what a rental includes and a cURL and Python snippet. Guide: [France location guide](https://ipvolt.com/guides/france-proxies.md) - [Netherlands proxies](https://ipvolt.com/proxies/netherlands.md): Netherlands proxies: storefront and delivery checks. Plan Dutch ecommerce checks around the right storefront, delivery postcode and collection options. Coolblue and bol examples show why edition, delivery postcode and collection eligibility are settled before the exit changes. Guide: [Netherlands location guide](https://ipvolt.com/guides/netherlands-proxies.md) - [Poland proxies](https://ipvolt.com/proxies/poland.md): Poland proxies: mobile proxies on Play. Buy a dedicated Polish mobile proxy on Play. The page lists the 1-day and 30-day prices with a link to checkout for each, three things to test from Poland, what a rental includes and a cURL and Python snippet. - [Singapore proxies](https://ipvolt.com/proxies/singapore.md): Singapore proxies: mobile proxies on Singtel and M1. Buy a dedicated Singapore mobile proxy on Singtel and M1. The page lists the 1-day and 30-day prices with a link to checkout for each, three things to test from Singapore, what a rental includes and a cURL and Python snippet. - [New Zealand proxies](https://ipvolt.com/proxies/new-zealand.md): New Zealand proxies: mobile proxies on One NZ. Buy a dedicated New Zealand mobile proxy on One NZ. The page lists the 1-day and 30-day prices with a link to checkout for each, three things to test from New Zealand, what a rental includes and a cURL and Python snippet. - [Georgia proxies](https://ipvolt.com/proxies/georgia.md): Georgia proxies: mobile proxies on Magti. Buy a dedicated Georgian mobile proxy on Magti. The page lists the 1-day and 30-day prices with a link to checkout for each, three things to test from Georgia, what a rental includes and a cURL and Python snippet. - [Australia proxies](https://ipvolt.com/proxies/australia.md): Australia proxies: mobile proxies on Vodafone. Buy a dedicated Australian mobile proxy on Vodafone. The page lists the 1-day and 30-day prices with a link to checkout for each, three things to test from Australia, what a rental includes and a cURL and Python snippet. Guide: [Australia location guide](https://ipvolt.com/guides/australia-proxies.md) - [Italy proxies](https://ipvolt.com/proxies/italy.md): Italy proxies: mobile proxies on WindTre. Buy a dedicated Italian mobile proxy on WindTre. The page lists the 1-day and 30-day prices with a link to checkout for each, three things to test from Italy, what a rental includes and a cURL and Python snippet. - [Brazil proxies](https://ipvolt.com/proxies/brazil.md): Brazil proxies: CEP, store locator and carrier checks. Read Vivo, Claro, TIM and Algar labels against Anatel's operator list before you test an exit. At Americanas and Shopee Brasil the customer supplies the CEP, and Magazine Luiza keeps a store list for each of the 27 federative units, so those inputs stay fixed while only the exit changes. Guide: [Brazil location guide](https://ipvolt.com/guides/brazil-proxies.md) - [Portugal proxies](https://ipvolt.com/proxies/portugal.md): Portugal proxies: delivery, search and checkout tests. Continente Online sets the delivery area from a typed postcode, and Amazon.es offers Premium delivery to Portugal only where the postcode qualifies. MB WAY, MULTIBANCO and the NIF field are checked on your own pt-PT checkout, and Google results are logged with the location Google reports. Guide: [Portugal location guide](https://ipvolt.com/guides/portugal-proxies.md) - [Canada proxies](https://ipvolt.com/proxies/canada.md): Canada proxies: localization and mobile network checks. Build Canadian storefront, language, delivery and carrier-testing workflows. Read Bell, Rogers, TELUS and Videotron/Freedom labels at the right network layer, then choose a practical location check. Guide: [Canada location guide](https://ipvolt.com/guides/canada-proxies.md) ## Researching another country? ipvolt doesn't sell mobile proxies in Japan today. Guides for more countries: [UK proxy guide](/guides/uk-proxies), [France proxy guide](/guides/france-proxies) and [Japan proxy guide](/guides/japan-proxies). Explore the full collection at [Country proxy guides](/guides/countries). ## Set up your first check. ### Establish the route first Use one documented proxy configuration and an authorized diagnostic destination before opening a retailer page or a shopping journey. [Set up curl](/guides/curl-proxy-setup) ### Hold browser settings steady Keep locale, time zone, cookies and account state consistent, so a new browser context does not become an unexplained second change. [Set up Playwright](/guides/playwright-proxy-setup) ### Keep the session consistent Decide whether the public exit IP may change between jobs or must stay the same through a multi-step visit, and check the provider’s documented session behavior before relying on continuity. [Compare rotating and sticky sessions](/guides/rotating-vs-sticky-proxies) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [See which countries and carriers are on sale.](https://ipvolt.com/pricing) [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 40 of 138: Germany mobile proxies. URL: https://ipvolt.com/proxies/germany Markdown: https://ipvolt.com/proxies/germany.md # Germany mobile proxies. Source: https://ipvolt.com/proxies/germany Markdown: https://ipvolt.com/proxies/germany.md [Home](https://ipvolt.com/index.md) / Germany proxies Germany · Mobile proxies on sale Dedicated mobile proxies on German carrier networks: one device and SIM per proxy, with HTTP and SOCKS5 and IP rotation on demand. Rent one for a day to test your workflow, or for 30 days. Compare carriers and prices, then choose your test settings. [Mobile proxies in Germany on O2 from $9 a day](https://ipvolt.com/dashboard/mobile?country=DE&plan=day&carrier=O2) Residential proxies from $2.20/GB, in prepaid packs. Country selection, HTTP and SOCKS5, sticky or rotating sessions. [Buy residential](https://ipvolt.com/dashboard/residential) ## What ipvolt sells ### Mobile proxies in Germany from $9 a day. Residential proxies from $2.20/GB, in prepaid packs. [Pricing and payments](https://ipvolt.com/pricing) ## Germany proxy use cases. Choose your use case Start with the location, access type and session behavior your test needs. Then use the workflows below to control inputs and record results. Choose your Germany proxy test | Your task | Choose first | What to verify | | --- | --- | --- | | German prices or localization | A German exit, with language, currency and delivery settings held fixed. | The exit location and the region, currency and delivery options the page actually shows. | | Mobile or fixed residential access | 4G/5G or fixed DSL, cable or fiber. Name a carrier when the test requires one. | Evidence of the access type and carrier, separately from the exit IP’s routing network. | | A multi-step session | A sticky session for the required duration, or rotation between separate jobs. | The exit IP at each step and after any requested rotation. | | A Berlin or Frankfurt check | The city as a separate requirement from the country. | A named geolocation source and the location reported by the application. | ### German ecommerce price monitoring Compare a product on idealo.de and its retailer page using a German exit. idealo’s stated delivery times refer to Germany unless noted otherwise, and its offers include an update timestamp. **Keep fixed:** Use the same product variant, seller and German delivery postcode. Keep language, currency selection and signed-in state consistent. **Record:** Displayed currency, item price, shipping charge, availability, delivery estimate and capture time. Keep idealo’s offer-update time alongside your own observation. Separate a changed offer from a changed delivery context. Set the delivery postcode in the shop; the proxy supplies the network viewpoint. [idealo: offer updates and delivery to Germany](https://www.idealo.de/legal/hinweis) [Validate price and currency together](https://ipvolt.com/blog/product-price-currency-validation) ### German search results and local SEO Review a German query such as “Laufschuhe kaufen” from a German exit. Google uses IP, device location and previous activity among its location signals; record the location shown beneath the results. **Keep fixed:** Query, search language, device, account state, location permission and session history. **Record:** Result URLs, visible result features, the reported location and the time of the check. Treat a Berlin-specific search as a separate location requirement. Build a documented German search snapshot. One exit does not represent every searcher in Germany. [Google: how Search determines location](https://support.google.com/websearch/answer/179386?co=GENIE.Platform%3DDesktop&hl=en) [Define country and city checks](https://ipvolt.com/guides/germany-proxies) ### Germany-targeted ads and regional offers Use Google’s Ad Preview for your search-ad appearance, then open your own landing URL directly through a German exit to inspect the destination. For Merchant Center regional offers, Germany supports postcode-based regions. **Keep fixed:** The product, campaign landing URL and configured region_id. Google requires the regional offer to survive cookies, previous visits and IP detection. **Record:** Redirects, the final URL, displayed price and availability against your regional product data. Check the national URL separately. Find a regional landing-page mismatch; use account diagnostics to assess ad delivery. [Google Ads: preview without adding impressions](https://support.google.com/google-ads/answer/148778?hl=en-GB) · [Merchant Center: regions and landing-page rules](https://support.google.com/merchants/answer/16786149?hl=en) [Set up a controlled browser check](https://ipvolt.com/guides/playwright-proxy-setup) ### German storefront localization and redirects Test your own German storefront alongside its Austrian or Swiss editions. A German-language preference alone does not select Germany: W3C distinguishes de-DE, de-AT and de-CH, and advises keeping regional settings explicit. **Change one input:** Keep de-DE fixed while comparing German and Austrian exits. Then keep the German exit fixed while changing only the browser locale to de-AT or de-CH. **Record:** The redirect chain, final page, language, currency and delivery selection. Start each comparison with the same cookie state and time zone. Check that visitors can still select your German, Austrian or Swiss edition when network and language settings differ. [W3C: language preferences versus locale](https://www.w3.org/International/questions/qa-accept-lang-locales) · [Playwright: locale and time zone](https://playwright.dev/docs/emulation#locale--timezone) [Set up browser proxy routing](https://ipvolt.com/guides/playwright-proxy-setup) ## Mobile proxy carriers in Germany. Understand the network Telekom, Vodafone, Telefónica/O2 and 1&1 are the four operators in the Bundesnetzagentur’s mobile subscriber table. Use this map to turn a carrier name into a clear requirement for your German proxy workflow. It's a map of Germany's networks, not a list of what ipvolt sells; checkout shows the carriers in stock. German mobile networks and the proxy checks they call for | Network name | What the name means | What to specify | | --- | --- | --- | | Telekom / D1 | D1 is the older network name associated with Telekom in the regulator’s records. [Bundesnetzagentur: mobile operators](https://www.bundesnetzagentur.de/DE/Fachthemen/Telekommunikation/Marktdaten/Mobilfunkteilnehmer/start.html) | Use Telekom in your carrier brief. State whether you need cellular access and which network evidence must accompany a sample. | | Vodafone / D2 | The regulator maps D2 to Vodafone. 1&1 names Vodafone as its national-roaming partner. [Bundesnetzagentur: mobile operators](https://www.bundesnetzagentur.de/DE/Fachthemen/Telekommunikation/Marktdaten/Mobilfunkteilnehmer/start.html) · [1&1: network and roaming FAQ](https://mobile.1und1.de/netzcheck) | Separate a Vodafone home-network requirement from a connection carried over Vodafone through roaming. | | O2 / Telefónica | O2 is associated with Telefónica Germany. Telefónica lists O2 home products spanning fixed broadband and 4G/5G access. [Bundesnetzagentur: mobile operators](https://www.bundesnetzagentur.de/DE/Fachthemen/Telekommunikation/Marktdaten/Mobilfunkteilnehmer/start.html) · [Telefónica: O2 access technologies](https://www.telefonica.de/network/fixed-network.html) | Specify mobile access when it matters. An O2 brand or home-internet label alone does not establish a cellular connection. | | 1&1 | 1&1 operates its own mobile network. Its network FAQ names Vodafone as the national-roaming partner where its own coverage is unavailable. [Bundesnetzagentur: mobile operators](https://www.bundesnetzagentur.de/DE/Fachthemen/Telekommunikation/Marktdaten/Mobilfunkteilnehmer/start.html) · [1&1: network and roaming FAQ](https://mobile.1und1.de/netzcheck) | Distinguish the SIM’s home operator, the serving radio network and the internet egress. Record the layer your carrier selection is meant to control. | An autonomous system number (ASN) identifies an internet routing network; it does not by itself identify the radio network carrying a particular connection. Keep carrier selection and observed exit-IP evidence in separate fields. ## Germany mobile proxies: what to compare. Choose the access model Use these checks to compare the access and session requirements you chose above. ### 4G and 5G proxies 4G/LTE and 5G describe cellular access technology. An IP-network lookup reports routing information, not the radio connection used by a modem. Ask how the access technology is documented and test the complete workflow. [IETF: 5G system architecture](https://www.rfc-editor.org/rfc/rfc9913.html#section-6.4.1) · [RIPE NCC: IP-network lookup scope](https://stat.ripe.net/docs/data-api/api-endpoints/network-info) ### Mobile versus fixed residential For a fixed residential requirement, name DSL, cable or fiber explicitly. Telefónica’s O2 portfolio also includes home internet over 4G/5G, showing why a connection used at home can still be cellular. [Telefónica: O2 access technologies](https://www.telefonica.de/network/fixed-network.html) ### Rotating or sticky sessions Decide whether the public exit IP may change between jobs or must stay the same through a multi-step visit. Record the required duration and compare the observed IP before and after the workflow. A dynamic address does not establish a particular rotation interval. [O2: public IPv4 explained](https://hilfe.o2online.de/o2-mobilfunknetz-einstellungen-zur-telefonie-129/oeffentliche-ipv4-adresse-was-solltest-du-beachten-672707) ### Dedicated access and shared IPs Ask what is dedicated: the modem or SIM, the proxy endpoint, or the public IP address. Carrier-grade NAT can let several subscribers share a public IPv4 address. A dedicated device therefore does not, by itself, establish exclusive public-IP use. [IETF: shared public IPv4](https://www.rfc-editor.org/rfc/rfc6888.html#section-1) [Compare mobile and residential proxy requirements](https://ipvolt.com/guides/mobile-vs-residential-proxies) ## Set up your first check. A practical starting point ### Define the location Write down the German page or endpoint, the expected behavior and whether country-level location meets the task. [Germany location guide](https://ipvolt.com/guides/germany-proxies) ### Choose your client Use a small command-line request or your existing Python workflow to establish a repeatable baseline. [Set up curl](https://ipvolt.com/guides/curl-proxy-setup) ### Control the browser Keep locale, time zone and session settings explicit when you test browser-based regional behavior. [Set up Playwright](https://ipvolt.com/guides/playwright-proxy-setup) ## Choose the right German network and location checks. Go deeper Our Germany guide covers local network names, city-level requirements, browser context and a practical verification process. [Read the Germany proxy guide](https://ipvolt.com/guides/germany-proxies) ## A clearer starting point. Questions ### What is a Germany proxy? A Germany proxy routes a request through an exit IP address recognized as German by the service you are using. Country recognition, a specific city and a particular network are separate requirements. ### Do I need a German browser profile? Set language, time zone, currency and delivery address to match the behavior you are testing. Keep those settings explicit and check them separately from the exit country. ### How much does a German mobile proxy cost? A dedicated German mobile proxy starts at $9 for one day and at $119 for 30 days, on O2, Vodafone and 1&1. Add funds with crypto and buy from your dashboard; nothing renews automatically. Checkout shows the live price and every carrier in stock. ### Which carrier should I choose for Germany mobile proxies? For a country-only storefront check, a named carrier may be unnecessary. For a network-specific issue, specify Telekom, Vodafone, O2/Telefónica or 1&1 and identify whether you need the SIM home operator, radio network or internet egress. Use the carrier table to define that requirement. Checkout shows the carriers in stock. ### Does 5G mean a faster or more reliable proxy? The 5G label describes access technology. It does not establish end-to-end proxy latency, website compatibility or session behavior. Compare completed tasks, response time and failures for your own workflow under the same test conditions. ### Can a German mobile proxy target Berlin or Frankfurt? Treat a city requirement separately from Germany country recognition and carrier selection. Define the location source used by your application and check the returned result. For a store locator, test an explicit city input separately from its IP-based default. ### Does a dedicated SIM give me a dedicated public IP? Not necessarily. A device can have its own SIM while sharing a public IPv4 address through carrier-grade NAT. Ask whether the offer dedicates a device, an endpoint or the public address, and whether that address is dynamic. ## Bring your next project to ipvolt. Mobile proxies in Germany are on sale now. Residential proxies are on sale from $2.20/GB. [Mobile proxies in Germany on O2 from $9 a day](https://ipvolt.com/dashboard/mobile?country=DE&plan=day&carrier=O2) [Buy residential](https://ipvolt.com/dashboard/residential) ## Workflow references - [RIPE NCC: IP-network lookup scope](https://stat.ripe.net/docs/data-api/api-endpoints/network-info) - [W3C: language preferences and locale](https://www.w3.org/International/questions/qa-accept-lang-locales) - [Playwright: locale and time zone emulation](https://playwright.dev/docs/emulation#locale--timezone) --- Document 41 of 138: USA proxies. URL: https://ipvolt.com/proxies/usa Markdown: https://ipvolt.com/proxies/usa.md # USA proxies. Source: https://ipvolt.com/proxies/usa Markdown: https://ipvolt.com/proxies/usa.md [Home](https://ipvolt.com/index.md) / USA proxies USA · Mobile proxies on sale Plan US retail monitoring around the stores, addresses and delivery methods your customers use. Choose the right location and network requirements. [Mobile proxies in the United States on AT&T from $17 a day](https://ipvolt.com/dashboard/mobile?country=US&plan=day&carrier=AT%26T) Residential proxies from $2.20/GB, in prepaid packs. Country selection, HTTP and SOCKS5, sticky or rotating sessions. [Buy residential](https://ipvolt.com/dashboard/residential) ## What ipvolt sells ### Mobile proxies in the United States from $17 a day. Residential proxies from $2.20/GB, in prepaid packs. [Pricing and payments](https://ipvolt.com/pricing) ## Separate the US exit from the delivery destination. Choose the retail question Choose the question your storefront check needs to answer. Keep the product and customer settings consistent, then change one location input at a time. Choose your USA proxy test | Your task | Choose first | What to verify | | --- | --- | --- | | Pickup, delivery or shipping availability | The fulfillment mode your customer uses, with product, seller, store and address held fixed. | The selected mode, item availability and delivery estimate, with the observation time. | | A store in range for an address | The delivery address and store on the site itself, before any change of exit. | Whether a store is offered for delivery and which store is selected. | | Shipping to Alaska or Hawaii | An explicit Alaska or Hawaii address case, separate from mainland cases. | The item restriction, shipping eligibility and estimated arrival shown for each destination. | | A state, metro or carrier requirement | A country-level US exit first. Add a state, metro or named network only for a documented network-location behavior, and say whether mobile or home access matters. | Evidence for the supplied exit and its access type. A coverage map is not an exit sample. | ### Is the item unavailable, or is the delivery mode different? Walmart separates pickup, delivery from a store and parcel shipping. An item that supports one mode may not support another. Start by choosing the mode your customer needs before comparing the page through a US exit. **Keep fixed:** Product variant, seller, selected store, address, account state and fulfillment mode. Reuse the same page and session settings when changing the exit. **Inspect:** Which mode is selected, item availability, delivery estimate and observation time. Save unavailable results too; do not combine different modes into one stock count. If an item is available for shipping but not local delivery, record that as a fulfillment difference. It does not, by itself, show that the proxy failed. [Walmart: pickup, delivery and shipping](https://www.walmart.com/help/article/the-walmart-site-and-app-experience/27f2678cb25a40a7b57a359fec3ca67f) ### Does the selected address have a store in range? For Walmart delivery, the entered address determines which stores are shown in range. Its help directs customers toward shipping or pickup when no stores are listed. This is a different question from whether a request has a US source address. **Keep fixed:** One authorized delivery address and the same basket. Compare local delivery with a separate pickup or shipping case, clearly labeled as a changed input. **Inspect:** Whether a store is offered for delivery, which store is selected and whether an alternative fulfillment mode remains available. Keep the selected store in the result record. Check the address and store selection first. Only escalate to a more precise exit location when your actual application requirement depends on the network location. [Walmart: pickup, delivery and shipping](https://www.walmart.com/help/article/the-walmart-site-and-app-experience/27f2678cb25a40a7b57a359fec3ca67f) ### Does nationwide include Alaska and Hawaii? Target says many items ship to all 50 states, while Alaska and Hawaii have item restrictions, including some heavy, oversized and direct-manufacturer items. Its item descriptions identify restrictions; estimated delivery dates depend on availability and the shipping address. **Keep fixed:** Exact item and variant, seller, shipping method and session state. Change the authorized destination address as its own test; keep an exit-location comparison separate. **Inspect:** The item restriction, shipping eligibility and estimated arrival shown for each destination. Label an ineligible item separately from a transport or page-loading failure. When those destinations matter, add explicit Alaska or Hawaii address cases. A successful mainland case cannot answer an address-specific restriction elsewhere in the US. [Target: shipping restrictions and delivery estimates](https://www.target.com/help/articles/delivery-options/ship-to-home) ### Which location requirement should you buy? Use the preceding results to write a narrow requirement. A US storefront check starts at country level. A selected-store or shipping-address question first needs the corresponding site settings. Add a state or metro requirement only for a documented network-location behavior. **Keep fixed:** The same product, site edition, address, store, fulfillment method and signed-in state across an exit comparison. Start with a small permitted check. **Inspect:** A separate outcome for page loading, regional content and fulfillment eligibility. Record the final URL and the changed input so a regional mismatch has a reproducible explanation. Example decision: if changing the delivery address removes a shipping option while the exit stays fixed, investigate delivery eligibility. If the same address and session produce a different regional page after only the exit changes, investigate that network-location behavior. [Walmart: pickup, delivery and shipping](https://www.walmart.com/help/article/the-walmart-site-and-app-experience/27f2678cb25a40a7b57a359fec3ca67f) · [Target: shipping restrictions and delivery estimates](https://www.target.com/help/articles/delivery-options/ship-to-home) ## US network names need a precise requirement. Specify the access type AT&T, Verizon and T-Mobile publish mobile coverage maps. These are examples for a network brief, not a list of ipvolt inventory. Retail coverage does not establish a seller’s proxy location or access. Network context to discuss with a provider | Network | Published context | Useful requirement | | --- | --- | --- | | AT&T | Its wireless map describes approximate outdoor coverage. [AT&T: wireless coverage map](https://www.att.com/maps/wireless-coverage.html) | Request evidence for the supplied exit and required access type; a map pin is not an exit sample. | | Verizon | Verizon distinguishes mobile service, fiber-based Fios and cellular 5G Home Internet. [Verizon: mobile and home coverage](https://www.verizon.com/coverage-map/) | Specify whether mobile or home access matters. The Verizon name alone leaves that distinction unanswered. | | T-Mobile | It publishes a mobile coverage map. [T-Mobile: mobile coverage map](https://www.t-mobile.com/coverage/coverage-map) | Ask whether the offered route meets your country or regional requirement; do not infer city targeting from retail coverage. | ## Prepare the route, then the storefront. Make the comparison repeatable ### Verify a single request Use your provider’s documented gateway and an authorized diagnostic destination. Establish routing before interpreting a retailer response. [Set up curl with a proxy](https://ipvolt.com/guides/curl-proxy-setup) ### Hold browser settings steady Keep cookies, language and account state consistent so a new browser context does not become an unexplained second change. [Set up a browser comparison](https://ipvolt.com/guides/playwright-proxy-setup) ## Need to verify a US exit? Technical evaluation Use the separate USA guide for country, state and city evidence, network identity and a bounded provider evaluation. Keep those observations alongside your storefront results. [Read the USA proxy evaluation guide](https://ipvolt.com/guides/usa-proxies) ## A clearer starting point. Questions ### Do I need a city proxy to check a selected US store? Start by setting the actual store and destination on the site. A city-level exit is a separate requirement when your application uses network location at that level. Define the behavior you need to verify before paying for a finer location selector. ### Can a US proxy remove an Alaska or Hawaii shipping restriction? Treat shipping eligibility as an item-and-destination question. The Target example above shows why a US network viewpoint is not enough to establish that a particular order can ship to either state. ### Are ipvolt USA proxies available now? Yes, mobile proxies. ipvolt sells mobile proxies in the United States, rented for 1 day or 30 days; checkout shows the live price and every carrier in stock. Residential proxies are on sale from $2.20/GB. ## Planning a US proxy workflow? Mobile proxies in the United States are on sale now. Residential proxies are on sale from $2.20/GB. [Mobile proxies in the United States on AT&T from $17 a day](https://ipvolt.com/dashboard/mobile?country=US&plan=day&carrier=AT%26T) [Buy residential](https://ipvolt.com/dashboard/residential) ## Workflow references - [Walmart: pickup, delivery and shipping](https://www.walmart.com/help/article/the-walmart-site-and-app-experience/27f2678cb25a40a7b57a359fec3ca67f) - [Target: shipping restrictions and delivery estimates](https://www.target.com/help/articles/delivery-options/ship-to-home) - [AT&T: wireless coverage map](https://www.att.com/maps/wireless-coverage.html) - [Verizon: mobile and home coverage](https://www.verizon.com/coverage-map/) - [T-Mobile: mobile coverage map](https://www.t-mobile.com/coverage/coverage-map) --- Document 42 of 138: Netherlands proxies. URL: https://ipvolt.com/proxies/netherlands Markdown: https://ipvolt.com/proxies/netherlands.md # Netherlands proxies. Source: https://ipvolt.com/proxies/netherlands Markdown: https://ipvolt.com/proxies/netherlands.md [Home](https://ipvolt.com/index.md) / Netherlands proxies Netherlands · Mobile proxies on sale Plan Dutch ecommerce checks around the right storefront, delivery postcode and collection options. Define your Netherlands location and network requirements. [Mobile proxies in the Netherlands on Vodafone from $9 a day](https://ipvolt.com/dashboard/mobile?country=NL&plan=day&carrier=Vodafone%20NL) Residential proxies from $2.20/GB, in prepaid packs. Country selection, HTTP and SOCKS5, sticky or rotating sessions. [Buy residential](https://ipvolt.com/dashboard/residential) ## What ipvolt sells ### Mobile proxies in the Netherlands from $9 a day. Residential proxies from $2.20/GB, in prepaid packs. [Pricing and payments](https://ipvolt.com/pricing) ## Match the Dutch storefront to the delivery journey. Choose the customer journey Check the country edition, delivery options and network viewpoint separately. Each comparison below gives you the customer settings to keep fixed and the result to investigate next. Choose your Netherlands proxy test | Your task | Choose first | What to verify | | --- | --- | --- | | The Dutch or the Belgian storefront | The website and destination pair: the Dutch edition with a Netherlands destination. | The hostname, selected delivery country and final URL, including any automatic redirect. | | A missing delivery option | The item and delivery postcode, held fixed before any change of exit. | Which options appear for the same order and destination, and when you checked. | | Collection-point eligibility | The same item, seller and basket, because collection depends on the order. | Whether collection is offered, and any eligibility message shown. | | An Amsterdam or named-network requirement | A Netherlands country requirement first. Add Amsterdam or a named network as a separate requirement, and say whether you mean mobile or home access. | Location evidence for the exit and the access type behind it. A brand name alone leaves both open. | ### Is this the Netherlands or Belgium storefront? Coolblue says orders on Coolblue.nl are delivered in the Netherlands, while Coolblue.be serves Belgium. You cannot order on its Dutch site for delivery in Belgium. Both markets can involve Dutch-language pages, so record the edition explicitly. **Keep fixed:** Product variant and language. Pair the Dutch edition with a Netherlands destination; make the Belgian edition and destination a separate case. **Inspect:** The website hostname, selected delivery country and final URL. If an automatic redirect occurs, record it before changing cookies, locale or exit location. Start with the website and destination pair. Changing an exit address is not a remedy for choosing the wrong ordering site. [Coolblue: delivery country and collection](https://www.coolblue.be/nl/klantenservice/leverings-en-ophaalopties) ### Why is the delivery option missing? bol shows extra delivery options per item while ordering, and some options are unavailable in certain postcode areas. Keep the delivery postcode visible in your comparison record before interpreting an absent option as a network problem. **Keep fixed:** The item, seller, delivery address, quantity and account state. Compare another postcode only as a separately labeled change. **Inspect:** Which options appear for the same order and destination, and when you checked. Keep an unavailable option distinct from an error loading the page. Check the postcode and item eligibility first. An Amsterdam exit label cannot establish delivery-slot availability for a particular order. [bol: delivery options and collection points](https://www.bol.com/nl/nl/klantenservice/info/blt59015a4311d01e18/bezorgen-en-ontvangen) ### Can this order use a collection point? bol says that when the collection-point option is absent, the order cannot use it. Large or heavy items and partner items are examples for which collection is not always possible. A pickup comparison therefore needs the same item and seller. **Keep fixed:** Product variant, seller, destination and basket contents. Use a separate case for a different item size or seller. **Inspect:** Whether collection is offered, the selected collection point if available, and any eligibility message. Record absence as an outcome rather than inventing a delivery estimate. Resolve the order’s collection eligibility before changing the proxy. If comparing sellers, label that change rather than interpreting the result as an IP effect. [bol: delivery options and collection points](https://www.bol.com/nl/nl/klantenservice/info/blt59015a4311d01e18/bezorgen-en-ontvangen) ### Which issue belongs in the proxy requirement? After checking edition and fulfillment settings, compare your own storefront with the same session through the required network viewpoint. Keep a Netherlands country requirement separate from Amsterdam targeting or a named access network. **Keep fixed:** The exact URL, locale, cookies, account state and destination settings. Change only the exit in the network comparison. **Inspect:** The final country edition, visible delivery settings and application outcome. A country match with an unexplained city result calls for location evidence, not an assumed Amsterdam guarantee. Use three destinations for the investigation: wrong edition goes to site selection; missing delivery or pickup goes to order eligibility; changed regional behavior with everything else held fixed goes to a network-location check. ## Dutch mobile network context. Turn a carrier name into a requirement RDI names KPN, Odido and VodafoneZiggo as the three Dutch mobile network operators. Use the distinctions below when describing a route. None of these public network facts confirms a proxy seller’s access. Dutch network names and the question to ask | Network name | Relevant distinction | Ask the provider | | --- | --- | --- | | KPN | KPN operates mobile and fixed networks. In July 2026 it announced home internet using an integrated SIM and its 5G network. [RDI: Dutch mobile network operators](https://www.rdi.nl/onderwerpen/telecommunicatie/telecomaanbieders/dekkingseis-en-snelheidsverplichting) · [KPN: mobile and fixed networks](https://www.overons.kpn/en/kpn-in-the-netherlands/our-network) · [KPN: 5G for home internet](https://www.overons.kpn/nieuws/en/kpn-is-now-also-deploying-5g-for-home-internet/) | Is this wired broadband or cellular access? A home-internet label alone does not settle the technology behind the exit. | | Odido | T-Mobile Netherlands and Tele2 mobiel became Odido in 2023. [Odido: T-Mobile Netherlands and Tele2 mobiel rebrand](https://newsroom.odido.nl/en-us/t-mobile-netherlands-becomes-odido/) | If an offer uses an older brand name, how does it map to the current network and requested access type? | | Vodafone / VodafoneZiggo | VodafoneZiggo describes its fixed and mobile networks separately. [VodafoneZiggo: fixed and mobile network context](https://www.vodafoneziggo.nl/en/nieuws/integrated-annual-report-2025-vodafoneziggo-is-committed-to-growth-with-a-strong-focus-on-customers-and-connectivity/) | Does the offer mean Vodafone mobile access, home access or only an IP organization label? | ## Make each changed input visible. Prepare a controlled comparison ### Establish the route first Use one documented proxy configuration and an authorized diagnostic destination before opening a more complex shopping journey. [Set up a proxy request](https://ipvolt.com/guides/curl-proxy-setup) ### Keep the shopping session consistent Separate intentional session resets from the exit comparison. Check the provider’s documented session behavior before relying on continuity. [Compare rotating and sticky sessions](https://ipvolt.com/guides/rotating-vs-sticky-proxies) ## Verify Netherlands, network and city separately. Technical evaluation The existing technical guide explains destination-observed IPs, RIPE routing evidence, location uncertainty and bounded trials. Use it when the unresolved question is the route itself. [Read the Netherlands proxy evaluation guide](https://ipvolt.com/guides/netherlands-proxies) ## A clearer starting point. Questions ### Does a Netherlands proxy select the right Dutch shop? Record the actual country edition and destination settings. The Coolblue example above ties delivery country to the ordering website; a Dutch-language page alone does not establish Netherlands delivery. ### Do I need an Amsterdam exit to check Dutch delivery? Start with the actual delivery address and the shop’s eligibility rules. Define Amsterdam as a separate network-location requirement only when your application needs that distinction. Country selection alone does not establish a city guarantee. ### Does a Dutch telecom name prove mobile access? Specify the required access type and ask for evidence about the offered route. The network table shows why a brand or group name alone can leave mobile and home access unresolved. ### Can I get Netherlands proxies from ipvolt today? Yes, mobile proxies. ipvolt sells mobile proxies in the Netherlands, rented for 1 day or 30 days; checkout shows the live price and every carrier in stock. Residential proxies are on sale from $2.20/GB. ## Planning a Dutch storefront workflow? Mobile proxies in the Netherlands are on sale now. Residential proxies are on sale from $2.20/GB. [Mobile proxies in the Netherlands on Vodafone from $9 a day](https://ipvolt.com/dashboard/mobile?country=NL&plan=day&carrier=Vodafone%20NL) [Buy residential](https://ipvolt.com/dashboard/residential) ## Workflow references - [Coolblue: delivery country and collection](https://www.coolblue.be/nl/klantenservice/leverings-en-ophaalopties) - [bol: delivery options and collection points](https://www.bol.com/nl/nl/klantenservice/info/blt59015a4311d01e18/bezorgen-en-ontvangen) - [RDI: Dutch mobile network operators](https://www.rdi.nl/onderwerpen/telecommunicatie/telecomaanbieders/dekkingseis-en-snelheidsverplichting) - [KPN: mobile and fixed networks](https://www.overons.kpn/en/kpn-in-the-netherlands/our-network) - [Odido: T-Mobile Netherlands and Tele2 mobiel rebrand](https://newsroom.odido.nl/en-us/t-mobile-netherlands-becomes-odido/) - [VodafoneZiggo: fixed and mobile network context](https://www.vodafoneziggo.nl/en/nieuws/integrated-annual-report-2025-vodafoneziggo-is-committed-to-growth-with-a-strong-focus-on-customers-and-connectivity/) --- Document 43 of 138: Brazil proxies. URL: https://ipvolt.com/proxies/brazil Markdown: https://ipvolt.com/proxies/brazil.md # Brazil proxies. Source: https://ipvolt.com/proxies/brazil Markdown: https://ipvolt.com/proxies/brazil.md [Home](https://ipvolt.com/index.md) / Brazil proxies Brazil · Mobile proxies not on sale A Brazilian exit can settle the country a site sees; the CEP, the CPF and the pt-BR setting still come from the customer. Decide which of them your test depends on. Mobile proxies aren't available in Brazil yet. [Residential proxies: countries, setup and questions](https://ipvolt.com/residential-proxies) Residential proxies from $2.20/GB, in prepaid packs. Country selection, HTTP and SOCKS5, sticky or rotating sessions. [Buy residential](https://ipvolt.com/dashboard/residential) ## What ipvolt sells ### ipvolt doesn't sell mobile proxies in Brazil today. Residential proxies are on sale from $2.20/GB. The dashboard lists the countries available now. [Pricing and payments](https://ipvolt.com/pricing) ## Four Brazilian checks, one variable at a time. Pick a Brazilian check Americanas and Shopee Brasil both work from the CEP a customer types, so fix the CEP, state and language before anything else. Limit proxied checks to your own service, authorized destinations, or a storefront's public, signed-out pages as its terms permit, by hand and at low volume; create no accounts, enter no personal or invented identity data such as a CPF, card or phone number, and place no orders. Bring in a Brazilian exit only when network location is the variable under test, and change one input at a time. Choose your Brazil proxy test | Your task | Choose first | What to verify | | --- | --- | --- | | Offers and shipping that follow the CEP | One approved CEP fixture, entered by hand and held fixed before you compare exits. | Offers, price, shipping charge and delivery estimate, with the CEP in use and the capture time. | | A store locator or a state-level check | The explicit state selection first. Bring in a Brazilian exit only when network location is the variable. | The store list for the chosen state, and the state a named geolocation service returns for the exit. | | pt-BR language and checkout fields | Your own or an authorized staging storefront, with pt-BR set in the browser. | The language served, the currency, whether the CPF field appears and the payment methods shown. | | A Vivo, Claro, TIM or Algar requirement | Mobile or fixed access, and the layer the label must fix: the subscription, the serving network or the exit. | The registry holder, the origin ASN and holder from a named lookup, and the address family, logged apart from the label. | ### CEP-driven regional offers and shipping Americanas uses the visitor's CEP to show offers for their region and to calculate shipping more precisely, and Shopee Brasil fills state, city and street from the CEP in its address form. Both take the CEP from the customer, so hold it fixed before you compare exits. **Keep fixed:** Product, seller, quantity, a signed-out session and one approved CEP fixture, entered by hand. A second CEP is a test case of its own, run and logged apart from any exit change. **Record:** Displayed offers, price, shipping charge, delivery estimate, the CEP in use and the capture time. If the CEP step asks you to sign in, stop and run the case on your own storefront. Separate an offer that changed with the CEP from one that changed with the exit. Only the second is a network-location finding. [Americanas: regional offers and shipping by CEP](https://www.americanas.com.br/especial/lojas-proximas-regras) · [Shopee Brasil: CEP auto-fill in the address form](https://help.shopee.com.br/portal/4/article/76400) [Check that each captured price is in BRL](https://ipvolt.com/blog/product-price-currency-validation) ### Store locators by state Magazine Luiza's store locator has a list for each federative unit, 27 from Lojas Acre to Lojas Tocantins, covering the 26 states and the Distrito Federal that IBGE calls the Unidades da Federação. Its “Localizando lojas próximo a você” message suggests it may also try to locate the visitor, which can come from the browser rather than the exit; the page does not document which. **Keep fixed:** The locator URL, browser language, time zone, cookie state and location permission (deny it, or set one emulated position and record it). Stay signed out. **Record:** Any default state or nearby-store list shown, the store list for the explicitly chosen state, and the exit's returned state from a named geolocation service. A state list with no stores is a result, not an error. Test the explicit state selection first. Then, if the locator shows a default, compare it for a Brazilian exit with no state chosen, and label a matching state as incidental unless the supplier documents state selection. [Magazine Luiza: store locator by state](https://lojas.magazineluiza.com.br/) · [IBGE: the 26 states and the Distrito Federal](https://www.ibge.gov.br/apps/quadrogeografico/pdf/qg_2024_020_UF.pdf) · [IBGE: Grandes Regiões and Unidades da Federação](https://www.ibge.gov.br/apps/quadrogeografico/pdf/qg_2024_010_GrandReg.pdf) [Write state and Distrito Federal pass conditions](https://ipvolt.com/guides/brazil-proxies) ### Google results in Brazil and your Shopping landing page Google said in April 2025 that local results had been the same on google.com and country domains since 2017, and that it would gradually redirect country-code domains such as google.com.br to google.com, so google.com.br may open google.com. Merchant Center lists Brazil as a target country with the Brazilian real (BRL) and the Shopping tab available. Google Ads is separate: location targeting is a best effort from signals such as settings, devices and behavior, and language targeting reads the search term and the user's settings, so an opened results page says nothing about whether a campaign served. **Keep fixed:** The query, the pt-BR interface language, a signed-out session, the device and location permission. Do not pin a country domain; google.com.br may redirect to google.com. **Record:** Capture time, final URL, result URLs and visible features, the location Google reports with the results, and the currency on your own landing page. Capture the results for one pt-BR query next to your own Shopping landing page in BRL, with the time. Whether a campaign served is a question for the Ads account, since opening a page records no impression. [Google: country-code domains redirected to google.com](https://blog.google/products/search/country-code-top-level-domains/) · [Google Ads: location targeting signals](https://support.google.com/google-ads/answer/1722043?hl=en) · [Google Ads: how language targeting reads the search term and settings](https://support.google.com/google-ads/answer/1722078?hl=en) · [Google Merchant Center: Brazil and BRL](https://support.google.com/merchants/answer/160637?hl=en) [Give each snapshot its own browser context](https://ipvolt.com/guides/playwright-proxy-setup) ### pt-BR checkout inputs on your own storefront Google's Play Console lists pt-BR and pt-PT as separate locales. If your storefront picks language from Accept-Language, a request through a Brazilian exit that sends pt-PT receives European Portuguese, which is a language-input result, not a network one. The CPF, administered by the Receita Federal, is unique and permanent for each citizen, so CPF tests belong on your own or an authorized staging storefront, never on a checkout you do not operate. **Two steps, one change each:** First keep the Brazilian exit fixed and switch only the browser language between pt-BR and pt-PT; then keep the language fixed and switch only the exit between Brazil and Portugal. **Record:** Language served, currency, whether the CPF field appears, payment methods shown, and the session identifier across the multi-step flow. Check that your own storefront renders pt-BR, shows the CPF field where you expect it and lists the payment options you configured, including Pix if you offer it. Test checkout fields only on your own or an authorized staging storefront with documented fixtures. [Google Play Console: pt-BR and pt-PT as separate languages](https://support.google.com/googleplay/android-developer/answer/9844778?hl=en) · [Receita Federal: the CPF, unique and permanent for each citizen](https://www.gov.br/receitafederal/pt-br/assuntos/meu-cpf) · [Banco Central do Brasil: Pix resolution](https://www.bcb.gov.br/content/estabilidadefinanceira/pix/Pix_Regulation/Resolution_BCB_1.pdf) [Keep one session through a checkout](https://ipvolt.com/guides/rotating-vs-sticky-proxies) ## Vivo, Claro, TIM and Algar: what each label means. Read Anatel's operator list Anatel, Brazil's telecom regulator, links to the coverage maps of Claro, TIM, Vivo, Algar and Sercomtel, and its Q2 2026 competition report counted 276.4 million mobile accesses. The rows turn four of those names into a requirement a supplier can answer. They are public facts about the operators, not evidence that ipvolt or any proxy provider can supply their networks. Four Brazilian operator labels and the layer each must name | Network name | What the name means | What to specify | | --- | --- | --- | | Vivo | The brand under which Telefônica Brasil, Telefónica's Brazilian operation, sells telecom and digital services. Telefónica calls Telefônica Brasil the leading integrated operator in the Brazilian market. [Telefónica: the Vivo brand and Telefônica Brasil](https://www.telefonica.com/en/about-us/countries-emerging-business-units/) · [NIC.br: responsibility for Brazilian IP and ASN resources under the LACNIC agreement](https://www.nic.br/pagina/nicbr-atividades-registro-br/159/) | Brazilian address space is registered through NIC.br (Registro.br). A Telefônica Brasil holder in that data is consistent with a Vivo selection, but it does not show whose antennas served the handset, so ask which layer the Vivo filter fixes. | | Claro | NET, Claro and Embratel are presented as three brands of one company, and NET is now Claro, so an older NET label can refer to the same organization. [Claro: NET, Claro and Embratel as one company](https://www.claro.com.br/faq/institucional/a-net-a-claro-e-a-embratel-se-juntaram) | Ask whether a Claro selection means mobile access or another Claro product, and count Claro, NET and Embratel as one company when you compare the registry holder and the origin ASN holder. | | TIM | TIM S.A. is controlled by TIM Brasil, a wholly owned subsidiary of Telecom Italia Finance, itself wholly owned by Telecom Italia S.p.A. [TIM S.A.: corporate control chain](https://ri.tim.com.br/en/our-tim/profile/) · [Anatel: MVNO (Rede Virtual) authorization and the host operator](https://www.gov.br/anatel/pt-br/regulado/outorga/telefonia-movel/mvno) | Match a TIM selection against TIM S.A., the Brazilian company; a Telecom Italia name belongs to the parent. Ask whether MVNO hosting or roaming sits between the label and the connection. | | Algar Telecom | A Brazilian provider headquartered in Uberlândia and part of Grupo Algar, with national operations and a primary focus on B2B clients. Its residential fiber and mobile offer covers cities in Minas Gerais, São Paulo, Goiás and Mato Grosso do Sul. [Algar Telecom: corporate profile and residential footprint](https://ri.algar.com.br/a-algar-telecom/perfil-corporativo-e-historico/) · [Anatel: operators with linked coverage maps](https://www.gov.br/anatel/pt-br/dados/qualidade/qualidade-dos-servicos/cobertura-da-telefonia-movel) | Treat a consumer Algar sample as regional: ask which state it comes from and whether it is mobile or fixed fiber. National B2B operations are not national consumer coverage. | Anatel's coverage data shows where a handset can expect radio service, per municipality and technology, and names no public address for a proxy request. Log four things apart: the carrier you asked for, the registry holder from the RIR record, the origin ASN and holder from a named routing lookup, with the lookup time, and the address family. ## Brazil mobile proxies: four things a label leaves open. Before you compare mobile offers Decide how you will handle possible IPv4 sharing at operators, national roaming, MVNO hosting and coarse location data for mobile ranges. Each one needs its own question to the supplier. ### Shared IPv4 on operator networks In a 2014 tutorial, NIC.br's IPv6.br program said CGNAT at operators made IPv4 sharing unavoidable for some time during the IPv6 transition, and NIC.br's projects and development manager said in 2023 that shared IPv4 causes problems for applications. That describes operators generally, not mobile networks alone, so ask whether the exit you are offered sits behind CGNAT and which address, IPv4 or IPv6, your destination sees. If an offer is sold as dedicated, get in writing whether exclusivity applies to the SIM, to the proxy port you connect to, or to the public IPv4 address itself. [NIC.br IPv6.br: 2014 tutorial on shared IPv4 and CGNAT](https://ipv6.nic.br/post/tutorial-log-da-porta-de-origem-para-ipv4-compartilhado/) · [NIC.br: 2023 ABRANET interview on IPv6 adoption and shared IPv4](https://www.nic.br/noticia/na-midia/ipv6-brasil-alcanca-50-de-migracao-mas-precisa-andar-mais-rapido/) ### National roaming in small municipalities Anatel makes national roaming mandatory in every municipality with fewer than 30,000 inhabitants, so a subscriber there may be served by another operator's network. The company on the SIM and the company whose antennas serve the handset can then differ; ask the supplier which one its carrier filter fixes. [Anatel: mandatory national roaming](https://www.gov.br/anatel/pt-br/regulado/universalizacao/telefonia-movel) ### MVNO hosting Anatel regulates virtual operators under Resolução nº 777/2025; an Autorizada de Rede Virtual provides service through network sharing with a Prestadora Origem. A retail brand that is not a network operator may sit on one of them, so ask which host carries the sample. [Anatel: MVNO (Rede Virtual) authorization](https://www.gov.br/anatel/pt-br/regulado/outorga/telefonia-movel/mvno) ### Coarse mobile geolocation Because one mobile address may serve phones spread over a large distance, MaxMind may give the country and state but omit city and postal-code data, and its data never identifies a household or street address. A Brazil result with no city is not by itself a defect, but it leaves a city requirement unmet; a state requirement passes only if the state field is returned and matches. [MaxMind: geolocation accuracy and mobile addresses without city data](https://support.maxmind.com/hc/en-us/articles/4407630607131-Geolocation-Accuracy) [Set a mobile or fixed residential requirement](https://ipvolt.com/guides/mobile-vs-residential-proxies) ## Confirm the exit, hold the address, then pick rows. Start small ### Confirm one Brazilian exit first Before any storefront, send one request through the supplier's documented gateway to an endpoint you operate and note the address, its family and the state a named geolocation service returns. If the exit answers over both IPv4 and IPv6, look up each address. [Send the first request with curl](https://ipvolt.com/guides/curl-proxy-setup) ### Hold one address through the CEP step A CEP entry followed by a product and shipping page takes several requests. Ask how long the supplier keeps one address, and keep it for the whole flow so a changed offer cannot come from a changed exit. [Choose a session type](https://ipvolt.com/guides/rotating-vs-sticky-proxies) ### Pick the trial rows you need Choose among the language, Distrito Federal, CEP, operator and session rows, six requests per block, and leave out any row your requirement does not use. Record a Vivo, Claro, TIM, Algar, state or Distrito Federal selection the supplier cannot make as unavailable; a generic Brazil exit never stands in for it. [Open the Brazil trial plan](https://ipvolt.com/guides/brazil-proxies) ## From Anatel labels to a CEP-level test plan. The full method The Brazil guide covers Anatel's operator names, MVNOs, roaming and residential access, shared IPv4 and IPv6, the 27 federative units and four time zones, CEP and CPF handling, and a trial run in blocks of six requests, scored request by request. [Read the Brazil guide in full](https://ipvolt.com/guides/brazil-proxies) ## A clearer starting point. Questions ### What does a Brazil proxy prove on its own? Only that the service you test places the exit in Brazil, once you have checked the supplier's label against that service's location source. Which of the 27 federative units the exit sits in, whether access is mobile or fixed residential, and whether Vivo, Claro, TIM or Algar carried it are separate claims to specify and evidence. ### Does a Brazilian exit change the CEP or CPF a site sees? No. The CEP is an eight-digit postal code the customer enters, and the CPF is the Receita Federal's number for one person, unique and permanent for each citizen. Both come from the customer; if a site pre-fills a region from the network address, test that default as a separate input. ### Why does my Brazilian mobile exit show no city? One mobile address may serve phones spread over a large distance, and MaxMind may then omit city and postal-code data. That is not by itself a defect, but it leaves a city requirement unmet, and a state requirement passes only when the returned state field matches; test storefront state behavior with an explicit state or CEP input. ### Does a Vivo or TIM label guarantee that network carried the connection? Not on its own. Anatel authorizes MVNOs to share a host operator's network and makes national roaming mandatory in municipalities under 30,000 inhabitants, so a label may name the subscription while another company's network carries the traffic. Get the supplier to say which layer its selector fixes. ### How should I set the browser time zone for a Brazil test? Brazilian legal time has four zones under Lei nº 12.876/2013, and the Observatório Nacional publishes the legal time for each. Look up the zone for the place your test case represents, set it explicitly and record it; the exit does not set it for you. ### Are ipvolt Brazil proxies available now? No. ipvolt doesn't sell mobile proxies in Brazil today. Residential proxies are on sale from $2.20/GB; the dashboard lists the countries available now. ## Testing for Brazilian customers? Residential proxies are on sale from $2.20/GB. The dashboard lists the countries available now. [Buy residential](https://ipvolt.com/dashboard/residential) ## Workflow references - [Anatel: Q2 2026 competition monitoring report](https://www.gov.br/anatel/pt-br/assuntos/noticias/anatel-divulga-relatorio-de-monitoramento-da-competicao-do-segundo-trimestre-de-2026) - [Anatel: mobile coverage page and linked operator maps](https://www.gov.br/anatel/pt-br/dados/qualidade/qualidade-dos-servicos/cobertura-da-telefonia-movel) - [Anatel: mandatory national roaming below 30,000 inhabitants](https://www.gov.br/anatel/pt-br/regulado/universalizacao/telefonia-movel) - [IBGE: Grandes Regiões and Unidades da Federação](https://www.ibge.gov.br/apps/quadrogeografico/pdf/qg_2024_010_GrandReg.pdf) - [Correios: the eight-digit CEP and its assignment](https://www.correios.com.br/enviar/precisa-de-ajuda/tudo-sobre-cep) - [Governo Federal / Observatório Nacional: four legal time zones](https://www.gov.br/pt-br/servicos/hora-falada-on) --- Document 44 of 138: Portugal proxies. URL: https://ipvolt.com/proxies/portugal Markdown: https://ipvolt.com/proxies/portugal.md # Portugal proxies. Source: https://ipvolt.com/proxies/portugal Markdown: https://ipvolt.com/proxies/portugal.md [Home](https://ipvolt.com/index.md) / Portugal proxies Portugal · Mobile proxies not on sale Portugal is a mainland of 18 districts plus two island regions, and the Azores keep legal time one hour behind the mainland. Treat island customers as separate cases. Mobile proxies aren't available in Portugal yet. [Residential proxies: countries, setup and questions](https://ipvolt.com/residential-proxies) Residential proxies from $2.20/GB, in prepaid packs. Country selection, HTTP and SOCKS5, sticky or rotating sessions. [Buy residential](https://ipvolt.com/dashboard/residential) ## What ipvolt sells ### ipvolt doesn't sell mobile proxies in Portugal today. Residential proxies are on sale from $2.20/GB. The dashboard lists the countries available now. [Pricing and payments](https://ipvolt.com/pricing) ## What to hold fixed on Portuguese pages. From delivery to checkout Each workflow names a Portuguese platform, the inputs to hold fixed and the result to record. Outside your own service and authorized destinations, stay on a storefront's public, signed-out pages where its terms permit, by hand and at low volume, and open no accounts, place no orders and enter no personal or invented identity data such as a NIF, card or phone number. Choose your Portugal proxy test | Your task | Choose first | What to verify | | --- | --- | --- | | Delivery by postcode | One postcode fixture in CTT's NNNN-NNN format, with device location permission denied. | The delivery area or store list shown, and whether it follows the postcode or the exit. | | Azores or Madeira customers | A separate island case with its own postcode fixture, and Azores time for Azores rows. | The region field returned for the exit. An island case passes only when it matches. | | pt-PT search results or ad regions | pt-PT as the interface language in a signed-out browser, with the country domain left unpinned. | Result URLs, the location Google reports and the capture time. | | A MEO, NOS, Vodafone or DIGI requirement | Mobile or fixed access, and whether the name means the SIM's home operator or the origin ASN holder. | The registry holder and the origin ASN holder from a named lookup. Leave DIGI out of island cases while its coverage page excludes them. | ### Grocery delivery postcodes on Continente Online Continente Online, the online shop of Continente, MC's (Sonae) food retail brand, takes the delivery location from a typed postcode or from device location, and offers Click&Go pickup at an available store. The help page ties delivery to those two inputs, so hold both fixed and change only the exit. **Keep fixed:** One NNNN-NNN postcode fixture in CTT's format, device location permission denied, a signed-out session and the same starting page. **Record:** The delivery area or store list shown before sign-in, whether Click&Go appears, the final URL and the capture time. If the postcode step requires an account, stop and use your own storefront instead. Find out whether a changed store list follows the postcode before crediting it to the exit. [Continente Online: choosing the delivery location](https://www.continente.pt/loja-online/ajuda/entregas/onde-posso-selecionar-o-local-de-entrega/) · [MC (Sonae): Continente business description](https://mc.sonae.pt/en/businesses/) · [CTT: postal code format](https://www.ctt.pt/ajuda/particulares/enviar/codigos-postais/o-que-sao) [Pin the browser for a postcode check](https://ipvolt.com/guides/playwright-proxy-setup) ### Mainland and island delivery rules, modeled on Amazon.es Amazon's list of European stores has no Portuguese one, and Amazon.es publishes shipping options for Portugal: Premium delivery covers most mainland postcodes but not the islands, and is offered at checkout only when the postcode qualifies. Use that split to define mainland and island cases on your own storefront; do not sign in, create an account, enter an address or open checkout on a third-party marketplace. **Keep fixed:** On your own storefront or an authorized staging storefront with documented fixtures: product, quantity, site language and one postcode fixture per case, a mainland code and an Azores or Madeira code. **Record:** Delivery options offered, the postcode used, displayed price and time, with mainland and island results in separate rows. Change the exit only once the postcode result is known. Find out whether a missing option comes from an island postcode before blaming the exit. [Amazon.es: shipping rates and options to Portugal](https://www.amazon.es/gp/help/customer/display.html?nodeId=GVVMYF6KMB3ZVNGR) · [Amazon: European stores list](https://sell.amazon.es/en/vender-en-toda-europa) [Check price and currency in one pass](https://ipvolt.com/blog/product-price-currency-validation) ### Portuguese search results and ad region targets On 15 April 2025 Google announced that its country-code addresses would move to google.com over time, noting that since 2017 the domain has not changed which local results a searcher gets. Google Ads lists Portugal as country target 2620 (PT), with Lisbon, Porto District, Azores and Madeira among its region targets. **Keep fixed:** The pt-PT query itself (for example "telemóvel usado"), pt-PT as interface language, one device, a signed-out browser, location permission and a clean session history. Google Play's language list separates pt-PT from pt-BR; your browser profile should too. **Record:** Result URLs, the location Google reports and the time. Leave the country domain unpinned: google.com in the address bar is the announced change. For ads, note the region target the campaign uses and open only your own landing URL through the exit. Snapshot Portuguese results with pt-PT set and the location Google reports; treat a Lisbon ad region as its own case. [Google: planned ccTLD redirect to google.com](https://blog.google/products/search/country-code-top-level-domains/) · [Google Ads API: geo targets CSV with Portugal 2620 (PT) and its region targets](https://developers.google.com/static/google-ads/api/data/geo/geotargets-2026-08-12.csv.zip) · [Google Play Console: pt-PT and pt-BR](https://support.google.com/googleplay/android-developer/answer/9844778?hl=en) [Separate region targets from exit labels](https://ipvolt.com/guides/portugal-proxies) ### Checkout methods and the NIF field on your Portuguese edition SIBS manages the MULTIBANCO network and offers MB WAY, a mobile payment method that links bank details to a phone number alias, plus MULTIBANCO reference payments generated in real time. The tax authority's e-Fatura FAQ explains what happens when a buyer asks for their NIF on an invoice. Run these checks only on your own storefront or an authorized staging storefront, with documented fixtures. **Keep fixed:** Your own or an authorized staging storefront with documented fixtures, the same basket, pt-PT locale, the NIF field left empty, no card or phone number, and one exit held through the whole basket-to-payment sequence. **Record:** Payment methods listed, whether the NIF field appears and can be left empty, the edition served, the exit's country classification and whether the exit stayed the same throughout. **Trial records:** Lei n.º 58/2019 implements the GDPR in Portugal and names the CNPD as the national supervisory authority. Keep screenshots and exit logs to what the check needs. Check that your own Portuguese edition shows MB WAY, a MULTIBANCO reference and an optional NIF field, then stop before payment. [SIBS: MULTIBANCO network operator](https://www.corporate.sibs.com/about-us/) · [SIBS: MB WAY payment method](https://www.docs.pay.sibs.com/portugal/mb-way-3/) · [SIBS: MULTIBANCO reference payments](https://www.docs.pay.sibs.com/portugal/multibanco-reference/) · [Portal das Finanças: NIF on invoices (e-Fatura FAQ)](https://info.portaldasfinancas.gov.pt/pt/faturas/Pages/faqs-00984.aspx) [Hold one exit from basket to payment](https://ipvolt.com/guides/rotating-vs-sticky-proxies) ## Mobile operators in Portugal, as ANACOM lists them. Learn the operator vocabulary ANACOM, the Portuguese regulator for postal and electronic communications, ranks MEO, NOS, Vodafone, Grupo DIGI/NOWO and Lycamobile by active mobile accesses in its report for the fourth quarter of 2025. Each row says what the name covers and what to write into a brief. The table is vocabulary only: it does not show that ipvolt or any provider can reach these networks. What MEO, NOS, Vodafone and DIGI mean in a proxy brief | Network name | What the name means | What to specify | | --- | --- | --- | | MEO | Listed in 2018 among the commercial brands Altice Portugal kept when PT (Portugal Telecom) became Altice Portugal. ANACOM's fourth-quarter 2025 report lists MEO as the leading mobile provider, with 36.0% of active mobile accesses with effective use, excluding M2M. [ANACOM: fourth-quarter 2025 mobile services report](https://www.anacom.pt/streaming/ServicosMoveis4T2025.pdf?contentId=1828056&field=ATTACHED_FILE) · [MEO: institutional history and Altice Portugal brands](https://en.institutional.meo.pt/meo/history) | Write MEO as the SIM's home operator when that is what matters, state mobile or fixed access explicitly, and ask how the provider verifies both. Altice Portugal kept several commercial brands in 2018, so record the label exactly as given. | | NOS | NOS Comunicações resulted from the 2014 merger of ZON TV Cabo into Optimus, per ANACOM. NOS describes itself as one of Portugal's main operators, serving residential and business customers with television, internet, voice and mobile data. [ANACOM: May 2021 MVNO report and the NOS merger](https://www.anacom.pt/streaming/MVNOemPortugal_maio2021.pdf?contentId=1644333&field=ATTACHED_FILE) · [NOS: company description](https://www.nos.pt/pt/institucional/a-nos/sobre-a-nos/grupo-nos/nos-comunicacoes) | State whether you need NOS mobile access or a fixed NOS connection. Because NOS sells both, a NOS holder name in a routing lookup cannot settle the access type either. | | Vodafone | Vodafone Portugal belongs to the global Vodafone group. ANACOM's May 2021 MVNO report records that Lycamobile, active since September 2012, uses Vodafone's network. [Vodafone Portugal: who we are](https://www.vodafone.pt/a-vodafone/quem-somos.html) · [ANACOM: May 2021 MVNO report, Lycamobile on Vodafone's network](https://www.anacom.pt/streaming/MVNOemPortugal_maio2021.pdf?contentId=1644333&field=ATTACHED_FILE) | Ask whether a Vodafone selection means Vodafone's own SIMs, SIMs of an MVNO such as Lycamobile, or only a holder name seen in routing data. Observe the origin ASN holder of a Lycamobile exit rather than assuming it is Vodafone. | | DIGI / NOWO | DIGI Portugal acquired 100% of Cabonitel, the owner of NOWO, and ANACOM approved the transfer of NOWO's 3.6 GHz spectrum rights to DIGI on 21 January 2025. DIGI's coverage page, checked in September 2026, said its mobile service was, for the moment, unavailable in the Azores and Madeira. [ANACOM: fourth-quarter 2025 report on DIGI and NOWO](https://www.anacom.pt/streaming/ServicosMoveis4T2025.pdf?contentId=1828056&field=ATTACHED_FILE) · [DIGI: mobile coverage, Azores and Madeira excluded](https://www.digi.pt/cobertura-movel) | Treat DIGI and NOWO labels as one group and date the observation. While DIGI's coverage page excludes the Azores and Madeira, leave DIGI out of any island case and recheck the page before each trial. | Market shares count active mobile accesses with effective use, not proxy exits. Keep the operator label a provider attaches apart from two observed fields, the registry holder from the RIR record and the origin ASN and holder from a named routing lookup with the lookup time, and log the address family beside them. ## Portugal mobile proxies: which layer does the label control? Define the mobile layer ANACOM's reports name the operators and the MVNO arrangement behind Lycamobile, DIGI's coverage page draws the island line, and MaxMind explains why a mobile range may carry no city. Settle each item below with the supplier before a Portugal mobile label enters your test plan. ### MVNO brands on a host network ANACOM's May 2021 report on mobile virtual network operators records that Lycamobile, active in Portugal since September 2012, uses Vodafone's network. Two menu labels can therefore describe one host network, while the origin ASN holder of a Lycamobile exit still has to be observed. Ask what each selection controls before counting it as a second network. [ANACOM: mobile virtual operators in Portugal, May 2021](https://www.anacom.pt/streaming/MVNOemPortugal_maio2021.pdf?contentId=1644333&field=ATTACHED_FILE) ### Roaming SIMs from other EU countries The European Commission says that since 15 June 2017 people pay nothing extra for roaming when traveling to other EU countries, so a SIM from elsewhere in the EU can use a Portuguese network with its home operator abroad. The charging rule says nothing about where that SIM's traffic reaches the internet; record the home operator and the exit's country classification as separate fields. [European Commission: roaming rules](https://digital-strategy.ec.europa.eu/en/policies/roaming) ### Mainland and island coverage DIGI's coverage page, checked in September 2026, said its mobile service was, for the moment, unavailable in the Azores and Madeira. While that exclusion stands, a DIGI selection cannot represent an island customer, and a mobile exit address may carry no city at all, so do not expect it to show which part of Portugal a handset is in. Write any island case explicitly, with its own postcode fixture. [DIGI: mobile coverage](https://www.digi.pt/cobertura-movel) ### City precision on mobile ranges MaxMind warns that a mobile network address can be in use by phones spread over a large distance, and that it may then return the country and region without a city or postal code. For a test plan, a missing city is not by itself a defect, but it leaves a city requirement unmet: a Lisbon case does not pass, while an Azores or Madeira case passes only when the returned region field matches. [MaxMind: geolocation accuracy](https://support.maxmind.com/hc/en-us/articles/4407630607131-Geolocation-Accuracy) [Choose between mobile and residential access](https://ipvolt.com/guides/mobile-vs-residential-proxies) ## Start with the mainland, then the islands. Order of work ### Write the island cases down Decide whether Azores and Madeira customers are in scope, and give every case in the plan a CTT-format postcode fixture and its own pass condition before any exit is involved. [Plan mainland and island cases](https://ipvolt.com/guides/portugal-proxies) ### Set pt-PT and the clock per case Run each case in an isolated browser context with pt-PT and no stored cookies, on mainland time for mainland and Madeira rows and one hour behind it for Azores rows. [Isolate one browser context per case](https://ipvolt.com/guides/playwright-proxy-setup) ### Let the region field open the island rows Look up each selection's exit in your application's location service, reading the address through one curl request to an endpoint you run. An island selection fails there if the returned region is missing or on the mainland; one the supplier cannot make is recorded as unavailable. [Get the exit address with curl](https://ipvolt.com/guides/curl-proxy-setup) ## Check mainland, island and operator claims. Island and operator detail Island scope and the Azores clock come first. The guide then reads ANACOM's operator names, the two network identity fields, search by reported location, the pt-PT pair test, the NIF field and a four-row trial that opens with the island fallback question. [Go to the Portugal guide](https://ipvolt.com/guides/portugal-proxies) ## A clearer starting point. Questions ### Does a Portugal exit cover the Azores and Madeira? Not by itself. The Azores keep legal time one hour behind the mainland, DIGI's coverage page, checked in September 2026, said its mobile service was unavailable in both autonomous regions, and Amazon.es Premium delivery excludes the islands. Give each island case its own postcode fixture, with Azores time for the Azores (Madeira keeps mainland time), and pass it only when the returned region field matches. ### Is a Portugal label evidence of where the exit is? Not on its own. It is the supplier's claim that destinations will classify the exit as Portuguese, so look up the observed address in the location service your destination uses and record the result. A district, an island, a city and a named operator each need their own evidence. ### Which operator name should I ask for? Use ANACOM's names, MEO, NOS, Vodafone, DIGI/NOWO and Lycamobile, and say which layer you mean: the SIM's home operator or the origin ASN holder a routing lookup returns. Lycamobile is the name to check first, because ANACOM's May 2021 MVNO report places it on Vodafone's network. Ask the provider to confirm the current host before you count a Lycamobile row as a separate network. ### What should a Portugal residential proxy request specify? The access type, not only the operator. NOS serves residential and business customers with television, internet, voice and mobile data, so a name alone cannot separate a fixed home line from a mobile or business connection. Ask how the access type is documented for your exit and how those connections are authorized for proxy use. ### Should my browser use pt-PT or pt-BR? Set pt-PT explicitly for a Portugal test; Google's Play Console language list separates it from pt-BR. If a Brazilian Portuguese page arrives through a Portuguese exit, first switch only the browser language with the exit held, then hold the language and switch only the exit. ### Are ipvolt Portugal proxies available now? No. ipvolt doesn't sell mobile proxies in Portugal today. Residential proxies are on sale from $2.20/GB; the dashboard lists the countries available now. ## Checking the islands as well as the mainland? Residential proxies are on sale from $2.20/GB. The dashboard lists the countries available now. [Buy residential](https://ipvolt.com/dashboard/residential) ## Workflow references - [ANACOM: regulator for postal and electronic communications in Portugal](https://www.anacom.pt/) - [Governo de Portugal: 18 mainland districts and 2 autonomous regions](https://portugal.gov.pt/pt/gc23/portugal/sobre-portugal) - [INE: the 18 districts of mainland Portugal](https://www.ine.pt/xportal/xmain?xpid=INE&xpgid=ine_cont_inst&INST=6251013&xlang=pt) - [Observatório Astronómico de Lisboa: legal time for the mainland, Madeira and the Azores](https://oal.ul.pt/hora-legal/legislacao/) - [CTT: the NNNN-NNN postal code format](https://www.ctt.pt/ajuda/particulares/enviar/codigos-postais/o-que-sao) - [Diário da República: Lei n.º 58/2019 implementing the GDPR and designating the CNPD](https://files.diariodarepublica.pt/1s/2019/08/15100/0000300040.pdf) --- Document 45 of 138: Canada proxies. URL: https://ipvolt.com/proxies/canada Markdown: https://ipvolt.com/proxies/canada.md # Canada proxies. Source: https://ipvolt.com/proxies/canada Markdown: https://ipvolt.com/proxies/canada.md [Home](https://ipvolt.com/index.md) / Canada proxies Canada · Mobile proxies not on sale Build a Canadian web-testing workflow for storefronts, localization, delivery and network-specific issues. Compare carrier labels and choose your test settings. Mobile proxies aren't available in Canada yet. [Residential proxies: countries, setup and questions](https://ipvolt.com/residential-proxies) Residential proxies from $2.20/GB, in prepaid packs. Country selection, HTTP and SOCKS5, sticky or rotating sessions. [Buy residential](https://ipvolt.com/dashboard/residential) ## What ipvolt sells ### ipvolt doesn't sell mobile proxies in Canada today. Residential proxies are on sale from $2.20/GB. The dashboard lists the countries available now. [Pricing and payments](https://ipvolt.com/pricing) ## What will you test from Canada? Put the location to work Start with the rule your application reads. Keep network location, language and delivery inputs separate so each comparison answers one question. Choose your Canada proxy test | Your task | Choose first | What to verify | | --- | --- | --- | | A Canadian storefront or market | A Canadian exit, with product, entry URL and browser preferences fixed and a fresh signed-out state. | The final URL, selected market and currency, and the location your application recognizes. | | English and French pages | The browser language preference, with the Canadian exit unchanged. French does not by itself call for a Montreal exit. | The page language, the redirect chain and whether the customer can choose another language. | | Delivery by postal code | An approved full address, with the exit, cart and fulfillment location held fixed. | The configured delivery zone, the address fixture and the delivery options offered. | | An issue on Bell, Rogers, TELUS or Videotron | The network layer that matters: retail brand, radio access or internet exit. | The retail brand, the supplier’s network declaration and the observed exit network. | ### Canadian storefronts and regional offers Check your own Canadian storefront through a Canadian exit. Shopify documents IP-based localization alongside market URLs, browser language and saved customer choices. **Keep fixed:** Product, entry URL, browser preferences and fresh signed-out state. **Record:** The final URL, selected market, displayed currency and the location your application recognizes. A Canadian result in one location checker does not establish the storefront’s decision. [Shopify: market localization](https://help.shopify.com/en/manual/markets/getting-started/localization) [Define Canadian location checks](https://ipvolt.com/guides/canada-proxies) ### English and French localization Test your configured English and French experiences with explicit browser preferences. Keep the Canadian exit unchanged when language is the variable. **Keep fixed:** Market URL, cookie state, product and exit selection. **Record:** The page language, redirect chain and the customer’s ability to choose another language. A French-language requirement does not by itself call for a Montreal exit. [Shopify: market localization](https://help.shopify.com/en/manual/markets/getting-started/localization) [Run the Shopify Canada localization workflow](https://ipvolt.com/guides/shopify-canada-localization) ### Postal-code delivery boundaries Use approved full addresses to test your store’s delivery rules. Shopify documents M5V* as an example local-delivery prefix; Canada Post separates the first three postal characters from the finer delivery unit. **Keep fixed:** Exit, cart, inventory, fulfillment location and checkout method. **Record:** The configured delivery zone, address fixture and offered delivery options. A Toronto IP label does not supply a shipping address or establish delivery eligibility. [Canada Post: postal-code structure](https://www.canadapost-postescanada.ca/cpc/en/support/articles/addressing-guidelines/postal-codes.page) · [Shopify: local-delivery zones and eligibility](https://help.shopify.com/en/manual/fulfillment/setup/delivery-methods/local-delivery) [Build the delivery test worksheet](https://ipvolt.com/guides/shopify-canada-localization) ### Carrier-specific website issues Reproduce a reported Bell, Rogers, TELUS or Videotron/Freedom issue using an authorized sample. Name the network layer that matters before comparing carrier selections. **Keep fixed:** Destination, client, account state, deadline and the steps being compared. **Record:** Retail brand, supplier’s network declaration, observed exit IP/network and each failure. Use the table below to distinguish brand families from the network evidence your test needs. [CRTC: mobile brand families](https://crtc.gc.ca/eng/publications/reports/PolicyMonitoring/comm.htm) · [CRTC: Freedom Mobile and Videotron](https://crtc.gc.ca/eng/archive/2026/2026-84.htm) [Evaluate Canadian network labels](https://ipvolt.com/guides/canada-proxies) ## Mobile proxy carriers in Canada. Understand the network The CRTC distinguishes main mobile brands and their related brands. Use this map to write a precise requirement; it is not a list of ipvolt networks. Canadian mobile brands and the evidence to request | Network name | What the name means | What to specify | | --- | --- | --- | | Bell / Virgin / Lucky | The CRTC groups Virgin Mobile and Lucky Mobile with Bell. [CRTC: mobile brand families](https://crtc.gc.ca/eng/publications/reports/PolicyMonitoring/comm.htm) | Name the retail or SIM brand if it matters. A Bell-family label alone does not identify the public exit or prove a separate radio path. | | Rogers / Fido / Chatr | The CRTC groups Fido and Chatr with Rogers. [CRTC: mobile brand families](https://crtc.gc.ca/eng/publications/reports/PolicyMonitoring/comm.htm) | Do not count related brand selections as independent network samples without evidence for the layer you are comparing. | | TELUS / Koodo / Public Mobile | The CRTC groups Koodo and Public Mobile with TELUS. Its 2025 decision describes Bell and TELUS sharing a radio access network. [CRTC: mobile brand families](https://crtc.gc.ca/eng/publications/reports/PolicyMonitoring/comm.htm) · [CRTC: Bell and TELUS shared radio access](https://crtc.gc.ca/eng/archive/2025/2025-245.htm) | Keep the subscriber’s operator, serving radio network and observed internet exit separate. Different operators need not mean separate radio infrastructure. | | Videotron / Freedom / Fizz | The CRTC identifies Videotron and Freedom Mobile as Quebecor subsidiaries and lists Fizz as a Videotron brand. [CRTC: mobile brand families](https://crtc.gc.ca/eng/publications/reports/PolicyMonitoring/comm.htm) · [CRTC: Freedom Mobile and Videotron](https://crtc.gc.ca/eng/archive/2026/2026-84.htm) | Record the exact selected brand and ask how native service, roaming or hosted access affects the sample you receive. | These relationships help interpret labels. They do not establish an offered endpoint’s carrier, province, city, performance or availability. ## Canadian mobile proxies: specify the network layer. Choose the connection A brand, a radio network and an internet exit answer different questions. Agree which one your provider’s selection controls. ### Related brands Virgin and Lucky, Fido and Chatr, and Koodo and Public Mobile belong to the CRTC’s listed brand families. Preserve the exact brand while grouping related labels in your comparison. [CRTC: mobile brand families](https://crtc.gc.ca/eng/publications/reports/PolicyMonitoring/comm.htm) ### Shared radio access The CRTC’s Bell/TELUS decision describes a shared radio access network. It does not identify the internet exit of a proxy sample; that still needs its own observation. [CRTC: Bell and TELUS shared radio access](https://crtc.gc.ca/eng/archive/2025/2025-245.htm) ### Roaming and hosted access The CRTC distinguishes incidental roaming from permanent access under its facilities-based MVNO framework. Ask the supplier which arrangement applies to a sample instead of inferring the serving network from a retail label. [CRTC: Freedom Mobile and Videotron](https://crtc.gc.ca/eng/archive/2026/2026-84.htm) [Read the Canadian proxy evaluation guide](https://ipvolt.com/guides/canada-proxies) ## Set up your first check. A practical starting point ### Define the location Choose the country, province, city or network condition the application actually needs. [Canada location guide](https://ipvolt.com/guides/canada-proxies) ### Choose your client Establish a repeatable request through an authorized endpoint to a destination you control. [Set up curl](https://ipvolt.com/guides/curl-proxy-setup) ### Control the browser Keep language, time zone, account and cookie state explicit when comparing exits. [Set up Playwright](https://ipvolt.com/guides/playwright-proxy-setup) ## Choose the right Canadian network and location checks. Go deeper The Canada guide separates carrier brands, network evidence, country and city requirements, with a practical acceptance matrix and an editable request brief. [Read the Canada proxy guide](https://ipvolt.com/guides/canada-proxies) ## A clearer starting point. Questions ### What is a Canada proxy? It routes a request through an exit IP that the destination recognizes as Canadian. Country recognition, a province or city result and a particular network are separate conditions to verify. ### Do I need a Toronto or Montreal proxy? Add a city requirement only when your application actually reads IP-derived city information. Browser language and delivery address should be configured separately. ### Which Canadian carrier should I choose? A country-only check may need no named carrier. For a network-specific issue, use the carrier table to distinguish the selected brand, radio access and observed internet exit before requesting a sample. ### Can a Canadian IP select French or validate delivery? Configure the language and full delivery address explicitly. The Shopify guide shows how to compare IP, language, market URL and delivery controls without attributing every change to the proxy. ### Are Canadian proxies available from ipvolt? No. ipvolt doesn't sell mobile proxies in Canada today. Residential proxies are on sale from $2.20/GB; the dashboard lists the countries available now. ## Testing for Canadian customers? Residential proxies are on sale from $2.20/GB. The dashboard lists the countries available now. [Buy residential](https://ipvolt.com/dashboard/residential) ## Workflow references - [CRTC: mobile brand families](https://crtc.gc.ca/eng/publications/reports/PolicyMonitoring/comm.htm) - [CRTC: Bell and TELUS shared radio access](https://crtc.gc.ca/eng/archive/2025/2025-245.htm) - [CRTC: Freedom Mobile and Videotron](https://crtc.gc.ca/eng/archive/2026/2026-84.htm) - [Shopify: market localization](https://help.shopify.com/en/manual/markets/getting-started/localization) - [Canada Post: postal-code structure](https://www.canadapost-postescanada.ca/cpc/en/support/articles/addressing-guidelines/postal-codes.page) --- Document 46 of 138: UK mobile proxies on Three. URL: https://ipvolt.com/proxies/uk Markdown: https://ipvolt.com/proxies/uk.md # UK mobile proxies on Three. Source: https://ipvolt.com/proxies/uk Markdown: https://ipvolt.com/proxies/uk.md [Home](https://ipvolt.com/index.md) / UK proxies UK · Mobile proxies on sale Each UK mobile proxy is one device on the Three network, and nobody else uses it while you rent it. Rent it for a day or for 30 days, pay with crypto, and nothing renews on its own. [Mobile proxies in the United Kingdom on Three from $14 a day](https://ipvolt.com/dashboard/mobile?country=GB&plan=day&carrier=Three) Residential proxies from $2.20/GB, in prepaid packs. Country selection, HTTP and SOCKS5, sticky or rotating sessions. [Buy residential](https://ipvolt.com/dashboard/residential) ## What ipvolt sells ### Mobile proxies in the United Kingdom from $14 a day. Residential proxies from $2.20/GB, in prepaid packs. [Pricing and payments](https://ipvolt.com/pricing) ## Mobile proxies | Carrier | 1 day | 30 days | | --- | --- | --- | | Three | [$14](https://ipvolt.com/dashboard/mobile?country=GB&plan=day&carrier=Three) | [$100](https://ipvolt.com/dashboard/mobile?country=GB&plan=month&carrier=Three) ($3.33/day) | Prices on 11 November 2026. Checkout shows the live price and every carrier in stock, including a carrier that has only one rental length available. Nothing renews on its own. If a device fails and we cannot repair or replace it, we credit the unused part of the rental to your balance, pro rata by the hour. ## What you can test from the UK. Uses Three jobs people rent a UK mobile IP for. Each is something you check yourself; none is a promise about what a site will show. ### Check your UK storefront on a mobile connection Open your UK storefront through a connection on Three and record the currency, the prices and the delivery options it shows. Keep the product, the account state and the delivery postcode the same between checks. ### Review UK search results and ad landing pages Run the same query, or open your own ad's landing page, from a UK mobile IP and save what appears with the time of the check. A UK exit doesn't place you in a particular city. ### Reproduce a report from a customer on Three When someone on Three reports a problem with your site or app, load the same page over the same carrier and compare it with a fixed-line connection. ## What a rental includes - No traffic limit. A rental is priced by time, not by the GB. - IP rotation on demand from the dashboard, or on a schedule as often as every 60 seconds, on devices that support it. The carrier assigns the new IP and may return the same one. - If a device fails and we cannot repair or replace it, the unused part of the rental is credited to your balance, pro rata by the hour. - Works over HTTP and SOCKS5. Started rentals are not refundable, except in the cases listed in the [Payments and Refunds Policy](https://ipvolt.com/refunds). ## Connect a mobile proxy with cURL or Python In the dashboard, open the device and select Show connection details. Most devices use one username and password for both protocols, on two ports; some list a separate host and login for each. Replace the placeholders with your values. ```sh curl -sS -x "http://USERNAME:PASSWORD@HOST:HTTP_PORT" https://api.ipify.org curl -sS -x "socks5h://USERNAME:PASSWORD@HOST:SOCKS5_PORT" https://api.ipify.org ``` ```python import os import requests proxy = os.environ["PROXY_URL"] # http://USERNAME:PASSWORD@HOST:HTTP_PORT response = requests.get("https://api.ipify.org", proxies={"http": proxy, "https": proxy}, timeout=30) print(response.text) ``` The printed IP should match the outgoing IP in your dashboard. For a socks5h:// URL in Python, install requests[socks] first. - [Quickstart](https://ipvolt.com/docs/quickstart.md) - [Endpoints and protocols](https://ipvolt.com/docs/endpoints.md) - [Code examples for Node.js, Playwright, Scrapy and Go](https://ipvolt.com/docs/code-examples.md) ## Test a UK proxy before you rely on it. Go deeper Our UK guide covers current carrier context, UK and GB geography, postcode limitations and a practical test plan for country or network requirements. [Read the UK proxy guide](https://ipvolt.com/guides/uk-proxies) ## A clearer starting point. Questions ### How much does a UK mobile proxy cost? Three: $14 for 1 day or $100 for 30 days ($3.33 a day). Add funds with crypto and buy from your dashboard; nothing renews automatically. Prices on 11 November 2026. Checkout shows the live price and every carrier in stock, including a carrier that has only one rental length available. ### Can I choose a city in the United Kingdom? No. Mobile proxies are targeted by country and carrier, not by city. ### How do I change the IP of a UK mobile proxy? Select Rotate IP now in the dashboard, or set automatic rotation to every 60 seconds, 5 minutes or 30 minutes on devices that support it. The carrier assigns the new IP and can return the same one. Rotation is controlled from the dashboard; there is no public API for it today. ### How do I pay for a UK mobile proxy? From a prepaid US-dollar balance that you top up with crypto through our NOWPayments checkout: Tether (USDT), USD Coin (USDC), Bitcoin (BTC), Ethereum (ETH), Solana (SOL) and more. Card payments are coming soon. ## Rent a UK mobile proxy. Mobile proxies in the United Kingdom are on sale now. Residential proxies from $2.20/GB, in prepaid packs. [Mobile proxies in the United Kingdom on Three from $14 a day](https://ipvolt.com/dashboard/mobile?country=GB&plan=day&carrier=Three) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 47 of 138: France mobile proxies on SFR and Free. URL: https://ipvolt.com/proxies/france Markdown: https://ipvolt.com/proxies/france.md # France mobile proxies on SFR and Free. Source: https://ipvolt.com/proxies/france Markdown: https://ipvolt.com/proxies/france.md [Home](https://ipvolt.com/index.md) / France proxies France · Mobile proxies on sale Each French mobile proxy is one device on the SFR or Free network, and nobody else uses it while you rent it. Rent it for a day or for 30 days, pay with crypto, and nothing renews on its own. [Mobile proxies in France on SFR from $9 a day](https://ipvolt.com/dashboard/mobile?country=FR&plan=day&carrier=SFR) Residential proxies from $2.20/GB, in prepaid packs. Country selection, HTTP and SOCKS5, sticky or rotating sessions. [Buy residential](https://ipvolt.com/dashboard/residential) ## What ipvolt sells ### Mobile proxies in France from $9 a day. Residential proxies from $2.20/GB, in prepaid packs. [Pricing and payments](https://ipvolt.com/pricing) ## Mobile proxies | Carrier | 1 day | 30 days | | --- | --- | --- | | SFR | [$9](https://ipvolt.com/dashboard/mobile?country=FR&plan=day&carrier=SFR) | [$100](https://ipvolt.com/dashboard/mobile?country=FR&plan=month&carrier=SFR) ($3.33/day) | | Free | [$12](https://ipvolt.com/dashboard/mobile?country=FR&plan=day&carrier=Free) | [$100](https://ipvolt.com/dashboard/mobile?country=FR&plan=month&carrier=Free) ($3.33/day) | Prices on 11 November 2026. Checkout shows the live price and every carrier in stock, including a carrier that has only one rental length available. Nothing renews on its own. If a device fails and we cannot repair or replace it, we credit the unused part of the rental to your balance, pro rata by the hour. ## What you can test from France. Uses Three jobs people rent a French mobile IP for. Each is something you check yourself; none is a promise about what a site will show. ### Check a French storefront in euros Open your French storefront through a mobile connection in France and record the language, the prices in euros and the delivery options. Keep the product, the account state and the delivery address the same between checks. ### See what a visitor on SFR or Free gets Rent a device on SFR or Free for a day and load the page you normally test on a fixed line. Record what differs instead of assuming mobile visitors see the same thing. ### Review French search results and ad landing pages Run the same French-language query, or open your own ad's landing page, from a French mobile IP and save what appears with the time of the check. ## What a rental includes - No traffic limit. A rental is priced by time, not by the GB. - IP rotation on demand from the dashboard, or on a schedule as often as every 60 seconds, on devices that support it. The carrier assigns the new IP and may return the same one. - If a device fails and we cannot repair or replace it, the unused part of the rental is credited to your balance, pro rata by the hour. - Works over HTTP and SOCKS5. Started rentals are not refundable, except in the cases listed in the [Payments and Refunds Policy](https://ipvolt.com/refunds). ## Connect a mobile proxy with cURL or Python In the dashboard, open the device and select Show connection details. Most devices use one username and password for both protocols, on two ports; some list a separate host and login for each. Replace the placeholders with your values. ```sh curl -sS -x "http://USERNAME:PASSWORD@HOST:HTTP_PORT" https://api.ipify.org curl -sS -x "socks5h://USERNAME:PASSWORD@HOST:SOCKS5_PORT" https://api.ipify.org ``` ```python import os import requests proxy = os.environ["PROXY_URL"] # http://USERNAME:PASSWORD@HOST:HTTP_PORT response = requests.get("https://api.ipify.org", proxies={"http": proxy, "https": proxy}, timeout=30) print(response.text) ``` The printed IP should match the outgoing IP in your dashboard. For a socks5h:// URL in Python, install requests[socks] first. - [Quickstart](https://ipvolt.com/docs/quickstart.md) - [Endpoints and protocols](https://ipvolt.com/docs/endpoints.md) - [Code examples for Node.js, Playwright, Scrapy and Go](https://ipvolt.com/docs/code-examples.md) ## Test a French proxy before you rely on it. Go deeper Our France guide covers carrier and brand distinctions, mainland and overseas scope, exit-IP evidence and a practical localization test matrix. [Read the France proxy guide](https://ipvolt.com/guides/france-proxies) ## A clearer starting point. Questions ### How much does a French mobile proxy cost? SFR: $9 for 1 day or $100 for 30 days ($3.33 a day). Free: $12 for 1 day or $100 for 30 days ($3.33 a day). Add funds with crypto and buy from your dashboard; nothing renews automatically. Prices on 11 November 2026. Checkout shows the live price and every carrier in stock, including a carrier that has only one rental length available. ### Can I choose a city in France? No. Mobile proxies are targeted by country and carrier, not by city. ### How do I change the IP of a French mobile proxy? Select Rotate IP now in the dashboard, or set automatic rotation to every 60 seconds, 5 minutes or 30 minutes on devices that support it. The carrier assigns the new IP and can return the same one. Rotation is controlled from the dashboard; there is no public API for it today. ### How do I pay for a French mobile proxy? From a prepaid US-dollar balance that you top up with crypto through our NOWPayments checkout: Tether (USDT), USD Coin (USDC), Bitcoin (BTC), Ethereum (ETH), Solana (SOL) and more. Card payments are coming soon. ## Rent a French mobile proxy. Mobile proxies in France are on sale now. Residential proxies from $2.20/GB, in prepaid packs. [Mobile proxies in France on SFR from $9 a day](https://ipvolt.com/dashboard/mobile?country=FR&plan=day&carrier=SFR) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 48 of 138: Poland mobile proxies on Play. URL: https://ipvolt.com/proxies/poland Markdown: https://ipvolt.com/proxies/poland.md # Poland mobile proxies on Play. Source: https://ipvolt.com/proxies/poland Markdown: https://ipvolt.com/proxies/poland.md [Home](https://ipvolt.com/index.md) / Poland proxies Poland · Mobile proxies on sale Each Polish mobile proxy is one device on the Play network, and nobody else uses it while you rent it. Rent it for a day or for 30 days, pay with crypto, and nothing renews on its own. [Mobile proxies in Poland on Play from $9 a day](https://ipvolt.com/dashboard/mobile?country=PL&plan=day&carrier=Play) Residential proxies from $2.20/GB, in prepaid packs. Country selection, HTTP and SOCKS5, sticky or rotating sessions. [Buy residential](https://ipvolt.com/dashboard/residential) ## What ipvolt sells ### Mobile proxies in Poland from $9 a day. Residential proxies from $2.20/GB, in prepaid packs. [Pricing and payments](https://ipvolt.com/pricing) ## Mobile proxies | Carrier | 1 day | 30 days | | --- | --- | --- | | Play | [$9](https://ipvolt.com/dashboard/mobile?country=PL&plan=day&carrier=Play) | [$100](https://ipvolt.com/dashboard/mobile?country=PL&plan=month&carrier=Play) ($3.33/day) | Prices on 11 November 2026. Checkout shows the live price and every carrier in stock, including a carrier that has only one rental length available. Nothing renews on its own. If a device fails and we cannot repair or replace it, we credit the unused part of the rental to your balance, pro rata by the hour. ## What you can test from Poland. Uses Three jobs people rent a Polish mobile IP for. Each is something you check yourself; none is a promise about what a site will show. ### Check a Polish storefront in złoty Open your Polish storefront through a mobile connection in Poland and record the language, the prices in złoty and the delivery options. Keep the product and the account state the same between checks. ### Walk through sign-up or checkout on Play Go through your own sign-up or checkout on a Polish mobile connection and note each step that behaves differently from your desktop test. ### Review Polish search results for your keywords Run the same Polish-language query from a Polish mobile IP on different days and save the results with the time of each check. ## What a rental includes - No traffic limit. A rental is priced by time, not by the GB. - IP rotation on demand from the dashboard, or on a schedule as often as every 60 seconds, on devices that support it. The carrier assigns the new IP and may return the same one. - If a device fails and we cannot repair or replace it, the unused part of the rental is credited to your balance, pro rata by the hour. - Works over HTTP and SOCKS5. Started rentals are not refundable, except in the cases listed in the [Payments and Refunds Policy](https://ipvolt.com/refunds). ## Connect a mobile proxy with cURL or Python In the dashboard, open the device and select Show connection details. Most devices use one username and password for both protocols, on two ports; some list a separate host and login for each. Replace the placeholders with your values. ```sh curl -sS -x "http://USERNAME:PASSWORD@HOST:HTTP_PORT" https://api.ipify.org curl -sS -x "socks5h://USERNAME:PASSWORD@HOST:SOCKS5_PORT" https://api.ipify.org ``` ```python import os import requests proxy = os.environ["PROXY_URL"] # http://USERNAME:PASSWORD@HOST:HTTP_PORT response = requests.get("https://api.ipify.org", proxies={"http": proxy, "https": proxy}, timeout=30) print(response.text) ``` The printed IP should match the outgoing IP in your dashboard. For a socks5h:// URL in Python, install requests[socks] first. - [Quickstart](https://ipvolt.com/docs/quickstart.md) - [Endpoints and protocols](https://ipvolt.com/docs/endpoints.md) - [Code examples for Node.js, Playwright, Scrapy and Go](https://ipvolt.com/docs/code-examples.md) ## A clearer starting point. Questions ### How much does a Polish mobile proxy cost? Play: $9 for 1 day or $100 for 30 days ($3.33 a day). Add funds with crypto and buy from your dashboard; nothing renews automatically. Prices on 11 November 2026. Checkout shows the live price and every carrier in stock, including a carrier that has only one rental length available. ### Can I choose a city in Poland? No. Mobile proxies are targeted by country and carrier, not by city. ### How do I change the IP of a Polish mobile proxy? Select Rotate IP now in the dashboard, or set automatic rotation to every 60 seconds, 5 minutes or 30 minutes on devices that support it. The carrier assigns the new IP and can return the same one. Rotation is controlled from the dashboard; there is no public API for it today. ### How do I pay for a Polish mobile proxy? From a prepaid US-dollar balance that you top up with crypto through our NOWPayments checkout: Tether (USDT), USD Coin (USDC), Bitcoin (BTC), Ethereum (ETH), Solana (SOL) and more. Card payments are coming soon. ## Rent a Polish mobile proxy. Mobile proxies in Poland are on sale now. Residential proxies from $2.20/GB, in prepaid packs. [Mobile proxies in Poland on Play from $9 a day](https://ipvolt.com/dashboard/mobile?country=PL&plan=day&carrier=Play) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 49 of 138: Singapore mobile proxies on Singtel and M1. URL: https://ipvolt.com/proxies/singapore Markdown: https://ipvolt.com/proxies/singapore.md # Singapore mobile proxies on Singtel and M1. Source: https://ipvolt.com/proxies/singapore Markdown: https://ipvolt.com/proxies/singapore.md [Home](https://ipvolt.com/index.md) / Singapore proxies Singapore · Mobile proxies on sale Each Singapore mobile proxy is one device on the Singtel or M1 network, and nobody else uses it while you rent it. Rent it for a day or for 30 days, pay with crypto, and nothing renews on its own. [Mobile proxies in Singapore on Singtel from $19 a day](https://ipvolt.com/dashboard/mobile?country=SG&plan=day&carrier=Singtel) Residential proxies from $2.20/GB, in prepaid packs. Country selection, HTTP and SOCKS5, sticky or rotating sessions. [Buy residential](https://ipvolt.com/dashboard/residential) ## What ipvolt sells ### Mobile proxies in Singapore from $19 a day. Residential proxies from $2.20/GB, in prepaid packs. [Pricing and payments](https://ipvolt.com/pricing) ## Mobile proxies | Carrier | 1 day | 30 days | | --- | --- | --- | | Singtel | [$19](https://ipvolt.com/dashboard/mobile?country=SG&plan=day&carrier=Singtel) | [$119](https://ipvolt.com/dashboard/mobile?country=SG&plan=month&carrier=Singtel) ($3.97/day) | | M1 | [$19](https://ipvolt.com/dashboard/mobile?country=SG&plan=day&carrier=M1) | [$119](https://ipvolt.com/dashboard/mobile?country=SG&plan=month&carrier=M1) ($3.97/day) | Prices on 11 November 2026. Checkout shows the live price and every carrier in stock, including a carrier that has only one rental length available. Nothing renews on its own. If a device fails and we cannot repair or replace it, we credit the unused part of the rental to your balance, pro rata by the hour. ## What you can test from Singapore. Uses Three jobs people rent a Singapore mobile IP for. Each is something you check yourself; none is a promise about what a site will show. ### Check prices in Singapore dollars Open your storefront through a mobile connection in Singapore and record the currency, the prices and the delivery options it shows. Keep the product and the account state the same between checks. ### See which regional edition your site serves If your site has regional editions, open it from a Singapore mobile IP and record which edition, language and currency it picks before you choose anything yourself. ### Check an ad landing page from Singapore Open your own ad's landing page from a Singapore mobile IP on Singtel or M1 and record the redirect chain, the final URL and the price it shows. ## What a rental includes - No traffic limit. A rental is priced by time, not by the GB. - IP rotation on demand from the dashboard, or on a schedule as often as every 60 seconds, on devices that support it. The carrier assigns the new IP and may return the same one. - If a device fails and we cannot repair or replace it, the unused part of the rental is credited to your balance, pro rata by the hour. - Works over HTTP and SOCKS5. Started rentals are not refundable, except in the cases listed in the [Payments and Refunds Policy](https://ipvolt.com/refunds). ## Connect a mobile proxy with cURL or Python In the dashboard, open the device and select Show connection details. Most devices use one username and password for both protocols, on two ports; some list a separate host and login for each. Replace the placeholders with your values. ```sh curl -sS -x "http://USERNAME:PASSWORD@HOST:HTTP_PORT" https://api.ipify.org curl -sS -x "socks5h://USERNAME:PASSWORD@HOST:SOCKS5_PORT" https://api.ipify.org ``` ```python import os import requests proxy = os.environ["PROXY_URL"] # http://USERNAME:PASSWORD@HOST:HTTP_PORT response = requests.get("https://api.ipify.org", proxies={"http": proxy, "https": proxy}, timeout=30) print(response.text) ``` The printed IP should match the outgoing IP in your dashboard. For a socks5h:// URL in Python, install requests[socks] first. - [Quickstart](https://ipvolt.com/docs/quickstart.md) - [Endpoints and protocols](https://ipvolt.com/docs/endpoints.md) - [Code examples for Node.js, Playwright, Scrapy and Go](https://ipvolt.com/docs/code-examples.md) ## A clearer starting point. Questions ### How much does a Singapore mobile proxy cost? Singtel: $19 for 1 day or $119 for 30 days ($3.97 a day). M1: $19 for 1 day or $119 for 30 days ($3.97 a day). Add funds with crypto and buy from your dashboard; nothing renews automatically. Prices on 11 November 2026. Checkout shows the live price and every carrier in stock, including a carrier that has only one rental length available. ### Can I choose a city in Singapore? No. Mobile proxies are targeted by country and carrier, not by city. ### How do I change the IP of a Singapore mobile proxy? Select Rotate IP now in the dashboard, or set automatic rotation to every 60 seconds, 5 minutes or 30 minutes on devices that support it. The carrier assigns the new IP and can return the same one. Rotation is controlled from the dashboard; there is no public API for it today. ### How do I pay for a Singapore mobile proxy? From a prepaid US-dollar balance that you top up with crypto through our NOWPayments checkout: Tether (USDT), USD Coin (USDC), Bitcoin (BTC), Ethereum (ETH), Solana (SOL) and more. Card payments are coming soon. ## Rent a Singapore mobile proxy. Mobile proxies in Singapore are on sale now. Residential proxies from $2.20/GB, in prepaid packs. [Mobile proxies in Singapore on Singtel from $19 a day](https://ipvolt.com/dashboard/mobile?country=SG&plan=day&carrier=Singtel) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 50 of 138: New Zealand mobile proxies on One NZ. URL: https://ipvolt.com/proxies/new-zealand Markdown: https://ipvolt.com/proxies/new-zealand.md # New Zealand mobile proxies on One NZ. Source: https://ipvolt.com/proxies/new-zealand Markdown: https://ipvolt.com/proxies/new-zealand.md [Home](https://ipvolt.com/index.md) / New Zealand proxies New Zealand · Mobile proxies on sale Each New Zealand mobile proxy is one device on the One NZ network, and nobody else uses it while you rent it. Rent it for a day or for 30 days, pay with crypto, and nothing renews on its own. [Mobile proxies in New Zealand on One NZ from $12 a day](https://ipvolt.com/dashboard/mobile?country=NZ&plan=day&carrier=OneNZ) Residential proxies from $2.20/GB, in prepaid packs. Country selection, HTTP and SOCKS5, sticky or rotating sessions. [Buy residential](https://ipvolt.com/dashboard/residential) ## What ipvolt sells ### Mobile proxies in New Zealand from $12 a day. Residential proxies from $2.20/GB, in prepaid packs. [Pricing and payments](https://ipvolt.com/pricing) ## Mobile proxies | Carrier | 1 day | 30 days | | --- | --- | --- | | One NZ | [$12](https://ipvolt.com/dashboard/mobile?country=NZ&plan=day&carrier=OneNZ) | [$129](https://ipvolt.com/dashboard/mobile?country=NZ&plan=month&carrier=OneNZ) ($4.30/day) | Prices on 11 November 2026. Checkout shows the live price and every carrier in stock, including a carrier that has only one rental length available. Nothing renews on its own. If a device fails and we cannot repair or replace it, we credit the unused part of the rental to your balance, pro rata by the hour. ## What you can test from New Zealand. Uses Three jobs people rent a New Zealand mobile IP for. Each is something you check yourself; none is a promise about what a site will show. ### Check your New Zealand storefront in NZ dollars Open your New Zealand storefront through a mobile connection there and record the currency, the prices and the delivery options. Keep the product and the account state the same between checks. ### See whether New Zealand visitors get their own edition If your site serves Australia and New Zealand separately, open it from a New Zealand mobile IP and record which edition, currency and delivery options appear. ### Check delivery messages for a New Zealand address Enter a New Zealand delivery address in your own checkout from a New Zealand mobile IP on One NZ and record the shipping options, the cost and the delivery estimate shown. ## What a rental includes - No traffic limit. A rental is priced by time, not by the GB. - IP rotation on demand from the dashboard, or on a schedule as often as every 60 seconds, on devices that support it. The carrier assigns the new IP and may return the same one. - If a device fails and we cannot repair or replace it, the unused part of the rental is credited to your balance, pro rata by the hour. - Works over HTTP and SOCKS5. Started rentals are not refundable, except in the cases listed in the [Payments and Refunds Policy](https://ipvolt.com/refunds). ## Connect a mobile proxy with cURL or Python In the dashboard, open the device and select Show connection details. Most devices use one username and password for both protocols, on two ports; some list a separate host and login for each. Replace the placeholders with your values. ```sh curl -sS -x "http://USERNAME:PASSWORD@HOST:HTTP_PORT" https://api.ipify.org curl -sS -x "socks5h://USERNAME:PASSWORD@HOST:SOCKS5_PORT" https://api.ipify.org ``` ```python import os import requests proxy = os.environ["PROXY_URL"] # http://USERNAME:PASSWORD@HOST:HTTP_PORT response = requests.get("https://api.ipify.org", proxies={"http": proxy, "https": proxy}, timeout=30) print(response.text) ``` The printed IP should match the outgoing IP in your dashboard. For a socks5h:// URL in Python, install requests[socks] first. - [Quickstart](https://ipvolt.com/docs/quickstart.md) - [Endpoints and protocols](https://ipvolt.com/docs/endpoints.md) - [Code examples for Node.js, Playwright, Scrapy and Go](https://ipvolt.com/docs/code-examples.md) ## A clearer starting point. Questions ### How much does a New Zealand mobile proxy cost? One NZ: $12 for 1 day or $129 for 30 days ($4.30 a day). Add funds with crypto and buy from your dashboard; nothing renews automatically. Prices on 11 November 2026. Checkout shows the live price and every carrier in stock, including a carrier that has only one rental length available. ### Can I choose a city in New Zealand? No. Mobile proxies are targeted by country and carrier, not by city. ### How do I change the IP of a New Zealand mobile proxy? Select Rotate IP now in the dashboard, or set automatic rotation to every 60 seconds, 5 minutes or 30 minutes on devices that support it. The carrier assigns the new IP and can return the same one. Rotation is controlled from the dashboard; there is no public API for it today. ### How do I pay for a New Zealand mobile proxy? From a prepaid US-dollar balance that you top up with crypto through our NOWPayments checkout: Tether (USDT), USD Coin (USDC), Bitcoin (BTC), Ethereum (ETH), Solana (SOL) and more. Card payments are coming soon. ## Rent a New Zealand mobile proxy. Mobile proxies in New Zealand are on sale now. Residential proxies from $2.20/GB, in prepaid packs. [Mobile proxies in New Zealand on One NZ from $12 a day](https://ipvolt.com/dashboard/mobile?country=NZ&plan=day&carrier=OneNZ) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 51 of 138: Georgia mobile proxies on Magti. URL: https://ipvolt.com/proxies/georgia Markdown: https://ipvolt.com/proxies/georgia.md # Georgia mobile proxies on Magti. Source: https://ipvolt.com/proxies/georgia Markdown: https://ipvolt.com/proxies/georgia.md [Home](https://ipvolt.com/index.md) / Georgia proxies Georgia · Mobile proxies on sale Each Georgian mobile proxy is one device on the Magti network, and nobody else uses it while you rent it. Rent it for a day or for 30 days, pay with crypto, and nothing renews on its own. [Mobile proxies in Georgia on Magti from $9 a day](https://ipvolt.com/dashboard/mobile?country=GE&plan=day&carrier=Magti) Residential proxies from $2.20/GB, in prepaid packs. Country selection, HTTP and SOCKS5, sticky or rotating sessions. [Buy residential](https://ipvolt.com/dashboard/residential) ## What ipvolt sells ### Mobile proxies in Georgia from $9 a day. Residential proxies from $2.20/GB, in prepaid packs. [Pricing and payments](https://ipvolt.com/pricing) ## Mobile proxies | Carrier | 1 day | 30 days | | --- | --- | --- | | Magti | [$9](https://ipvolt.com/dashboard/mobile?country=GE&plan=day&carrier=Magti) | [$109](https://ipvolt.com/dashboard/mobile?country=GE&plan=month&carrier=Magti) ($3.63/day) | Prices on 11 November 2026. Checkout shows the live price and every carrier in stock, including a carrier that has only one rental length available. Nothing renews on its own. If a device fails and we cannot repair or replace it, we credit the unused part of the rental to your balance, pro rata by the hour. ## What you can test from Georgia. Uses Three jobs people rent a Georgian mobile IP for. Each is something you check yourself; none is a promise about what a site will show. ### Check a Georgian-language page and prices in lari Open your Georgian page through a mobile connection in Georgia and record the language, the prices in lari and the payment options. Keep the product and the account state the same between checks. ### See how your site treats a visitor from Georgia Open your own site from a Georgian mobile IP and record the language, the currency and any availability message it shows for the country. ### Test your page on the Magti network Load your page or app over Magti and compare loading, redirects and what is shown with a fixed-line connection. ## What a rental includes - No traffic limit. A rental is priced by time, not by the GB. - IP rotation on demand from the dashboard, or on a schedule as often as every 60 seconds, on devices that support it. The carrier assigns the new IP and may return the same one. - If a device fails and we cannot repair or replace it, the unused part of the rental is credited to your balance, pro rata by the hour. - Works over HTTP and SOCKS5. Started rentals are not refundable, except in the cases listed in the [Payments and Refunds Policy](https://ipvolt.com/refunds). ## Connect a mobile proxy with cURL or Python In the dashboard, open the device and select Show connection details. Most devices use one username and password for both protocols, on two ports; some list a separate host and login for each. Replace the placeholders with your values. ```sh curl -sS -x "http://USERNAME:PASSWORD@HOST:HTTP_PORT" https://api.ipify.org curl -sS -x "socks5h://USERNAME:PASSWORD@HOST:SOCKS5_PORT" https://api.ipify.org ``` ```python import os import requests proxy = os.environ["PROXY_URL"] # http://USERNAME:PASSWORD@HOST:HTTP_PORT response = requests.get("https://api.ipify.org", proxies={"http": proxy, "https": proxy}, timeout=30) print(response.text) ``` The printed IP should match the outgoing IP in your dashboard. For a socks5h:// URL in Python, install requests[socks] first. - [Quickstart](https://ipvolt.com/docs/quickstart.md) - [Endpoints and protocols](https://ipvolt.com/docs/endpoints.md) - [Code examples for Node.js, Playwright, Scrapy and Go](https://ipvolt.com/docs/code-examples.md) ## A clearer starting point. Questions ### How much does a Georgian mobile proxy cost? Magti: $9 for 1 day or $109 for 30 days ($3.63 a day). Add funds with crypto and buy from your dashboard; nothing renews automatically. Prices on 11 November 2026. Checkout shows the live price and every carrier in stock, including a carrier that has only one rental length available. ### Can I choose a city in Georgia? No. Mobile proxies are targeted by country and carrier, not by city. ### How do I change the IP of a Georgian mobile proxy? Select Rotate IP now in the dashboard, or set automatic rotation to every 60 seconds, 5 minutes or 30 minutes on devices that support it. The carrier assigns the new IP and can return the same one. Rotation is controlled from the dashboard; there is no public API for it today. ### How do I pay for a Georgian mobile proxy? From a prepaid US-dollar balance that you top up with crypto through our NOWPayments checkout: Tether (USDT), USD Coin (USDC), Bitcoin (BTC), Ethereum (ETH), Solana (SOL) and more. Card payments are coming soon. ## Rent a Georgian mobile proxy. Mobile proxies in Georgia are on sale now. Residential proxies from $2.20/GB, in prepaid packs. [Mobile proxies in Georgia on Magti from $9 a day](https://ipvolt.com/dashboard/mobile?country=GE&plan=day&carrier=Magti) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 52 of 138: Australia mobile proxies on Vodafone. URL: https://ipvolt.com/proxies/australia Markdown: https://ipvolt.com/proxies/australia.md # Australia mobile proxies on Vodafone. Source: https://ipvolt.com/proxies/australia Markdown: https://ipvolt.com/proxies/australia.md [Home](https://ipvolt.com/index.md) / Australia proxies Australia · Mobile proxies on sale Each Australian mobile proxy is one device on the Vodafone network, and nobody else uses it while you rent it. Rent it for a day or for 30 days, pay with crypto, and nothing renews on its own. [Mobile proxies in Australia on Vodafone from $19 a day](https://ipvolt.com/dashboard/mobile?country=AU&plan=day&carrier=Vodafone%20Australia) Residential proxies from $2.20/GB, in prepaid packs. Country selection, HTTP and SOCKS5, sticky or rotating sessions. [Buy residential](https://ipvolt.com/dashboard/residential) ## What ipvolt sells ### Mobile proxies in Australia from $19 a day. Residential proxies from $2.20/GB, in prepaid packs. [Pricing and payments](https://ipvolt.com/pricing) ## Mobile proxies | Carrier | 1 day | 30 days | | --- | --- | --- | | Vodafone | [$19](https://ipvolt.com/dashboard/mobile?country=AU&plan=day&carrier=Vodafone%20Australia) | [$119](https://ipvolt.com/dashboard/mobile?country=AU&plan=month&carrier=Vodafone%20Australia) ($3.97/day) | Prices on 11 November 2026. Checkout shows the live price and every carrier in stock, including a carrier that has only one rental length available. Nothing renews on its own. If a device fails and we cannot repair or replace it, we credit the unused part of the rental to your balance, pro rata by the hour. ## What you can test from Australia. Uses Three jobs people rent an Australian mobile IP for. Each is something you check yourself; none is a promise about what a site will show. ### Check your Australian storefront on a mobile connection Open your Australian storefront through a connection on Vodafone and record the currency, the prices in Australian dollars and the delivery options. Keep the product, the account state and the delivery postcode the same between checks. ### Review Australian search results and ad landing pages Run the same query, or open your own ad's landing page, from an Australian mobile IP and save what appears with the time of the check. An Australian exit doesn't place you in a particular city or state. ### Reproduce a report from a customer on Vodafone When someone on Vodafone reports a problem with your site or app, load the same page over the same carrier and compare it with a fixed-line connection. ## What a rental includes - No traffic limit. A rental is priced by time, not by the GB. - IP rotation on demand from the dashboard, or on a schedule as often as every 60 seconds, on devices that support it. The carrier assigns the new IP and may return the same one. - If a device fails and we cannot repair or replace it, the unused part of the rental is credited to your balance, pro rata by the hour. - Works over HTTP and SOCKS5. Started rentals are not refundable, except in the cases listed in the [Payments and Refunds Policy](https://ipvolt.com/refunds). ## Connect a mobile proxy with cURL or Python In the dashboard, open the device and select Show connection details. Most devices use one username and password for both protocols, on two ports; some list a separate host and login for each. Replace the placeholders with your values. ```sh curl -sS -x "http://USERNAME:PASSWORD@HOST:HTTP_PORT" https://api.ipify.org curl -sS -x "socks5h://USERNAME:PASSWORD@HOST:SOCKS5_PORT" https://api.ipify.org ``` ```python import os import requests proxy = os.environ["PROXY_URL"] # http://USERNAME:PASSWORD@HOST:HTTP_PORT response = requests.get("https://api.ipify.org", proxies={"http": proxy, "https": proxy}, timeout=30) print(response.text) ``` The printed IP should match the outgoing IP in your dashboard. For a socks5h:// URL in Python, install requests[socks] first. - [Quickstart](https://ipvolt.com/docs/quickstart.md) - [Endpoints and protocols](https://ipvolt.com/docs/endpoints.md) - [Code examples for Node.js, Playwright, Scrapy and Go](https://ipvolt.com/docs/code-examples.md) ## Test an Australian proxy before you rely on it. Go deeper Our Australia guide helps you choose the evidence an Australian proxy test needs: country or city, Telstra/Optus/TPG network labels, nbn provider layers and session requirements. [Read the Australia proxy guide](https://ipvolt.com/guides/australia-proxies) ## A clearer starting point. Questions ### How much does an Australian mobile proxy cost? Vodafone: $19 for 1 day or $119 for 30 days ($3.97 a day). Add funds with crypto and buy from your dashboard; nothing renews automatically. Prices on 11 November 2026. Checkout shows the live price and every carrier in stock, including a carrier that has only one rental length available. ### Can I choose a city in Australia? No. Mobile proxies are targeted by country and carrier, not by city. ### How do I change the IP of an Australian mobile proxy? Select Rotate IP now in the dashboard, or set automatic rotation to every 60 seconds, 5 minutes or 30 minutes on devices that support it. The carrier assigns the new IP and can return the same one. Rotation is controlled from the dashboard; there is no public API for it today. ### How do I pay for an Australian mobile proxy? From a prepaid US-dollar balance that you top up with crypto through our NOWPayments checkout: Tether (USDT), USD Coin (USDC), Bitcoin (BTC), Ethereum (ETH), Solana (SOL) and more. Card payments are coming soon. ## Rent an Australian mobile proxy. Mobile proxies in Australia are on sale now. Residential proxies from $2.20/GB, in prepaid packs. [Mobile proxies in Australia on Vodafone from $19 a day](https://ipvolt.com/dashboard/mobile?country=AU&plan=day&carrier=Vodafone%20Australia) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 53 of 138: Italy mobile proxies on WindTre. URL: https://ipvolt.com/proxies/italy Markdown: https://ipvolt.com/proxies/italy.md # Italy mobile proxies on WindTre. Source: https://ipvolt.com/proxies/italy Markdown: https://ipvolt.com/proxies/italy.md [Home](https://ipvolt.com/index.md) / Italy proxies Italy · Mobile proxies on sale Each Italian mobile proxy is one device on the WindTre network, and nobody else uses it while you rent it. Rent it for a day or for 30 days, pay with crypto, and nothing renews on its own. [Mobile proxies in Italy on WindTre from $9 a day](https://ipvolt.com/dashboard/mobile?country=IT&plan=day&carrier=WindTre) Residential proxies from $2.20/GB, in prepaid packs. Country selection, HTTP and SOCKS5, sticky or rotating sessions. [Buy residential](https://ipvolt.com/dashboard/residential) ## What ipvolt sells ### Mobile proxies in Italy from $9 a day. Residential proxies from $2.20/GB, in prepaid packs. [Pricing and payments](https://ipvolt.com/pricing) ## Mobile proxies | Carrier | 1 day | 30 days | | --- | --- | --- | | WindTre | [$9](https://ipvolt.com/dashboard/mobile?country=IT&plan=day&carrier=WindTre) | [$127](https://ipvolt.com/dashboard/mobile?country=IT&plan=month&carrier=WindTre) ($4.23/day) | Prices on 11 November 2026. Checkout shows the live price and every carrier in stock, including a carrier that has only one rental length available. Nothing renews on its own. If a device fails and we cannot repair or replace it, we credit the unused part of the rental to your balance, pro rata by the hour. ## What you can test from Italy. Uses Three jobs people rent an Italian mobile IP for. Each is something you check yourself; none is a promise about what a site will show. ### Check an Italian storefront in euros Open your Italian storefront through a mobile connection in Italy and record the language, the prices in euros and the delivery options. Keep the product and the account state the same between checks. ### Walk through sign-up or checkout on WindTre Go through your own sign-up or checkout on an Italian mobile connection and note each step that behaves differently from your desktop test. ### Review Italian search results for your keywords Run the same Italian-language query from an Italian mobile IP on different days and save the results with the time of each check. ## What a rental includes - No traffic limit. A rental is priced by time, not by the GB. - IP rotation on demand from the dashboard, or on a schedule as often as every 60 seconds, on devices that support it. The carrier assigns the new IP and may return the same one. - If a device fails and we cannot repair or replace it, the unused part of the rental is credited to your balance, pro rata by the hour. - Works over HTTP and SOCKS5. Started rentals are not refundable, except in the cases listed in the [Payments and Refunds Policy](https://ipvolt.com/refunds). ## Connect a mobile proxy with cURL or Python In the dashboard, open the device and select Show connection details. Most devices use one username and password for both protocols, on two ports; some list a separate host and login for each. Replace the placeholders with your values. ```sh curl -sS -x "http://USERNAME:PASSWORD@HOST:HTTP_PORT" https://api.ipify.org curl -sS -x "socks5h://USERNAME:PASSWORD@HOST:SOCKS5_PORT" https://api.ipify.org ``` ```python import os import requests proxy = os.environ["PROXY_URL"] # http://USERNAME:PASSWORD@HOST:HTTP_PORT response = requests.get("https://api.ipify.org", proxies={"http": proxy, "https": proxy}, timeout=30) print(response.text) ``` The printed IP should match the outgoing IP in your dashboard. For a socks5h:// URL in Python, install requests[socks] first. - [Quickstart](https://ipvolt.com/docs/quickstart.md) - [Endpoints and protocols](https://ipvolt.com/docs/endpoints.md) - [Code examples for Node.js, Playwright, Scrapy and Go](https://ipvolt.com/docs/code-examples.md) ## A clearer starting point. Questions ### How much does an Italian mobile proxy cost? WindTre: $9 for 1 day or $127 for 30 days ($4.23 a day). Add funds with crypto and buy from your dashboard; nothing renews automatically. Prices on 11 November 2026. Checkout shows the live price and every carrier in stock, including a carrier that has only one rental length available. ### Can I choose a city in Italy? No. Mobile proxies are targeted by country and carrier, not by city. ### How do I change the IP of an Italian mobile proxy? Select Rotate IP now in the dashboard, or set automatic rotation to every 60 seconds, 5 minutes or 30 minutes on devices that support it. The carrier assigns the new IP and can return the same one. Rotation is controlled from the dashboard; there is no public API for it today. ### How do I pay for an Italian mobile proxy? From a prepaid US-dollar balance that you top up with crypto through our NOWPayments checkout: Tether (USDT), USD Coin (USDC), Bitcoin (BTC), Ethereum (ETH), Solana (SOL) and more. Card payments are coming soon. ## Rent an Italian mobile proxy. Mobile proxies in Italy are on sale now. Residential proxies from $2.20/GB, in prepaid packs. [Mobile proxies in Italy on WindTre from $9 a day](https://ipvolt.com/dashboard/mobile?country=IT&plan=day&carrier=WindTre) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 54 of 138: ipvolt documentation URL: https://ipvolt.com/docs Markdown: https://ipvolt.com/docs.md # ipvolt documentation Source: https://ipvolt.com/docs Markdown: https://ipvolt.com/docs.md Connect an ipvolt mobile or residential proxy, from the first request to sessions, code and troubleshooting. ## Get started Your first request, and the credentials it needs. - [Quickstart](https://ipvolt.com/docs/quickstart.md): Create an account, add balance with crypto, rent a mobile proxy by country and carrier, copy its connection details and send a first HTTP or SOCKS5 request. - [Authentication](https://ipvolt.com/docs/authentication.md): Where to find your mobile proxy username and password, how to pass them in a proxy URL, and how to keep them out of code and logs. ## Mobile proxies Endpoints, IP rotation and where the devices are. - [Endpoints and protocols](https://ipvolt.com/docs/endpoints.md): What the host, HTTP port, SOCKS5 port and outgoing IP mean, how to choose between HTTP and SOCKS5, and why to use socks5h. - [IP rotation](https://ipvolt.com/docs/rotation.md): Rotate a mobile proxy's IP from the dashboard or every 60 seconds, 5 or 30 minutes, what clients see during a rotation, and how to keep one IP. - [Locations and carriers](https://ipvolt.com/docs/locations.md): The countries and mobile carriers available for ipvolt mobile proxies, how to choose a location, and why targeting is by country and carrier. ## Residential proxies A first request, countries and sessions, and how GB are counted. - [Residential quickstart](https://ipvolt.com/docs/residential-quickstart.md): Buy a prepaid residential pack, find the host, username and key in the dashboard, and send a first request over HTTP or SOCKS5. - [Targeting and sessions](https://ipvolt.com/docs/residential-sessions.md): The residential username format: how to select a country, rotate the IP on every connection or keep a sticky session, and how long a session lasts. - [Usage and billing](https://ipvolt.com/docs/residential-usage.md): How residential GB are counted, where the dashboard shows what is used and left, how to add traffic, and what happens when a pack runs out. ## Build Code, tool setup and error messages. - [Code examples](https://ipvolt.com/docs/code-examples.md): Copy-ready examples for ipvolt mobile and residential proxies in cURL, Python Requests, HTTPX, aiohttp, Node.js, Playwright, Puppeteer, Scrapy and Go. - [Integrations](https://ipvolt.com/docs/integrations.md): Step-by-step proxy setup for curl, Python, Node.js, Axios, Playwright, Scrapy, Git, npm and AI coding agents, with tested errors and fixes. - [Errors and status codes](https://ipvolt.com/docs/errors.md): What 407, 403, 502, 503, WRONG_VERSION_NUMBER and other proxy errors mean with an ipvolt mobile or residential proxy, and the guide that fixes each. ## Account Balance, rentals, renewals and common questions. - [Billing and renewals](https://ipvolt.com/docs/billing.md): How ipvolt's prepaid US-dollar balance, crypto top-ups from $1, mobile rentals and their renewals, residential packs and the refund rules work. - [FAQ](https://ipvolt.com/docs/faq.md): Answers to common questions about ipvolt mobile and residential proxies: payments, renewals, expiry, city targeting, rotation, sessions and support. [Agent reading index](https://ipvolt.com/llms.txt) --- Document 55 of 138: Quickstart URL: https://ipvolt.com/docs/quickstart Markdown: https://ipvolt.com/docs/quickstart.md # Quickstart Source: https://ipvolt.com/docs/quickstart Markdown: https://ipvolt.com/docs/quickstart.md [Home](https://ipvolt.com/index.md) / [Docs](https://ipvolt.com/docs.md) / [Quickstart](https://ipvolt.com/docs/quickstart.md) Section: Get started Updated: 2026-11-05 Author: ipvolt Create an account, add balance with crypto, rent a mobile proxy by country and carrier, copy its connection details and send a first HTTP or SOCKS5 request. This page takes you from a new account to a working request through an ipvolt mobile proxy. It takes a few minutes, plus the time your crypto payment needs to confirm. ## Create an account Open the [dashboard](https://ipvolt.com/dashboard) and sign in with an email address and a one-time code, or by signing a message with an Ethereum, Solana or TRON wallet. There is no password to remember. You accept the [Terms of Service](/terms) when you create the account. ## Add balance ipvolt runs on a prepaid US-dollar balance. In the dashboard, open **Add funds**, enter an amount and select **Continue to NOWPayments**. On NOWPayments' page, choose a coin and network, such as Tether (USDT), USD Coin (USDC), Bitcoin (BTC), Ethereum (ETH) or Solana (SOL), and pay there. Your balance is credited once NOWPayments reports the payment confirmed. Card payments are coming soon. The [Payments and Refunds Policy](/refunds) covers the details. ## Rent a mobile proxy Open [Buy a mobile proxy](https://ipvolt.com/dashboard/mobile), pick a country and a carrier, and choose 1 day or 30 days. The price is reserved from your balance when you confirm and charged once the device is delivered. The device then appears in your dashboard with its outgoing IP, its rotation setting and the time the rental ends. ## Copy the connection details On the device, select **Show connection details**. You get the host, the HTTP port, the SOCKS5 port, the username and the password, and a **Copy details** button. Some devices list a separate host and login for each protocol. The outgoing IP shown above them is the address websites see. ## Send a test request Replace the placeholders with your connection details and run: ```sh curl -x "http://USERNAME:PASSWORD@HOST:HTTP_PORT" https://api.ipify.org ``` The command prints one IP address, which should match the outgoing IP in your dashboard. The same check over SOCKS5: ```sh curl -x "socks5h://USERNAME:PASSWORD@HOST:SOCKS5_PORT" https://api.ipify.org ``` If the request fails, [Errors and status codes](/docs/errors) lists the common messages and what each one means. ## Next steps - [Authentication](/docs/authentication): pass the credentials safely from your code. - [IP rotation](/docs/rotation): change the IP now or on a schedule. - [Code examples](/docs/code-examples): Python, Node.js, Playwright, Puppeteer, Scrapy and Go. ## More documentation - Next: [Authentication](https://ipvolt.com/docs/authentication.md) - [All documentation](https://ipvolt.com/docs.md) --- Document 56 of 138: Authentication URL: https://ipvolt.com/docs/authentication Markdown: https://ipvolt.com/docs/authentication.md # Authentication Source: https://ipvolt.com/docs/authentication Markdown: https://ipvolt.com/docs/authentication.md [Home](https://ipvolt.com/index.md) / [Docs](https://ipvolt.com/docs.md) / [Authentication](https://ipvolt.com/docs/authentication.md) Section: Get started Updated: 2026-11-05 Author: ipvolt Where to find your mobile proxy username and password, how to pass them in a proxy URL, and how to keep them out of code and logs. Every ipvolt mobile proxy has its own username and password. You send them to the proxy, never to the website you visit. This page shows the formats clients accept and how to keep the credentials out of your code. ## Where to find the credentials In the [dashboard](https://ipvolt.com/dashboard), open the device and select **Show connection details**. Most devices use one username and password for both protocols, on two ports. Some list a separate host, port, username and password for HTTP and for SOCKS5; use the set that belongs to the protocol you connect with. ## The proxy URL Most clients take the proxy as one URL: ```text http://USERNAME:PASSWORD@HOST:HTTP_PORT socks5h://USERNAME:PASSWORD@HOST:SOCKS5_PORT ``` The scheme describes how your client talks to the proxy, not to the website. Use `http://` for the HTTP port even when the website is `https://`: the client asks the proxy for a tunnel, and the TLS session with the website runs inside it. If the username or password contains characters such as `@`, `:`, `/` or `%`, percent-encode them in the URL, or use your client's separate username and password fields. ## How the credentials travel On the HTTP port, clients send a `Proxy-Authorization: Basic` header to the proxy, either with each plain HTTP request or once with the `CONNECT` request that opens a tunnel. On the SOCKS5 port, they use the username and password method of the SOCKS5 handshake. In both cases the website never receives them. ## Keep them out of code Store the proxy URL in an environment variable or your secret manager and read it at runtime: ```sh export PROXY_URL="http://USERNAME:PASSWORD@HOST:HTTP_PORT" ``` Do not commit it, print it or paste it into error reports. When you share logs with [support](/support), remove the password and keep the host, the port and the error. ## Dashboard sign-in is separate The email code or wallet you sign in with only opens the dashboard. Proxy credentials cannot sign in to the dashboard, and your dashboard sign-in cannot authenticate proxy traffic. ## When authentication fails A wrong or missing password makes the proxy answer `407 Proxy Authentication Required`. [Fix proxy error 407](/guides/fix-proxy-error-407) shows the symptom in each client and the order of checks. ## More documentation - Previous: [Quickstart](https://ipvolt.com/docs/quickstart.md) - Next: [Endpoints and protocols](https://ipvolt.com/docs/endpoints.md) - [All documentation](https://ipvolt.com/docs.md) --- Document 57 of 138: Endpoints and protocols URL: https://ipvolt.com/docs/endpoints Markdown: https://ipvolt.com/docs/endpoints.md # Endpoints and protocols Source: https://ipvolt.com/docs/endpoints Markdown: https://ipvolt.com/docs/endpoints.md [Home](https://ipvolt.com/index.md) / [Docs](https://ipvolt.com/docs.md) / [Endpoints and protocols](https://ipvolt.com/docs/endpoints.md) Section: Mobile proxies Updated: 2026-11-05 Author: ipvolt What the host, HTTP port, SOCKS5 port and outgoing IP mean, how to choose between HTTP and SOCKS5, and why to use socks5h. Each mobile proxy is its own endpoint: a host and two ports that belong to your device, not a shared gateway name. This page explains each field and how to choose between HTTP and SOCKS5. ## What the dashboard shows | Field | What it is | | --- | --- | | Host | The address your client connects to. | | HTTP port | Accepts HTTP proxy requests, including `CONNECT` tunnels for `https://` websites. | | SOCKS5 port | Accepts SOCKS5 connections with a username and password. | | Username and password | The device's proxy credentials. | | Outgoing IP | The carrier IP websites see. It changes when the device rotates. | Some devices list the HTTP and SOCKS5 endpoints separately, each with its own host and login. ## HTTP or SOCKS5 | | HTTP port | SOCKS5 port | | --- | --- | --- | | Proxy URL | `http://USERNAME:PASSWORD@HOST:HTTP_PORT` | `socks5h://USERNAME:PASSWORD@HOST:SOCKS5_PORT` | | `https://` websites | Tunnelled with `CONNECT` | Tunnelled | | Errors from the proxy | HTTP status codes such as `407` or `502` | SOCKS replies or a closed connection | | Browsers with a login | Playwright and Puppeteer | Chromium does not send SOCKS credentials | | Libraries | curl, Requests, HTTPX, aiohttp, Node.js, Scrapy, Go | curl; Requests and HTTPX with their SOCKS extras | Start with the HTTP port unless your tool only speaks SOCKS5. [HTTP vs SOCKS5 proxies](/guides/http-vs-socks5-proxies) compares the two in more detail. ## Use socks5h for SOCKS5 With `socks5h://` the proxy resolves the website's hostname, so the DNS lookup also leaves from the mobile network. With `socks5://` most clients resolve the name on your machine first and send only the IP address, which exposes the lookup to your own resolver. [socks5 vs socks5h](/blog/socks5-vs-socks5h) shows the difference across six clients. ## Check the connection Request an IP echo service through the proxy and compare the result with the outgoing IP in your dashboard: ```sh curl -sS -x "http://USERNAME:PASSWORD@HOST:HTTP_PORT" https://api.ipify.org ``` ## Common mistakes - An `https://` proxy URL on the HTTP port makes the client start TLS with the proxy, which fails with `SSL: WRONG_VERSION_NUMBER`. Use `http://` for the proxy. See [SSL WRONG_VERSION_NUMBER behind a proxy](/guides/fix-ssl-wrong-version-number-proxy). - An HTTP client pointed at the SOCKS5 port gets no status at all, for example `curl: (56) Proxy CONNECT aborted`. Check the port. See [Tunnel connection failed: 502](/guides/fix-proxy-tunnel-502-503). - A leftover `HTTPS_PROXY` or `NO_PROXY` variable can send traffic somewhere else or around the proxy. See [Proxy environment variables](/guides/proxy-environment-variables). ## More documentation - Previous: [Authentication](https://ipvolt.com/docs/authentication.md) - Next: [IP rotation](https://ipvolt.com/docs/rotation.md) - [All documentation](https://ipvolt.com/docs.md) --- Document 58 of 138: IP rotation URL: https://ipvolt.com/docs/rotation Markdown: https://ipvolt.com/docs/rotation.md # IP rotation Source: https://ipvolt.com/docs/rotation Markdown: https://ipvolt.com/docs/rotation.md [Home](https://ipvolt.com/index.md) / [Docs](https://ipvolt.com/docs.md) / [IP rotation](https://ipvolt.com/docs/rotation.md) Section: Mobile proxies Updated: 2026-11-05 Author: ipvolt Rotate a mobile proxy's IP from the dashboard or every 60 seconds, 5 or 30 minutes, what clients see during a rotation, and how to keep one IP. An ipvolt mobile proxy is one device on a carrier network, and its outgoing IP is the address the carrier assigns to that device. You can ask for a new one at any time, or let the device rotate on a schedule. ## Rotate now In the [dashboard](https://ipvolt.com/dashboard), select **Rotate IP now** on the device. The device reconnects to the carrier and the dashboard reports the result, usually with the new outgoing IP. The carrier can hand back the same IP; if that happens, wait a little and try again. ## Rotate on a schedule Under **Automatic rotation**, choose an interval and select **Save interval**: | Setting | Effect | | --- | --- | | Off | No scheduled rotation. The IP changes only when you rotate it or the carrier reassigns it. | | Every 60 seconds | A new IP about every minute. **Enable 60s rotation** sets this in one click. | | Every 5 minutes | A new IP about every five minutes. | | Every 30 minutes | A new IP about every half hour. | The dashboard shows the setting the device last reported. ## What happens during a rotation Rotation may briefly interrupt traffic. Requests in flight while the device reconnects can fail, and new connections can be refused until the new IP is up. Depending on the client, this shows up as a `502` or `503` on `CONNECT` or as a closed connection; [Tunnel connection failed: 502](/guides/fix-proxy-tunnel-502-503) shows each client's message and a retry pattern. Retry only idempotent requests such as `GET`, and pause your workers around a rotation you start yourself. ## Keep the same IP For logins, carts and other multi-step sessions, set automatic rotation to **Off** and rotate between sessions. A device has one outgoing IP at a time, so every request through it shares that IP. [Rotating vs sticky proxies](/guides/rotating-vs-sticky-proxies) helps you decide how long a session needs one exit. ## Automation Rotation and the rotation interval are controlled from the dashboard. There is no public API for them today. ## More documentation - Previous: [Endpoints and protocols](https://ipvolt.com/docs/endpoints.md) - Next: [Locations and carriers](https://ipvolt.com/docs/locations.md) - [All documentation](https://ipvolt.com/docs.md) --- Document 59 of 138: Locations and carriers URL: https://ipvolt.com/docs/locations Markdown: https://ipvolt.com/docs/locations.md # Locations and carriers Source: https://ipvolt.com/docs/locations Markdown: https://ipvolt.com/docs/locations.md [Home](https://ipvolt.com/index.md) / [Docs](https://ipvolt.com/docs.md) / [Locations and carriers](https://ipvolt.com/docs/locations.md) Section: Mobile proxies Updated: 2026-11-05 Author: ipvolt The countries and mobile carriers available for ipvolt mobile proxies, how to choose a location, and why targeting is by country and carrier. Mobile proxies are available in the countries and on the carriers below. Each rental is one device on the carrier you choose, so the outgoing IP belongs to that carrier's network in that country. ## Countries and carriers | Country | Carriers | | --- | --- | | Germany (DE) | O2, Vodafone, 1&1 | | United States (US) | Verizon, T-Mobile 5G, T-Mobile, AT&T | | United Kingdom (GB) | Three | | France (FR) | SFR, Free | | Netherlands (NL) | Vodafone, Odido | | Poland (PL) | Play | | Singapore (SG) | Singtel, M1 | | New Zealand (NZ) | One NZ | | Georgia (GE) | Magti | | Australia (AU) | Vodafone | | Italy (IT) | WindTre | Stock changes. The table shows the catalog on 11 November 2026; the [checkout](https://ipvolt.com/dashboard/mobile) always shows the carriers in stock right now, and [Pricing](/pricing) lists the price of each for 1 day and 30 days. ## Choosing a location Pick the country whose websites, prices or app behaviour you need to see as a local mobile user, then the carrier. The country guides for the [United States](/guides/usa-proxies), the [United Kingdom](/guides/uk-proxies), [Germany](/guides/germany-proxies), [France](/guides/france-proxies) and the [Netherlands](/guides/netherlands-proxies) explain what to check in each. ## Cities and regions Mobile proxies are targeted by country and carrier, not by city. Where an IP appears to be located is decided by the carrier's network and by geolocation databases, and can differ between rotations. ## More documentation - Previous: [IP rotation](https://ipvolt.com/docs/rotation.md) - Next: [Residential quickstart](https://ipvolt.com/docs/residential-quickstart.md) - [All documentation](https://ipvolt.com/docs.md) --- Document 60 of 138: Residential quickstart URL: https://ipvolt.com/docs/residential-quickstart Markdown: https://ipvolt.com/docs/residential-quickstart.md # Residential quickstart Source: https://ipvolt.com/docs/residential-quickstart Markdown: https://ipvolt.com/docs/residential-quickstart.md [Home](https://ipvolt.com/index.md) / [Docs](https://ipvolt.com/docs.md) / [Residential quickstart](https://ipvolt.com/docs/residential-quickstart.md) Section: Residential proxies Updated: 2026-11-11 Author: ipvolt Buy a prepaid residential pack, find the host, username and key in the dashboard, and send a first request over HTTP or SOCKS5. This page takes you from a new account to a first request through an ipvolt residential proxy: buy a pack, find the connection details, send a request. ## Buy a pack Residential proxies are sold as prepaid packs of GB, paid from your balance. Create an account in the [dashboard](https://ipvolt.com/dashboard) and add funds with crypto, as [Billing and renewals](/docs/billing) describes. Then open the residential proxies page of the dashboard, select a pack under **Choose a pack** and confirm it. | Prepaid pack | Price | Per GB | | --- | --- | --- | | 1 GB | $2.20 | $2.20 | | 5 GB | $11 | $2.20 | | 25 GB | $55 | $2.20 | | 50 GB | $110 | $2.20 | | 100 GB | $220 | $2.20 | | 250 GB | $550 | $2.20 | Every pack costs the same $2.20 per GB. A pack is a one-time purchase. Nothing renews on its own, and we set no expiry date on the GB you buy. ## Find the connection details When the pack is on your key, the same page shows **Your key** and **Connection details**: - the host, `res.ipvolt.com`, with port `7000` for HTTP and `7001` for SOCKS5; - a username, which you get by choosing a network and a country and selecting **Get username**; - your key, which is the password. **Copy proxy URL** copies the whole line, and **Copy command** copies a ready curl command. ## Send a first request Put the proxy URL in an environment variable so that the key stays out of your code and your shell history: ```sh export PROXY_URL="http://USERNAME:KEY@res.ipvolt.com:7000" ``` USERNAME is the whole username from the dashboard, such as `ACCOUNT-peer-us-iptype-residential`, and KEY is your key. Then: ```sh curl -sS -x "http://USERNAME:KEY@res.ipvolt.com:7000" https://api.ipify.org curl -sS -x "socks5h://USERNAME:KEY@res.ipvolt.com:7001" https://api.ipify.org ``` ```python import os import requests proxy = os.environ["PROXY_URL"] # http://USERNAME:KEY@res.ipvolt.com:7000 response = requests.get("https://api.ipify.org", proxies={"http": proxy, "https": proxy}, timeout=30) print(response.text) ``` The printed IP is the address the website sees. For a `socks5h://` URL in Python, install `requests[socks]` first. Your key is sent unencrypted to the gateway, so connect from networks you trust and select **Regenerate** if the key is exposed. ## Next steps - [Targeting and sessions](/docs/residential-sessions): choose a country and keep or rotate the IP. - [Usage and billing](/docs/residential-usage): how GB are counted and what happens at zero. - [Code examples](/docs/code-examples): the same proxy URL works in every example. ## More documentation - Previous: [Locations and carriers](https://ipvolt.com/docs/locations.md) - Next: [Targeting and sessions](https://ipvolt.com/docs/residential-sessions.md) - [All documentation](https://ipvolt.com/docs.md) --- Document 61 of 138: Targeting and sessions URL: https://ipvolt.com/docs/residential-sessions Markdown: https://ipvolt.com/docs/residential-sessions.md # Targeting and sessions Source: https://ipvolt.com/docs/residential-sessions Markdown: https://ipvolt.com/docs/residential-sessions.md [Home](https://ipvolt.com/index.md) / [Docs](https://ipvolt.com/docs.md) / [Targeting and sessions](https://ipvolt.com/docs/residential-sessions.md) Section: Residential proxies Updated: 2026-11-11 Author: ipvolt The residential username format: how to select a country, rotate the IP on every connection or keep a sticky session, and how long a session lasts. The username carries your choices. This page explains what each part does. The dashboard's **Advanced** section builds these usernames for you, so copy lines from there rather than typing them: a misspelt word is ignored without an error. ## The username format The username is your account name followed by your choices, joined by hyphens: the network, the country, then any session settings. The password is always your key. ```text ACCOUNT-peer-us-iptype-residential ``` | Part | Meaning | | --- | --- | | `ACCOUNT` | Your account name, shown in the dashboard's connection details. | | `peer` | The residential network. `mbl` is the mobile network (see below). | | `us` | The two-letter country code. | | `iptype-residential` | Asks for addresses classed as residential. | ## Choose a country Change the country code: `ACCOUNT-peer-de-iptype-residential`, `ACCOUNT-peer-gb-iptype-residential`. A pack is not tied to a country, and the same GB work in every country the network has. The dashboard lists the countries available now. Availability changes with the network, and a filter that matches nothing is refused rather than widened. ## Rotating sessions Without a session ID, each new connection is routed again and can leave from a different IP. This is the username the dashboard gives you first, and it suits requests that do not depend on each other. ## Sticky sessions Add a session ID to keep one binding across connections: ```text ACCOUNT-peer-us-iptype-residential-sid-task1-rot-sticky-ttl-3600 ``` | Part | Meaning | | --- | --- | | `sid-task1` | The session ID: lowercase letters, digits and underscores, up to 64 characters. Reuse it to return to the same binding. | | `rot-sticky` | Sticky rotation: prefer the same IP for the whole session. | | `ttl-3600` | How long the binding is kept, in seconds. | Instead of `rot-sticky`, a timed rotation moves the session to a new IP after a set time: `rot-auto5`, `rot-auto10`, `rot-auto20`, `rot-auto60` for 5, 10, 20 or 60 minutes. It is checked on the next connection after the interval. Open connections are not cut, and a different IP is not guaranteed. ## How long a sticky session lasts The dashboard offers five lifetimes for the binding: 1 hour, 6 hours, 1 day, 7 days and 30 days. That is how long the session is remembered. It is not a promise that one IP or one connection lasts that long: a network change can still change the IP. Keep one session for the steps of one task on one site, such as a login. For many sites, use a separate session for each. After a 502 or a dropped connection, try again with a new session ID, because the same session returns to the same device. ## Mobile per GB Dedicated mobile is one device rented by the day, with no traffic limit. Mobile per GB uses the same prepaid GB on a shared pool of carrier modems. Pick Mobile as the network in the dashboard, and the username names the mobile network instead: ```text ACCOUNT-mbl-us ``` The mobile network takes no `iptype` setting, and it has fewer countries than the residential network. ## More documentation - Previous: [Residential quickstart](https://ipvolt.com/docs/residential-quickstart.md) - Next: [Usage and billing](https://ipvolt.com/docs/residential-usage.md) - [All documentation](https://ipvolt.com/docs.md) --- Document 62 of 138: Usage and billing URL: https://ipvolt.com/docs/residential-usage Markdown: https://ipvolt.com/docs/residential-usage.md # Usage and billing Source: https://ipvolt.com/docs/residential-usage Markdown: https://ipvolt.com/docs/residential-usage.md [Home](https://ipvolt.com/index.md) / [Docs](https://ipvolt.com/docs.md) / [Usage and billing](https://ipvolt.com/docs/residential-usage.md) Section: Residential proxies Updated: 2026-11-11 Author: ipvolt How residential GB are counted, where the dashboard shows what is used and left, how to add traffic, and what happens when a pack runs out. Residential proxies are billed by traffic from prepaid packs. This page summarizes how the GB are counted and what happens when they run out; the [Terms](/terms) and the [Payments and Refunds Policy](/refunds) are the binding text. ## How GB are counted Traffic is counted as upload plus download, where 1 GB is 1,024 MB. A 1 GB pack carries 1 GB of traffic in any country and on either network, residential or mobile. Failed and retried requests use traffic too, like any other request. ## Where to see your balance Open the residential proxies page of the dashboard. **Your key** shows the traffic used, the traffic left and the total you have bought, and **Usage, last 30 days** lists it by day. The figures come from the network's counters, which run behind actual use, so the number can be late and the real figure may be higher. ## Add traffic Select **Add traffic** and choose a pack. A later pack adds GB to the same key and does not reset what you have used. Nothing renews automatically, and we set no expiry date on the GB you buy. ## What happens at zero When you have used over 80% of your traffic, the dashboard marks the key **Almost used**. When the traffic is used up, the key stops and new connections are refused. Traffic on connections that are still open keeps counting and comes out of your next pack. Buy another pack to switch the key back on, which can take a minute or two. A pack that is smaller than the traffic already used past the limit is refused without charge. ## Refunds Packs are not refundable once the traffic is on your key, even if you have not used it. If your key fails and we cannot get it working again, we credit your unused GB to your balance. The [Payments and Refunds Policy](/refunds) lists the other cases. ## More documentation - Previous: [Targeting and sessions](https://ipvolt.com/docs/residential-sessions.md) - Next: [Code examples](https://ipvolt.com/docs/code-examples.md) - [All documentation](https://ipvolt.com/docs.md) --- Document 63 of 138: Code examples URL: https://ipvolt.com/docs/code-examples Markdown: https://ipvolt.com/docs/code-examples.md # Code examples Source: https://ipvolt.com/docs/code-examples Markdown: https://ipvolt.com/docs/code-examples.md [Home](https://ipvolt.com/index.md) / [Docs](https://ipvolt.com/docs.md) / [Code examples](https://ipvolt.com/docs/code-examples.md) Section: Build Updated: 2026-11-11 Author: ipvolt Copy-ready examples for ipvolt mobile and residential proxies in cURL, Python Requests, HTTPX, aiohttp, Node.js, Playwright, Puppeteer, Scrapy and Go. Each example sends one request through an ipvolt proxy and prints the outgoing IP. They read the connection details from environment variables, so no credentials end up in your code: ```sh export PROXY_URL="http://USERNAME:PASSWORD@HOST:HTTP_PORT" export PROXY_HOST="HOST" export PROXY_HTTP_PORT="HTTP_PORT" export PROXY_USERNAME="USERNAME" export PROXY_PASSWORD="PASSWORD" ``` With a mobile proxy, the values are the device's host, ports, username and password, and the printed IP should match the outgoing IP in your dashboard. With a residential proxy, the host is `res.ipvolt.com`, the HTTP port is `7000`, the username is the one the dashboard builds for your network and country, and the password is your key; see the [Residential quickstart](/docs/residential-quickstart). The examples are the same for both. Each section links to a guide that covers the client's options and errors in depth. ## cURL ```sh curl -sS -x "$PROXY_URL" https://api.ipify.org ``` For SOCKS5, use `-x "socks5h://USERNAME:PASSWORD@HOST:SOCKS5_PORT"`. See [Use a proxy with curl](/guides/curl-proxy-setup). ## Python Requests ```python import os import requests proxy = os.environ["PROXY_URL"] response = requests.get("https://api.ipify.org", proxies={"http": proxy, "https": proxy}, timeout=30) print(response.text) ``` For a `socks5h://` URL, install `requests[socks]` first. See [Python Requests proxy](/guides/python-requests-proxy). ## Python HTTPX ```python import os import httpx with httpx.Client(proxy=os.environ["PROXY_URL"], timeout=30) as client: print(client.get("https://api.ipify.org").text) ``` See [HTTPX async proxies](/guides/httpx-async-proxy). ## Python aiohttp ```python import asyncio import os import aiohttp async def main(): async with aiohttp.ClientSession() as session: async with session.get("https://api.ipify.org", proxy=os.environ["PROXY_URL"]) as response: print(await response.text()) asyncio.run(main()) ``` See [aiohttp proxies](/guides/aiohttp-proxy-setup). ## Node.js ```js import { fetch, ProxyAgent } from 'undici'; const dispatcher = new ProxyAgent(process.env.PROXY_URL); const response = await fetch('https://api.ipify.org', { dispatcher }); console.log(await response.text()); ``` On Node.js 24.5 or later, the built-in `fetch` can use the proxy without undici: run your script with `NODE_USE_ENV_PROXY=1` and `HTTPS_PROXY` set to the proxy URL. See [Use a proxy with Node.js fetch](/guides/nodejs-fetch-proxy). ## Playwright ```js import { chromium } from 'playwright'; const browser = await chromium.launch({ proxy: { server: `http://${process.env.PROXY_HOST}:${process.env.PROXY_HTTP_PORT}`, username: process.env.PROXY_USERNAME, password: process.env.PROXY_PASSWORD, }, }); const page = await browser.newPage(); await page.goto('https://api.ipify.org'); console.log(await page.textContent('body')); await browser.close(); ``` Use the HTTP port for browsers: Chromium does not send SOCKS5 credentials. See [Configure a proxy in Playwright](/guides/playwright-proxy-setup). ## Puppeteer ```js import puppeteer from 'puppeteer'; const browser = await puppeteer.launch({ args: [`--proxy-server=http://${process.env.PROXY_HOST}:${process.env.PROXY_HTTP_PORT}`], }); const page = await browser.newPage(); await page.authenticate({ username: process.env.PROXY_USERNAME, password: process.env.PROXY_PASSWORD }); await page.goto('https://api.ipify.org'); console.log(await page.evaluate(() => document.body.innerText)); await browser.close(); ``` See [Fix ERR_TUNNEL_CONNECTION_FAILED](/guides/fix-err-tunnel-connection-failed) if the page does not load. ## Scrapy ```python import os import scrapy class IpSpider(scrapy.Spider): name = "ip" async def start(self): yield scrapy.Request("https://api.ipify.org", meta={"proxy": os.environ["PROXY_URL"]}) def parse(self, response): self.logger.info("Outgoing IP: %s", response.text) ``` See [Scrapy proxies](/guides/scrapy-proxy-setup). ## Go ```go package main import ( "fmt" "io" "net/http" "net/url" "os" "time" ) func main() { proxyURL, err := url.Parse(os.Getenv("PROXY_URL")) if err != nil { panic(err) } client := &http.Client{ Transport: &http.Transport{Proxy: http.ProxyURL(proxyURL)}, Timeout: 30 * time.Second, } resp, err := client.Get("https://api.ipify.org") if err != nil { panic(err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { panic(err) } fmt.Println(string(body)) } ``` ## More documentation - Previous: [Usage and billing](https://ipvolt.com/docs/residential-usage.md) - Next: [Integrations](https://ipvolt.com/docs/integrations.md) - [All documentation](https://ipvolt.com/docs.md) --- Document 64 of 138: Integrations URL: https://ipvolt.com/docs/integrations Markdown: https://ipvolt.com/docs/integrations.md # Integrations Source: https://ipvolt.com/docs/integrations Markdown: https://ipvolt.com/docs/integrations.md [Home](https://ipvolt.com/index.md) / [Docs](https://ipvolt.com/docs.md) / [Integrations](https://ipvolt.com/docs/integrations.md) Section: Build Updated: 2026-11-05 Author: ipvolt Step-by-step proxy setup for curl, Python, Node.js, Axios, Playwright, Scrapy, Git, npm and AI coding agents, with tested errors and fixes. An ipvolt mobile proxy works with any tool that accepts an HTTP or SOCKS5 proxy. These guides show the exact settings, tested error messages and fixes for common tools. Use the host, ports and login from your dashboard wherever a guide uses a placeholder. ## HTTP clients and libraries | Tool | Guide | | --- | --- | | cURL | [Use a proxy with curl: -x, env vars, SOCKS5, auth](/guides/curl-proxy-setup) | | Python Requests | [Python Requests proxy: proxies dict, auth, SOCKS5](/guides/python-requests-proxy) | | Python HTTPX | [HTTPX async proxies](/guides/httpx-async-proxy) | | Python aiohttp | [aiohttp proxies: auth, env vars and errors](/guides/aiohttp-proxy-setup) | | curl_cffi | [curl_cffi proxies: auth, 407 and SOCKS](/guides/curl-cffi-proxy-setup) | | Node.js fetch | [Use a proxy with Node.js fetch](/guides/nodejs-fetch-proxy) | | Axios | [Axios proxy setup: routing, auth and NO_PROXY](/guides/axios-proxy-setup) | ## Browsers and automation | Tool | Guide | | --- | --- | | Playwright | [Configure a proxy in Playwright](/guides/playwright-proxy-setup) | | Playwright, saving traffic | [Block images, fonts and media in Playwright](/guides/playwright-block-images-save-bandwidth) | | Playwright and Puppeteer errors | [Fix ERR_TUNNEL_CONNECTION_FAILED](/guides/fix-err-tunnel-connection-failed) | | MostLogin | [MostLogin proxy setup](/blog/mostlogin-proxy-setup) | ## Crawlers and developer tools | Tool | Guide | | --- | --- | | Scrapy | [Scrapy proxies: auth, rotation and errors](/guides/scrapy-proxy-setup) | | Git | [Git proxy setup](/guides/git-proxy-setup) | | npm | [npm proxy settings](/guides/npm-proxy-settings) | | Any tool that reads `HTTP_PROXY` | [Proxy environment variables: HTTP_PROXY and NO_PROXY](/guides/proxy-environment-variables) | ## AI coding agents [Proxy Toolkit MCP](/mcp) gives MCP-compatible agents proxy configuration templates and error diagnostics. Give it the client and a sanitized error message, never your proxy password. ## More documentation - Previous: [Code examples](https://ipvolt.com/docs/code-examples.md) - Next: [Errors and status codes](https://ipvolt.com/docs/errors.md) - [All documentation](https://ipvolt.com/docs.md) --- Document 65 of 138: Errors and status codes URL: https://ipvolt.com/docs/errors Markdown: https://ipvolt.com/docs/errors.md # Errors and status codes Source: https://ipvolt.com/docs/errors Markdown: https://ipvolt.com/docs/errors.md [Home](https://ipvolt.com/index.md) / [Docs](https://ipvolt.com/docs.md) / [Errors and status codes](https://ipvolt.com/docs/errors.md) Section: Build Updated: 2026-11-11 Author: ipvolt What 407, 403, 502, 503, WRONG_VERSION_NUMBER and other proxy errors mean with an ipvolt mobile or residential proxy, and the guide that fixes each. Most proxy errors say which side failed: your client, the proxy, or the website behind it. Find the message you see, then follow the guide for the exact fix. ## Messages and what they mean | What you see | Usually means | Guide | | --- | --- | --- | | `407 Proxy Authentication Required` | The username or password did not reach the proxy, or is wrong. | [Fix proxy error 407](/guides/fix-proxy-error-407) | | `CONNECT tunnel failed, response 403` | The proxy or a firewall on your side refused that destination. | [CONNECT tunnel failed, response 403](/blog/connect-tunnel-failed-403) | | `502`, `503` or `504` while the tunnel opens | The proxy could not reach the website, or the device was offline or rotating. | [Tunnel connection failed: 502](/guides/fix-proxy-tunnel-502-503) | | A `502` response after the tunnel opened | The website, or something in front of it, returned the error. | [Tunnel connection failed: 502](/guides/fix-proxy-tunnel-502-503) | | `Proxy CONNECT aborted` or a closed connection with no status | Often the wrong port or protocol, or a rotation in progress. | [Endpoints and protocols](/docs/endpoints) | | `SSL: WRONG_VERSION_NUMBER` | An `https://` proxy URL on the HTTP port. | [SSL WRONG_VERSION_NUMBER behind a proxy](/guides/fix-ssl-wrong-version-number-proxy) | | `net::ERR_TUNNEL_CONNECTION_FAILED` | Chromium could not open the tunnel. | [Fix ERR_TUNNEL_CONNECTION_FAILED](/guides/fix-err-tunnel-connection-failed) | | `TypeError: fetch failed` in Node.js | The real cause is in `err.cause`. | [Fix Node.js fetch failed behind a proxy](/guides/fix-node-fetch-failed-proxy) | | `Missing dependencies for SOCKS support` | A `socks5h://` URL without the SOCKS extra installed. | [Fix Missing dependencies for SOCKS support](/guides/fix-missing-dependencies-for-socks-support) | | Timeouts | One of DNS, connect, tunnel or response took too long. | [Troubleshoot proxy timeouts](/guides/proxy-timeout-troubleshooting) | ## Check one request first Before changing your application, run one request with curl and print both status codes: ```sh curl -sS -o /dev/null -x "http://USERNAME:PASSWORD@HOST:HTTP_PORT" \ -w 'connect=%{http_connect} http=%{http_code} exit=%{exitcode}\n' \ https://api.ipify.org ``` `connect` is the proxy's answer to the tunnel request and `http` is the website's answer. If curl works and your application does not, compare how the application passes the proxy settings. ## Check the device For a mobile proxy, the dashboard shows whether the device is online, its outgoing IP and when the rental ends. An expired rental stops working; see [Billing and renewals](/docs/billing). If a website blocks the current IP, rotating gives the device a new one, although the carrier can return the same IP. ## Check a residential key For a residential proxy, open the residential proxies page of the dashboard and look at **Your key**. A key marked **Used up** has no traffic left and refuses new connections until you add a pack; a key marked **Paused** needs an email to support. A username that selects a country or a filter with nothing available is refused rather than widened, so check the country against the list in the dashboard. After a 502 or a dropped connection on a sticky session, try again with a new session ID. See [Targeting and sessions](/docs/residential-sessions) and [Usage and billing](/docs/residential-usage). ## Contact support If the device still does not work, email hello@ipvolt.com with the device name, its outgoing IP, the order number from your dashboard, what you tried (rotating, HTTP and SOCKS5) and the exact error. For a residential key, send the first characters of the key shown in the dashboard, the time in UTC, the country and session settings you used and the error. Never include your password or the full key. [Support](/support) lists reply times. ## More documentation - Previous: [Integrations](https://ipvolt.com/docs/integrations.md) - Next: [Billing and renewals](https://ipvolt.com/docs/billing.md) - [All documentation](https://ipvolt.com/docs.md) --- Document 66 of 138: Billing and renewals URL: https://ipvolt.com/docs/billing Markdown: https://ipvolt.com/docs/billing.md # Billing and renewals Source: https://ipvolt.com/docs/billing Markdown: https://ipvolt.com/docs/billing.md [Home](https://ipvolt.com/index.md) / [Docs](https://ipvolt.com/docs.md) / [Billing and renewals](https://ipvolt.com/docs/billing.md) Section: Account Updated: 2026-11-11 Author: ipvolt How ipvolt's prepaid US-dollar balance, crypto top-ups from $1, mobile rentals and their renewals, residential packs and the refund rules work. ipvolt runs on a prepaid US-dollar balance. You top it up with crypto, rent mobile proxies and buy residential packs from it, and nothing renews on its own. This page summarizes how that works; the [Payments and Refunds Policy](/refunds) is the binding text. ## Top up your balance In the dashboard, open **Add funds**, enter the amount you want, from $1, and select **Continue to NOWPayments**. Choose a coin and network on NOWPayments' page and pay the amount it shows before its timer ends. Your balance is credited automatically once NOWPayments reports the payment confirmed. If a payment is short, late or on the wrong network, the policy explains what happens and [Support](/support) explains what to send us. ## Rent a device A mobile proxy is rented for 1 day or for 30 days. When you confirm an order, the price is reserved from your balance and charged only once the device is delivered; if the order cannot be fulfilled, the amount returns to your balance. Current prices are on the [Pricing](/pricing) page, and the checkout always shows the live price. ## Renew before the rental ends Rentals do not renew automatically. To keep a device, open it in the dashboard, choose 1 day or 30 days under **Renew this device** and select **Get renewal price**. The quote is valid for two minutes; confirm it to pay from your balance. The dashboard warns you when a rental ends within 24 hours. When a rental ends, the device and its credentials stop working. ## Buy a residential pack Residential proxies are billed per GB from prepaid packs. Open the residential proxies page of the dashboard, choose a pack and confirm it: the price is reserved from your balance and charged only once the traffic is added to your key. Packs do not renew automatically, and we set no expiry date on the GB you buy. [Usage and billing](/docs/residential-usage) explains how GB are counted and what happens when they run out, and [Pricing](/pricing) lists the packs. ## Refunds Residential packs are not refundable once the traffic is on your key, even if you have not used it, except in the cases the policy lists. Started rentals are not refundable, except that unused time is credited to your balance, pro rata by the hour, if a device fails and cannot be repaired or replaced, or if we stop a rental for a reason other than a breach of the [Terms](/terms) or the [Acceptable Use Policy](/acceptable-use). Rotation, the carrier returning the same IP, or a website blocking a device do not qualify. Order refunds are credited to your balance. Balance does not expire, and cannot be withdrawn or transferred. ## More documentation - Previous: [Errors and status codes](https://ipvolt.com/docs/errors.md) - Next: [FAQ](https://ipvolt.com/docs/faq.md) - [All documentation](https://ipvolt.com/docs.md) --- Document 67 of 138: FAQ URL: https://ipvolt.com/docs/faq Markdown: https://ipvolt.com/docs/faq.md # FAQ Source: https://ipvolt.com/docs/faq Markdown: https://ipvolt.com/docs/faq.md [Home](https://ipvolt.com/index.md) / [Docs](https://ipvolt.com/docs.md) / [FAQ](https://ipvolt.com/docs/faq.md) Section: Account Updated: 2026-11-11 Author: ipvolt Answers to common questions about ipvolt mobile and residential proxies: payments, renewals, expiry, city targeting, rotation, sessions and support. ## What is an ipvolt mobile proxy? A dedicated device on a carrier network. You rent it for a day or for 30 days, connect over HTTP or SOCKS5, and rotate its IP on demand or on a schedule. Nobody else uses the device while you rent it. ## Do you have residential proxies? Yes. Residential proxies are sold in prepaid packs, billed per GB: IPs from a mixed peer network, with country selection, over HTTP and SOCKS5. Dedicated mobile is one device rented by the day, with no traffic limit. Mobile per GB uses the same prepaid GB on a shared pool of carrier modems. [Pricing](/pricing) lists the packs, and the [Residential quickstart](/docs/residential-quickstart) takes you to a first request. ## Do residential GB expire? No. We set no expiry date on the GB you buy, and a later pack adds GB to the same key. See [Usage and billing](/docs/residential-usage). ## Can I keep the same residential IP? Use a sticky session, which keeps one binding for 1 hour to 30 days and prefers the same IP. A network change can still change it. See [Targeting and sessions](/docs/residential-sessions). ## Which payment methods can I use? Crypto, through our NOWPayments checkout: Tether (USDT), USD Coin (USDC), Bitcoin (BTC), Ethereum (ETH), Solana (SOL) and more. Card payments are coming soon. See [Billing and renewals](/docs/billing). ## Does anything renew automatically? No. A mobile rental ends with the period you chose, and you can renew it from the dashboard before it ends. Residential packs are prepaid and are bought one at a time. ## Can I choose a city? No. Mobile proxies are targeted by country and carrier; see [Locations and carriers](/docs/locations). Residential proxies are selected by country in the username; see [Targeting and sessions](/docs/residential-sessions). ## Can I rotate the IP from my code? Not for a mobile device today: rotation and the rotation interval are controlled from the dashboard. See [IP rotation](/docs/rotation). A residential proxy rotates through its username: without a session ID each connection is routed again. ## HTTP or SOCKS5? Use the HTTP port unless your tool only speaks SOCKS5; browsers need it for authentication. See [Endpoints and protocols](/docs/endpoints). ## How do I check that the proxy works? Request an IP echo service through it, as in the [Quickstart](/docs/quickstart), and compare the result with the outgoing IP in your dashboard. ## What may I use it for? Lawful use only, under the [Acceptable Use Policy](/acceptable-use). Rentals stopped for a breach are not refunded. ## How do I contact support? Email hello@ipvolt.com. [Support](/support) explains what to include and how quickly we reply. ## More documentation - Previous: [Billing and renewals](https://ipvolt.com/docs/billing.md) - [All documentation](https://ipvolt.com/docs.md) --- Document 68 of 138: Use a proxy with curl: -x, env vars, SOCKS5, auth URL: https://ipvolt.com/guides/curl-proxy-setup Markdown: https://ipvolt.com/guides/curl-proxy-setup.md # Use a proxy with curl: -x, env vars, SOCKS5, auth Source: https://ipvolt.com/guides/curl-proxy-setup Markdown: https://ipvolt.com/guides/curl-proxy-setup.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) Category: Integration Published: 2026-09-11 Reading time: 7 minutes Author: ipvolt How to use a proxy with curl: the -x flag, http_proxy and https_proxy variables, SOCKS5 with socks5h, proxy authentication, and reading CONNECT and 407 errors. ## The starting point Every way curl selects a proxy, from one -x flag to environment variables, with the authentication, SOCKS5 and tunnel details that decide whether the request succeeds. ## Set a proxy for one request with -x The -x option, spelled --proxy in long form, routes a single curl request through a proxy. Give it the proxy scheme, host and port. When the scheme is omitted curl assumes http://, and when the port is omitted it assumes 1080, so write both explicitly. The scheme describes the connection to the proxy, not the destination. An https:// destination through an ordinary HTTP proxy still uses -x http://host:port; curl opens a CONNECT tunnel through it. Write -x https://host:port only when the provider terminates TLS on the proxy itself. curl also accepts socks4://, socks4a://, socks5:// and socks5h:// here. The command below keeps two habits from the rest of this guide: --disable ignores a curlrc that might add its own proxy, and --noproxy '' cancels any inherited no_proxy exclusion so the request really goes through the gateway you named. proxy.example.invalid deliberately cannot resolve; substitute your provider's gateway. Without --compressed, the command sends no Accept-Encoding header, so a server that compresses only when asked returns the full uncompressed page through the proxy; if you pay per GB, see [which clients skip compression and how to check the bytes](/guides/curl-compressed-accept-encoding). ### curl -x · one request through a proxy ```sh curl --disable --noproxy '' \ -x http://proxy.example.invalid:8080 \ https://example.com/ ``` ## Proxy authentication: -U, --proxy-user and 407 Proxy credentials are separate from destination credentials. -U or --proxy-user sends them to the proxy; -u or --user sends them to the destination. Using the wrong option can leave the proxy asking for credentials with 407 or the destination asking with 401, even when the supplied password is correct. When the 407 persists with correct credentials, work through [fix proxy error 407](/guides/fix-proxy-error-407) one variable at a time. You can also embed credentials in the proxy URL as http://user:password@host:port. Percent-encode reserved characters first: an @ in the password must become %40 or curl reads it as the start of the host. Basic is the default proxy authentication scheme; --proxy-digest, --proxy-ntlm and --proxy-anyauth select others when the provider documents them. Typing a password directly in either form can record it in shell history and exposes it in the initial process arguments. A shell variable can avoid a literal password in the command you type, if you populate it privately, but --proxy-user "$PROXY_USERNAME:$PROXY_PASSWORD" still expands the secret into an argument before curl starts. curl hides that argument on supported systems only after startup; a later process listing can miss the exposure. See the [curl proxy-user documentation](https://curl.se/docs/manpage.html#--proxy-user). For scripts with curl 8.3.0 or later, the example below imports exported variables inside curl. Have your secret manager supply them, keep shell tracing off, and do not paste secret-bearing export commands into history. This avoids a password in curl's arguments; it does not hide the inherited environment or process memory from accounts permitted to inspect them. For an interactive check, --proxy-user username with no colon prompts for the password instead. Argument handling does not encrypt the proxy connection. HTTP Basic credentials sent to an http:// proxy are not protected by the later HTTPS destination tunnel. Use an https:// gateway when your provider supports it, and keep proxy certificate verification enabled. - connect=407 or the message Received HTTP code 407 from proxy after CONNECT means the proxy rejected the credentials or received none. Check the -U value, the encoding and the provider's username format. - A 401 from the destination while the tunnel succeeded is a destination problem; the proxy step is already working. - If your provider encodes country, session or protocol options in the username, follow its documented format. --proxy-user expects the supplied username and password separated by a colon; it is not a URL-encoding step. ### curl 8.3+ · import credentials inside curl ```sh : "${PROXY_USERNAME:?}" "${PROXY_PASSWORD:?}" curl --disable --noproxy '' \ -x http://proxy.example.invalid:8080 \ --variable %PROXY_USERNAME \ --variable %PROXY_PASSWORD \ --expand-proxy-user '{{PROXY_USERNAME}}:{{PROXY_PASSWORD}}' \ https://example.com/ ``` ## Environment variables: http_proxy, https_proxy, no_proxy and .curlrc Without -x, curl looks for a proxy in the environment. It reads http_proxy in lowercase only, because the uppercase name can be set by CGI request headers; it accepts https_proxy or HTTPS_PROXY, all_proxy or ALL_PROXY, and no_proxy or NO_PROXY. The variable is chosen by the destination scheme: an https:// destination uses https_proxy, so http_proxy alone does not configure the HTTPS route; an ALL_PROXY fallback or another setting can still affect it. curl_cffi, the Python binding to libcurl, follows the same lowercase rule; [curl_cffi proxies](/guides/curl-cffi-proxy-setup) records it together with the exceptions that a rejected CONNECT and a failed SOCKS handshake raise. no_proxy is a comma-separated list of hostnames or domain suffixes that bypass the proxy, and a single * disables proxying entirely. -x overrides the gateway selected by proxy environment variables, but no_proxy can still bypass that gateway. --noproxy overrides no_proxy; an empty --noproxy value cancels inherited exclusions. The [proxy environment variables guide](/guides/proxy-environment-variables) covers how other clients read the same variables, which matters when curl behaves differently from the application you are debugging. A ~/.curlrc file can set proxy = "http://host:port" for every invocation, which is convenient on a workstation and surprising inside a container or CI job. Run curl with --disable, or its short form -q as the first argument, when a script must ignore it. ### http_proxy and https_proxy · shell session ```sh export http_proxy='http://proxy.example.invalid:8080' export https_proxy='http://proxy.example.invalid:8080' export no_proxy='localhost,127.0.0.1,.internal.example' curl https://example.com/ # uses https_proxy curl --noproxy '*' https://example.com/ # bypasses the proxy once ``` ## SOCKS5 with curl: socks5 versus socks5h curl speaks SOCKS through the same -x option. socks5:// resolves the destination hostname on your machine and sends the proxy an IP address. socks5h:// sends the hostname and lets the proxy resolve it, which is what you want when the destination must be resolved from the proxy's network or when local DNS should not see the destination at all. The long options --socks5 and --socks5-hostname are equivalent. If you are still deciding between the two protocols, [HTTP vs SOCKS5 proxies](/guides/http-vs-socks5-proxies) explains where DNS and TLS happen in each. Username and password authentication for SOCKS5 uses the same --proxy-user option. SOCKS has no HTTP CONNECT status; a rejected SOCKS handshake can surface as curl exit code 97 with a reason, rather than an HTTP 407. The shell-expanded credentials in this compatibility example still enter the initial argument list; use the curl 8.3+ import form above when that exposure must be avoided. ### curl socks5h · proxy-side DNS ```sh curl --disable --noproxy '' \ -x socks5h://proxy.example.invalid:1080 \ --proxy-user "$PROXY_USERNAME:$PROXY_PASSWORD" \ https://example.com/ ``` ## HTTPS destinations: the CONNECT tunnel and -v For an https:// destination through an HTTP proxy, curl first sends CONNECT example.com:443 to the proxy. After a successful CONNECT response, curl starts TLS with the destination inside the tunnel. An ordinary forwarding proxy cannot read that encrypted HTTP exchange; a TLS-intercepting proxy trusted by your client is a different case. Run with -v to watch both steps; the CONNECT response arrives before any destination headers. -p or --proxytunnel forces the same tunnel for a plain http:// destination. For a plain http:// destination there is no tunnel. curl sends the full URL to the proxy, the proxy fetches it, and the response headers you see may come from either party. When a status code needs attributing to a layer, prefer the tunneled case and read the CONNECT status separately with the %{http_connect} write-out variable. With an https:// proxy, curl verifies the proxy's certificate as well as the destination's. --proxy-cacert supplies a private trust bundle for the proxy; keep both verifications enabled rather than reaching for --proxy-insecure or -k. ## Send one bounded request as a baseline Save this as proxy-check.sh and run it with sh proxy-check.sh. It requires curl 8.3.0 or later and HTTP Basic proxy authentication. Have your secret manager export PROXY_USERNAME and PROXY_PASSWORD, and export PROXY_URL with your provider's gateway with its scheme and port; https://proxy.example.invalid:8443 is an illustrative value that deliberately cannot connect. curl imports the credentials itself, so the password is not passed in curl's arguments. The guards reject missing or empty values; environment and tracing limits still apply. The command prints the destination status, the CONNECT status and the elapsed time, and discards the response body. Keep this baseline before adding a browser, concurrency or application code. If this baseline works but an HTTP(S) Git repository download fails, use [Git proxy setup](/guides/git-proxy-setup) to inspect Git's URL and remote settings. curl's configuration does not select Git's route. ### proxy-check.sh · curl 8.3+ ```sh : "${PROXY_URL:?Set your provider proxy URL}" : "${PROXY_USERNAME:?}" "${PROXY_PASSWORD:?}" curl --disable --silent --show-error --fail \ --noproxy '' \ --proxy "$PROXY_URL" \ --variable %PROXY_USERNAME \ --variable %PROXY_PASSWORD \ --expand-proxy-user '{{PROXY_USERNAME}}:{{PROXY_PASSWORD}}' \ --connect-timeout 10 --max-time 30 \ --output /dev/null \ --write-out 'http=%{http_code} connect=%{http_connect} seconds=%{time_total}\n' \ 'https://example.com/' ``` ## Read curl exit codes and find the failing layer A synthetic loopback check with curl 8.7.1 compared the credential paths: shell expansion put the password in the initial arguments; curl-internal import did not. Both sent the same test credentials. A later process listing showed curl had cleared the shell-expanded value, so that listing alone would have missed the exposure. These checks establish local command behavior, not provider security or proxy performance. Reproduce the check with the [loopback fixture](/downloads/curl-proxy-auth/credential_fixture.py) and inspect the [synthetic results](/downloads/curl-proxy-auth/credential-results.json). It tests HTTP Basic with invented credentials; it does not test an external proxy service. A successful response proves this request completed; it does not establish a particular exit country or carrier. For that, use your provider's documented diagnostic endpoint or an endpoint you control that reports the observed source address. Keep the same destination and credentials when comparing your application with curl. Changing three settings at once makes a successful retry hard to explain. Share the exit code, timing and sanitized status with support, rather than a verbose trace containing authentication data. Exit 35 and exit 56 can print the same unexpected eof while reading text and give different retry answers; [SSL EOF occurred in violation of protocol behind a proxy](/guides/fix-ssl-unexpected-eof-proxy) separates them. - Exit 5, could not resolve proxy: the gateway hostname is wrong or local DNS cannot see it. - Exit 7, failed to connect: the proxy host resolved but the port is closed, filtered or unreachable from this network. - Exit 28, operation timed out: compare the connection and total time limits with the recorded timing. A repeat does not by itself identify whether the gateway, destination or chosen deadline caused it. - connect=407: the proxy requires authentication. Our curl 8.7.1 loopback test returned exit 22 with the baseline's --fail and exit 56 without it. Read the CONNECT status with the exit code; do not require exit 56 before checking proxy credentials. - Exit 97, proxy handshake error: the SOCKS handshake was rejected; check the socks5 versus socks5h scheme and the credentials. - Exit 35 or 60, TLS failure: check the hostname, trust chain and clock. Keep certificate verification enabled. - Exit 35 with wrong version number is not a certificate problem: a TLS handshake was answered in plaintext, either by the proxy port or by the destination port. [SSL WRONG_VERSION_NUMBER behind a proxy](/guides/fix-ssl-wrong-version-number-proxy) shows how %{http_connect} tells the two apart. ## Before you ship - Use an actual gateway from your provider, with the scheme and port it documents. - Inject credentials privately; do not paste secrets into shell history. - Record one bounded baseline before testing parallel traffic. - Note whether the failure came from the CONNECT step or the destination before changing settings. ## Sources & further reading - [curl manual: -x, --proxy-user, --noproxy and write-out variables](https://curl.se/docs/manpage.html) - [Everything curl: proxy environment variables](https://everything.curl.dev/usingcurl/proxies/env.html) - [Everything curl: SOCKS proxies and hostname resolution](https://everything.curl.dev/usingcurl/proxies/socks.html) - [Everything curl: proxy authentication](https://everything.curl.dev/usingcurl/proxies/auth.html) - [Everything curl: separate proxy and destination connections](https://everything.curl.dev/transfers/conn/proxies.html) - [libcurl error codes](https://curl.se/libcurl/c/libcurl-errors.html) ## Related guides - [Fix proxy error 407 without guessing](https://ipvolt.com/guides/fix-proxy-error-407.md) - [HTTP vs SOCKS5 proxies: choose by the connection](https://ipvolt.com/guides/http-vs-socks5-proxies.md) - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md) - [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md) - [curl --compressed: which clients skip compression](https://ipvolt.com/guides/curl-compressed-accept-encoding.md) - [curl_cffi proxies: auth, the 407 that ProxyError misses, and SOCKS](https://ipvolt.com/guides/curl-cffi-proxy-setup.md) - [Git proxy setup: HTTPS, config scope and safe removal](https://ipvolt.com/guides/git-proxy-setup.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 69 of 138: Python Requests proxy: proxies dict, auth, SOCKS5 URL: https://ipvolt.com/guides/python-requests-proxy Markdown: https://ipvolt.com/guides/python-requests-proxy.md # Python Requests proxy: proxies dict, auth, SOCKS5 Source: https://ipvolt.com/guides/python-requests-proxy Markdown: https://ipvolt.com/guides/python-requests-proxy.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md) Category: Integration Reviewed: 2026-09-19 Published: 2026-09-11 Reading time: 7 minutes Author: ipvolt Configure a proxy in Python Requests: the proxies dictionary, Session defaults, credentials, SOCKS5 via requests[socks], environment variables and ProxyError. ## The starting point The proxies dictionary, Session-level defaults, credential encoding, SOCKS5, environment behavior and the exceptions Requests raises when the proxy step fails. ## Set a proxy on a request with the proxies dictionary Requests selects a proxy from a dictionary whose keys are destination schemes. The value for https is used for https:// destinations, and the value for http is used for http:// destinations; both usually point at the same gateway. The key all applies to any scheme, and a key such as https://example.com pins one host to a specific gateway. The value is the proxy URL, with its own scheme. http://host:port is an ordinary HTTP proxy; for an https:// destination Requests asks it to open a CONNECT tunnel. Only use https://host:port as the proxy URL when the provider terminates TLS on the proxy. Always pass a timeout; without one a stalled proxy blocks the call indefinitely. ### requests.get with proxies · one request ```python import requests PROXIES = { "http": "http://proxy.example.invalid:8080", "https": "http://proxy.example.invalid:8080", } response = requests.get( "https://example.com/", proxies=PROXIES, timeout=(10, 20), ) print(response.status_code) ``` ## Use a Session so every request shares the proxy A Session keeps the connection pool, cookies and proxy settings together. Set session.proxies once and every request made through that Session uses the gateway, while a proxies argument on an individual call still overrides it. This is also where you decide whether the process environment may contribute settings: trust_env=False stops Requests from reading HTTP_PROXY, HTTPS_PROXY, NO_PROXY, netrc credentials and the REQUESTS_CA_BUNDLE variable, so the code alone defines the route. For asynchronous workloads that need the same control over a connection pool, see the [httpx async proxy guide](/guides/httpx-async-proxy). ### requests.Session · shared proxy settings ```python import requests with requests.Session() as session: session.trust_env = False session.proxies.update({ "http": "http://proxy.example.invalid:8080", "https": "http://proxy.example.invalid:8080", }) for url in ("https://example.com/", "https://example.com/robots.txt"): response = session.get(url, timeout=(10, 20)) print(url, response.status_code) ``` ## Proxy authentication: encode credentials in the URL Requests sends proxy credentials from the proxy URL itself, as http://username:password@host:port; it adds the Proxy-Authorization header for you. The auth argument is destination authentication and does not reach the proxy. Encode the username and password individually so characters such as @, : or / cannot change the URL structure, and keep the original PROXY_URL free of credentials. Save the script below as proxy_check.py and run python proxy_check.py after installing Requests in a virtual environment with python -m pip install requests. https://proxy.example.invalid:8443 is only a nonworking illustration. ### proxy_check.py · Python 3 + Requests ```python import os from urllib.parse import quote, urlsplit, urlunsplit import requests gateway = urlsplit(os.environ["PROXY_URL"]) if gateway.scheme not in {"http", "https"} or not gateway.hostname: raise ValueError("Use your provider's HTTP(S) proxy URL") if gateway.username is not None or gateway.path not in {"", "/"} or gateway.query or gateway.fragment: raise ValueError("Keep credentials and paths out of PROXY_URL") username = quote(os.environ["PROXY_USERNAME"], safe="") password = quote(os.environ["PROXY_PASSWORD"], safe="") proxy = urlunsplit((gateway.scheme, f"{username}:{password}@{gateway.netloc}", "", "", "")) with requests.Session() as session: session.trust_env = False with session.get( "https://example.com/", proxies={"http": proxy, "https": proxy}, timeout=(10, 20), allow_redirects=False, stream=True, ) as response: response.raise_for_status() print({"status": response.status_code}) ``` ## Environment variables and trust_env When trust_env is left at its default of True, Requests fills in any scheme you did not set from the environment through urllib.request.getproxies(). It accepts HTTP_PROXY, HTTPS_PROXY, ALL_PROXY and NO_PROXY in upper or lower case, and on macOS it also reads the system proxy configuration. That is convenient on a workstation and a common source of surprise in containers, where an HTTPS_PROXY inherited from the image routes traffic you believed was direct. NO_PROXY is a comma-separated list of hostnames, domain suffixes or IP addresses that bypass the proxy. Requests and urllib do not match it the same way (Requests honors CIDR ranges, urllib does not); [the NO_PROXY matrix](/blog/no-proxy-matching-tested) compares Requests with urllib, HTTPX and aiohttp. For a job whose route must be reproducible, set trust_env=False and pass the proxies explicitly; for a workstation script, setting the variables and calling Requests with no proxies argument is enough. The [proxy environment variables guide](/guides/proxy-environment-variables) shows how to observe which route a client actually selected before blaming the proxy. ### HTTPS_PROXY · picked up when trust_env is True ```sh export HTTPS_PROXY='http://proxy.example.invalid:8080' export NO_PROXY='localhost,127.0.0.1,.internal.example' python -c 'import requests; print(requests.get("https://example.com/", timeout=(10, 20)).status_code)' ``` ## SOCKS5 proxies: requests[socks], socks5 versus socks5h SOCKS support comes from the PySocks extra: install it with python -m pip install "requests[socks]", then use a socks5:// or socks5h:// proxy URL in the same dictionary. socks5 resolves the destination hostname locally and sends the proxy an IP address; socks5h sends the hostname so the proxy resolves it, which is usually what a remote gateway expects. Username and password go in the URL exactly as for HTTP proxies. Scrapy is different: its default download handler has no SOCKS support, so [Scrapy proxy setup](/guides/scrapy-proxy-setup) shows what works there. If a Scrapy spider logs Crawled 0 pages after an upgrade, see [start_requests() not called](/guides/scrapy-start-requests-not-called). If Requests raises InvalidSchema: Missing dependencies for SOCKS support, PySocks is not importable from the interpreter running your code, or a variable such as ALL_PROXY is supplying a SOCKS URL you never set. [Fix Missing dependencies for SOCKS support](/guides/fix-missing-dependencies-for-socks-support) covers each case, including pip failing with the same message. ### socks5h proxy · requests[socks] ```python import requests PROXIES = { "http": "socks5h://proxy.example.invalid:1080", "https": "socks5h://proxy.example.invalid:1080", } response = requests.get("https://example.com/", proxies=PROXIES, timeout=(10, 20)) print(response.status_code) ``` ## Rotate between several proxies When a job needs to spread requests across gateways, keep one Session for the connection pool and choose the proxies argument per request. The example cycles through a list; a real job would draw from configuration, record which gateway served each request, and retire a gateway after repeated failures rather than retrying it immediately. Whether consecutive requests should keep the same exit address is a session-model decision, and many providers express it through the username or a dedicated port. Follow the provider's documentation rather than inferring it from one successful request. In Scrapy the same rotation is a per-request proxy value in Request.meta, set by a downloader middleware; [Scrapy proxies in 2.19](/guides/scrapy-proxy-setup) shows it and what happens to a hand-set Proxy-Authorization header when the proxy changes. ### itertools.cycle · one Session, several gateways ```python from itertools import cycle import requests GATEWAYS = cycle([ "http://proxy-a.example.invalid:8080", "http://proxy-b.example.invalid:8080", ]) with requests.Session() as session: session.trust_env = False for url in ("https://example.com/", "https://example.com/robots.txt"): gateway = next(GATEWAYS) response = session.get(url, proxies={"http": gateway, "https": gateway}, timeout=(10, 20)) print(gateway, url, response.status_code) ``` ## Know what the timeout measures The tuple supplies separate connect and read timeouts. A read timeout limits waiting for socket data; it is not a total download deadline. Apply a separate wall-clock budget in your job runner when a whole task must finish by a fixed time. The diagnostic above streams and closes the response without downloading the full body. When a request still stalls, [troubleshoot proxy timeouts one stage at a time](/guides/proxy-timeout-troubleshooting) to find which stage consumed the budget. Setting trust_env to False also disables Requests' environment-derived CA-bundle settings. If your organization uses a custom trust bundle, pass its approved file explicitly with verify. Do not use verify=False to make a failing test pass. ## Read the errors: ProxyError, 407 and timeouts How a proxy failure surfaces depends on the destination scheme. For an https:// destination the failure happens during the CONNECT tunnel, and Requests raises requests.exceptions.ProxyError whose message includes the proxy's reply, for example Tunnel connection failed: 407 Proxy Authentication Required. For a plain http:// destination there is no tunnel, so a 407 arrives as an ordinary Response with status_code 407 and no exception at all; check for it explicitly. Run the same gateway and destination in curl before adding retry logic. Record the exception class, attempt number and elapsed time, with credentials removed. A reproducible authentication error needs a configuration change; repeating it at higher concurrency adds noise. If the message names RemoteDisconnected or SSLEOFError, [check whether the request was sent](/guides/fix-ssl-unexpected-eof-proxy) before mounting Retry or max_retries: ProxyError can appear after a delivered request. - ProxyError with 407: the proxy rejected the credentials in the URL. Re-check the encoding and the provider's username format. Requests also lets an HTTPS_PROXY variable override Session.proxies; the [407 guide](/guides/fix-proxy-error-407) reproduces that and the other ways credentials fail to reach the proxy. - ProxyError with Cannot connect to proxy or a name-resolution message: the gateway host or port is wrong, or this network cannot reach it. - ProxyError saying Your proxy appears to only use HTTP and not HTTPS, or SSLError with WRONG_VERSION_NUMBER: a TLS handshake was answered in plaintext. The first points at an https:// proxy URL on a plain HTTP proxy port, the second at the destination port; [which hop failed](/guides/fix-ssl-wrong-version-number-proxy) separates the two. - ConnectTimeout: the connect part of the timeout tuple expired before the proxy or destination answered. ReadTimeout: the connection worked but no data arrived within the read limit. - SSLError after a successful tunnel: certificate verification failed for the destination, or the proxy is intercepting TLS. Keep verification on and confirm with the provider. - A successful HTTP request alone does not verify the exit's location. ## Before you ship - Use a project virtual environment. - Encode credentials separately from the gateway. - Decide explicitly whether the environment may contribute proxy settings. - Keep a job deadline in addition to network timeouts. ## Sources & further reading - [Requests: proxies, environment configuration and SOCKS](https://requests.readthedocs.io/en/latest/user/advanced/#proxies) - [Requests: timeouts and errors](https://requests.readthedocs.io/en/latest/user/quickstart/#timeouts) - [Requests API: Session.trust_env and Session.proxies](https://requests.readthedocs.io/en/latest/api/#requests.Session.trust_env) - [urllib3: proxies and tunneling](https://urllib3.readthedocs.io/en/stable/advanced-usage.html#proxies) - [Python: urllib.request.getproxies and environment variables](https://docs.python.org/3/library/urllib.request.html#urllib.request.getproxies) - [Python: URL parsing and quoting](https://docs.python.org/3/library/urllib.parse.html) ## Related guides - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md) - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md) - [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md) - [Fix proxy error 407 without guessing](https://ipvolt.com/guides/fix-proxy-error-407.md) - [Fix "Missing dependencies for SOCKS support" in Requests, pip and HTTPX](https://ipvolt.com/guides/fix-missing-dependencies-for-socks-support.md) - [Scrapy proxies in 2.19: auth, rotation and the errors you'll hit](https://ipvolt.com/guides/scrapy-proxy-setup.md) - [SSL EOF occurred in violation of protocol behind a proxy: was the request sent?](https://ipvolt.com/guides/fix-ssl-unexpected-eof-proxy.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 70 of 138: Use a proxy with Node.js fetch URL: https://ipvolt.com/guides/nodejs-fetch-proxy Markdown: https://ipvolt.com/guides/nodejs-fetch-proxy.md # Use a proxy with Node.js fetch Source: https://ipvolt.com/guides/nodejs-fetch-proxy Markdown: https://ipvolt.com/guides/nodejs-fetch-proxy.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Use a proxy with Node.js fetch](https://ipvolt.com/guides/nodejs-fetch-proxy.md) Category: Integration Published: 2026-09-11 Reading time: 4 minutes Author: ipvolt Route Node.js native fetch through an Undici ProxyAgent with explicit authentication, an abort deadline and response cleanup. ## The starting point Use a dispatcher for one fetch call so the proxy is explicit and other network clients in your process keep their own configuration. ## Choose a compatible runtime and dispatcher This server-side example targets Node.js 24 and Undici 7. The agent must come from an undici major that the runtime's built-in fetch accepts: on Node 26, undici 5 and 6 agents fail with invalid onError method, and on Node 22 or 24, undici 8 agents fail with invalid onRequestStart method ([how to fix both](/guides/fix-node-fetch-failed-proxy)). In a separate example project, run npm install undici@7. Node's built-in fetch accepts an Undici-compatible dispatcher. This is different from browser fetch, where page JavaScript cannot select an arbitrary system proxy. On Node.js 26, [fetch failed: invalid onError method on Node.js 26](/guides/node-26-invalid-onerror-method) shows how to find an older undici copy and replace its agent. If npm install undici@7 fails behind your gateway, [npm proxy settings](/guides/npm-proxy-settings) checks registry metadata and the package archive separately. npm's installation settings do not configure this runtime fetch dispatcher. Use a provider-documented HTTP(S) gateway in PROXY_URL, for example the deliberately nonworking https://proxy.example.invalid:8443. Inject PROXY_USERNAME and PROXY_PASSWORD through your deployment's secret manager. Do not put gateway credentials in frontend code. If the same gateway works from the [curl baseline](/guides/curl-proxy-setup) but not from Node, the difference is in the dispatcher configuration, not the proxy. ## Keep proxy authentication on the dispatcher Save as proxy-check.mjs and run node proxy-check.mjs. The Basic token belongs to the proxy agent, not to the destination's Authorization header. The request has a 30-second abort deadline and does not follow redirects automatically. A 407 at this step means the proxy rejected those credentials; [fix proxy error 407](/guides/fix-proxy-error-407) lists what to check in order. ### proxy-check.mjs · Node.js 24 + Undici 7 ```javascript import { ProxyAgent } from 'undici'; function required(name) { const value = process.env[name]; if (!value) throw new Error('Missing environment variable: ' + name); return value; } const gateway = new URL(required('PROXY_URL')); if (!['http:', 'https:'].includes(gateway.protocol) || gateway.username || gateway.password) { throw new Error('Use a credential-free HTTP(S) proxy URL'); } const credentials = required('PROXY_USERNAME') + ':' + required('PROXY_PASSWORD'); const dispatcher = new ProxyAgent({ uri: gateway.href, token: 'Basic ' + Buffer.from(credentials).toString('base64'), }); try { const response = await fetch('https://example.com/', { dispatcher, signal: AbortSignal.timeout(30_000), redirect: 'manual', }); await response.body?.cancel(); if (!response.ok) throw new Error('Destination HTTP ' + response.status); console.log({ status: response.status }); } finally { await dispatcher.close(); } ``` ## Move from a diagnostic to a worker This script deliberately cancels the response body because the diagnostic needs only a status. A worker that uses the result should consume the body within its budget. Always consume or cancel it before moving on, and close the dispatcher when the worker shuts down. For repeated jobs, reuse a dispatcher with bounded concurrency rather than creating one per request. Keep each job's deadline separate. Do not install a process-wide dispatcher unless changing every affected client's routing is intentional. If you rely on HTTP_PROXY and NO_PROXY instead of an explicit dispatcher, [proxy environment variables](/guides/proxy-environment-variables) covers how they are read and where NO_PROXY changes the route. When a request does fail, print the whole err.cause chain before changing anything: [Fix Node.js TypeError: fetch failed behind a proxy](/guides/fix-node-fetch-failed-proxy) decodes each cause string, from an ignored HTTPS_PROXY and undici version skew to the CONNECT status the error hides. If you work in an MCP-compatible coding agent, [Proxy Toolkit MCP](/mcp) can suggest causes and next checks from a sanitized error. Keep passwords, private URLs and full logs out of the prompt; the toolkit does not route your application's requests. - An HTTP error is a response; fetch does not reject merely because its status is 4xx or 5xx. - A rejected CONNECT, such as a 407 or 403, rejects with TypeError: fetch failed before any Response exists; the real reason is in err.cause, one or two levels down. - Capture sanitized error categories; do not log the Basic token or full credential-bearing URLs. ## Before you ship - Use the documented Node and Undici major versions. - Pass the dispatcher explicitly. - Consume or cancel response bodies and close the agent. ## Sources & further reading - [Node.js: fetch and custom dispatchers](https://nodejs.org/api/globals.html#fetch) - [Undici 7: ProxyAgent authentication and lifecycle](https://github.com/nodejs/undici/blob/v7.16.0/docs/docs/api/ProxyAgent.md) - [Undici: runtime support and response body handling](https://github.com/nodejs/undici) ## Related guides - [fetch failed: invalid onError method on Node 26 (undici fix)](https://ipvolt.com/guides/node-26-invalid-onerror-method.md) - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md) - [HTTP vs SOCKS5 proxies: choose by the connection](https://ipvolt.com/guides/http-vs-socks5-proxies.md) - [Node.js fetch Ignores HTTPS_PROXY: Fix UND_ERR_CONNECT_TIMEOUT in One Line](https://ipvolt.com/guides/node-fetch-ignores-https-proxy.md) - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) - [Fix Node.js TypeError: fetch failed behind a proxy](https://ipvolt.com/guides/fix-node-fetch-failed-proxy.md) - [npm proxy settings: npmrc, precedence and install failures](https://ipvolt.com/guides/npm-proxy-settings.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 71 of 138: Configure a proxy in Playwright URL: https://ipvolt.com/guides/playwright-proxy-setup Markdown: https://ipvolt.com/guides/playwright-proxy-setup.md # Configure a proxy in Playwright Source: https://ipvolt.com/guides/playwright-proxy-setup Markdown: https://ipvolt.com/guides/playwright-proxy-setup.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Configure a proxy in Playwright](https://ipvolt.com/guides/playwright-proxy-setup.md) Category: Integration Reviewed: 2026-09-19 Published: 2026-09-11 Reading time: 4 minutes Author: ipvolt Set an authenticated HTTP proxy for a Playwright browser context, keep test state isolated, and diagnose navigation separately from subresources. ## The starting point Route a controlled browser test through a proxy while keeping credentials, browser state and navigation failures easy to reason about. ## Choose the scope of the test Playwright supports a proxy at browser launch or on an individual browser context. Use a context for an isolated scenario. The proxy username and password are separate from httpCredentials, which authenticates to a website. Whether the whole scenario should keep one exit is a session question; [rotating vs sticky proxies](/guides/rotating-vs-sticky-proxies) explains how to align a proxy session with a complete workflow. Images, fonts and media load through the proxy too. On a plan billed per GB, [block images and fonts in Playwright](/guides/playwright-block-images-save-bandwidth) to cut those bytes. In a Node.js example project, install playwright and its Chromium browser with npm install playwright followed by npx playwright install chromium. Set PROXY_URL to your actual HTTP(S) gateway; https://proxy.example.invalid:8443 is an illustration. Inject PROXY_USERNAME and PROXY_PASSWORD privately. ## Run a bounded navigation Save as proxy-browser.mjs and run node proxy-browser.mjs. This example uses username/password authentication for an HTTP(S) proxy; do not assume these authentication options also work with a SOCKS gateway. If the navigation fails with net::ERR_TUNNEL_CONNECTION_FAILED, the [tunnel error guide](/guides/fix-err-tunnel-connection-failed) shows how to read what the proxy answered to CONNECT; if it times out instead, the [407 guide](/guides/fix-proxy-error-407) explains why a rejected proxy login looks like a slow page under the default waitUntil. ### proxy-browser.mjs · Playwright Chromium ```javascript import { chromium } from 'playwright'; function required(name) { const value = process.env[name]; if (!value) throw new Error('Missing environment variable: ' + name); return value; } const proxy = { server: required('PROXY_URL'), username: required('PROXY_USERNAME'), password: required('PROXY_PASSWORD'), }; const browser = await chromium.launch({ timeout: 30_000 }); try { const context = await browser.newContext({ proxy }); context.setDefaultTimeout(15_000); context.setDefaultNavigationTimeout(30_000); const page = await context.newPage(); const response = await page.goto('https://example.com/', { waitUntil: 'domcontentloaded', }); if (!response || !response.ok()) throw new Error('Navigation did not succeed'); console.log({ status: response.status() }); await context.close(); } finally { await browser.close(); } ``` ## Separate page success from network success A navigation response describes the main document, not every image, script or API request the page makes. For a real test, assert the exact screen or response your workflow depends on. Use a page you control and keep the assertion tied to one observable outcome. A page that loads but shows a challenge instead of content is a different failure; [Cloudflare AI agent blocks: what to fix first](/blog/cloudflare-ai-agent-proxy-setup) works through that case. A single page can generate many requests. If your provider rotates per request, confirm how it handles those connections before expecting one stable exit throughout a browser flow. Cookies remain browser state; choosing a sticky proxy does not create or restore them. When a page times out, first repeat a small request through the same gateway in curl. Then inspect sanitized browser request failures and the specific failing resource. Avoid collecting screenshots or traces containing real account data during a basic connectivity check. ## Before you ship - Use a fresh context for the scenario. - Keep proxy and website credentials separate. - Verify the application's real success condition after navigation. ## Sources & further reading - [Playwright: HTTP proxy and network events](https://playwright.dev/docs/network#http-proxy) - [Playwright: browser contexts and timeouts](https://playwright.dev/docs/api/class-browsercontext) - [Playwright: navigation response behavior](https://playwright.dev/docs/api/class-page#page-goto) ## Related guides - [Block Images, Fonts and Media in Playwright to Cut Proxy Bandwidth](https://ipvolt.com/guides/playwright-block-images-save-bandwidth.md) - [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md) - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) - [Mobile vs residential proxies: build a useful evaluation](https://ipvolt.com/guides/mobile-vs-residential-proxies.md) - [Fix ERR_TUNNEL_CONNECTION_FAILED in Playwright and Puppeteer](https://ipvolt.com/guides/fix-err-tunnel-connection-failed.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Residential from $2.20 per GB. Mobile from $9 a day. [Buy residential](https://ipvolt.com/dashboard/residential) [Buy mobile](https://ipvolt.com/dashboard/mobile) --- Document 72 of 138: HTTP vs SOCKS5 proxies: choose by the connection URL: https://ipvolt.com/guides/http-vs-socks5-proxies Markdown: https://ipvolt.com/guides/http-vs-socks5-proxies.md # HTTP vs SOCKS5 proxies: choose by the connection Source: https://ipvolt.com/guides/http-vs-socks5-proxies Markdown: https://ipvolt.com/guides/http-vs-socks5-proxies.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [HTTP vs SOCKS5 proxies: choose by the connection](https://ipvolt.com/guides/http-vs-socks5-proxies.md) Category: Concept Reviewed: 2026-09-19 Published: 2026-09-11 Reading time: 4 minutes Author: ipvolt Compare HTTP CONNECT and SOCKS5, understand DNS placement and TLS boundaries, and select a protocol your actual client and provider support. ## The starting point Choose the proxy protocol independently from the type of exit IP. An HTTP or SOCKS label does not tell you whether the exit is mobile or residential. ## Start with the client and destination An HTTP proxy understands HTTP requests. For an HTTPS destination, a common approach is CONNECT: the proxy establishes a tunnel to the destination host and port, then the client negotiates destination TLS through it. SOCKS5 negotiates a relay connection at a different protocol layer and defines TCP and UDP operations. Protocol capability is not a service promise. A SOCKS5 provider or client may not implement the UDP behavior your application needs. Confirm support for the exact operation, authentication method and destination port before selecting it. Client support differs too: [Python Requests](/guides/python-requests-proxy) needs the requests[socks] extra for SOCKS, and [Node.js fetch](/guides/nodejs-fetch-proxy) selects the proxy through an Undici dispatcher. ## Decide where destination DNS runs In curl's URL convention, socks5:// resolves the destination locally; socks5h:// sends the destination hostname to the proxy for resolution. This affects which resolver sees the query and which address it returns. The gateway's own hostname still needs to be resolved by your client. The [curl guide](/guides/curl-proxy-setup) shows the same distinction as socks5:// versus socks5h:// on the command line. Other clients do not all follow curl's convention: [socks5 vs socks5h, tested](/blog/socks5-vs-socks5h) records what six of them actually send to the proxy. For a regional QA test, record DNS placement alongside the exit region. Otherwise two runs can differ because of the resolver rather than the network you intended to compare. Changing to remote DNS is a controlled test parameter, not a guarantee that the returned content belongs to a specific region. ## Draw both TLS boundaries An HTTPS proxy encrypts the client-to-proxy connection. An HTTPS destination encrypts the destination connection. These are independent layers, with independent certificate validation. A plain HTTP gateway can tunnel an HTTPS destination, but its own authentication exchange is not thereby protected by destination TLS. Ask your provider whether it offers TLS to the gateway and whether it intercepts destination TLS. Standard tunneling and an inspecting corporate proxy have different trust requirements. Keep verification enabled on whichever TLS layers are in use. ## Use a small selection test For a web-only application, begin with the protocol its HTTP client supports cleanly. If another application specifically requires SOCKS, verify that requirement directly. Compare both on the same permitted destination before making performance claims. - Can the client authenticate using the provider's method? - Can it resolve the destination at the intended side of the connection? - Does it support the required ports and transport? - Can your team diagnose and monitor failures at each layer? ## Before you ship - Separate protocol, exit type and rotation mode. - Record destination DNS behavior. - Verify both gateway and destination TLS where applicable. ## Sources & further reading - [RFC 9110: CONNECT semantics](https://www.rfc-editor.org/rfc/rfc9110.html#name-connect) - [RFC 1928: SOCKS5 operations](https://datatracker.ietf.org/doc/html/rfc1928) - [Everything curl: SOCKS and DNS](https://everything.curl.dev/usingcurl/proxies/socks.html) - [Everything curl: proxy TLS connections](https://everything.curl.dev/transfers/conn/proxies.html) ## Related guides - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) - [Use a proxy with Node.js fetch](https://ipvolt.com/guides/nodejs-fetch-proxy.md) - [Mobile vs residential proxies: build a useful evaluation](https://ipvolt.com/guides/mobile-vs-residential-proxies.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 73 of 138: Rotating vs sticky proxies: plan for session continuity URL: https://ipvolt.com/guides/rotating-vs-sticky-proxies Markdown: https://ipvolt.com/guides/rotating-vs-sticky-proxies.md # Rotating vs sticky proxies: plan for session continuity Source: https://ipvolt.com/guides/rotating-vs-sticky-proxies Markdown: https://ipvolt.com/guides/rotating-vs-sticky-proxies.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md) Category: Concept Reviewed: 2026-09-19 Published: 2026-09-11 Reading time: 4 minutes Author: ipvolt Choose rotation around the smallest complete workflow, distinguish exit affinity from cookies, and test what happens when a sticky session ends early. ## The starting point The useful question is how long a workflow needs the same exit, and what your application should do when that continuity disappears. ## Read the provider's definition of a session Rotating and sticky describe exit selection policies. Rotating usually changes the assigned exit between requests, connections or time windows. Sticky requests affinity to one exit for a defined session. The trigger, duration and failover behavior depend on the provider; there is no universal username parameter for all services. For example, Decodo documents per-request mobile rotation and configurable sticky sessions, while warning that an exit can disappear before the requested duration. Treat any provider's session duration as something to test, not a substitute for an application recovery path. ## Align a session with a complete workflow Consider a checkout test on your own staging store: load the product, add it to the cart and verify the delivery estimate. A practical starting point is one browser context and one proxy session for that entire scenario. Keep both consistent until the assertion finishes, then dispose of the scenario's state. For independent regional availability checks, each check can be its own unit. Give every result the intended region, observed exit when available and timestamp. Do not assume that a newly selected exit is unique or that changing exits grants a higher request allowance. Retries interact with this state: [one lost response, two created jobs](/blog/proxy-retries-duplicate-jobs) shows what happens when a retry replays a request whose first attempt already succeeded. ## Separate three kinds of state Troubleshooting becomes clearer when the following are logged as separate, non-secret identifiers. A proxy session cannot restore a lost cookie jar, and a persistent cookie jar cannot force an unavailable exit to return. In a browser flow the same three layers apply; the [Playwright proxy guide](/guides/playwright-proxy-setup) keeps them separate at the context level. - Application session: cookies, tokens and state owned by the destination. - Client connection: a TCP connection or reusable connection pool. - Proxy session: the provider's mapping from a session identifier to an exit. ## Test expiry before raising concurrency Choose a permitted diagnostic endpoint and make a few sequential requests inside the requested session window. Record the observed exit. Repeat after the documented expiry, and separately test a forced reconnect. Mark these as measurements from your sample, not a guarantee about the whole pool. For asynchronous clients, the [httpx async proxy guide](/guides/httpx-async-proxy) shows how a connection pool and a proxy session interact under concurrency. Decide what an early exit change means for your workflow: restart a read-only scenario, stop and report failure, or recover from a checkpoint. Do not automatically replay an operation that may already have created an order or changed account state. Put the recovery decision in the job specification before running many workers. ## Before you ship - Define one complete workflow before selecting a session length. - Keep cookie state and proxy affinity distinct. - Test early exit loss and expiry with a small sample. ## Sources & further reading - [Decodo: mobile session types and premature rotation](https://help.decodo.com/docs/mobile-proxy-session-types) - [Playwright: isolated browser contexts](https://playwright.dev/docs/browser-contexts) - [RFC 9110: idempotent methods and retries](https://www.rfc-editor.org/rfc/rfc9110.html#name-idempotent-methods) ## Related guides - [Configure a proxy in Playwright](https://ipvolt.com/guides/playwright-proxy-setup.md) - [Mobile vs residential proxies: build a useful evaluation](https://ipvolt.com/guides/mobile-vs-residential-proxies.md) - [Japan proxies: IP location and mobile network checks](https://ipvolt.com/guides/japan-proxies.md) - [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 74 of 138: Fix proxy error 407 without guessing URL: https://ipvolt.com/guides/fix-proxy-error-407 Markdown: https://ipvolt.com/guides/fix-proxy-error-407.md # Fix proxy error 407 without guessing Source: https://ipvolt.com/guides/fix-proxy-error-407 Markdown: https://ipvolt.com/guides/fix-proxy-error-407.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Fix proxy error 407 without guessing](https://ipvolt.com/guides/fix-proxy-error-407.md) Category: Troubleshooting Reviewed: 2026-09-19 Published: 2026-09-11 Reading time: 11 minutes Author: ipvolt Diagnose Proxy Authentication Required in a repeatable order: gateway, authentication method, credential encoding, account scope and client configuration. A 407 points to the proxy authentication layer. Start there before changing your destination request or adding retries. This guide gives the order of checks, the exact symptom in curl, Python requests, httpx, aiohttp and urllib3, Playwright and Puppeteer, and one working sample per client. Every error string and sample below was recorded against a small loopback proxy that demands Basic authentication; the lab and the recorded run are linked at the end. Using Axios in Node.js? [Axios proxy not working: 16 causes and fixes](/guides/fix-axios-proxy-not-working) shows where its proxy credentials go and what it does with special characters in a password. ## Identify who is asking for credentials HTTP 407 means the proxy requires authentication. The response includes a `Proxy-Authenticate` challenge, and the client supplies proxy credentials using `Proxy-Authorization`, as defined in [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-407-proxy-authentication-req). Destination authentication is separate: the website's own login uses `401` and `Authorization`. Putting your proxy password in the destination's Authorization header, or in the website-authentication option of your client, is the wrong fix; each client section below names that option so you can rule it out. Where the 407 appears depends on the destination. For an `http://` destination the proxy forwards the request itself, so a 407 arrives as an ordinary response: status code 407, a `Proxy-Authenticate` header, sometimes a short body. For an `https://` destination the client first sends `CONNECT host:443` to open a tunnel. A 407 at that step happens before any exchange with the destination, so most clients raise a proxy or tunnel exception instead of handing you a response object. curl 8.15, 8.16 and 8.17, for example, print `curl: (56) CONNECT tunnel failed, response 407`; curl 8.18.0 and 8.22.0 printed the same message with exit code 7 in our runs. Same proxy, same credentials, different symptoms: | Client | https:// destination (CONNECT) | http:// destination | | --- | --- | --- | | requests 2.34 | `requests.exceptions.ProxyError` with `Tunnel connection failed: 407 Proxy Authentication Required` | `Response` with `status_code == 407` | | httpx 0.28 | `httpx.ProxyError: 407 Proxy Authentication Required` | `Response` with `status_code == 407` | | aiohttp 3.14 | `aiohttp.ClientHttpProxyError: 407, message='Proxy Authentication Required'` | response with `status == 407` | | urllib3 2.8 | `urllib3.exceptions.ProxyError` with `Tunnel connection failed: 407` | response with `status == 407` | | Playwright 1.63 | with the default `waitUntil: "load"`, `page.goto` rejects with `Timeout 30000ms exceeded` and `requestfailed` reports `net::ERR_TUNNEL_CONNECTION_FAILED`; with `waitUntil: "commit"` it resolves with `status() === 407` | `page.goto` resolves with status 407 and the proxy's error body | | Puppeteer 25 | `page.goto` rejects with `net::ERR_INVALID_AUTH_CREDENTIALS` (no credentials) or resolves with status 407 plus `net::ERR_HTTP_RESPONSE_CODE_FAILURE` (wrong credentials) | rejects with `net::ERR_INVALID_AUTH_CREDENTIALS` | | curl 8.15 to 8.17 | exit 56, `curl: (56) CONNECT tunnel failed, response 407`, `%{http_connect}` is 407 | `http=407` | | curl 8.18.0 | exit 7, `curl: (7) CONNECT tunnel failed, response 407`, `%{http_connect}` is 407 | `http=407` | If the code you see is 429, 502 or 504 rather than 407, [proxy errors explained](/blog/proxy-status-codes-407-429-502) identifies which layer produced it, and [Tunnel connection failed: 502](/guides/fix-proxy-tunnel-502-503) tells a proxy's 502, 503 or 504 on CONNECT apart from the website's own 502. When Chromium reports the CONNECT failure without a status, the [tunnel error guide](/guides/fix-err-tunnel-connection-failed) covers the rest of its `net::ERR_*` family. Scrapy is not in the table: Scrapy 2.19 raises `TunnelError: Could not open CONNECT tunnel with proxy` for an `https://` URL and drops the 407 on an `http://` URL with one INFO log line; [Scrapy proxies in 2.19](/guides/scrapy-proxy-setup) covers both. curl_cffi is not in the table either: 0.16.3 raises `ConnectionError` with `curl: (7) CONNECT tunnel failed, response 407` for an `https://` URL, not `ProxyError`, and returns the 407 as an ordinary response for an `http://` URL; [curl_cffi proxies](/guides/curl-cffi-proxy-setup) shows how to catch both. ## Check one variable at a time Use this order to produce a useful reproduction rather than a sequence of unrelated changes. Inherited settings are the usual surprise; [proxy environment variables](/guides/proxy-environment-variables) explains how to see which gateway a client really chose. - Gateway: copy the exact scheme, hostname and port from the account's current setup instructions. - Method: confirm whether this endpoint expects a username/password, an allowed source IP or another documented authentication mechanism. A password sent to a port that authenticates by source IP is answered with 407 from a new machine. - Credential scope: confirm that the username belongs to this product or subuser, not merely the dashboard login. - Encoding: percent-encode credentials when embedding them in a URL; use separate credential fields when the client supports them. - Client: check inherited proxy settings and verify that the intended gateway is actually selected. A stale `HTTPS_PROXY`, a `.curlrc`, a container environment or a CI secret can point at a different gateway or an old password. Log the host and port the client resolved, never the password. ## Start with one curl request Before touching application code, prove that the gateway, username and password work at all. Proxy credentials are separate from destination credentials: `-U` or `--proxy-user` sends them to the proxy; `-u` or `--user` sends them to the destination. With the wrong flag the proxy still sees no `Proxy-Authorization` and answers 407, even though the password is right. ```sh curl --disable -sS -o /dev/null --noproxy '' \ -x "$PROXY_URL" --proxy-user "$PROXY_USERNAME:$PROXY_PASSWORD" \ -w 'http=%{http_code} connect=%{http_connect} exit=%{exitcode}\n' \ https://example.com/ ``` `connect=200 http=200` means the credentials are accepted and the problem is in your application. `connect=407` with `CONNECT tunnel failed, response 407` means the account itself is not being accepted; check the gateway, method and scope above, then send the report described at the end. The [curl proxy guide](/guides/curl-proxy-setup) has the complete flag reference. ## Compare curl with the failing application If the curl request works, concentrate on how the application maps those settings. In Playwright, for example, proxy credentials belong in `proxy.username` and `proxy.password` rather than `httpCredentials`. The client sections below show the exact exception or status each client produces and a working sample for each. If both clients fail, remove optional provider-specific country or session modifiers and test the simplest documented credential format, then add one modifier at a time. Confirm account access and the endpoint's authentication instructions with the provider. Do not assume that every provider uses 407 for the same billing or product-access condition. ## Python requests: ProxyError, Tunnel connection failed: 407 Requests takes proxy credentials only from the proxy URL. There is no separate proxy-auth argument that survives the CONNECT step: `requests.auth.HTTPProxyAuth` adds a `Proxy-Authorization` header to the request, which works for an `http://` destination and does nothing for an `https://` one, because the tunnel is opened by urllib3 before that header is ever sent. The same is true for a `Proxy-Authorization` entry in `headers=`. In the recorded run both variants returned 200 for `http://example.com/` and `ProxyError` for `https://example.com/`. Three more things break the URL form: - **Special characters.** A password such as `p@ss/w0rd#1` pasted straight into `http://user:p@ss/w0rd#1@host:port` makes the URL parser treat `ss` as the host. Requests then fails with `NameResolutionError` for host `'ss'`, which looks nothing like an authentication problem. Percent-encode the username and the password separately with `urllib.parse.quote(value, safe="")`. - **Both keys.** The `proxies` dictionary is keyed by the destination scheme. A dictionary with only an `"http"` entry sends `https://` requests directly, with no proxy at all. Set `"http"` and `"https"` to the same authenticated URL. - **Environment variables win over the Session.** If `HTTPS_PROXY` is set in the environment, `Session.proxies` loses to it, and a credential-free variable turns a correct Session configuration into a 407. A `proxies=` argument on the request itself still wins. The cleanest fix is `session.trust_env = False`, which also disables `NO_PROXY` inheritance; the [environment variable guide](/guides/proxy-environment-variables) explains what else that setting controls. The sample below applies all three. It is the file `fix_requests.py` in the lab download and was run with a plain password, a special-character password and a wrong password; the first two printed `200`, the third printed the `ProxyError` message. ```python import os from urllib.parse import quote import requests # PROXY_URL is scheme://host:port with no credentials inside, for example http://gate.example.net:8080 proxy_url = os.environ["PROXY_URL"] username = quote(os.environ["PROXY_USERNAME"], safe="") password = quote(os.environ["PROXY_PASSWORD"], safe="") target = os.environ.get("TARGET_URL", "https://example.com/") scheme, host_port = proxy_url.split("://", 1) authenticated_proxy = f"{scheme}://{username}:{password}@{host_port}" proxies = {"http": authenticated_proxy, "https": authenticated_proxy} session = requests.Session() session.trust_env = False # HTTP_PROXY, HTTPS_PROXY and NO_PROXY can no longer override these proxies try: response = session.get(target, proxies=proxies, timeout=(5, 15)) print(response.status_code) except requests.exceptions.ProxyError as error: print("proxy rejected the request:", error) ``` The [Python Requests proxy guide](/guides/python-requests-proxy) covers Sessions, SOCKS and rotation on top of this; the sample here is the minimum that makes a 407 go away. ## Python httpx: httpx.ProxyError: 407 Proxy Authentication Required httpx has a dedicated object for this: `httpx.Proxy(url, auth=(username, password))`. The credentials go into the CONNECT request and never touch the URL, so a special-character password needs no encoding. The `auth=` argument on `httpx.get` or on the `Client` is website authentication; in the recorded run it left the proxy challenge unanswered and raised `httpx.ProxyError: 407 Proxy Authentication Required`. Credentials inside the proxy URL also work when they are percent-encoded; pasted raw, the same `p@ss/w0rd#1` password produced `httpx.ConnectError: [Errno -3] Temporary failure in name resolution`, again because the parser read the password as a hostname. ```python import os import httpx proxy = httpx.Proxy( url=os.environ["PROXY_URL"], # scheme://host:port, no credentials inside auth=(os.environ["PROXY_USERNAME"], os.environ["PROXY_PASSWORD"]), ) target = os.environ.get("TARGET_URL", "https://example.com/") with httpx.Client(proxy=proxy, trust_env=False, timeout=15.0) as client: try: response = client.get(target) print(response.status_code) except httpx.ProxyError as error: print("proxy rejected the request:", error) ``` `httpx.AsyncClient` takes the same `proxy=` argument, and so does `httpx.HTTPTransport` if you route only some URL patterns through the proxy with `mounts`. Both were exercised in the lab and returned 200. For a fully asynchronous worker, the [httpx async proxy guide](/guides/httpx-async-proxy) builds on the same `Proxy` object. ## Python aiohttp: ClientHttpProxyError 407 aiohttp separates the two credentials explicitly: `proxy_auth=aiohttp.BasicAuth(username, password)` is for the proxy, `auth=` is for the website. Passing the proxy login through `auth=` raised `aiohttp.client_exceptions.ClientHttpProxyError: 407, message='Proxy Authentication Required'` in the recorded run. Credentials embedded in the proxy URL are also accepted. aiohttp 3.14 deprecates `proxy_auth` and `BasicAuth`: the call below still works but prints two `DeprecationWarning`s. [aiohttp proxies in 3.14](/guides/aiohttp-proxy-setup) shows the replacement and the case where it does not authenticate. One aiohttp-specific trap: `ClientSession` ignores `HTTP_PROXY` and `HTTPS_PROXY` unless you create it with `trust_env=True`. With the default, a session that has no `proxy=` argument connects directly, so a script that "worked on the other machine because the variable was set there" silently stops using the proxy rather than failing with 407. ```python import asyncio import os import aiohttp async def main() -> None: proxy_url = os.environ["PROXY_URL"] # scheme://host:port, no credentials inside proxy_auth = aiohttp.BasicAuth(os.environ["PROXY_USERNAME"], os.environ["PROXY_PASSWORD"]) target = os.environ.get("TARGET_URL", "https://example.com/") timeout = aiohttp.ClientTimeout(total=15) async with aiohttp.ClientSession(timeout=timeout) as session: try: async with session.get(target, proxy=proxy_url, proxy_auth=proxy_auth) as response: print(response.status) except aiohttp.ClientHttpProxyError as error: print("proxy rejected the request:", error.status, error.message) asyncio.run(main()) ``` ## urllib3 and urllib.request If you use urllib3 directly, `ProxyManager` does not read credentials from the proxy URL for the tunnel: `ProxyManager("http://user:pass@host:port")` still produced `ProxyError` with `Tunnel connection failed: 407` for an `https://` destination. Pass them as `proxy_headers=urllib3.util.make_headers(proxy_basic_auth="user:pass")` instead. The `headers=` argument of `request()` is not used for CONNECT either. The standard-library `urllib.request.ProxyHandler` is the opposite case: it does parse `http://user:pass@host:port` and answered the challenge correctly in the same run. ## Playwright: Timeout exceeded, status 407 and net::ERR_TUNNEL_CONNECTION_FAILED Playwright configures the proxy through the `proxy` option, either on `browserType.launch` or on `browser.newContext`, with three fields: `server`, `username` and `password`. When the credentials are missing or wrong, the symptom depends on what `page.goto` waits for. With the default `waitUntil: "load"`, and with `"domcontentloaded"`, no document ever loads, so the call rejects with `page.goto: Timeout 30000ms exceeded` after the full navigation timeout, and the only hint is a `requestfailed` event carrying `net::ERR_TUNNEL_CONNECTION_FAILED`. That is why a proxy 407 in Playwright is so often reported as "the proxy is slow". With `waitUntil: "commit"` the same navigation resolves in milliseconds with a response whose `status()` is 407, whose `statusText()` is `Proxy Authentication Required` and whose headers include the proxy's `Proxy-Authenticate`. The sample below waits for `commit` first, checks the status, and only then waits for `domcontentloaded`; in the recorded run the wrong-password case failed in under a second with the 407 message instead of after thirty seconds. Two placements look right and are not: - **Credentials inside `server`.** `{ server: "http://user:pass@host:port" }` is accepted without complaint, and the proxy then receives a CONNECT with no `Proxy-Authorization` at all. Chromium ignores the userinfo part of a proxy URL. - **`httpCredentials` on the context.** In the recorded run, Chromium 153 did answer the proxy challenge with `httpCredentials`, so the navigation succeeded. It is still the wrong place: `httpCredentials` is the website login, and Playwright will offer the same username and password to any origin that answers 401. Keep the proxy password in `proxy.username` and `proxy.password`. ```javascript import { chromium } from 'playwright'; const proxy = { server: process.env.PROXY_URL, // scheme://host:port, no credentials inside username: process.env.PROXY_USERNAME, // proxy credentials belong here, not in httpCredentials password: process.env.PROXY_PASSWORD, }; const target = process.env.TARGET_URL ?? 'https://example.com/'; const browser = await chromium.launch(); try { const context = await browser.newContext({ proxy }); const page = await context.newPage(); page.on('requestfailed', (request) => console.error('failed:', request.url(), request.failure()?.errorText)); // Wait for 'commit' first: a proxy 407 never reaches 'domcontentloaded', it would surface as a TimeoutError instead. const response = await page.goto(target, { timeout: 30_000, waitUntil: 'commit' }); if (!response || response.status() === 407) { throw new Error(`proxy rejected the credentials: ${response?.status()} ${response?.statusText()}`); } await page.waitForLoadState('domcontentloaded'); console.log(response.status()); } finally { await browser.close(); } ``` A per-context proxy needs `chromium.launch({ proxy: { server: 'per-context' } })` first; the lab run confirms that a context configured this way authenticates on its own. The `request.newContext` API used for API tests takes the identical `proxy` object and returned 200 with credentials and 407 without. Special characters in the password need no encoding here because Playwright never builds a URL from them. One limit is not Playwright's: Chromium has no support for username and password on SOCKS5 proxies, as its [proxy documentation](https://chromium.googlesource.com/chromium/src/+/HEAD/net/docs/proxy.md) states, so a `socks5://` gateway that requires a login cannot be used from Chromium at all, and the [HTTP vs SOCKS5 guide](/guides/http-vs-socks5-proxies) helps pick the HTTP gateway instead. The [Playwright proxy guide](/guides/playwright-proxy-setup) shows how to keep this configuration isolated per scenario. ## Puppeteer: net::ERR_INVALID_AUTH_CREDENTIALS Puppeteer passes the proxy to Chromium as a launch flag, `--proxy-server=host:port`, and there is no flag for the password. Without a `page.authenticate` call, the first navigation rejects with `net::ERR_INVALID_AUTH_CREDENTIALS`; this is Chromium reporting that a proxy challenge arrived and nothing was registered to answer it. With a wrong password, `page.goto` resolves with a 407 status and Chromium's own error page in the document, and `requestfailed` reports `net::ERR_HTTP_RESPONSE_CODE_FAILURE`. What does not work, from the recorded run: - `--proxy-server=http://user:pass@host:port` fails immediately with `net::ERR_NO_SUPPORTED_PROXIES`. - `page.setExtraHTTPHeaders({ 'Proxy-Authorization': ... })` fails with `net::ERR_INVALID_ARGUMENT`; Chromium refuses to let page code set that header. What does work: call `page.authenticate({ username, password })` on the page before its first navigation. The credentials are then cached for the browser context, so a second page opened with `browser.newPage()` loaded without its own call, while a page in a new context from `browser.createBrowserContext()` failed with `ERR_INVALID_AUTH_CREDENTIALS` until it had one. Calling `page.authenticate` after a failed navigation and retrying `page.goto` also succeeded, which is useful when the credentials are only known later. ```javascript import puppeteer from 'puppeteer'; const target = process.env.TARGET_URL ?? 'https://example.com/'; const browser = await puppeteer.launch({ args: [`--proxy-server=${process.env.PROXY_URL}`], // scheme://host:port, credentials are not accepted here }); try { const page = await browser.newPage(); // Register the proxy credentials before the first navigation; every new browser context needs its own call. await page.authenticate({ username: process.env.PROXY_USERNAME, password: process.env.PROXY_PASSWORD }); const response = await page.goto(target, { timeout: 30_000, waitUntil: 'domcontentloaded' }); if (!response || response.status() === 407) { throw new Error(`proxy rejected the credentials: ${response?.status()}`); } console.log(response.status()); } finally { await browser.close(); } ``` Node.js code that only needs HTTP, not a browser, should not launch Chromium for this; the [Node.js fetch proxy guide](/guides/nodejs-fetch-proxy) puts the same credentials on an Undici `ProxyAgent`. ## Send a reproducible, sanitized report Keep the client version, UTC timestamp, gateway host and port, destination hostname, authentication method and status or exception class. State whether the minimal curl reproduction also fails. Those details let support find the attempt without receiving your password. Remove tokens, credential-bearing URLs, cookies and authorization headers from logs. Stop automatic retries while diagnosing a persistent 407: a retry loop turns one 407 into a burst of failed logins, and [one lost response, two created jobs](/blog/proxy-retries-duplicate-jobs) explains why blind retries hurt for other reasons too. Once corrected, rerun one request and then the smallest application scenario before restoring normal concurrency. For help inside an MCP-compatible coding agent, [Proxy Toolkit MCP](/mcp) offers error diagnostics and supported configuration templates. Describe the client and sanitized error without sending proxy credentials or full logs; verify any suggested change with the bounded reproduction above. - Identify proxy authentication separately from website authentication. - Reproduce with the same settings in a second client. - Share sanitized diagnostics instead of credentials or raw traces. ## Reproduce the recorded run The client symptoms and samples above were recorded with the lab in the [download folder](/downloads/fix-407-proxy-authentication-required/README.md): a fake proxy on `127.0.0.1` that demands Basic authentication and forwards to `https://example.com/`, the `symptoms.py` script that produces every Python error string, the Playwright, Puppeteer and curl cases, and the five `fix_*` samples run with a normal password, a special-character password and a wrong password. The recorded [results.json](/downloads/fix-407-proxy-authentication-required/results.json) names the versions used: Python 3.14, requests 2.34, httpx 0.28, aiohttp 3.14, urllib3 2.8, Node.js 24, Playwright 1.63 with Chromium 153, Puppeteer 25 and curl 8.18. The curl 8.15 to 8.17 and 8.22.0 messages come from the loopback lab published with [CONNECT tunnel failed, response 403](/blog/connect-tunnel-failed-403). Newer releases can change an error string; the mechanism, proxy credentials in the proxy option and nothing else, does not. ## Sources & further reading - [RFC 9110: 407 Proxy Authentication Required](https://www.rfc-editor.org/rfc/rfc9110.html#name-407-proxy-authentication-req) - [Everything curl: proxy authentication](https://everything.curl.dev/usingcurl/proxies/auth.html) - [Playwright: proxy credentials](https://playwright.dev/docs/network#http-proxy) - [Requests documentation: proxies](https://requests.readthedocs.io/en/latest/user/advanced/#proxies) - [HTTPX documentation: proxies](https://www.python-httpx.org/advanced/proxies/) - [aiohttp documentation: proxy support](https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support) - [urllib3 documentation: proxies](https://urllib3.readthedocs.io/en/stable/advanced-usage.html#http-and-https-proxies) - [Puppeteer API: page.authenticate](https://pptr.dev/api/puppeteer.page.authenticate) - [Chromium proxy support: SOCKS authentication](https://chromium.googlesource.com/chromium/src/+/HEAD/net/docs/proxy.md) ## Related guides - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) - [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md) - [Configure a proxy in Playwright](https://ipvolt.com/guides/playwright-proxy-setup.md) - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md) - [Fix ERR_TUNNEL_CONNECTION_FAILED in Playwright and Puppeteer](https://ipvolt.com/guides/fix-err-tunnel-connection-failed.md) - ["Tunnel connection failed: 502 Bad Gateway" (and 503, 504) behind a proxy](https://ipvolt.com/guides/fix-proxy-tunnel-502-503.md) - [aiohttp proxies in 3.14: auth without BasicAuth, env vars and the errors you'll hit](https://ipvolt.com/guides/aiohttp-proxy-setup.md) - [Scrapy proxies in 2.19: auth, rotation and the errors you'll hit](https://ipvolt.com/guides/scrapy-proxy-setup.md) - [curl_cffi proxies: auth, the 407 that ProxyError misses, and SOCKS](https://ipvolt.com/guides/curl-cffi-proxy-setup.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 75 of 138: Mobile vs residential proxies: build a useful evaluation URL: https://ipvolt.com/guides/mobile-vs-residential-proxies Markdown: https://ipvolt.com/guides/mobile-vs-residential-proxies.md # Mobile vs residential proxies: build a useful evaluation Source: https://ipvolt.com/guides/mobile-vs-residential-proxies Markdown: https://ipvolt.com/guides/mobile-vs-residential-proxies.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Mobile vs residential proxies: build a useful evaluation](https://ipvolt.com/guides/mobile-vs-residential-proxies.md) Category: Concept Reviewed: 2026-09-19 Published: 2026-09-11 Reading time: 4 minutes Author: ipvolt Compare carrier and household exit networks for QA, keep browser emulation separate, and measure the capabilities your workflow actually needs. ## The starting point Start with the network condition you need to observe. An IP category alone does not establish speed, location accuracy or suitability for your test. ## Separate network type from device type In provider catalogs, mobile proxies generally describe exits on cellular carrier networks, while residential proxies describe consumer household internet connections. Provider terminology and sourcing models vary, so ask how a particular pool is obtained and classified. A mobile exit does not turn a desktop browser into a phone. Viewport, touch support, user agent, locale and browser geolocation are separate test settings. Playwright's device emulation controls browser characteristics; proxy configuration controls a network route. Neither alone reproduces every property of a physical phone on a cellular connection. Session behaviour is a third setting again; [rotating vs sticky proxies](/guides/rotating-vs-sticky-proxies) explains how to keep one exit for a whole scenario. ## Choose a test question before choosing a pool If the question is whether your service behaves differently for a named carrier, evaluate mobile exits with documented carrier selection and an observable result. If the question is how your own regional storefront responds over household networks, evaluate residential exits in the intended regions. If datacenter exits are also on the table, [residential vs datacenter proxies](/blog/residential-vs-datacenter-proxies) applies the same test-first approach to that choice. If you only need to check a narrow viewport or translated interface, begin with browser emulation and explicit locale settings. Adding a proxy to that test may introduce a variable you do not need. Write down which part of the outcome is supposed to change with the network. ## Use the same scorecard for both candidates Request a small evaluation and keep the destination, request schedule and payload constant. Suggested acceptance criteria should come from your application, not from a generic ranking of proxy types. The [USA proxies guide](/guides/usa-proxies) turns this scorecard into a regional test matrix you can copy. - Selection: can you request the specific country or carrier you need, and verify the observed exit independently? - Continuity: does one complete scenario keep a usable exit for its required duration? - Performance: record median and slow-end latency, failures and transferred bytes for the same workload. - Operations: document protocol support, concurrency limits, metering, account controls and support escalation. - Sourcing: obtain a clear explanation of participant consent, removal and acceptable-use controls. ## Make the decision conditional on evidence Record the sample size, dates, regions and scenario alongside the result. A successful small trial supports that measured use case; it does not establish global coverage or a universal success rate. Keep untested regions and unavailable carrier filters visibly marked as unknown. Prefer the option that satisfies your stated test at an acceptable observed cost. If neither does, change the requirement or obtain a different evaluation rather than attributing the failure to every mobile or residential network. These criteria are an evaluation framework, not a claim about any provider's pool, ipvolt's included. ipvolt, which publishes this guide, sells both: [mobile proxies](/mobile-proxies) on a dedicated device rented by the day, and [residential proxies](/residential-proxies) in prepaid packs billed per GB. ## Before you ship - Define the network condition the test must observe. - Separate proxy routing from browser device emulation. - Compare providers using the same bounded workload and record unknowns. ## Sources & further reading - [Decodo: provider definitions of proxy types](https://decodo.com/proxies/buy) - [Playwright: device, locale and geolocation emulation](https://playwright.dev/docs/emulation) - [Decodo: session continuity limitations](https://help.decodo.com/docs/mobile-proxy-session-types) ## Related guides - [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md) - [HTTP vs SOCKS5 proxies: choose by the connection](https://ipvolt.com/guides/http-vs-socks5-proxies.md) - [Japan proxies: IP location and mobile network checks](https://ipvolt.com/guides/japan-proxies.md) - [Configure a proxy in Playwright](https://ipvolt.com/guides/playwright-proxy-setup.md) - [Netherlands proxies: location and carrier checks](https://ipvolt.com/guides/netherlands-proxies.md) - [USA proxies: regions, networks and testing](https://ipvolt.com/guides/usa-proxies.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 76 of 138: Proxy environment variables: HTTP_PROXY and NO_PROXY URL: https://ipvolt.com/guides/proxy-environment-variables Markdown: https://ipvolt.com/guides/proxy-environment-variables.md # Proxy environment variables: HTTP_PROXY and NO_PROXY Source: https://ipvolt.com/guides/proxy-environment-variables Markdown: https://ipvolt.com/guides/proxy-environment-variables.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md) Category: Troubleshooting Published: 2026-09-11 Reading time: 6 minutes Author: ipvolt Diagnose HTTP_PROXY, HTTPS_PROXY, ALL_PROXY and NO_PROXY routing differences in curl, Python Requests and Node.js with an isolated local check. ## The starting point A proxy variable can be present while a request goes directly to its destination. Check the client, destination scheme and bypass rules before blaming the gateway. ## Separate destination selection from the proxy connection These variables are conventions interpreted by each client, not an operating-system switch that routes every application. A working curl command does not prove that another library inherited or honored the same settings. The [curl guide](/guides/curl-proxy-setup) lists exactly which variables curl reads, and in which case, so you can tell that baseline apart from the client under test. The variable name usually selects the destination scheme. HTTPS_PROXY can contain an http:// proxy URL: the destination uses HTTPS, while the client first connects to an HTTP proxy and requests a CONNECT tunnel. The proxy URL's scheme describes the connection to the proxy itself. Replacing an undici proxy agent with these variables on Node.js 26? [fetch failed: invalid onError method on Node.js 26](/guides/node-26-invalid-onerror-method) explains why the old agent fails and how NO_PROXY matched under NODE_USE_ENV_PROXY. - http_proxy / HTTP_PROXY: choose a proxy for an HTTP destination, subject to the client's case rules. - https_proxy / HTTPS_PROXY: choose a proxy for an HTTPS destination. - all_proxy / ALL_PROXY: a fallback in curl and Requests when no applicable destination-specific proxy is selected. Do not assume every client implements it. - no_proxy / NO_PROXY: request direct connections for matching destinations when the client's environment proxy selection applies. This is a routing exception, not another proxy address. ## Identify the client and version actually making the request Local routing checks for this guide used curl 8.7.1, Requests 2.34.2 on Python 3.14.7, and Node.js 26.8.1. The Node.js 24.5.0 release notes separately document the introduction of environment proxy support for its default HTTP/HTTPS agents; fetch gained its opt-in earlier, in 24.0.0. Those historical versions were documentation-reviewed, not executed here. For a library-level example of the same decision, [Python Requests](/guides/python-requests-proxy) exposes it as trust_env, which either admits or ignores every one of these variables. Without the opt-in, Node's built-in fetch connects directly and nothing reports that the proxy was skipped; [the Node.js fetch failed guide](/guides/fix-node-fetch-failed-proxy) shows how to confirm it from the error chain and the proxy log. For HTTP(S) repository downloads, [Git proxy setup](/guides/git-proxy-setup) shows how inherited variables interact with http.proxy and URL-specific settings. For package installs, [npm proxy settings](/guides/npm-proxy-settings) covers npmrc precedence and separate checks for registry metadata and package archives. npm's install configuration does not configure your application's Node.js HTTP clients. - curl accepts lowercase http_proxy but deliberately ignores uppercase HTTP_PROXY because CGI environments can derive that name from an incoming request header. HTTPS_PROXY and ALL_PROXY are accepted. A protocol-specific variable takes priority over ALL_PROXY. - Requests normally reads all four variable families, including uppercase names. Its Python proxy discovery prefers lowercase when both cases disagree; CGI environments with REQUEST_METHOD set ignore uppercase HTTP_PROXY. Environment values can override session.proxies, so a session dictionary alone is not an isolation boundary. - Node's built-in environment support requires opt-in: start the process with NODE_USE_ENV_PROXY=1. The default HTTP/HTTPS agents and native fetch then use HTTP_PROXY, HTTPS_PROXY and NO_PROXY; lowercase takes precedence. ALL_PROXY alone is not a substitute in this built-in mode. Custom agents, dispatchers and third-party packages need their own configuration review. ## Treat NO_PROXY as a route change Start with a comma-separated list of exact authorized destination hosts, then verify which requests actually match. Do not paste full URLs or paths into a host list. A wildcard of * requests direct routing for every destination in the clients discussed here; it is unsuitable as a casual fix for a required proxy. There is no portable matching grammar you can assume across these clients. For example, curl documents CIDR matching from 7.86.0; Node's built-in documentation lists hostnames, domain suffixes, address ranges and host:port entries. A domain entry, wildcard or subnet that works in one client needs a separate test in another; [a tested NO_PROXY matrix](/blog/no-proxy-matching-tested) shows which wildcard, leading-dot, CIDR and port entries behave the same in curl, Python, Node, Go and wget. DNS aliases and IP literals also change the name being matched. If an internal request unexpectedly uses the proxy, inspect the actual destination hostname and client-specific match rules. If an external request unexpectedly goes direct, inspect both cases of NO_PROXY and any explicit agent configuration. Change only the routing rule approved for that deployment. ## Observe proxy selection without a real gateway Save this as proxy_env_lab.py and run python3 proxy_env_lab.py with curl installed. It starts two HTTP marker servers on random loopback ports: one represents a direct destination and one represents the selected proxy. The proxy marker answers locally; it does not forward traffic or test CONNECT, TLS, authentication or an exit IP. Each curl process receives only the supplied test environment. --disable is its first option so a personal curlrc cannot change the experiment. The expected results are proxy, direct, direct, proxy. This demonstrates that even an explicit --proxy remains subject to NO_PROXY unless the bypass list is explicitly cleared for this local diagnostic. When the selected route is right but the proxy still answers 407, continue with [fix proxy error 407](/guides/fix-proxy-error-407). ### proxy_env_lab.py · Python 3 standard library + curl ```python import shutil import subprocess import threading from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer curl = shutil.which("curl") if not curl: raise SystemExit("Install curl before running this local lab") def marker(label): class Handler(BaseHTTPRequestHandler): def do_GET(self): body = label.encode() self.send_response(200) self.send_header("Content-Length", str(len(body))) self.end_headers() self.wfile.write(body) def log_message(self, *_): pass server = ThreadingHTTPServer(("127.0.0.1", 0), Handler) threading.Thread(target=server.serve_forever, daemon=True).start() return server, "http://127.0.0.1:" + str(server.server_port) origin, destination = marker("direct") proxy_server, proxy = marker("proxy") cases = [ ("environment", {"http_proxy": proxy}, [], "proxy"), ("host bypass", {"http_proxy": proxy, "NO_PROXY": "127.0.0.1"}, [], "direct"), ("explicit + bypass", {"NO_PROXY": "127.0.0.1"}, ["--proxy", proxy], "direct"), ("explicit + cleared bypass", {"NO_PROXY": "127.0.0.1"}, ["--proxy", proxy, "--noproxy", ""], "proxy"), ] try: for label, environment, options, expected in cases: result = subprocess.run( [curl, "--disable", "--silent", "--show-error", "--fail", "--connect-timeout", "2", "--max-time", "3", *options, destination], env=environment, capture_output=True, text=True, timeout=5, ) if result.returncode or result.stdout != expected: raise SystemExit("Local route check failed: " + label) print(label + ": " + result.stdout) finally: for server in (origin, proxy_server): server.shutdown() server.server_close() ``` ## Make the application baseline deliberate For a required-proxy curl diagnostic, use an explicit --proxy and --noproxy '' together, as the existing curl setup guide demonstrates. For Requests, supply the proxies argument on the request; use a dedicated Session with trust_env=False when the baseline must ignore inherited proxy settings. That also stops environment-derived authentication and CA-bundle configuration, so supply an approved custom trust bundle explicitly when needed. For Node, choose either reviewed environment opt-in or an explicit compatible agent/dispatcher. Do not assume a library's custom agent inherits the global setting. Confirm the exact runtime used by the worker or service, not only the version installed in an interactive terminal. Once the local rule is understood, compare one authorized destination with one provider-documented gateway. Keep TLS verification enabled, use a deadline, and confirm the request path with controlled endpoint or proxy observations. A successful HTTP status by itself does not establish which route was taken. ## Record decisions without recording secrets Compare the environment of the process that makes the request with its launcher, container or service configuration. Record variable names and whether they are set, the client version, destination scheme and observed route. Avoid whole-environment dumps, shell tracing, verbose protocol logs and raw exception text: a proxy URL may contain a password. Have an approved secret manager populate any required credentials privately in the process environment. Do not paste them into a command, commit an environment file or send raw configuration to support. Environment variables are a delivery mechanism, not a secret vault. This local lab uses no credentials and doesn't test ipvolt's service. ## Before you ship - Identify the actual client, runtime version and destination scheme. - Check uppercase and lowercase variable names without logging their values. - Verify NO_PROXY matching and the selected route on an authorized destination. - Compare a controlled environment with an explicit configuration before adding retries. ## Sources & further reading - [Everything curl: proxy environment variables and case rules](https://everything.curl.dev/usingcurl/proxies/env.html) - [curl manual: --disable, --proxy and --noproxy](https://curl.se/docs/manpage.html) - [Requests: environment proxy configuration](https://requests.readthedocs.io/en/latest/user/advanced/#proxies) - [Python: proxy discovery and CGI handling](https://docs.python.org/3/library/urllib.request.html#urllib.request.getproxies) - [Node.js 24.5.0: environment proxy support in HTTP clients](https://nodejs.org/en/blog/release/v24.5.0) - [Node.js HTTP documentation: built-in proxy and NO_PROXY rules](https://nodejs.org/docs/latest-v24.x/api/http.html#built-in-proxy-support) ## Related guides - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) - [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md) - [Node.js fetch Ignores HTTPS_PROXY: Fix UND_ERR_CONNECT_TIMEOUT in One Line](https://ipvolt.com/guides/node-fetch-ignores-https-proxy.md) - [Use a proxy with Node.js fetch](https://ipvolt.com/guides/nodejs-fetch-proxy.md) - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md) - [Fix Node.js TypeError: fetch failed behind a proxy](https://ipvolt.com/guides/fix-node-fetch-failed-proxy.md) - [Git proxy setup: HTTPS, config scope and safe removal](https://ipvolt.com/guides/git-proxy-setup.md) - [npm proxy settings: npmrc, precedence and install failures](https://ipvolt.com/guides/npm-proxy-settings.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 77 of 138: Troubleshoot proxy timeouts one stage at a time URL: https://ipvolt.com/guides/proxy-timeout-troubleshooting Markdown: https://ipvolt.com/guides/proxy-timeout-troubleshooting.md # Troubleshoot proxy timeouts one stage at a time Source: https://ipvolt.com/guides/proxy-timeout-troubleshooting Markdown: https://ipvolt.com/guides/proxy-timeout-troubleshooting.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md) Category: Troubleshooting Reviewed: 2026-09-19 Published: 2026-09-11 Reading time: 9 minutes Author: ipvolt Separate proxy DNS, TCP, CONNECT, TLS and response delays with curl timings, then set request deadlines and decide whether a retry is safe. ## The starting point A timeout tells you a clock expired. Find the last completed stage before changing the deadline, gateway or retry policy. ## Map the path that actually timed out For an HTTPS destination through an HTTP proxy, the usual path is: resolve the proxy, connect to it over TCP, obtain a successful CONNECT tunnel, complete destination TLS, send the request, then receive headers and the body. An HTTPS proxy adds its own TLS handshake before CONNECT. The two TLS connections have separate trust settings. The proxy normally resolves the destination hostname in this setup. A fast local DNS measurement therefore says nothing about the proxy's destination lookup. SOCKS5 can resolve locally or remotely, depending on the client configuration; identify that choice before interpreting a DNS error. Start with one approved, small GET endpoint and one gateway. Keep authentication and routing explicit. A browser navigation or application job may also wait for a connection pool, redirects, scripts or local processing; its timeout is not automatically a proxy timeout. ## Capture a single attempt without a trace This shell example requires curl 8.3 or later because curl imports the authentication variables itself. Check curl --version, including its TLS backend and features. Set PROXY_URL to a credential-free HTTP(S) gateway supplied by your provider; https://proxy.example.invalid:8443 is a deliberately nonworking illustration. Inject PROXY_USERNAME and PROXY_PASSWORD privately. This example uses Basic proxy authentication; adapt authentication only to the provider's documented method. Save as proxy-timing.sh and run sh proxy-timing.sh. CHECK_URL defaults to https://example.com/; you can substitute a small HTTPS endpoint that you are authorized to test. Use URLs without embedded credentials or sensitive parameters. The script discards the body, prints selected numeric results and preserves curl's exit status. It does not follow redirects or retry. Do not run it with shell tracing enabled. --disable stays first to ignore curlrc settings, and --noproxy with an empty value prevents an inherited NO_PROXY rule from bypassing the selected gateway; which hosts such a rule actually matches depends on the client, as [the NO_PROXY matching matrix](/blog/no-proxy-matching-tested) shows. The [curl guide](/guides/curl-proxy-setup) explains those two flags and the rest of curl's proxy selection. ### proxy-timing.sh · curl 8.3+ · one HTTPS GET ```sh : "${PROXY_URL:?Set a credential-free HTTP(S) proxy URL}" CHECK_URL=${CHECK_URL:-https://example.com/} case "$PROXY_URL" in http://*|https://*) ;; *) printf '%s\n' 'PROXY_URL must use http:// or https://' >&2; exit 2 ;; esac case "$CHECK_URL" in https://*) ;; *) printf '%s\n' 'CHECK_URL must use https://' >&2; exit 2 ;; esac case "$PROXY_URL $CHECK_URL" in *'@'*|*'?'*|*'#'*) printf '%s\n' 'Use URLs without credentials, queries or fragments' >&2 exit 2 ;; esac curl --disable --silent --fail --http1.1 \ --noproxy '' --proxy "$PROXY_URL" --proxy-basic \ --variable %PROXY_USERNAME --variable %PROXY_PASSWORD \ --expand-proxy-user '{{PROXY_USERNAME}}:{{PROXY_PASSWORD}}' \ --connect-timeout 5 --max-time 15 --retry 0 \ --output /dev/null \ --write-out 'exit=%{exitcode} http=%{http_code} tunnel=%{http_connect} dns=%{time_namelookup} tcp=%{time_connect} tls=%{time_appconnect} ready=%{time_pretransfer} first=%{time_starttransfer} total=%{time_total} bytes=%{size_download}\n' \ "$CHECK_URL" ``` ## Read milestones, not independent timers The time fields are seconds measured from the start of the transfer. They are not separate durations to add together. This example starts a fresh curl process and asks for HTTP/1.1 to make one request easier to inspect. Reused connections, multiplexing, proxy chains and followed redirects need additional interpretation. A zero field can reflect rounding, a stage not reached or a stage that did not apply; it does not prove an instantaneous operation. Treat differences as clues only when both milestones completed in this simple request. For example, tls minus tcp includes the CONNECT exchange and destination handshake for an HTTP proxy; it is not a measurement of destination TLS alone. first minus ready includes sending the request and waiting across the network and server. It does not isolate the destination's CPU time. - dns = time_namelookup: completion of the client-side lookup. With this proxy configuration, the relevant hostname is the gateway, not the destination's proxy-side lookup. - tcp = time_connect: the connection to the proxy completed. This does not establish that the tunnel or destination connection works. - tls = time_appconnect: TLS setup completed. ready = time_pretransfer: protocol setup reached the point where the transfer can begin. An HTTPS proxy introduces another handshake; these fields do not provide separate timings for every hop. - first = time_starttransfer: first response byte, including preceding setup. Interpret it alongside tunnel and http; a received proxy response is not evidence of destination success. - total = time_total and bytes = size_download: elapsed transfer time and downloaded body bytes. An HTTP 200 with exit 28 can still be an incomplete download. ## Follow the last completed stage Use the following order for the single-request example. Stop at the first unresolved stage. The suggested checks narrow the investigation; timings alone cannot identify which machine dropped a packet or explain a provider's internal queue. In Node.js fetch, a proxy that never completes the TCP handshake surfaces inside TypeError: fetch failed as ETIMEDOUT or UND_ERR_CONNECT_TIMEOUT, and one that never answers CONNECT produces no error until undici's 300-second headers timeout; [the Node.js fetch failed guide](/guides/fix-node-fetch-failed-proxy) decodes each case. - No proxy address: exit 5 means curl could not resolve the proxy. Verify the gateway spelling and the resolver available inside the actual container or service. Exit 6 concerns a hostname curl tried to resolve locally; revisit routing and DNS mode before blaming proxy-side destination DNS. - No TCP connection: exit 7 indicates connection failure; exit 28 before tcp completes can indicate the connection budget expired. Check the configured port, outbound route and firewall from the same runtime. An immediate refusal and a silent network drop call for different checks. - TCP completed, tunnel still 000: there is no usable CONNECT response recorded. For an HTTPS proxy, its own TLS setup may be the unfinished stage. For an HTTP proxy, investigate CONNECT negotiation, gateway availability and the allowed destination port. Provider diagnostics are needed to separate its destination DNS, connect and policy failures. - tunnel is 407: follow the proxy authentication guide. A larger timeout will not correct credentials. Other non-2xx CONNECT responses require checking proxy policy and the provider's documented error meaning; they are not destination HTTP statuses. - tunnel is 200, destination TLS unfinished: the proxy accepted the tunnel, but HTTPS setup did not complete. Exit 35 indicates a TLS handshake failure and exit 60 a certificate verification failure. Check destination name, approved CA trust and clock; keep certificate verification enabled. A timeout here can also arise from a stalled tunnel path. - TLS and ready completed, http is 000: investigate the wait for a destination response, including the remote application and path back through the proxy. Check an approved control endpoint through the same gateway, then the original endpoint again; change one variable at a time. - http is 200, bytes stopped and exit is 28: headers arrived, but the body did not finish within the limit. Compare expected response size and transfer progress. Raising the connect timeout does not address this stage. - http is 504: an HTTP gateway reported its own upstream timeout. With --fail the example normally exits 22. This differs from curl exit 28, where a client-side time limit expired; investigate which gateway generated the response before changing the client's deadline. ## Give each attempt a share of the job deadline In curl, --connect-timeout covers connection establishment, including DNS and required protocol negotiations; it is not only a TCP timer. --max-time covers the entire transfer, including connection setup and body transfer. The connection budget sits inside the transfer budget. The example's five and fifteen seconds are starting values for a small diagnostic, not service guarantees or universal production defaults. An application still needs an overall deadline covering pool waits, attempts, backoff, body handling and cleanup. Work backwards from the caller's limit. For an illustrative twenty-second job, you might reserve two seconds for local work, allow an eight-second initial attempt, wait one second, and permit at most an eight-second retry if sufficient time remains. Use a monotonic clock and cap each next attempt by the remaining budget; do not reset the job deadline when retrying. The [httpx async proxy guide](/guides/httpx-async-proxy) applies the same budget to a connection pool, where a slow pool acquire counts against the job as much as a slow connect. A socket read timeout generally limits an interval waiting for data, not the complete job. Slow progress may repeatedly avoid it. curl's --speed-limit with --speed-time can abort persistently slow transfers, but that is a minimum-throughput policy, not a precise replacement for an application's read-idle timeout. Long polling and streaming need a policy matched to their expected pauses, plus cancellation and an overall lifetime where appropriate. ## Retry only when repetition is safe and useful The baseline deliberately has no retries. After locating the failure, a bounded retry can be reasonable for an approved GET or HEAD whose application semantics are safe and idempotent, and for a failure you expect to be temporary. HTTP method semantics are a starting point; an endpoint that triggers an action despite using GET needs its own review. A timeout after a write leaves the outcome uncertain. Check the operation's state or documented idempotency mechanism before resubmitting it. [One lost response, two created jobs](/blog/proxy-retries-duplicate-jobs) is a worked example of what a retry does when that check is skipped. When the connection closes instead of timing out, [SSL EOF occurred in violation of protocol behind a proxy](/guides/fix-ssl-unexpected-eof-proxy) shows which curl results and Python exceptions mean that attempt was not sent, and when an earlier attempt may already have landed. For a reviewed safe GET, adding --retry 1 --retry-max-time 20 permits at most one retry for curl's supported transient conditions. It does not make twenty seconds a strict job deadline: --max-time restarts for each attempt, and an attempt started inside the retry window can finish after that window. Keep an outer deadline when the caller needs a firm limit. Respect Retry-After and stop when the required wait cannot fit; application retry loops should use bounded backoff with jitter and a concurrency limit. - Do not repeatedly retry unchanged authentication, certificate, URL or policy errors. Correct the configuration first. - Do not add --retry-all-errors to a general client as a timeout fix. That broadens repetition to failures whose recovery and side effects have not been reviewed. - Do not replay a payment, form submission, message send or other state-changing request merely because its response was lost. A lost response does not prove the operation failed. - Do not use retries to push through a block or increase load on an overloaded destination. Reduce concurrency and honor the service's limits. ## What the local checks established Reviewed on 11 September 2026 using curl 8.7.1 on macOS, with its reported SecureTransport/LibreSSL build. Controlled loopback fixtures exercised an HTTP proxy CONNECT exchange and a local HTTPS destination with an explicitly trusted test certificate. A stalled CONNECT and a stalled destination TLS handshake both exited 28 near a 0.3-second connection budget, but only the latter had tunnel=200. A separate stalled HTTPS-proxy TLS handshake also exited before CONNECT. After TLS completed, stalled headers and a stalled body instead reached a 1.2-second total budget. The body case retained http=200 and one downloaded byte. A supplied HTTP 504 returned exit 22. A delayed CONNECT increased tls minus tcp, confirming that this difference includes tunnel setup. A retry fixture with a two-second retry window and 0.7-second attempts ran for about 2.4 seconds, confirming that the retry window alone is not a strict total deadline. Its final total field described the last attempt, so a retrying job also needs an outer elapsed-time measurement. These fixtures establish client behavior under controlled failures. They do not benchmark a provider, exercise real DNS outages, validate every curl build or prove how HTTP/2, SOCKS or a multi-hop proxy behaves. Keep the runtime version, stage, statuses, timings, byte count and attempt count with the incident. Share only sanitized details; destination URLs, headers and traces can contain private data. The examples do not test ipvolt's service or gateway. ## Before you ship - Record the actual runtime, proxy scheme, destination scheme and DNS mode. - Capture one explicit attempt before adding redirects, concurrency or retries. - Use status codes and completed timing milestones together to choose the next check. - Keep connection and transfer budgets inside an overall job deadline. - Retry only approved safe, idempotent work within the remaining budget. ## Sources & further reading - [Everything curl: proxy connections and DNS responsibility](https://everything.curl.dev/transfers/conn/proxies.html) - [curl manual: variables, numeric output and retry-window limits](https://curl.se/docs/manpage.html) - [libcurl: connection-completion timing](https://curl.se/libcurl/c/CURLINFO_CONNECT_TIME.html) - [libcurl: TLS-completion timing](https://curl.se/libcurl/c/CURLINFO_APPCONNECT_TIME.html) - [libcurl: pre-transfer timing](https://curl.se/libcurl/c/CURLINFO_PRETRANSFER_TIME.html) - [libcurl: time to first response byte](https://curl.se/libcurl/c/CURLINFO_STARTTRANSFER_TIME.html) - [Everything curl: exit-code meanings](https://everything.curl.dev/cmdline/exitcode.html) - [libcurl: connection timeout within the total timeout](https://curl.se/libcurl/c/CURLOPT_CONNECTTIMEOUT.html) - [libcurl: average-speed timeout policy](https://curl.se/libcurl/c/CURLOPT_LOW_SPEED_LIMIT.html) - [Requests: read timeouts are not whole-download limits](https://requests.readthedocs.io/en/latest/user/quickstart/#timeouts) - [Everything curl: retry behavior](https://everything.curl.dev/usingcurl/downloads/retry.html) - [RFC 9110: idempotent retry semantics and gateway statuses](https://www.rfc-editor.org/rfc/rfc9110.html) ## Related guides - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) - [Fix proxy error 407 without guessing](https://ipvolt.com/guides/fix-proxy-error-407.md) - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md) - [Fix ERR_TUNNEL_CONNECTION_FAILED in Playwright and Puppeteer](https://ipvolt.com/guides/fix-err-tunnel-connection-failed.md) - [Fix Node.js TypeError: fetch failed behind a proxy](https://ipvolt.com/guides/fix-node-fetch-failed-proxy.md) - [SSL EOF occurred in violation of protocol behind a proxy: was the request sent?](https://ipvolt.com/guides/fix-ssl-unexpected-eof-proxy.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 78 of 138: Netherlands proxies: location and carrier checks URL: https://ipvolt.com/guides/netherlands-proxies Markdown: https://ipvolt.com/guides/netherlands-proxies.md # Netherlands proxies: location and carrier checks Source: https://ipvolt.com/guides/netherlands-proxies Markdown: https://ipvolt.com/guides/netherlands-proxies.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Countries](https://ipvolt.com/guides/countries.md) / [Netherlands proxies: location and carrier checks](https://ipvolt.com/guides/netherlands-proxies.md) Category: Country Reviewed: 2026-09-19 Published: 2026-09-11 Reading time: 9 minutes Author: ipvolt Evaluate Netherlands proxies with Dutch network context, exit-IP and city checks, ASN evidence, and a practical trial checklist before choosing a provider. ## The starting point Decide what a Dutch exit must demonstrate, distinguish KPN, Odido and Vodafone from fixed Ziggo access, and collect evidence you can compare. ipvolt sells mobile proxies in the Netherlands. ## Define your Netherlands requirement A Netherlands proxy routes a request through an exit presented as Dutch. That description leaves several decisions open: whether you need country recognition, an Amsterdam city label, a fixed broadband connection or a particular mobile network. Write the requirement before comparing plans so a country match does not accidentally become proof of everything else. For example, a team checking the Dutch version of its own storefront may need a Netherlands exit and a controlled browser language. A team investigating a network-specific issue needs documented network selection and samples from that selection. An Amsterdam delivery test may depend on a delivery address as well as IP location. These are different experiments, even when the same provider offers them in one menu. Set the destination, expected result, session duration and acceptable uncertainty in advance. Keep the proxy choice separate from application settings such as account region, cookies and language. Otherwise a localized page can look correct while the network requirement remains untested. ipvolt sells mobile proxies in the Netherlands (see the [Netherlands proxies](/proxies/netherlands) page); the requirement you write here is what a later trial would be judged against. ## Read Dutch network names correctly The Dutch regulator RDI identifies KPN, Odido and VodafoneZiggo as the three mobile-network operators. This is useful context for evaluating a carrier claim. It is not a list of proxy suppliers, and the existence of those networks establishes no relationship with a proxy service. KPN describes both fixed and mobile networks. VodafoneZiggo distinguishes the Vodafone mobile network from the Ziggo fixed network. A broad company label therefore needs an access-type explanation before you treat it as a mobile or residential sample. - KPN: ask whether the offered exit uses mobile access or fixed broadband, and how the provider verifies that distinction. - Odido: its September 2023 announcement renamed T-Mobile Netherlands and Tele2 mobiel to Odido. If a listing uses an older name, request the current network mapping and the date it was checked. - Vodafone: distinguish the mobile network from the wider VodafoneZiggo group name. A group match alone does not settle the access type. - Ziggo: the group's fixed-network brand belongs in a fixed-access comparison; do not count it as a fourth independent Dutch mobile network. - Other retail brands: RDI explains that mobile virtual network operators use mobile-network operators' networks. Keep the retail brand and underlying network as separate fields; a different brand is not automatically independent network coverage. ## Choose the access type you need For evaluation purposes, distinguish a hosting or datacenter exit, an exit represented as fixed residential access, and one represented as mobile access. Ask the provider to define its categories and explain the address provenance. A Dutch location result can be relevant to all three, but does not classify the connection by itself. Use the requirement to decide whether access type matters. Checking a country-selection feature on your own service may start with any documented Dutch exit. Reproducing behavior seen on Dutch mobile access needs a more specific sample. Paying for a mobile label adds little evidence if the provider cannot explain how its selection corresponds to the requested network. Ask how participating connections are authorized, what use restrictions apply, and which part of the service the provider operates directly. Request an explanation you can retain with your evaluation. A familiar telecom brand, an ASN match or a location database entry cannot answer those sourcing questions. ## Measure the exit, not the gateway The gateway is the host and port your client connects to. The exit is the source address your destination sees for the proxied request. They may be different. Looking up the gateway hostname, its resolved IP or the machine running your test does not establish the exit location. The [Germany proxies guide](/guides/germany-proxies) captures the same exit address in its acceptance matrix, so both evaluations can share one diagnostic. Start with the related curl setup guide and a provider-documented diagnostic endpoint or an HTTPS endpoint you control that reports the observed source address. The curl guide's baseline discards the response body: adapt that diagnostic step to retain only the reported exit address and necessary test fields. Keep credentials out of the record and retain certificate verification and request deadlines. If your endpoint sits behind another proxy or CDN, establish how it obtains the original connecting address. A value copied from an arbitrary request header is not sufficient evidence. Record IPv4 or IPv6 as observed; do not assume a result for one address family establishes the other. ## Separate Netherlands from Amsterdam Look up the observed exit address in a named geolocation service and record the lookup time and database version when available. MaxMind explains that accuracy varies with network type and other factors, and different services may disagree. Its city data includes an accuracy radius; mobile addresses can cover a broad area or lack a city result. An Amsterdam label is therefore an estimate with a scope, not a street location. The [France proxies guide](/guides/france-proxies) makes the same point about Paris and the overseas territories. Keep country and city outcomes in separate columns. If a lookup returns Netherlands but no city, the country requirement might pass while the Amsterdam requirement remains unresolved. If two services return different Dutch cities, retain both results. Do not turn agreement at country level into a city-level conclusion. For a city-sensitive application, agree which location source matters and what happens when its result changes. Check the application's actual behavior with its other location inputs held constant. If the provider only offers country selection, treat Amsterdam as an observation from that sample rather than a selectable or retained capability. ## Use ASN evidence with clear limits An autonomous system number, or ASN, identifies a network in Internet routing. RIPEstat's Network Info lookup returns an address's containing prefix and announcing ASN or ASNs from RIPE RIS observations. Save that result alongside the exact exit address and query time, then inspect the corresponding network information instead of guessing from a brand name. RIPE's database documentation explicitly warns that the country attribute is not a reliable way to map an IP address to a country. The field's meaning can vary, including organizational or infrastructure location. Use registration data to understand the resource record, and a separate geolocation result for your location assessment. Treat a match to an expected network as supporting routing evidence. It does not, on its own, prove a SIM connection, a specific retail subscription, residential participation or a supplier agreement. Where the marketing label and recorded organization differ, ask the provider to explain that exact address and prefix. Preserve the uncertainty until there is a supported mapping. ## Run a small, repeatable trial Request a trial that supports the specific country, access type and optional carrier selection you need. Use one client and one approved diagnostic destination first. The following is a suggested evaluation procedure, not a benchmark or a report of tests performed by ipvolt. Keep this initial sample small so mismatches are easy to investigate. Its purpose is to expose assumptions and establish a reproducible baseline. It cannot estimate a provider's entire address pool, long-term reliability or success rate across unrelated destinations. - Prepare a row for each request: timestamp, requested country and network, session label, observed exit IP and family, diagnostic result, elapsed time, geolocation source and result, prefix, ASN and unresolved questions. - Make three sequential requests with the same documented session settings and a small pause between them. Keep the destination and client configuration constant. Record each result, including failures, instead of saving only the successful example. - If rotation is supported, use the provider's documented operation and repeat the sequence. An unchanged address is an observation to compare with the rotation contract; a changed address is not proof that all future requests will change. - If your workflow needs continuity, repeat a check after the interval your application requires. Compare the exit address, country and network again. A few retained samples cannot establish a permanent address guarantee. - Once the baseline is understood, test your own application at its permitted rate. Record both transport failures and application outcomes so a connection success is not confused with a correct regional result. ## Resolve a mismatch before scaling Suppose your selection requests Netherlands mobile access, the diagnostic reports a Dutch country result, and the routing lookup returns a broad telecom organization. Mark the country observation as recorded and the mobile classification as pending explanation. Do not silently promote the whole row to a verified carrier result. For a wrong-country result, repeat the same configuration once, confirm which address was looked up, and compare a second dated location source if necessary. Send support the sanitized timestamp, requested selection and observed result. Agree whether the remedy is a configuration correction, a replacement sample or a geolocation-data review before increasing traffic. A timeout belongs in a separate failure category. Follow the related timeout troubleshooting guide to distinguish connection, TLS and destination waits. A missing response provides no exit-location result and should remain visible in the trial record. ## Make the provider decision explicit Before committing, ask which selections are guaranteed versus best effort, how unavailable country or network selections behave, and whether a fallback can change either. Also clarify session expiration, concurrency limits, supported protocols, billing for failed traffic and the support process for location disputes. Use the answers to define acceptance criteria for your own workload. ipvolt sells mobile proxies in the Netherlands, and checkout shows the carriers in stock and the live price. This guide is an evaluation method for any provider, ipvolt included; being on sale does not promise a specific Dutch IP or carrier. ## Before you ship - Write separate acceptance criteria for Netherlands, Amsterdam if needed, access type and named network. - Capture the destination-observed exit address, with its timestamp and address family. - Keep geolocation estimates, routing records and provider sourcing explanations separate. - Retain failed and unresolved trial rows alongside successful observations. - Confirm session behavior, fallback rules and commercial terms before increasing usage. ## Sources & further reading - [RDI: Dutch mobile-network operators and coverage obligations](https://www.rdi.nl/onderwerpen/telecommunicatie/telecomaanbieders/dekkingseis-en-snelheidsverplichting) - [RDI: mobile virtual network operators use MNO networks](https://www.rdi.nl/vraag-en-antwoord/dekkings--en-snelheidsverplichting/veelgestelde-vragen-over-de-dekkings--en-snelheidsverplichting) - [KPN: fixed and mobile network overview](https://www.overons.kpn/en/kpn-in-the-netherlands/our-network) - [VodafoneZiggo: Vodafone mobile and Ziggo fixed networks](https://www.vodafoneziggo.nl/netwerk/) - [Odido: T-Mobile Netherlands and Tele2 mobiel rebrand, September 2023](https://newsroom.odido.nl/en-us/t-mobile-netherlands-becomes-odido/) - [RIPEstat: Network Info prefix and announcing ASN lookup](https://stat.ripe.net/docs/data-api/api-endpoints/network-info) - [RIPE Database: primary objects and country-attribute limitations](https://docs.db.ripe.net/RPSL-Object-Types/Descriptions-of-Primary-Objects/) - [MaxMind: geolocation uncertainty, mobile addresses and accuracy radius](https://support.maxmind.com/knowledge-base/articles/maxmind-geolocation-accuracy) ## Related guides - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) - [Mobile vs residential proxies: build a useful evaluation](https://ipvolt.com/guides/mobile-vs-residential-proxies.md) - [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md) - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile proxies in the Netherlands from $9 a day. Residential proxies from $2.20/GB, in prepaid packs. [See which countries and carriers are on sale.](https://ipvolt.com/pricing) [Netherlands mobile proxies: carriers and prices](https://ipvolt.com/proxies/netherlands) [Mobile proxies in the Netherlands on Vodafone from $9 a day](https://ipvolt.com/dashboard/mobile?country=NL&plan=day&carrier=Vodafone%20NL) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 79 of 138: USA proxies: regions, networks and testing URL: https://ipvolt.com/guides/usa-proxies Markdown: https://ipvolt.com/guides/usa-proxies.md # USA proxies: regions, networks and testing Source: https://ipvolt.com/guides/usa-proxies Markdown: https://ipvolt.com/guides/usa-proxies.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Countries](https://ipvolt.com/guides/countries.md) / [USA proxies: regions, networks and testing](https://ipvolt.com/guides/usa-proxies.md) Category: Country Reviewed: 2026-09-19 Published: 2026-09-11 Reading time: 9 minutes Author: ipvolt Evaluate USA proxies by country, state and city. Compare network evidence, plan regional checks and measure session behavior before choosing a provider. ## The starting point Turn a broad US location requirement into a regional test plan, separate carrier labels from evidence, and evaluate the route your application actually uses. ## Decide what a US exit must accomplish A USA proxy routes a request through an intermediary with a US exit address. That can help you inspect your own regional website, reproduce a reported access problem or compare an authorized workflow across networks. The useful question is which result must change when the request leaves through that address. ipvolt sells mobile proxies in the United States. This guide explains how to evaluate any provider's offer, ipvolt's included; it does not report measurements from a US proxy pool. Nothing on the [USA proxies](/proxies/usa) page alters the evaluation described here. Write the acceptance condition before choosing a location. A US country response, a California-specific page and a Los Angeles-specific page are three different tests. Define which application signal decides the result and whether a neighboring location would be acceptable. This prevents a plausible map pin from becoming the entire buying decision. ## Build a regional test matrix Treat these as example test cases, not recommended proxy inventory. Select the smallest set that answers your application's question. Add locations because your users, deployment regions or support reports require them. A long city menu by itself supplies no evidence that the routes behave differently. For a nationwide audience, separate the contiguous states from Alaska, Hawaii and any territories you need to support. Ask the provider how its country selector treats each area. Record the actual locations included in your evaluation instead of writing nationwide after testing a few mainland exits. The [UK proxies guide](/guides/uk-proxies) applies the same discipline to London and postcode rules, which is the closest analogue to a US state matrix. - Country-level localization: request US, hold language and account settings constant, and check your application's country decision. A city constraint may add nothing to this test. - State-specific content: choose the actual states your application distinguishes, such as California and New York. Check the state decision and resulting page, including the fallback when state information is missing. - Metro-specific behavior: if your product distinguishes New York City from nearby New Jersey, define that boundary explicitly. Compare the application's result with the location evidence used by the provider. - Regional response time: if East, Central and West users matter, choose documented exits relevant to those groups, such as New York, Dallas and Los Angeles, and run the same small transaction against the same target. - Outside the contiguous states: create separate Alaska or Hawaii cases when needed. Keep their measurements separate until you have enough evidence to decide whether combining them is meaningful. ## Read network names as evidence to investigate AT&T, Verizon and T-Mobile each publish US mobile coverage maps. They are examples of mobile networks to investigate, not an exhaustive list of operators, brands or purchasable proxy routes. Their retail coverage pages do not establish that a proxy seller has access to them. The relationship between a retail brand and a network can be more complicated than one name. Boost Mobile's current transparency disclosure describes a hybrid network and identifies AT&T and T-Mobile as radio-network partners. That is a useful reason to ask what a seller means by its carrier field: subscription brand, access network, IP organization or a classifier's label. Verizon's coverage page also separates mobile service, Fios and 5G Home Internet. A familiar telecom name does not, by itself, distinguish a handset connection from home broadband. Ask for the access type relevant to your test and the evidence supporting it. Do not collapse mobile, fixed wireless, fiber and cable into one undifferentiated residential category. - Mobile requirement: request a documented cellular exit and ask how the seller establishes the underlying access network. - Fixed broadband requirement: clarify whether the offer uses a fixed subscriber connection, fixed wireless access or another arrangement, and whether that distinction matters to your application. - Datacenter requirement: if your task only needs a US server route, include a clearly described hosting-network option in the evaluation. Do not assume a residential label is necessary. ## Use coverage maps for context The FCC National Broadband Map uses provider-submitted availability data. Its fixed-location records and mobile coverage layers answer different questions. The mobile layers use propagation models for outdoor or in-vehicle service; they do not represent indoor availability. The FCC also explains that carrier maps can differ because of assumptions such as roaming. Use those maps to understand a claimed access network in a region. They are not proxy directories, IP geolocation databases or measurements of your application's route. A colored area around Chicago cannot establish that a seller has a Chicago exit, that its exit uses a particular carrier or that a request will finish within your deadline. When a supplier cites a map, save the page, date and exact claim it is being used to support. Then request separate evidence for the supplied proxy route. This gives your review a traceable distinction between a public network fact and the service being offered to you. ## Keep IP, network and location observations separate Begin with the source IP observed by a diagnostic destination you control or your provider documents. Record the address family too. The proxy gateway you connect to and the exit seen by the destination are different observations; a lookup of the gateway hostname does not verify the exit. ARIN's Whois/RDAP service returns registration records for IP ranges, autonomous system numbers and organizations. Its documentation explicitly notes that organization address fields need not reflect physical location. Use registration data to investigate who holds a resource, not to certify the city of a proxy device. An ASN lookup also does not prove a seller's commercial relationship with that network. MaxMind describes IP location as an estimate with variable precision. Mobile addresses can span broad areas; city fields may be absent, and an accuracy radius qualifies returned coordinates. Record the lookup service and date, keep missing values missing, and preserve disagreements between services. If an offer promises a state or city, ask which database or destination defines a match, how recently it was checked and what happens when your target disagrees. Two lookup services agreeing is useful evidence for those services. Your actual application test remains a separate result. ## Run a small, repeatable evaluation This is a proposed evaluation protocol, not a benchmark already performed by ipvolt. Agree on trial limits and use an endpoint you control or are authorized to test. Choose a small request budget and stop conditions before starting. The goal is a reproducible comparison you can discuss with the provider. - Prepare one case per required region. Record the requested country, state or city, requested access type, protocol, client version, target and a nonsecret reference for the provider configuration. - Establish a direct baseline and then one explicit proxy request. The related curl guide provides a bounded diagnostic command. Confirm routing before introducing browsers, concurrent traffic or retries. - Capture the observed exit IP using the diagnostic endpoint. Record the timestamp, lookup provenance, country/state/city results and any network classification. Keep credentials and authentication headers out of the worksheet. - Repeat a short sequence using the provider's documented session behavior. For example, cap a case at 20 requests split across two scheduled windows; this is an adjustable diagnostic budget, not a statistically representative sample. - Use the same target, payload, request spacing and client settings for every regional case. Record success, failure category, elapsed time and exit changes for each attempt. Keep any later retry outcomes distinguishable from first attempts. - Recheck the diagnostic endpoint after reconnecting or requesting rotation. Record what changed rather than assuming a new session guarantees a previously unseen IP. - Stop at the agreed budget or an unexpected response that needs investigation. Resolve authentication, certificate and routing failures before increasing traffic. Retain a sanitized result file for comparison and support. ## Measure the complete regional workflow A regional comparison includes your client, the gateway, the exit and the destination. If the application runs in Europe, its results describe that deployment's route. They do not automatically describe a browser physically located on the US East Coast. Use the deployment location you actually intend to run and keep it in the report. Separate connection setup, time to first byte and completed-transaction time where your client exposes them. Compare like-for-like requests and keep failed attempts in the results. A fastest successful response can hide frequent timeouts; one overall average can hide a weak regional case. Keep the original timing rows alongside any summary. With a small sample, report the count, observed range and failure breakdown without presenting them as stable population statistics. Schedule a later check during another relevant operating window. A brief trial cannot establish long-term capacity or reliability. ## Check browser state and session continuity An exit IP is only one input to a regional browser test. W3C's Geolocation specification describes device location sources that can include GPS and Wi-Fi as well as IP information. Routing browser requests through a proxy does not establish that the browser's separate location API will report that exit's city. For your own site, write down which inputs it uses: IP classification, a selected store, account settings, locale or an explicit location permission. Reset or deliberately preserve those inputs for each case. Otherwise a remembered location can make two different US exits appear identical, or make the same exit appear inconsistent. If the workflow spans several requests, test that entire sequence under the documented session mode. Check the observed exit at useful boundaries and record interruptions. Ask what happens when an exit disappears during a session, whether the provider substitutes another location, and how your client is expected to recover. [Rotating vs sticky proxies](/guides/rotating-vs-sticky-proxies) covers how to align a session window with a complete scenario before running many of them. ## Turn the results into a purchase decision Keep the selection tied to your original matrix. Record each requirement as supported by the trial, unsupported or still unknown, with a pointer to the relevant observations. A provider can satisfy a country-only task while leaving a city-specific task unresolved. That is more useful than a single unexplained best-provider score. Before committing, clarify billing units, treatment of failed requests, concurrent connection limits, session duration, geographic fallback, replacement policy and support evidence. Ask the seller to explain how its access is authorized and how it handles abuse reports. A successful request does not answer those operational questions. ipvolt sells mobile proxies in the United States, and checkout shows the carriers in stock and the live price; being on sale does not promise a specific carrier or city. Use the checklist below to evaluate any service, ipvolt's included, before you buy. ## Before you ship - Define the required country, state or city decision and its acceptable fallback. - Separate requested access type, observed exit IP, network registration and location estimates. - Keep regional results and first-attempt failures visible within the agreed test budget. - Exercise the actual application sequence with controlled browser and session state. - Resolve unknown coverage, authorization, billing and recovery terms before purchase. ## Sources & further reading - [AT&T: official wireless coverage map](https://www.att.com/maps/wireless-coverage.html) - [Verizon: mobile, Fios and 5G Home coverage distinctions](https://www.verizon.com/coverage-map/) - [T-Mobile: official mobile coverage map](https://www.t-mobile.com/coverage/coverage-map) - [Boost Mobile: current hybrid network and partner disclosure](https://help.boostmobile.com/docs/open-internet-transparency) - [FCC: National Broadband Map data and modeling limits](https://help.bdc.fcc.gov/hc/en-us/articles/13532984820379-What-s-on-the-National-Broadband-Map) - [ARIN: interpreting IP, ASN and organization registration records](https://www.arin.net/resources/registry/whois/) - [MaxMind: geolocation precision and mobile-address limits](https://support.maxmind.com/knowledge-base/articles/maxmind-geolocation-accuracy) - [W3C: Geolocation API and device location sources](https://www.w3.org/TR/geolocation/) ## Related guides - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) - [Mobile vs residential proxies: build a useful evaluation](https://ipvolt.com/guides/mobile-vs-residential-proxies.md) - [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md) - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md) - [Netherlands proxies: location and carrier checks](https://ipvolt.com/guides/netherlands-proxies.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile proxies in the United States from $17 a day. Residential proxies from $2.20/GB, in prepaid packs. [See which countries and carriers are on sale.](https://ipvolt.com/pricing) [USA mobile proxies: carriers and prices](https://ipvolt.com/proxies/usa) [Mobile proxies in the United States on AT&T from $17 a day](https://ipvolt.com/dashboard/mobile?country=US&plan=day&carrier=AT%26T) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 80 of 138: UK proxies: networks, regions and location checks URL: https://ipvolt.com/guides/uk-proxies Markdown: https://ipvolt.com/guides/uk-proxies.md # UK proxies: networks, regions and location checks Source: https://ipvolt.com/guides/uk-proxies Markdown: https://ipvolt.com/guides/uk-proxies.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Countries](https://ipvolt.com/guides/countries.md) / [UK proxies: networks, regions and location checks](https://ipvolt.com/guides/uk-proxies.md) Category: Country Reviewed: 2026-11-10 Published: 2026-09-11 Reading time: 9 minutes Author: ipvolt Evaluate UK proxies with current carrier context, UK and GB geography, postcode limitations and a practical test plan for country or network requirements. ## The starting point Understand UK carrier labels after the Vodafone and Three merger, separate country recognition from precise location, and design a useful trial. ipvolt sells mobile proxies in the UK. ## Choose the UK behaviour you need to verify Looking for the offer itself? [UK mobile proxies](/proxies/uk) lists the carriers in stock and their prices; this guide covers how to test one before you rely on it. A UK proxy provides an intermediary exit that a supplier represents as being in the United Kingdom. That can help you evaluate your own service from a different network perspective, but the country label leaves important questions unanswered. A UK storefront check, a London location rule and an issue reported by an O2 mobile user need different evidence. Begin with a sentence describing the expected application behaviour. For example: our country selector should offer the UK experience when the request arrives from an address our location database classifies as UK. That criterion can be tested. Requiring an authentic British user experience is too broad: account settings, delivery details and browser state may change the result independently of the proxy. Name the destination, the location source your application uses, the required access type and any city or network restriction. Decide which findings would stop the trial. This guide helps you specify that evaluation; it does not describe ipvolt endpoints. Checkout shows the carriers in stock. The [country guides index](/guides/countries) lists the other regions covered with the same approach. ## Resolve UK, GB and the geographical scope The UK includes England, Scotland, Wales and Northern Ireland. Great Britain means England, Scotland and Wales, excluding Northern Ireland. Government geographical guidance also identifies Jersey, Guernsey and the Isle of Man as Crown Dependencies outside the UK. A broad British label therefore deserves a precise scope before it enters a test specification. There is a separate naming trap in country codes. The same government guidance gives GB and GBR as the ISO codes for the United Kingdom. A documented GB country selector can consequently include Northern Ireland: it does not necessarily mean the geographical island of Great Britain. Use the supplier's documented parameter and meaning instead of guessing between uk and gb. A country selection still does not promise an exit in each UK nation. If reproducing an issue requires Belfast or Glasgow specifically, request that capability separately and agree how it will be evidenced. Include a Crown Dependency only when your application has an explicit case for it; do not silently count it as a UK sample. ## Account for the Vodafone and Three merger VodafoneThree's completion announcement states that Vodafone UK and Three UK merged on 31 May 2025. Its current company description includes Vodafone UK, Three UK, VOXI, SMARTY and Talkmobile. Seeing Vodafone and Three listed separately in a proxy menu is therefore insufficient evidence of two independent operator businesses. Ofcom's August 2025 coverage methodology names EE, Virgin Media O2 and VodafoneThree as the mobile-network operators providing predictions. Its consumer checker still displays EE, O2, Three and Vodafone labels. These sources describe different layers of a changing market; preserve the label and date of each observation instead of making a four-brand menu your ownership model. For a provider offering both Vodafone and Three selections, request the definition of each filter and its current verification method. Do they describe subscription brands, different address groups, or something else? A merger announcement alone does not tell you whether two requested selections produce the same exit route, nor does it prove that either selection is available from that provider. Germany raises the same question in a different form: the [Germany proxies guide](/guides/germany-proxies) explains what 1&1's national roaming on Vodafone means for a carrier label. ## Keep the brand, host network and access type separate Ofcom's checker FAQ illustrates the distinction between a retail service and its underlying network. It maps BT Mobile and 1p Mobile to EE; Tesco Mobile, giffgaff and Sky Mobile to O2; VOXI to Vodafone; and SMARTY to Three. Treat these as dated reference mappings, then ask for the current mapping of the specific service under evaluation. That distinction matters when building a comparison. Two different retail names may share a host network, so counting their names can overstate the diversity of your sample. Conversely, a different routing organization is a finding to investigate, not automatic proof that the retail description is false. Ask how the actual connection and exit address relate to the label. Keep mobile access, fixed broadband and hosting access in separate fields. VodafoneThree itself serves fixed and mobile markets, so a group-name match cannot classify an exit on its own. For a claimed mobile sample, request evidence of the access arrangement as well as the network selection. For a country-only application check, decide whether a documented hosting exit already satisfies the narrower requirement. Also establish how the underlying connections are authorized for the offered service. A familiar carrier name does not supply that explanation. Record the supplier's answer alongside its definition of the product, especially if your requirement depends on household or mobile participation rather than simply a UK location result. ## Use coverage maps for the question they answer Ofcom's Map Your Mobile offers local signal information and a separate performance view. Its methodology uses operator predictions for coverage and crowdsourced measurements aggregated into postal districts or areas for performance. The regulator explicitly describes uncertainty in predicting service at a particular location. This information is relevant when evaluating where a handset might obtain mobile service. It does not identify the public IP a proxy request will use, establish the location assigned to that address, or measure the proxy gateway between your client and the destination. A favourable local map result cannot substitute for a successful application trial. Suppose a provider uses a Manchester coverage screenshot to support a Manchester mobile-proxy claim. Ask for the missing link: what connects this supplied exit to the claimed access arrangement and selectable location? Keep the screenshot as background context, then evaluate the destination-observed address and the provider's documented selection. Do not infer a proxy speed or a city guarantee from the radio-coverage display. ## Test London and postcode rules independently IP geolocation is an estimate. MaxMind says its data cannot locate a particular household or street address, and accuracy depends on the network and address type. City results may include an accuracy radius; mobile addresses may lack a city or postal-code result. A London label should therefore be read with its available precision, not converted into an exact postcode. For an application you control, distinguish the inferred city from a postcode someone enters. A delivery checker may use the supplied address; a country banner may use IP location; a language preference may come from the browser or an account. Determine which input the feature is intended to use before calling a result incorrect. If your test requires a London-classified exit, retain the named location service, lookup timestamp, returned city and any radius or confidence field. An absent city is unresolved evidence for that requirement, even if the country passes. If the test instead checks postcode rules, use approved synthetic address fixtures and vary that input while holding the network configuration constant. ## Build an evidence record for each selection Use the related curl setup guide to establish connectivity with deadlines and private credentials. For exit identification, use a documented diagnostic service or an endpoint you control that records the connecting source address. The proxy gateway's resolved address is a different observation. If your destination is behind a CDN, verify its trusted forwarding configuration before relying on a reported client address. Capture the observed exit IP, address family, time, requested country and optional network filter. RIPEstat's Network Info endpoint supplies a containing prefix and announcing ASN information from RIPE RIS. Save that routing observation alongside the geographic lookup and the supplier's explanation of its brand mapping. RIPE's resource documentation warns that its country attribute cannot reliably locate an IP address: the value can refer to different aspects of the resource or organization. A GB registration field therefore does not complete a UK exit-location test. An ASN match similarly provides routing context rather than proof of a SIM, postcode or supplier contract. Preserve requested and observed labels separately. For example, keep a requested Three filter and the returned organization exactly as recorded, plus the explanation you obtained. Do not rewrite historical rows when a brand or mapping changes. Dated evidence makes a later support conversation much more useful than a screenshot labelled working UK proxy. The [France proxies guide](/guides/france-proxies) keeps its evidence record in the same shape. ## Run a bounded UK application trial The following matrix is a suggested experiment for your own service, not a report of tests performed by ipvolt. Select only the rows your application needs and obtain the necessary trial access. An unavailable carrier or city selection should remain unavailable in the record; a generic UK substitute cannot complete that row. For an initial pass, choose two documented proxy selections and make three sequential diagnostic requests for each, with a short pause between requests and a fixed deadline. That is six diagnostic requests, with no automatic retries. Keep session settings unchanged within a selection and retain unsuccessful attempts. This small sample is intended to uncover configuration and classification problems, not to estimate long-term reliability. The [USA proxies guide](/guides/usa-proxies) extends the same bounded trial to a regional matrix when several locations must be compared. - UK country rule: hold the account and browser settings constant; compare the observed exit country with the location service used by your application. Pass only the country criterion, leaving city and carrier outside that result. - London location rule: use a documented city selection if offered; capture its city evidence and the application's response. If selection is country-only, label a London result incidental rather than repeatable city targeting. - Northern Ireland application case: use an approved Belfast address fixture for address-driven behaviour. If the issue requires a local network exit as well, require separate location evidence; a GB country code alone does not establish Belfast. - EE or O2 network issue: keep the same small application fixture and request a documented network selection. Record the retail label, host explanation and routing evidence. Do not count two O2-hosted brands as two independent host-network samples. - Vodafone versus Three comparison: retain both requested filters and all observed prefixes, including identical results. Ask the supplier to explain overlap before treating the pair as independent network coverage. ## Decide what passed and what still needs explanation Separate transport success, country classification, optional city classification and application behaviour. A UK exit with no city can satisfy the first location requirement while leaving the London row open. A correctly classified exit followed by the wrong storefront language calls for an application-input check before switching networks. When the returned country is unexpected, first confirm the exact exit address and the documented selector. Keep any disagreement between dated location services visible and send the provider a sanitized example. For a timeout, follow the related troubleshooting guide and record a transport failure rather than inventing a location result for a response that never arrived. Before committing, clarify what happens when a requested network is unavailable, whether fallback changes the country or carrier, and how session expiry affects the selections you tested. Ask how location disputes are handled and which promises are contractual. The useful outcome is an agreed acceptance record with limitations, not a claim that a handful of requests represents every UK user. ipvolt sells mobile proxies in the United Kingdom, and checkout shows the carriers in stock and the live price. This educational guide applies to any provider, ipvolt included; being on sale does not promise a specific British IP address or network. ## Before you ship - Confirm the documented meaning of UK or GB and any requirement for a particular UK nation. - Keep VodafoneThree ownership context separate from retail labels, host networks and measured routing. - Treat coverage predictions, exit geolocation and postcode-driven application behaviour as separate evidence. - Record failures and unresolved carrier or city selections in the small trial, without silently substituting broader access. - Agree on fallback and session behaviour before expanding the test or committing to a provider. ## Sources & further reading - [UK government: geographical scope and UK/GB terminology](https://www.gov.uk/government/publications/toponymic-guidelines/toponymic-guidelines-for-map-and-other-editors-united-kingdom-of-great-britain-and-northern-ireland--2) - [VodafoneThree: merger completion and current company brands](https://www.vodafonethree.com/completion-of-vodafone-and-three-merger-in-the-uk/) - [Ofcom: Map Your Mobile methodology and operator context](https://www.ofcom.org.uk/siteassets/resources/documents/phones-telecoms-and-internet/comparing-service-quality/2025/map-your-mobile-2025-threshold-methodology.pdf?v=401713) - [Ofcom: coverage checker FAQ and retail network examples](https://www.ofcom.org.uk/mobile-coverage-checker/frequently-asked-questions?language=en) - [Ofcom: local mobile coverage and performance checker](https://www.ofcom.org.uk/mobile-coverage-checker?language=en) - [MaxMind: city, postcode and mobile geolocation limits](https://support.maxmind.com/knowledge-base/articles/maxmind-geolocation-accuracy) - [RIPEstat: observed prefix and announcing ASN information](https://stat.ripe.net/docs/data-api/api-endpoints/network-info) - [RIPE Database: limits of the country attribute in resource records](https://docs.db.ripe.net/RPSL-Object-Types/Descriptions-of-Primary-Objects/) ## Related guides - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) - [Mobile vs residential proxies: build a useful evaluation](https://ipvolt.com/guides/mobile-vs-residential-proxies.md) - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md) - [How to test a Germany proxy: networks, cities and regions](https://ipvolt.com/guides/germany-proxies.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile proxies in the United Kingdom from $14 a day. Residential proxies from $2.20/GB, in prepaid packs. [See which countries and carriers are on sale.](https://ipvolt.com/pricing) [UK mobile proxies: carriers and prices](https://ipvolt.com/proxies/uk) [Mobile proxies in the United Kingdom on Three from $14 a day](https://ipvolt.com/dashboard/mobile?country=GB&plan=day&carrier=Three) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 81 of 138: How to test a Germany proxy: networks, cities and regions URL: https://ipvolt.com/guides/germany-proxies Markdown: https://ipvolt.com/guides/germany-proxies.md # How to test a Germany proxy: networks, cities and regions Source: https://ipvolt.com/guides/germany-proxies Markdown: https://ipvolt.com/guides/germany-proxies.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Countries](https://ipvolt.com/guides/countries.md) / [How to test a Germany proxy: networks, cities and regions](https://ipvolt.com/guides/germany-proxies.md) Category: Country Reviewed: 2026-09-19 Published: 2026-09-11 Reading time: 9 minutes Author: ipvolt Evaluate Germany proxies with current carrier and roaming context, city-location limits, browser-language controls and a practical acceptance checklist. ## The starting point Build a useful German proxy trial by separating country recognition, network identity and regional page behavior. ## Decide what your German test must establish Looking for the offer itself? [Germany proxies](/proxies/germany) lists the use cases and mobile carriers; this guide covers how to test one before you rely on it. A Germany proxy should give your request an exit address that meets your German location requirement. That could mean recognition as Germany by your application, a specific city result, or a documented connection through a particular network. Decide which of those matters before treating a country selector as a complete specification. Consider three different jobs: checking the German version of your own storefront, reproducing an issue reported by an O2 mobile user, and validating a Berlin store locator. The first needs controlled regional settings; the second needs relevant network evidence; the third needs a defined location input. One successful page load cannot settle all three. Write down the page or endpoint, the decision it makes, the inputs it uses and the evidence that will count as a pass. If country recognition alone meets your requirement, leave city and carrier optional. If a named network is essential, an unexplained network label is an unresolved requirement even when the page looks correct. ipvolt sells mobile proxies in Germany (see the [Germany proxies](/proxies/germany) page); this guide is about deciding what such an exit would have to prove. ## Use the current German network map The Bundesnetzagentur's mobile subscriber table lists Telekom, Vodafone, Telefónica and 1&1 Mobilfunk as network operators. It also maps the older D1 and D2 names to Telekom and Vodafone, and associates O2 with Telefónica Germany. These names help interpret a provider's description; the regulator's table does not identify available proxy exits. Keep a retail brand, a mobile-network operator and an observed IP-network organization in separate fields. A retailer may use another company's infrastructure, and a familiar telecom group can offer several access types. Ask for the current mapping for the actual sample rather than copying a comparison chart from an older article. - Telekom or D1: request the exact selection supported by the proxy provider and how that selection is verified for the observed address. - Vodafone or D2: record the access technology as well as the name; a brand match alone does not establish mobile access. - O2 or Telefónica: treat O2 as the brand context, then clarify the access product and network evidence behind the offered exit. - 1&1: evaluate it as a fourth mobile-network operator and account for its national-roaming arrangement; do not describe it simply as an O2 reseller. ## Understand what 1&1 roaming can change In its announcement dated 11 November 2025, 1&1 reported completion of customer migration into its own network. Its current network-check FAQ says customers use antennas from national-roaming partner Vodafone where 1&1's own network is unavailable. That combination matters when reading older descriptions of 1&1 service. A customer relationship, the radio network carrying a connection and the network announcing its Internet address answer different questions. The roaming description is not a rule that every 1&1 sample must show a Vodafone ASN. Nor does a 1&1 label establish which radio infrastructure handled a specific request. Ask which layer the provider's carrier selector actually controls. If you need to reproduce a radio-network problem, request evidence about the access connection and roaming state. If you need to reproduce behavior based on an Internet address's network classification, retain the address and the classifier's result instead. When that distinction cannot be established, describe the trial as a sample of the offered selection rather than a verified test of a particular antenna network. The [UK proxies guide](/guides/uk-proxies) works through the same problem for the Vodafone and Three merger, where two menu labels may share one network. ## Separate mobile, fixed and home access German home Internet branding illustrates why product names need interpretation. Telefónica describes O2 home access over fiber, cable and DSL supplied through infrastructure partners, alongside its O2 Homespot product delivered over 4G or 5G. A connection used at home is therefore not necessarily a fixed-line connection. For a fixed residential trial, ask whether the sample uses DSL, cable or fiber and how the provider establishes its sourcing. For a mobile trial, ask how mobile access is documented. A German address registered to a telecom organization provides useful context but does not supply those answers on its own. Avoid changing categories halfway through a comparison. If one candidate provides fixed broadband and another provides mobile access, record that difference before comparing application outcomes. If your task accepts either, say so explicitly. Also ask how the participating connection is authorized for this use; a network's public existence is not evidence of a proxy supplier's rights to offer it. ## Treat Berlin and Frankfurt as separate requirements Keep Germany, a requested city and the location source in different columns. A Frankfurt result does not satisfy a Berlin-specific requirement merely because both are German cities. Conversely, a city mismatch need not fail an evaluation that explicitly requires only country recognition. Specify the rule before seeing the result. MaxMind explains that IP geolocation accuracy varies by factors including network type and address family, and that results can differ between databases. Its data cannot locate a specific household or street address. Treat a city label as an estimate to evaluate against your application's location source, rather than proof of the physical position of a subscriber or device. Mobile coverage maps answer another question. The Bundesnetzagentur says its map predicts outdoor reception using operator-supplied information; buildings, terrain, equipment and network load can affect actual reception. A colored area around Berlin is not evidence that a proxy provider has Berlin exits or that an address will be classified there. For a store-locator test, use an explicit test location if the application supports one, and test its IP-based default separately. Record which input produced each result. This prevents a manually selected Berlin address from being mistaken for evidence that the network exit was recognized as Berlin. ## Capture the address your destination sees Start with the related curl setup guide to confirm the gateway connection. Then use an approved diagnostic destination that reports the source address it observes. Looking up the gateway host or your workstation's address tests a different part of the path. If you operate the destination behind a CDN, use its trusted connection metadata rather than an arbitrary client-supplied forwarding header. For each observed exit, record the timestamp and address family. RIPEstat's Network Info endpoint supplies the containing prefix and announcing ASN or ASNs using RIPE RIS data. Preserve the lookup result and time as routing evidence, then request an explanation for any mismatch with the provider's network description. RIPE's database documentation warns that the country attribute cannot reliably map addresses to countries. A DE registration field is therefore insufficient evidence of the location required by your test. Keep registration, routing and geolocation results separate, and leave unknown access details unresolved instead of inferring them from an organization name. ## Control German language and regional settings A German-language page does not prove a German exit. W3C explains that Accept-Language expresses language preferences and should not be used alone to determine a user's locale. A German speaker can be elsewhere, and a visitor in Germany can prefer another language. Your test should preserve that distinction. For a hypothetical German storefront check, record language preferences, the selected market, currency, account state, cookies and browser time zone. An example configuration might use de-DE, EUR and Europe/Berlin. These are chosen application inputs, not values that a proxy necessarily changes or evidence that the request came from Germany. Use a fresh test profile for the baseline. Keep the exit selection fixed while changing one regional input at a time, and save the expected behavior from your own application specification. A remembered market cookie may explain a result that would otherwise appear to be a location failure. Treat delivery addresses and browser location permission as additional inputs when the page uses them. ## Build a small acceptance matrix The following cases form an illustrative evaluation matrix. They are a suggested procedure, not measurements performed by ipvolt or a promise that any provider supports the selections. Choose only the cases relevant to your workload and write the acceptance conditions before requesting a trial. The [France proxies guide](/guides/france-proxies) uses the same matrix shape, so a team evaluating both countries can keep one format. - Country case: request Germany and keep the browser profile fixed. Pass when the agreed location source recognizes the observed exit as Germany and your application's country-dependent behavior matches its specification. Record city as informational if it is outside scope. - City case: request Berlin only if the provider documents city selection. Pass the location check only when the agreed source meets your Berlin criterion. Record a German result without the required city as unresolved for this case. - Network case: request the specific access type and network you need. Retain the observed prefix, ASN and provider explanation of its selection, including roaming where relevant. A matching country with undocumented mobile access does not complete this case. - Locale case: retain the same documented exit selection while comparing a fresh profile with your controlled German regional profile. Compare the page behavior with your specification; do not promote a correct currency or translation into proof of location. ## Resolve failures before expanding the trial For each selected case, begin with two sequential diagnostic requests using identical session settings, then one approved application check. Set a request deadline, disable automatic retries for the baseline and pause between requests. This small starting sequence exposes configuration differences; it does not estimate pool size, uptime or long-term success rates. Retain failed attempts in the same worksheet as successful ones. A timeout leaves location unknown. A correct Germany result with an unexplained ASN leaves the network requirement open. A correct exit with an unexpected language calls for a regional-state investigation. Use the related environment-variable and timeout guides when the same settings behave differently between clients. Before a larger evaluation, ask how unavailable country, city or network selections behave, whether fallback is possible, and what persists during a documented sticky session. If continuity matters, schedule a separate follow-up at the interval your workflow requires. Keep sanitized evidence of the requested selection, time, observed result and support explanation. ## Before you ship - Define separate country, city, network and application-behavior acceptance conditions. - Keep retail brand, roaming radio network and Internet routing evidence distinct. - Confirm the actual access technology, especially for home Internet products. - Record the destination-observed address and dated location and ASN lookups. - Control German language, currency, account state and time zone independently. - Retain unresolved results and confirm fallback and session behavior before expanding. ## Sources & further reading - [Bundesnetzagentur: current mobile operators and historical network names](https://www.bundesnetzagentur.de/DE/Fachthemen/Telekommunikation/Marktdaten/Mobilfunkteilnehmer/start.html) - [1&1: completed customer migration, 11 November 2025](https://unternehmen.1und1.de/o-ran-mobilfunknetz/2025/1-1-o-ran-groesste-kundenmigration-der-deutschen-mobilfunkgeschichte-abgeschlossen) - [1&1: current network FAQ and Vodafone national roaming](https://mobile.1und1.de/netzcheck) - [Telefónica Germany: fixed-line partnerships and mobile O2 Homespot access](https://www.telefonica.de/network/fixed-network.html) - [Bundesnetzagentur: coverage-map predictions and reception limitations](https://www.bundesnetzagentur.de/DE/Vportal/TK/InternetTelefon/Mobilfunkversorgung/_faq/faq_Mobilfunk.html) - [RIPEstat: observed prefix and announcing ASN lookup](https://stat.ripe.net/docs/data-api/api-endpoints/network-info) - [RIPE Database: country attributes are not reliable geolocation](https://docs.db.ripe.net/RPSL-Object-Types/Descriptions-of-Primary-Objects/) - [MaxMind: network-dependent geolocation accuracy and limits](https://support.maxmind.com/knowledge-base/articles/maxmind-geolocation-accuracy) - [W3C: language preferences do not determine a user's locale](https://www.w3.org/International/questions/qa-accept-lang-locales) ## Related guides - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) - [Mobile vs residential proxies: build a useful evaluation](https://ipvolt.com/guides/mobile-vs-residential-proxies.md) - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md) - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md) - [Netherlands proxies: location and carrier checks](https://ipvolt.com/guides/netherlands-proxies.md) - [France proxies: networks, regions and local testing](https://ipvolt.com/guides/france-proxies.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile proxies in Germany from $9 a day. Residential proxies from $2.20/GB, in prepaid packs. [See which countries and carriers are on sale.](https://ipvolt.com/pricing) [Germany mobile proxies: carriers and prices](https://ipvolt.com/proxies/germany) [Mobile proxies in Germany on O2 from $9 a day](https://ipvolt.com/dashboard/mobile?country=DE&plan=day&carrier=O2) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 82 of 138: France proxies: networks, regions and local testing URL: https://ipvolt.com/guides/france-proxies Markdown: https://ipvolt.com/guides/france-proxies.md # France proxies: networks, regions and local testing Source: https://ipvolt.com/guides/france-proxies Markdown: https://ipvolt.com/guides/france-proxies.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Countries](https://ipvolt.com/guides/countries.md) / [France proxies: networks, regions and local testing](https://ipvolt.com/guides/france-proxies.md) Category: Country Reviewed: 2026-11-10 Published: 2026-09-11 Reading time: 9 minutes Author: ipvolt Evaluate France proxies with carrier and brand distinctions, mainland and overseas scope, exit-IP evidence, and a practical localization test matrix. ## The starting point Plan a French proxy trial that distinguishes Paris from wider coverage, network names from retail brands, and IP location from application settings. ipvolt sells mobile proxies in France. ## Define France beyond a Paris label Looking for the offer itself? [France mobile proxies](/proxies/france) lists the carriers in stock and their prices; this guide covers how to test one before you rely on it. A France proxy should be evaluated against the French experience you actually need to reproduce. Checking the language of your own storefront, testing a delivery rule for Lyon, and investigating a mobile-network problem are different tasks. A provider's country selector does not define the expected result for all three. The [Netherlands proxies guide](/guides/netherlands-proxies) separates Amsterdam from the Netherlands in the same way; the [country guides index](/guides/countries) collects the rest. Write down whether your scope is mainland France, Corsica, or a named overseas territory such as Guadeloupe or La Réunion. ARCEP treats overseas connectivity separately, including territorial frequency assignments and network deployment information. A provider's France option should not be assumed to include every territory, and a sample labeled Paris does not establish an overseas exit. For a national requirement, accept a country result only according to a named location source and your application's rules. If the task specifically needs Paris, record that as an additional condition. For an overseas test, ask the provider how the territory is selected and identified in diagnostics before requesting a sample. Keep unsupported selections visible as gaps in the evaluation. ## Separate networks from retail brands ARCEP's Mon réseau mobile documentation identifies Orange, SFR, Bouygues Telecom and Free Mobile for its metropolitan network comparison. These are reference points for understanding an advertised carrier label. The list says nothing about which connections a proxy provider controls or is authorized to supply. Retail names can make a list of offered connections look more diverse than the underlying evidence supports. Keep separate fields for the advertised brand, the claimed underlying network and the observed routing information. The official brand pages support these practical distinctions: - Orange and Sosh: Sosh's mobile migration guidance says customers retain the Orange network. Do not count those two labels as two independent mobile networks. - SFR and RED by SFR: RED describes access to SFR's mobile and fixed networks. A RED label alone does not identify whether an exit uses mobile data or fixed broadband. - Bouygues Telecom and B&YOU: Bouygues offers B&YOU plans on its network and describes both fixed and mobile services. Record the access type as well as the brand. - Free Mobile: retain the distinction between a specific mobile-network claim and a broad company label. Ask how the provider establishes the actual access path for the tested address. ## Date claims about network changes On 6 June 2026, Orange, Bouygues Telecom and Free–iliad announced a memorandum of understanding for the acquisition of SFR. Orange's announcement makes completion conditional on approvals and describes a possible closing in the second half of 2027. It explicitly says completion is uncertain. This is a proposed transaction, not evidence that SFR connections have already migrated to another network. For a trial, save the carrier mapping and the date the provider confirmed it. If a supplier describes a future ownership change, ask what works with today's selection and what notice accompanies a later migration. Do not replace the observed network in a current test record with a proposed future owner. Revisit this section when the official transaction status changes. ## Use coverage maps for the right question ARCEP's Mon réseau mobile separates theoretical coverage supplied by operators from service-quality measurements. It covers metropolitan and overseas areas and lets readers inspect particular places and uses. Those sources help investigate the telecom context around a claimed connection. Choose the relevant place, operator, technology and data date. Record whether you examined predicted coverage, an antenna layer or actual service measurements. A map of radio coverage does not enumerate proxy exits, establish an IP address's location or show whether a supplier has an available connection there. For example, an antenna near Marseille is not evidence that an offered exit is in Marseille. Likewise, an operator's favorable coverage result does not predict your proxy gateway's performance to your destination. Ask the supplier for evidence tied to the offered service; retain the map as background rather than a substitute for that evidence. ## Check the address and access claim separately Start with the related curl setup guide to establish a bounded connection. Then use an approved diagnostic service or an HTTPS endpoint you control to capture the source address seen at the destination. Looking up the proxy gateway's address tests the wrong point when the gateway and exit differ. Record the address family, timestamp and requested selection with the result. RIPEstat's Network Info endpoint returns the containing prefix and announcing ASN or ASNs from RIPE RIS routing data. This adds a routing observation; it does not certify a SIM, a household, a retail subscription or permission to supply that connection. Request the provider's documented access classification and sourcing explanation separately. Run the observed exit through your chosen geolocation source. MaxMind explains that accuracy varies by network and address type, that providers can disagree, and that an IP lookup cannot identify a specific street address. A French country result and a broad telecom organization may therefore support two limited observations while leaving a claimed Paris mobile connection unresolved. ## Control language and address inputs A page displayed in French does not prove that it received a French source IP. MDN explains that Accept-Language expresses a language preference; a server can also respect an explicit user choice. Set and record the browser locale and inspect the language header received by your own test endpoint. Use a fresh test profile when stored preferences would obscure the result. For your own application, define which input should control each outcome. The page language might follow a French preference, while delivery eligibility follows the test address and a fraud or regional rule uses IP location. Save those expected rules before changing the proxy. Avoid using real customer addresses or submitting purchases to check a localization screen. Treat browser location permission and any configured location override as separate test inputs. Record whether they are enabled. A Paris location supplied by your test runner must not be reported as a Paris proxy measurement. The related Playwright guide provides the browser proxy setup; add only the locale, session and application fixtures required by your own test. ## Build a France acceptance matrix The following rows are hypothetical acceptance cases for a team's own storefront. They are proposed tests, not results, and no ipvolt network was used. Replace the expected application outcomes with your actual requirements. Keep the country, optional city, network and application verdicts separate so one correct screen cannot conceal an unresolved connection. The [Germany proxies guide](/guides/germany-proxies) uses the same matrix, including the carrier column. - Mainland baseline: request a documented France exit, keep a French browser preference and a mainland test address constant, and record both the destination-observed IP and the resulting storefront region. A French screen with a wrong-country IP fails the network condition even if the language condition passes. - Paris-specific case: add a documented Paris selection only if offered. Record the named geolocation source's city result and any uncertainty it provides. A France result without sufficient city evidence leaves the Paris condition unresolved; it does not automatically fail an otherwise separate national test. - Lyon address case: hold the proxy and browser profile constant while changing only the synthetic delivery fixture from Paris to Lyon. Check your application's expected delivery behavior. This tests an address rule; it does not require or prove a Lyon exit unless you explicitly add that requirement. - Overseas case: request the exact territory needed, such as La Réunion, and agree how the provider and your geolocation source identify it. Use a separate application fixture. If only mainland France is offered, mark this case unavailable instead of silently substituting a Paris sample. - Named mobile network: request the documented mobile selection, preserve the supplier's network mapping and compare its explanation with the observed prefix and ASN. If the retail brand matches but the access type is unexplained, mark the mobile requirement unresolved. ## Keep the first trial small and reproducible Begin with one supported selection, one client and one permitted diagnostic destination. As an illustrative starting procedure, make three sequential diagnostic requests with the same session settings and a short pause between them. Use a finite request deadline and keep certificate verification enabled. This is a debugging sample, not a statistical estimate of French inventory or reliability. For each request, retain the timestamp, requested territory, optional city and network, session label, observed exit IP, diagnostic status and elapsed time. Add the dated geolocation and routing results afterwards. Never include the proxy password, full authorization headers or unrelated personal data in the worksheet. After the baseline succeeds, run only the matrix rows your provider supports and your application needs. When a browser page loads many resources, bound the test by a short scenario and time limit; three navigations are not necessarily three network requests. Keep transport failures in the report and use the timeout guide to diagnose them before interpreting geography. If continuity matters, check the same documented session after the interval your workflow requires. If rotation matters, perform one documented rotation and inspect the new observation. A repeated address or an address change must be compared with the agreed behavior; neither demonstrates the behavior of every future session. ## Decide what passed and what still needs evidence For a geographic mismatch, confirm that you looked up the destination-observed address, then repeat the same setup once. Compare another dated location source if the result remains disputed. Give the provider a sanitized record and ask whether the cause is a selection error, a different territory convention, stale location data or unsupported availability. Do not erase the failed row after receiving a replacement sample. The [UK proxies guide](/guides/uk-proxies) describes the same decision step, including when a merger changes what a label means. Before committing, clarify whether unavailable selections fail explicitly or fall back elsewhere, how sessions expire, which protocols and concurrency limits apply, and how disputed or failed traffic is billed. Ask how participating connections are authorized and what usage restrictions apply. Carrier names and successful diagnostics cannot establish those terms. ipvolt sells mobile proxies in France, and checkout shows the carriers in stock and the live price. This guide helps evaluate any provider, ipvolt included; being on sale does not promise a specific French address, an overseas location or a particular carrier. ## Before you ship - Specify mainland France, Corsica or the exact overseas territory before comparing selections. - Separate Orange/Sosh, SFR/RED and Bouygues/B&YOU brand labels from network and access evidence. - Keep a dated current carrier mapping; do not treat a proposed transaction as completed migration. - Record exit-IP, routing and geolocation observations independently of browser language and address fixtures. - Retain passed, failed, unresolved and unavailable cases, with explicit fallback and session terms. ## Sources & further reading - [ARCEP: Mon réseau mobile methodology, operators and geographic scope (PDF)](https://www.arcep.fr/fileadmin/user_upload/observatoire/mon-reseau-mobile/dossier-de-presse_MRM_nouvelle-version_juil2025.pdf) - [ARCEP: overseas telecom regulation and territorial network context](https://www.arcep.fr/la-regulation/grands-dossiers-thematiques-transverses/la-regulation-des-telecoms-outre-mer.html) - [Sosh: retaining the Orange network when changing mobile offers](https://assistance.sosh.fr/article/offre-mobile-changer-pour-une-offre-sosh_50081) - [RED by SFR: SFR mobile and fixed networks](https://www.red-by-sfr.fr/couverture-reseau/) - [Bouygues Telecom: fixed and mobile networks, including B&YOU](https://www.bouyguestelecom.fr/reseau) - [Orange: conditional SFR acquisition memorandum, 6 June 2026](https://newsroom.orange.com/orange-signe-un-accord-pour-lacquisition-conjointe-de-sfr-une-etape-decisive-pour-renforcer-son-leadership-en-france-476238/?lang=eng) - [RIPEstat: Network Info prefix and announcing ASN observations](https://stat.ripe.net/docs/data-api/api-endpoints/network-info) - [MaxMind: geolocation accuracy and address-level limitations](https://support.maxmind.com/knowledge-base/articles/maxmind-geolocation-accuracy) - [MDN: Accept-Language preferences and explicit user choices](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Accept-Language) ## Related guides - [UK proxies: networks, regions and location checks](https://ipvolt.com/guides/uk-proxies.md) - [Configure a proxy in Playwright](https://ipvolt.com/guides/playwright-proxy-setup.md) - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) - [Mobile vs residential proxies: build a useful evaluation](https://ipvolt.com/guides/mobile-vs-residential-proxies.md) - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile proxies in France from $9 a day. Residential proxies from $2.20/GB, in prepaid packs. [See which countries and carriers are on sale.](https://ipvolt.com/pricing) [France mobile proxies: carriers and prices](https://ipvolt.com/proxies/france) [Mobile proxies in France on SFR from $9 a day](https://ipvolt.com/dashboard/mobile?country=FR&plan=day&carrier=SFR) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 83 of 138: Brazil proxies: carriers, states and location tests URL: https://ipvolt.com/guides/brazil-proxies Markdown: https://ipvolt.com/guides/brazil-proxies.md # Brazil proxies: carriers, states and location tests Source: https://ipvolt.com/guides/brazil-proxies Markdown: https://ipvolt.com/guides/brazil-proxies.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Countries](https://ipvolt.com/guides/countries.md) / [Brazil proxies: carriers, states and location tests](https://ipvolt.com/guides/brazil-proxies.md) Category: Country Reviewed: 2026-09-23 Published: 2026-09-23 Reading time: 10 minutes Author: ipvolt Brazil proxies, mobile or residential: what the label proves, Vivo, Claro and TIM context, states and time zones, CEP and CPF inputs and a trial plan. ## The starting point Turn a Brazil requirement into checks that can pass or fail: Anatel's operator names, mobile and residential access, 27 federative units across four time zones, and the CEP and CPF that come from the customer. ipvolt doesn't sell mobile proxies in Brazil today. ## Decide what a Brazil label has to prove Brazil proxies give your request an exit that the supplier labels as Brazilian, and whether your destination's location service agrees is the first thing to test. The label does not say which of the 27 federative units the exit sits in, which operator carried it, whether access is mobile or fixed residential, or whether its IPv4 address is shared. Write the pass condition first: when our location database returns BR, with Accept-Language unchanged, our storefront switches to Brazilian Portuguese and prices in the Brazilian real (BRL). No exit reproduces one customer's view, since the CEP, account and payment details come from the customer, and a region a site pre-fills from the network address is an input of its own. Give each requirement its own row: a São Paulo state check needs a state result, a fault from a TIM subscriber needs operator evidence, and a pt-BR rendering test may need only the country. The [Brazil proxies page](/proxies/brazil) turns these rows into storefront workflows, and the [country guides index](/guides/countries) covers other markets. ## Learn the operator names Anatel uses Anatel, the telecom regulator, publishes a Relatório de Competição; its Q2 2026 edition counted 276.4 million mobile accesses, up 3.7 percent year over year, with Vivo at 37.9 percent and TIM at 22.4 percent. The news summary gives only those two mobile shares, so it supports no ranking that includes Claro. Its mobile coverage page links to the maps of five network operators, Claro, TIM, Vivo, Algar and Sercomtel, and publishes coverage by municipality and technology from base-station licensing data: where a handset can expect radio service, not which public address a proxy request carries or where a geolocation database places it. Record the brand a supplier's menu shows apart from the company that owns it; the ownership notes below are background from each company's own pages. Then ask which layer a carrier filter fixes: the SIM, the antennas that served it, or the holder a registry or routing lookup names for the exit address. - Vivo: the brand of Telefônica Brasil, which Telefónica calls the leading integrated operator in the Brazilian market. - Claro: NET, Claro and Embratel are three brands of one company, and NET is now Claro, so any of those names can mean the same organization. - TIM: TIM S.A. is ultimately controlled by Telecom Italia S.p.A. through TIM Brasil; a Telecom Italia name belongs to the parent. - Algar Telecom: a Brazilian provider with national operations and a primary focus on B2B clients, but its residential fiber and mobile offer covers cities in four states, so a consumer sample is regional. ## Account for MVNOs, roaming, home lines and fallback Anatel regulates mobile virtual network operators under Resolução nº 777/2025: an Autorizada de Rede Virtual provides mobile service over a host operator's network, the Prestadora Origem, so a retail brand describes a subscription, not necessarily the network that carried the connection. National roaming is mandatory in every municipality with fewer than 30,000 inhabitants, where a subscriber may use another operator's network. Brazil residential proxies need their own requirement: a fixed home line, such as Algar's fiber broadband in cities of four states, is a different access type from a phone and not automatically exclusive, since the NIC.br sources below describe shared IPv4 at operators generally. Record mobile or fixed residential as its own field, and ask how the supplier sources and authorizes those connections for proxy use. Ask, too, what happens when a selection cannot be met: if no Vivo or Distrito Federal exit is free, does the request fail, use another operator or state, or fall back to any Brazilian exit, and does the response say so? The trial records such a selection as unavailable and never counts a substitute exit as a pass. ## Map the states and regions, then read the state field IBGE's 2024 framework has 26 states, each in one Grande Região, plus the Distrito Federal, together the Unidades da Federação. The Distrito Federal cannot be divided into municipalities and its seat, Brasília, is the federal capital, so a Brasília requirement passes on a returned Distrito Federal, not a city string. For per-state rows, borrow the layout of the [USA proxies guide](/guides/usa-proxies). IBGE groups the units into five Grandes Regiões, so list the member states in any regional requirement. The Northeast runs to nine states from Maranhão to Bahia, while the Center-West includes Goiás and the Distrito Federal, so a Northeast selection is met by a Bahia result, not a Goiás one. Read the returned state as a database estimate. MaxMind says accuracy varies with country, distance and IP type, and that one mobile address may serve phones across a large distance, so it may return the country and state but no city. A missing city is not by itself a defect, but it leaves a city requirement unmet; a state or Distrito Federal requirement passes only when that returned field matches. ## Treat the CEP and the CPF as customer inputs The CEP (Código de Endereçamento Postal) is an eight-digit number that Correios assigns to localities, streets, public bodies, companies and buildings, a precision MaxMind says its GeoIP data never reaches. Americanas uses it to show regional offers and calculate shipping, and Shopee Brasil fills state, city and street from it; at both, the customer supplies it, so hold one CEP fixed whenever the exit is the variable. The CPF, administered by the Receita Federal, is unique and permanent for each citizen, and Shopee Brasil requires one in regular status to complete a purchase. A location test therefore stops before any third-party checkout, with no CPF entered, real or invented. Test checkout fields only on your own or an authorized staging storefront, with documented fixtures and any Receita Federal status lookup stubbed. Pix is the Banco Central do Brasil's instant payment scheme, established by Resolution BCB 1 of 12 August 2020. Whether a checkout lists it is the merchant's configuration, not a location result, so check it only on your own staging storefront, as an option you set up. ## Log who holds a Brazilian address, and over which family Operator names describe companies; address records describe holders. For every exit, log two identity fields apart, next to the address family: the registry holder, from the RIR record, and the origin ASN and holder, from a named routing lookup with the lookup time. Brazilian IPv4, IPv6 and ASN resources are NIC.br's responsibility, through Registro.br, while LACNIC is the regional registry. Neither field places the exit. In 2018 LACNIC noted that the geographic information it lists includes the holder's country of legal domicile, often not where the address is used, so a registry country cannot settle a state requirement. Likewise, a Telefônica Brasil holder is consistent with a Vivo selection but does not show whose antennas served the handset. In a 2014 tutorial, NIC.br's IPv6.br program said CGNAT at operators made sharing IPv4 addresses among customers unavoidable for some time during the transition to IPv6, and that identifying one user behind CGNAT also takes the source port. In 2023 NIC.br's projects and development manager said the large operators and large internet providers run 100% IPv6 networks, while shared IPv4 causes problems for applications. Record each address an exit presents, IPv6 or shared IPv4. ## Set the legal time zone and pt-BR in the browser Brazilian legal time uses four zones under Lei nº 12.876 of 30 October 2013, and an exit does not choose one. Look up the legal time for the place your test represents on the Observatório Nacional's Hora Legal Brasileira page, set that zone in your browser tooling and record it with each capture, along with the cookie state and location permission. Google's Play Console lists Brazilian and European Portuguese as separate locales, pt-BR and pt-PT, and a storefront that reads the browser's language may serve either one to a Brazilian exit. Until the trial's language row has separated those two causes, a European Portuguese page seen through a Brazilian exit is a language result, not a network one. ## Observe Magazine Luiza and Google from public pages Magazine Luiza's store locator has a list for each federative unit, 27 from Lojas Acre to Lojas Tocantins, so an explicit state choice can be observed on a public, signed-out page. Its “Localizando lojas próximo a você” message suggests it may also locate the visitor, possibly through the browser, so test the chosen state first and treat any default state as incidental unless the supplier documents state selection. Hold every third-party site to the same bounds: limit proxied checks to your own service, authorized destinations, or a storefront's public, signed-out pages as its terms permit, by hand and at low volume; create no accounts, enter no personal or invented identity data such as a CPF, card or phone number, and place no orders. Brazil's data-protection law, the LGPD (Lei nº 13.709/2018), is supervised by the ANPD; ask your legal advisor how it applies to your records. Google said in April 2025 that since 2017 it had given the same local results whether people used google.com or their country's domain, and that it would gradually redirect country-code domains such as google.com.br to google.com. Do not pin the domain; record the query, the interface language, the location Google reports and the time. ## Run the Brazil trial in blocks of six requests Connect with the [curl setup guide](/guides/curl-proxy-setup), then read each exit from an endpoint you operate that sees the connection directly, not through a CDN, over your destination's address families or through separate IPv4-only and IPv6-only endpoints. A block is six requests: two documented selections, three apiece in sequence, one fixed pause, one per-request deadline and no automatic retries. Log those settings and any session parameter with the block, so a difference between its two selections cannot come from timing. Score every request on four lines: completed; BR returned; the required state or Distrito Federal, N/A where a row makes no state claim; and pt-BR text with BRL prices, N/A except on storefront rows, which add one page capture per request. Beside the score, keep both identity fields, the observed address and family, the zoned timestamp and the geolocation answer. A selection the supplier cannot make is scored unavailable, never replaced by a generic Brazil exit. Run only the rows you need; the language and CEP rows take two blocks each, so all five come to 42 requests at most. Verify the language row's Portuguese exit as the [Portugal proxies guide](/guides/portugal-proxies) describes before relying on it. None of the rows has been run by ipvolt, which doesn't sell mobile proxies in Brazil today; your results describe the supplier you test. - Language row, two blocks, on your own storefront: hold one Brazilian exit and send three requests with pt-BR and three with pt-PT; then hold pt-BR and send three through the Brazilian exit and three through a Portuguese one. It passes when, with pt-BR fixed, the Brazilian exit returns BR and gets pt-BR text and BRL prices; it makes no state claim. - Distrito Federal row: pass a Brasília selection only when the named geolocation service returns the Distrito Federal; Goiás or another Center-West unit fails it. - CEP row, two blocks, on your own storefront: hold one exit and send three requests with each of two approved CEP fixtures, then hold one CEP and send three through each of two exit selections. Only an offer that moves in the second block is a network finding. - Operator row: for a Vivo, Claro or TIM selection, record the label, any MVNO or roaming explanation and both identity fields, counting Claro, NET and Embratel as one company. - Session row: per selection, send two requests at the fixed pause and a third after the documented address lifetime; pass if the address holds or changes as documented. Source ports help match a disputed connection across logs but prove nothing about exclusive use. ## Before you ship - Write the Brazil pass condition first, naming your application's location service and the state or Distrito Federal field it must return. - Ask what a Vivo, Claro, TIM, Algar or state selection falls back to when it cannot be met, and record any selection the supplier cannot make as unavailable. - Keep the operator label, the registry holder from the RIR record, and the origin ASN and holder from a named routing lookup with its lookup time in separate fields, beside the address family. - Set the CEP, pt-BR and the time zone yourself, and test checkout fields only on your own or an authorized staging storefront with documented fixtures. - Log each request's source port and zoned timestamp, assume an operator's IPv4 address may be shared, and settle access type and session length with the supplier before you commit. ## Sources & further reading - [Anatel: Q2 2026 competition report, mobile accesses and Vivo and TIM shares](https://www.gov.br/anatel/pt-br/assuntos/noticias/anatel-divulga-relatorio-de-monitoramento-da-competicao-do-segundo-trimestre-de-2026) - [ANPD: the LGPD, Lei nº 13.709/2018, and the agency that supervises it](https://www.gov.br/anpd/pt-br/acesso-a-informacao/institucional) - [IBGE: the five Grandes Regiões and the Unidades da Federação](https://www.ibge.gov.br/apps/quadrogeografico/pdf/qg_2024_010_GrandReg.pdf) - [Google: country-code domains redirected to google.com, with the same local results on any domain since 2017](https://blog.google/products/search/country-code-top-level-domains/) - [Correios: the eight-digit CEP and what a code can be assigned to](https://www.correios.com.br/enviar/precisa-de-ajuda/tudo-sobre-cep) - [NIC.br IPv6.br: 2014 tutorial on CGNAT, shared IPv4 and the source port](https://ipv6.nic.br/post/tutorial-log-da-porta-de-origem-para-ipv4-compartilhado/) - [LACNIC: 2018 note that the registry country reflects legal domicile](https://blog.lacnic.net/en/lacnic-to-launch-ip-geolocation-initiative/) - [MaxMind: accuracy by country and IP type, and missing city data for mobile addresses](https://support.maxmind.com/hc/en-us/articles/4407630607131-Geolocation-Accuracy) ## Related guides - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) - [Mobile vs residential proxies: build a useful evaluation](https://ipvolt.com/guides/mobile-vs-residential-proxies.md) - [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md) - [Portugal proxies: islands, operators and checks](https://ipvolt.com/guides/portugal-proxies.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Residential proxies are on sale from $2.20/GB. The dashboard lists the countries available now. ipvolt doesn't sell mobile proxies in Brazil today. [See which countries and carriers are on sale.](https://ipvolt.com/pricing) [Explore Brazil proxy workflows](https://ipvolt.com/proxies/brazil) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 84 of 138: Portugal proxies: islands, operators and checks URL: https://ipvolt.com/guides/portugal-proxies Markdown: https://ipvolt.com/guides/portugal-proxies.md # Portugal proxies: islands, operators and checks Source: https://ipvolt.com/guides/portugal-proxies Markdown: https://ipvolt.com/guides/portugal-proxies.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Countries](https://ipvolt.com/guides/countries.md) / [Portugal proxies: islands, operators and checks](https://ipvolt.com/guides/portugal-proxies.md) Category: Country Reviewed: 2026-09-23 Published: 2026-09-23 Reading time: 10 minutes Author: ipvolt Specify and verify Portugal proxies: mainland and island scope, ANACOM operator names, pt-PT settings, Portuguese checkout fields and a four-row trial. ## The starting point Start with the islands: decide whether Azores and Madeira customers are in scope, then read MEO, NOS, Vodafone, DIGI and Lycamobile as ANACOM vocabulary and write down questions a provider can answer. ipvolt doesn't sell mobile proxies in Portugal today. ## Settle the island question before anything else Portugal proxies are exits a supplier represents as Portuguese, and the first question they raise is which part of Portugal your customers are in. The government describes the country as 18 districts on the mainland and two autonomous regions, the Azores and Madeira. Decide whether island customers are in scope before comparing operators or planning a trial, because several published rules split at the coast and a mainland result cannot stand in for an island one. Three examples show the split. The Azores keep legal time one hour behind the mainland, while Madeira keeps mainland time. DIGI's coverage page, checked in September 2026, said its mobile service was then unavailable in the Azores and Madeira. Amazon.es offers Premium delivery to most mainland postcodes but not to the islands, and Amazon's list of European stores has no Portuguese one. Each island case therefore needs its own row, its own postcode fixture and, for the Azores, its own clock. The district question comes second. Statistics Portugal (INE) lists the 18 mainland districts from Aveiro to Viseu, with Lisbon (Lisboa) and Porto among them. If a Lisbon or Porto result matters, make it a separate requirement, ask for a documented city or region selection and keep the returned city with its accuracy radius; under country-only selection, a Lisbon result is incidental. Other markets have their own pages in the [country guides index](/guides/countries). ## Pin the clock, the postcode and the test limits for each case Legal time comes from three decrees. Under Decreto-Lei n.º 17/96 the mainland keeps UTC from the last Sunday of October to the last Sunday of March and UTC+1 in summer. Madeira's regional decree applies the same rule, while the Azores' decree sets one hour less, UTC-1 in winter and UTC in summer. The Lisbon Astronomical Observatory reproduces all three texts. A browser time zone that disagrees with the case under test is a second changed input. The delivery postcode is the other input to fix. CTT, the postal operator, defines it as seven digits, the first four separated from the last three by a hyphen: NNNN-NNN. Keep one documented mainland fixture and, when the islands are in scope, one Azores or Madeira fixture; use them on your own or an authorized staging storefront, and on a third-party site only in a postcode field that needs no sign-in. Change the postcode only as its own labeled step. The plan also sets limits for every fixture and row. Proxied checks stay on your own service, destinations you are authorized to test, or a storefront's public, signed-out pages where its terms permit, by hand and at low volume. Open no accounts, place no orders and type no personal or invented identity data, whether a NIF, a card or a phone number. Checkout-field tests run only on your own or an authorized staging storefront with documented fixtures. Then list what a supplier must answer: the destination, the location service your application reads, mobile, fixed or hosted access, any operator condition and the outcomes that end the evaluation. ipvolt doesn't sell mobile proxies in Portugal today, nothing here documents its endpoints or an arrangement with the operators below, and it has run none of the trial rows at the end. The [Portugal proxies](/proxies/portugal) page applies these inputs to storefront checks. ## Use ANACOM's operator names as vocabulary, not as inventory ANACOM, the postal and electronic communications regulator, publishes a quarterly mobile report that names the operators. Its report for the fourth quarter of 2025 gives shares of active mobile accesses with effective use, excluding M2M: MEO 36.0%, NOS 31.1%, Vodafone 27.6%, Grupo DIGI/NOWO 3.3% and Lycamobile 2.0%. Appearing there proves nothing about any supplier's access to these networks; check for a newer edition before quoting the figures. Each name carries history that a menu label hides. When a provider offers an operator selection, ask whether MEO means the SIM's home operator, the origin ASN holder a routing lookup returns or a geolocation vendor's label, how the mapping is verified and when it was last checked. The [UK proxies guide](/guides/uk-proxies) records operator labels with the date of each observation, a habit worth copying for Portuguese names. - MEO: one of the commercial brands Altice Portugal kept in 2018, when PT (Portugal Telecom) became Altice Portugal. - NOS: per ANACOM, NOS Comunicações resulted from the 2014 merger of ZON TV Cabo into Optimus. - Vodafone: Vodafone Portugal is part of a global telecommunications group; the Lycamobile entry explains why its network can sit behind two labels. - DIGI and NOWO: DIGI Portugal acquired 100% of Cabonitel, NOWO's owner, and ANACOM approved the transfer of NOWO's 3.6 GHz spectrum rights to DIGI on 21 January 2025. - Lycamobile: a mobile virtual network operator since September 2012 whose services, per ANACOM's May 2021 report, use Vodafone's network. That names the host network, not the origin ASN holder of a Lycamobile exit address. ## Separate access type, mobile home operator and serving network A Portugal mobile proxy label can describe three layers: the operator that issued the SIM, the network carrying the connection and the origin ASN holder that a routing lookup returns for the exit address. Lycamobile shows how they come apart. On ANACOM's 2021 evidence, Lycamobile and Vodafone rows in a menu may describe one host network twice, while the origin ASN and holder behind either exit still have to be observed rather than assumed. A registry lookup is no shortcut to that third layer. RIPE Database documentation says the country attribute on inetnum and inet6num objects was never defined and cannot be relied on to place an address in a country. Log network identity as two separate fields beside the address family: the registry holder, from the regional internet registry (RIR) record, and the origin ASN and holder, from a named routing lookup, with the lookup time. Roaming is the other case where the first two layers differ. The European Commission says that since 15 June 2017 people pay nothing extra for roaming in other EU countries, so a SIM from elsewhere in the EU can use a Portuguese radio network while its home operator is abroad. That charging rule says nothing about where the SIM's traffic reaches the internet. German operators get the same three-layer reading in the [Germany proxies guide](/guides/germany-proxies). A Portugal residential proxy request needs the access type written down too. NOS offers television, internet, voice and mobile data to residential and business customers, so an operator name cannot tell a fixed home line from a mobile or business connection. Ask how the access type is documented for your exit and on what basis those connections were authorized for proxy use. ## Log search by reported location, then test pt-PT in two steps Search comes first because its domain is no longer a variable. In April 2025 Google announced a gradual move of its country-code addresses to google.com, and said that since 2017 its local results had been the same whichever of the two addresses a searcher used. Do not pin google.pt, and do not treat google.com in the address bar as a proxy fault. A Portuguese search snapshot records the query, the interface language, the location Google reports and the time. For advertising, Google Ads lists Portugal as country target 2620 with country code PT, and its geo-target file carries Lisbon, Porto District, Azores and Madeira as region targets alongside hundreds of Portuguese cities. An island campaign therefore has a documented region name to put in the brief, while an exit labeled Portugal maps onto no particular region target by itself. The interface language needs its own test, since Google's Play Console lists pt-PT and pt-BR as separate languages. Decide what a pass looks like before either step, for example: our storefront opens its pt-PT edition when our location service classifies the request as Portuguese, and not otherwise. Then hold the exit and switch only the browser language between pt-PT and pt-BR; after that, hold pt-PT and switch only the exit, Portuguese to non-Portuguese. ## Choose Portuguese destinations that show their location input Continente Online, the online shop of Continente, MC's (Sonae) food retail brand, takes the delivery location from a typed postcode or from device location and offers Click&Go pickup at an available store. Deny device location, type one mainland fixture and hold both before crediting a changed store list to the exit. If the postcode step asks for sign-in, stop there, inside the limits the plan already sets. Amazon.es publishes shipping options for Portugal: Premium delivery covers most mainland postcodes, not the islands, and appears at checkout only when the postcode qualifies. So reproduce the mainland and island split on your own storefront or an authorized staging storefront, with documented postcode fixtures for the mainland and for the Azores or Madeira. Record the final URL, the language served and any location the page shows before you enter one. ## Recognize Portuguese checkout fields on your own edition Start with the NIF field. The tax authority's e-Fatura FAQ explains that when a buyer asks for their tax identification number (NIF) on an invoice, the invoice details become available for classification in e-Fatura once the issuer reports it. Check on your own or an authorized staging storefront that the field appears and can be left empty, and enter no NIF, real or invented, anywhere else. The [Brazil proxies guide](/guides/brazil-proxies) draws the same line for Brazil's CPF field. Payment methods come second. SIBS, which manages the MULTIBANCO network, documents MB WAY, its mobile payment solution that links bank details to a phone number alias, and MULTIBANCO reference payments, also called Payment for Services, whose references can be generated in real time for online checkouts. If either is missing on your edition, check your payment configuration, then repeat the same basket through a Portuguese and a non-Portuguese exit, with no card or MB WAY phone number entered. ## Expect a lookup to confirm Portugal, not Lisbon or an island MaxMind estimates its country-level accuracy at 99.8% and says its data is never precise enough to identify a household, individual or street address. A mobile address may serve phones across a large distance, and MaxMind may then return the country and subdivision (region) without a city or postal code. A missing city is not by itself a defect, but it leaves a city requirement unmet, so a Lisbon case does not pass; an Azores or Madeira requirement passes only when the returned region field matches. Read the exit the destination sees, not the gateway: the [curl proxy setup guide](/guides/curl-proxy-setup) covers the connection, and a diagnostic endpoint you control, or one the provider documents, reports the observed address. Look up an IPv6 exit separately from an IPv4 one, and keep the region and any city your location service returns, with the accuracy radius; a country-only answer leaves an island requirement unmet. ## Build the Portugal trial from four rows Open the trial with a question to the supplier, not a request: when an Azores selection cannot be met, what does it fall back to, a Madeira, mainland or non-Portuguese exit, and is the substitution visible in the response? The answer decides whether the island row can run at all. Any island, district or operator option the supplier cannot select is recorded as unavailable, and a generic Portugal exit never silently takes its place. Each row below states what it holds fixed, the one input it changes and the result that passes it; keep only the rows your requirement uses. The case rows are read against the two control rows, so every row you keep runs under one trial header, for example four requests, a 5-second pause and a 20-second deadline, with automatic retries off. An island row that fails where the mainland control passes then points at the island selection, not at a longer wait or a hidden second attempt. Log each request with the requested selection, observed address and family, zoned timestamp, named geolocation service and result, both identity fields with the routing lookup's time, browser locale and time zone, and the application outcome, failures included. Lei n.º 58/2019 of 8 August implements the GDPR in Portugal and names the CNPD as the national supervisory authority in Article 3, so treat these logs as records that may identify someone: keep what the trial needs, strip credentials and agree on retention first. - Mainland control row: pt-PT, mainland time, a mainland postcode fixture and account state pinned on your own storefront; it passes when your location service returns Portugal and the pt-PT edition opens. - Island case row: the same settings with an Azores fixture and the browser one hour behind mainland time, or a Madeira fixture on mainland time; it passes only when the returned region field names that region. - Operator case row: one MEO, NOS, Vodafone, DIGI or Lycamobile selection, its label logged beside both identity fields. DIGI stays a mainland case while its coverage page excludes the Azores and Madeira, and a Lycamobile and Vodafone difference is a question for the provider, not proof of a mislabel. - Non-Portuguese control row: the mainland row's browser settings through a non-Portuguese exit or your normal connection. If it also gets the pt-PT edition, a Portugal pass says nothing about location handling. ## Before you ship - State whether the test covers only the mainland or also Azores and Madeira cases, each with its own postcode fixture and, for the Azores, a browser time zone one hour behind the mainland. - Ask the provider to define each ANACOM operator label it offers, and log the registry holder from the RIR record and the origin ASN and holder from a named routing lookup, with the lookup time, as separate fields beside the address family. - Set pt-PT, time zone and account state explicitly, and add a non-Portuguese control row so a pass says something about location handling. - Keep checkout-field tests on your own storefront or an authorized staging storefront with documented fixtures, and enter no NIF, card or phone data on third-party sites. - Put the Azores fallback question to the supplier before the first request, and record any island, district or operator option it cannot select as unavailable. ## Sources & further reading - [ANACOM: fourth-quarter 2025 mobile services report, operator shares and DIGI's acquisition of NOWO](https://www.anacom.pt/streaming/ServicosMoveis4T2025.pdf?contentId=1828056&field=ATTACHED_FILE) - [ANACOM: May 2021 MVNO report, Lycamobile on Vodafone's network and the NOS merger](https://www.anacom.pt/streaming/MVNOemPortugal_maio2021.pdf?contentId=1644333&field=ATTACHED_FILE) - [Governo de Portugal: 18 mainland districts and the Azores and Madeira autonomous regions](https://portugal.gov.pt/pt/gc23/portugal/sobre-portugal) - [Observatório Astronómico de Lisboa: legal time decrees for the mainland, Madeira and the Azores](https://oal.ul.pt/hora-legal/legislacao/) - [Amazon.es: shipping options to Portugal, Premium delivery for most mainland postcodes](https://www.amazon.es/gp/help/customer/display.html?nodeId=GVVMYF6KMB3ZVNGR) - [Google: country addresses move to google.com; same local results on either address since 2017](https://blog.google/products/search/country-code-top-level-domains/) - [MaxMind: country accuracy, accuracy radius and mobile ranges without city data](https://support.maxmind.com/hc/en-us/articles/4407630607131-Geolocation-Accuracy) - [RIPE Database: what the inetnum and inet6num country field does not establish](https://docs.db.ripe.net/RPSL-Object-Types/Descriptions-of-Primary-Objects/) ## Related guides - [Brazil proxies: carriers, states and location tests](https://ipvolt.com/guides/brazil-proxies.md) - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) - [Configure a proxy in Playwright](https://ipvolt.com/guides/playwright-proxy-setup.md) - [Mobile vs residential proxies: build a useful evaluation](https://ipvolt.com/guides/mobile-vs-residential-proxies.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Residential proxies are on sale from $2.20/GB. The dashboard lists the countries available now. ipvolt doesn't sell mobile proxies in Portugal today. [See which countries and carriers are on sale.](https://ipvolt.com/pricing) [Explore Portugal proxy workflows](https://ipvolt.com/proxies/portugal) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 85 of 138: HTTPX async proxies: setup and PoolTimeout diagnosis URL: https://ipvolt.com/guides/httpx-async-proxy Markdown: https://ipvolt.com/guides/httpx-async-proxy.md # HTTPX async proxies: setup and PoolTimeout diagnosis Source: https://ipvolt.com/guides/httpx-async-proxy Markdown: https://ipvolt.com/guides/httpx-async-proxy.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [HTTPX async proxies: setup and PoolTimeout diagnosis](https://ipvolt.com/guides/httpx-async-proxy.md) Category: Integration Reviewed: 2026-09-13 Published: 2026-09-13 Reading time: 7 minutes Author: ipvolt Configure an HTTPX async proxy client, close streamed responses correctly, and reproduce a PoolTimeout locally before changing your proxy settings. Use one `httpx.AsyncClient` for a group of requests, set its `proxy=` explicitly, and close each streamed response when its work ends. If the error is `PoolTimeout`, first inspect who owns the client's connections: that exception means a request could not acquire a connection within its pool-wait limit. It does not, by itself, show that the proxy failed. [HTTPX async support](https://www.python-httpx.org/async/), [timeout phases](https://www.python-httpx.org/advanced/timeouts/). This guide includes a runnable example and a local failure demonstration. The demonstration holds two responses open, observes a third request fail before it reaches the proxy, then closes one response and verifies that another request succeeds. That gives you a concrete way to separate connection ownership from remote network trouble. ## Start with an explicit client The examples require Python 3.11 or later and pin HTTPX 0.28.1. The recorded run used Python 3.14.7 and HTTPcore 1.0.9; the download contains the complete dependency pins. HTTPX 0.28 removed the older `proxies=` argument: use singular `proxy=` for this configuration. [Tagged HTTPX changelog](https://raw.githubusercontent.com/encode/httpx/0.28.1/CHANGELOG.md). The reusable client factory in the download is: ```python import httpx def make_client(proxy_url: str) -> httpx.AsyncClient: return httpx.AsyncClient( proxy=proxy_url, trust_env=False, http2=False, follow_redirects=False, limits=httpx.Limits(max_connections=2, max_keepalive_connections=2), timeout=httpx.Timeout(connect=5.0, read=5.0, write=5.0, pool=0.25), ) ``` The small two-connection pool makes this exercise easy to inspect; it is not a recommended production capacity. HTTPX's connection limit and keep-alive limit control different things. `max_connections` bounds the pool's connections, while `max_keepalive_connections` bounds retained idle connections. A connection limit also does not bound how many application tasks you create. [HTTPX resource limits](https://www.python-httpx.org/advanced/resource-limits/). The complete `async_proxy_check.py` example sends exactly three GETs through one client. A semaphore admits at most two at once. Each request has a ten-second operation deadline starting before that admission wait, as well as the client timeouts above. Responses are read inside `async with client.stream(...)`, and reading stops with `BodyTooLarge` if the decoded body exceeds 65,536 bytes. The byte cap limits accepted response content; it is not a hard limit on decompressor memory. These are deliberate limits for a small diagnostic, not workload sizing advice. There is no automatic retry loop. Keep the same client around for the work it owns instead of creating a new client inside every request task. Context-managed streams close on exit; manual `client.send(..., stream=True)` calls make response closure your responsibility. [HTTPX client and stream lifetime](https://www.python-httpx.org/async/). ## Keep the proxy connection separate from the destination An HTTPS destination does not automatically require an `https://` proxy address. With an HTTP proxy, the client can request a CONNECT tunnel and then negotiate TLS with the HTTPS destination through that tunnel. Use the proxy scheme and authentication method your provider documents. The local experiment below exercises plain HTTP forwarding, not CONNECT, TLS, SOCKS, authentication, or a provider's service. [HTTPX proxy configuration](https://www.python-httpx.org/advanced/proxies/). For this baseline, `proxy=` selects the route and `trust_env=False` keeps inherited environment configuration out of the client. In HTTPX 0.28.1, do not expect `NO_PROXY` to override an explicitly supplied `proxy=`. If you need route exceptions, configure and verify them deliberately rather than assuming the environment bypassed this client; when HTTPX does read the environment, [the NO_PROXY matching matrix](/blog/no-proxy-matching-tested) shows which entries it matches and that a bracketed IPv6 entry such as `[::1]` made HTTPX 0.28.1 raise `InvalidURL` before sending any request. [Tagged client routing](https://raw.githubusercontent.com/encode/httpx/0.28.1/httpx/_client.py). There is a certificate consequence too: `trust_env=False` disables HTTPX's use of `SSL_CERT_FILE` and `SSL_CERT_DIR`. The example keeps normal certificate verification enabled. If your deployment requires a private CA, configure an explicit trusted `SSLContext` as described in the [HTTPX SSL guide](https://www.python-httpx.org/advanced/ssl/); do not fix a trust error with `verify=False`. See also [HTTPX environment variables](https://www.python-httpx.org/environment_variables/). ## Reproduce the pool failure without a proxy account Download and extract the [HTTPX async proxy example](https://ipvolt.com/downloads/httpx-async-proxy/httpx-async-proxy.zip). From the extracted directory, run: ```sh python3 -m venv .venv . .venv/bin/activate python -m pip install -r requirements.txt python pool_timeout_demo.py ``` Dependency installation uses the package index. The demonstration itself creates a temporary HTTP origin and forward proxy on loopback and sends no requests to an external destination. It uses the same client factory shown above, with HTTP/1.1 and a two-connection pool. The important result is the request sequence, not a speed score: | Step | Client observation | Proxy and origin observation | |---|---|---| | Open `/hold/1` and `/hold/2` as manual streams | Both response bodies remain unfinished | Both paths have arrived | | Request `/blocked` with the pool full | `PoolTimeout` | `/blocked` has not arrived at either hop | | Call `aclose()` on the first held response | One occupied connection is released | The second response remains deliberately open | | Request `/ok` | HTTP 200 with the expected JSON body | `/ok` arrives at both hops | The recorded run produced exactly `/hold/1`, `/hold/2`, and `/ok` at the proxy and at the origin. Its cleanup checks reported no outstanding fixture handlers or writers. This is an executed local behavior demonstration; it does not measure an external proxy's latency, availability, or throughput. The recovered response matters because it shows the client can make progress without changing the proxy, destination, or connection limit. The absence of `/blocked` at the proxy gives a second observation of where this particular attempt stopped. Do not generalize that trace into a claim that every pool timeout is a leak: legitimate long streams and more concurrent work than available connections can also create a wait. ## Fix ownership before adding capacity For normal streaming work, keep the response lifetime inside a context manager. The downloaded checker owns both the response and its bounded read loop; its result is returned only after the stream has been consumed or the operation has failed. For manual streaming, close the response with `await response.aclose()` on every exit path, including exceptions and cancellation. [HTTPX streaming documentation](https://www.python-httpx.org/async/). Closing a response releases its resources; it does not promise that a partially consumed HTTP/1.1 connection will be reusable. The next request may need a new connection. If every open stream still has useful work, reducing admitted concurrency or selecting a larger bounded pool may be appropriate. If abandoned responses still own connections, a larger pool postpones the same problem. [Tagged response closure](https://raw.githubusercontent.com/encode/httpx/0.28.1/httpx/_models.py), [HTTPcore connection-pool ownership](https://raw.githubusercontent.com/encode/httpcore/1.0.9/httpcore/_async/connection_pool.py). Also distinguish a quiet connection from a slow complete operation. An HTTPX read timeout limits a wait for a data chunk; it is not a deadline for downloading an entire slowly arriving response. The checker adds a separate whole-operation deadline. A production queue also needs its own admission, memory, cancellation, and shutdown policy; this three-request demonstration is not a complete worker system. [HTTPX timeouts](https://www.python-httpx.org/advanced/timeouts/), [Python operation deadlines](https://docs.python.org/3/library/asyncio-task.html#asyncio.timeout). ## Check your own route with the complete example Have your environment or secret manager provide `PROXY_URL` and an authorized `TARGET_URL`, then run: ```sh python async_proxy_check.py ``` This sends three GETs. Choose a small endpoint you control or are allowed to test; avoid a URL whose GET operation triggers work you do not intend to repeat. The checker prints status, decoded byte count, and a SHA-256 digest on success, or an error class on failure. It does not print the URLs, response bodies, or raw exception messages, which may contain sensitive data. A matching digest only shows that the observed bodies match. It does not prove that they contain useful content: a repeated challenge page can also have a stable digest. The local demonstration separately checks its expected JSON body. Add the equivalent content check for your destination before treating your own route as successful. Use the result to choose the next investigation: - **`PoolTimeout`:** inspect open response ownership, concurrent work, and pool-wait limits first. Use a trace like the local example to determine whether an attempt reached the proxy. - **Connection or proxy errors:** investigate the configured gateway and the failed stage. A proxy exception and a destination HTTP status are different observations. - **`ReadTimeout` or `OperationDeadline`:** find what was still waiting when the limit expired. The whole-operation deadline also includes time waiting for admission. - **`HTTPStatusError` or `BodyTooLarge`:** inspect the response policy and the expected resource. Increasing the connection pool does not change either check. The [network timeout guide](https://ipvolt.com/guides/proxy-timeout-troubleshooting) covers DNS, TCP, CONNECT, TLS and body-stage diagnosis. The [environment-variable guide](https://ipvolt.com/guides/proxy-environment-variables) compares routing behavior across other clients. For synchronous Python code, use the separate [Requests proxy guide](https://ipvolt.com/guides/python-requests-proxy). If your async client is aiohttp, [aiohttp proxies in 3.14](/guides/aiohttp-proxy-setup) covers its proxy authentication, `trust_env` and error messages. ## Downloads and method The [archive](https://ipvolt.com/downloads/httpx-async-proxy/httpx-async-proxy.zip) includes the complete checker, loopback demonstration, dependency pins, test suite and README. Individual files are also available: [checker](https://ipvolt.com/downloads/httpx-async-proxy/async_proxy_check.py), [demonstration](https://ipvolt.com/downloads/httpx-async-proxy/pool_timeout_demo.py), [requirements](https://ipvolt.com/downloads/httpx-async-proxy/requirements.txt), [tests](https://ipvolt.com/downloads/httpx-async-proxy/test_httpx_proxy.py), [README](https://ipvolt.com/downloads/httpx-async-proxy/README.md), and [recorded output](https://ipvolt.com/downloads/httpx-async-proxy/example-output.json). Method: ipvolt ran controlled loopback checks on 13 September 2026 using the pinned versions above. The exercised cases cover pool exhaustion and recovery, the complete checker, HTTP-status and oversized-body failures, and cancellation cleanup. The fixture sends `Connection: close`, so it demonstrates reuse of a client and release of pool capacity, not TCP keep-alive reuse. These checks do not establish behavior for every Python version, operating system, HTTP/2 server, authentication scheme, or proxy product. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). These examples are client diagnostics, not documentation of an ipvolt endpoint. ## Sources & further reading - [HTTPX async support](https://www.python-httpx.org/async/) - [timeout phases](https://www.python-httpx.org/advanced/timeouts/) - [Tagged HTTPX changelog](https://raw.githubusercontent.com/encode/httpx/0.28.1/CHANGELOG.md) - [HTTPX resource limits](https://www.python-httpx.org/advanced/resource-limits/) - [HTTPX proxy configuration](https://www.python-httpx.org/advanced/proxies/) - [Tagged client routing](https://raw.githubusercontent.com/encode/httpx/0.28.1/httpx/_client.py) - [HTTPX SSL guide](https://www.python-httpx.org/advanced/ssl/) - [HTTPX environment variables](https://www.python-httpx.org/environment_variables/) - [Tagged response closure](https://raw.githubusercontent.com/encode/httpx/0.28.1/httpx/_models.py) - [HTTPcore connection-pool ownership](https://raw.githubusercontent.com/encode/httpcore/1.0.9/httpcore/_async/connection_pool.py) - [Python operation deadlines](https://docs.python.org/3/library/asyncio-task.html#asyncio.timeout) ## Related guides - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md) - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md) - [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md) - [aiohttp proxies in 3.14: auth without BasicAuth, env vars and the errors you'll hit](https://ipvolt.com/guides/aiohttp-proxy-setup.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Residential from $2.20 per GB. Mobile from $9 a day. [Buy residential](https://ipvolt.com/dashboard/residential) [Buy mobile](https://ipvolt.com/dashboard/mobile) --- Document 86 of 138: Amazon SP-API notifications: deduplicate and reconcile URL: https://ipvolt.com/guides/amazon-listing-notifications Markdown: https://ipvolt.com/guides/amazon-listing-notifications.md # Amazon SP-API notifications: deduplicate and reconcile Source: https://ipvolt.com/guides/amazon-listing-notifications Markdown: https://ipvolt.com/guides/amazon-listing-notifications.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Amazon SP-API notifications: deduplicate and reconcile](https://ipvolt.com/guides/amazon-listing-notifications.md) Category: Integration Reviewed: 2026-09-16 Published: 2026-09-16 Reading time: 6 minutes Author: ipvolt Handle Amazon SP-API listing events with a tested SQLite inbox: deduplicate deliveries, recover after restart and reject superseded reads. By ipvolt · Checked 16 September 2026 Persist each validated Amazon listing notification **and the work it creates in one transaction** before acknowledging delivery. Use the notification to schedule a listing read. If another accepted notification arrives during that read, keep the work pending and read again. This prevents a specific local race: an older in-flight result clearing a newer refresh request. This guide is for developers with an authorized SP-API application and an existing EventBridge delivery pipeline. Integration requires your own validated event adapter and authenticated listing-read adapter. The downloadable SQLite lab runs offline with synthetic events, one reconciliation worker and Python's standard library; it implements the persistence and completion checks between those adapters. **Method:** ipvolt ran the demo and 12 tests on 16 September 2026 using CPython 3.14.7 and SQLite 3.53.4. Python 3.11+ is the source target; 3.11 was not exercised in that recorded run. No Amazon account, API request or real queue acknowledgment was tested. ## Run the local lab Download and extract the [complete lab ZIP](https://ipvolt.com/downloads/amazon-listing-notifications/amazon-listing-notifications.zip). Open a terminal in the directory containing `consumer.py`, then run: ```sh python3 -B demo.py python3 -B -m unittest -v test_consumer.py ``` There are no packages to install. Both commands use temporary databases. The demo prints deterministic JSON; compare it with the [recorded output](https://ipvolt.com/downloads/amazon-listing-notifications/example-output.json). The [README](https://ipvolt.com/downloads/amazon-listing-notifications/README.md) documents the complete contract. Inspect [consumer.py](https://ipvolt.com/downloads/amazon-listing-notifications/consumer.py), [demo.py](https://ipvolt.com/downloads/amazon-listing-notifications/demo.py), the [test suite](https://ipvolt.com/downloads/amazon-listing-notifications/test_consumer.py) and [synthetic fixture](https://ipvolt.com/downloads/amazon-listing-notifications/fixtures/scenario.json) individually if you prefer. ## Normalize a trusted event before storing it Listing status and issues notifications use Amazon's **EventBridge workflow**. An SQS queue can be a downstream rule target; that is different from subscribing through the direct SP-API SQS workflow. Follow Amazon's [EventBridge setup](https://developer-docs.amazon/sp-api/docs/set-up-notifications-with-amazon-eventbridge) for destinations, subscriptions and delivery permissions. Pin the raw type and payload version in your adapter. The lowercase names below belong to this lab: | Documented Amazon type | Payload version | Normalized lab type | | --- | --- | --- | | `LISTINGS_ITEM_STATUS_CHANGE` | `1.0` | `listing_status_changed` | | `LISTINGS_ITEM_ISSUES_CHANGE` | `2023-12-13` | `listing_issues_changed` | Amazon directs users of issues version `1.0` to migrate to `2023-12-13`. Status events concern creation, deletion and buyability; issue events contain summaries that can prompt a fuller read. They do not describe every possible listing problem. [Amazon notification types](https://developer-docs.amazon/sp-api/docs/notification-type-values). Both raw payloads allow `MarketplaceId` to be absent. Resolve it only through trusted, authorized configuration; otherwise hold the event for investigation before creating a normalized record. Never silently supply your default marketplace. The lab requires explicit seller, SKU and marketplace. See the pinned [status schema](https://raw.githubusercontent.com/amzn/selling-partner-api-models/3659f96867bfc669aca7a524c2f95744ff0e4478/schemas/notifications/ListingsItemStatusChangeNotification.json) and [issues schema](https://raw.githubusercontent.com/amzn/selling-partner-api-models/3659f96867bfc669aca7a524c2f95744ff0e4478/schemas/notifications/ListingsItemIssuesChangeNotification_2023-12-13.json). There is also a naming inconsistency: that status schema's enum says `LISTINGS_ITEM_STATUS_CHANGED`, while its example and the documentation say `LISTINGS_ITEM_STATUS_CHANGE`. Keep any validation exception narrow, versioned and covered by your adapter tests. The normalized lab neither parses that envelope nor certifies its schema conformance. This is the exact first synthetic record in the fixture: ```json { "schema_version": 1, "source": "fixture:eventbridge:bus-A", "subscription": "fixture-subscription-A", "notification_id": "notice-001", "seller_id": "seller-A", "sku": "SKU-RED", "marketplace_id": "market-A", "notification_type": "listing_status_changed", "event_time": "2026-09-16T10:00:00Z", "payload": {"hint": "synthetic status change"} } ``` `Store.ingest()` accepts this object as JSON text. The adapter must validate source, application/subscription context, seller authorization and scope first. Preserve the inner notification identity separately from EventBridge's outer event ID and any queue receipt handle. The [EventBridge envelope](https://docs.aws.amazon.com/eventbridge/latest/ref/events-structure.html) and [SQS deletion contract](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_DeleteMessage.html) describe those distinct transport values. The lab deduplicates `(source, subscription, notification_id)`. This composite is an application policy. Keep delivery-attempt counters, receipt handles and receive times out of the normalized object: they change between deliveries. The README lists its strict field, size and JSON validation bounds. ## Commit acceptance and pending work together EventBridge can deliver duplicates and provides no ordering guarantee. A downstream SQS standard queue also permits duplicates and out-of-order delivery. [AWS delivery comparison](https://docs.aws.amazon.com/decision-guides/latest/decision-guides/sns-or-sqs-or-eventbridge.html), [SQS standard queues](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/standard-queues.html). The executable core handles that uncertainty in four steps: 1. Start a SQLite transaction. For a new identity, insert the inbox record and increment the work generation for `(seller_id, sku, marketplace_id)` together. 2. For an existing identity, compare canonical normalized content. Identical content returns `duplicate` without incrementing work. Different content raises `IdentityConflict` and preserves the original state. 3. Return `may_ack=True` only after commit. This is a logical decision for your transport adapter; the download makes zero queue acknowledgment calls. Validation, conflict and storage errors do not produce that decision. 4. Scan `dirty_keys()` after restart and between runs. A key is dirty when `generation > applied_generation`. Capture its generation, perform the read outside the transaction, then save the result only if the key and generation still match. Every newly accepted identity advances its key, including an event with an older `event_time`. The payload is retained for identity comparison and never applied as current listing state. The inspected [status model](https://raw.githubusercontent.com/amzn/selling-partner-api-models/3659f96867bfc669aca7a524c2f95744ff0e4478/schemas/notifications/ListingsItemStatusChangeNotification.json) defines `EventTime` as a timestamp, not a shared listing revision. This design does not discard work merely because its timestamp is older. ## Observe the restart and in-flight read race This compact trace is drawn from the recorded demo for `seller-A / SKU-RED / market-A`: | Case | Generation | Applied generation | Dirty | Observed result | | --- | --- | --- | --- | --- | | Process exits after commit | 1 | 0 | true | One inbox row survives | | Redelivery after restart | 1 | 0 | true | `duplicate`, `may_ack: true` | | Initial synthetic read | 1 | 1 | false | `read-1` saved | | Older event arrives | 2 | 1 | true | New refresh required | | Another event arrives during generation-2 read | 3 | 1 | true | `completion_applied: false` | | Following read fails | 3 | 1 | true | Previous snapshot retained | | Later successful refresh | 3 | 3 | false | `read-3` saved | The generation-2 result cannot clear generation 3. Its rejected `read-2` document never replaces `read-1`; the subsequent failure also leaves work pending. The demo finishes with five inbox rows, three independent clean keys and zero external acknowledgments. All 12 recorded tests pass. They include a hard child-process exit after commit, injected SQLite failures that roll back inbox and work together, conflicting identities, wrong-key results and the race above. This establishes local process-restart behavior, not power-loss or filesystem-corruption durability. “Clean” means a read was accepted against the latest **persisted local generation**. It cannot prove that Amazon's response includes the triggering change, that another notification is not delayed, or that delivery was complete. The counter is not an Amazon revision or a distributed exactly-once guarantee. ## Validate the read before clearing work Your read adapter must choose `getListingsItem` datasets explicitly and validate HTTP status, response content and the intended seller/SKU/marketplace meaning before returning `ReadResult`. Amazon's [listing retrieval tutorial](https://developer-docs.amazon/sp-api/docs/retrieve-details-about-a-listing) explains which datasets answer which questions. It now supports multiple marketplaces in the same region for sellers; this lab deliberately keeps one marketplace per work key. **The core does not validate a real Amazon response.** It checks the adapter-declared key, JSON bounds and local generation. Even `{}` passes its object-shape check. If required data is missing, the response belongs elsewhere, or the request fails, your adapter must raise instead of returning a success-shaped placeholder. `refresh_once()` then leaves the work dirty and the previous snapshot intact. For the separate decision about accepted submissions, current offers, inventory and unknown observations, use [Amazon listing updates: accepted is not live](https://ipvolt.com/blog/amazon-listing-update-reconciliation). A successful storage operation cannot make an incomplete observation meaningful. ## Add recovery around the core Use one reconciliation worker for this example. Its tickets are generation checks, not worker leases. The database retains inbox identities indefinitely; deleting them changes the deduplication horizon. Scheduling, backoff, rate limits, retention and concurrent worker ownership require additional design. A production pipeline also needs durable handling for malformed or conflicting events, delivery-failure recovery and periodic reconciliation of authorized listing scope. Amazon recommends a [backup retrieval mechanism](https://developer-docs.amazon/sp-api/docs/notifications-api); EventBridge stops retrying after its configured policy is exhausted and supports a [dead-letter queue](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-rule-retry-policy.html). A sweep and DLQ recovery are outside this lab. They cover failures an inbox cannot see because the event never reached it. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources & further reading - [Set up notifications using the Amazon EventBridge workflow](https://developer-docs.amazon/sp-api/docs/set-up-notifications-with-amazon-eventbridge) - [Notification Type Values](https://developer-docs.amazon/sp-api/docs/notification-type-values) - [Listings Item Status Change Notification schema](https://raw.githubusercontent.com/amzn/selling-partner-api-models/3659f96867bfc669aca7a524c2f95744ff0e4478/schemas/notifications/ListingsItemStatusChangeNotification.json) - [Listings Item Issues Change Notification schema2023-12-13](https://raw.githubusercontent.com/amzn/selling-partner-api-models/3659f96867bfc669aca7a524c2f95744ff0e4478/schemas/notifications/ListingsItemIssuesChangeNotification_2023-12-13.json) - [AWS service event metadata](https://docs.aws.amazon.com/eventbridge/latest/ref/events-structure.html) - [DeleteMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_DeleteMessage.html) - [Amazon SQS, Amazon SNS, or Amazon EventBridge?](https://docs.aws.amazon.com/decision-guides/latest/decision-guides/sns-or-sqs-or-eventbridge.html) - [Amazon SQS standard queues](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/standard-queues.html) - [Retrieve details about a listing for single or multiple Amazon stores](https://developer-docs.amazon/sp-api/docs/retrieve-details-about-a-listing) - [Notifications API](https://developer-docs.amazon/sp-api/docs/notifications-api) - [How EventBridge retries delivering events](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-rule-retry-policy.html) ## Related guides - [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md) - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 87 of 138: Fix ERR_TUNNEL_CONNECTION_FAILED in Playwright and Puppeteer URL: https://ipvolt.com/guides/fix-err-tunnel-connection-failed Markdown: https://ipvolt.com/guides/fix-err-tunnel-connection-failed.md # Fix ERR_TUNNEL_CONNECTION_FAILED in Playwright and Puppeteer Source: https://ipvolt.com/guides/fix-err-tunnel-connection-failed Markdown: https://ipvolt.com/guides/fix-err-tunnel-connection-failed.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Fix ERR_TUNNEL_CONNECTION_FAILED in Playwright and Puppeteer](https://ipvolt.com/guides/fix-err-tunnel-connection-failed.md) Category: Troubleshooting Reviewed: 2026-09-17 Published: 2026-09-17 Reading time: 9 minutes Author: ipvolt ERR_TUNNEL_CONNECTION_FAILED and ERR_PROXY_CONNECTION_FAILED explained with a verified failure matrix, plus how to recover the CONNECT status Chromium hides. `net::ERR_TUNNEL_CONNECTION_FAILED` means Chromium reached your proxy, asked it to open a tunnel to an HTTPS destination with a `CONNECT` request, and the proxy answered with something other than success. `net::ERR_PROXY_CONNECTION_FAILED` means Chromium never got that far: it could not establish a connection to the proxy at all. Both codes come from Chromium's network stack, so Playwright, Puppeteer and any other tool driving Chromium report the same strings, usually as `page.goto: net::ERR_TUNNEL_CONNECTION_FAILED at https://...`. The frustrating part is what Chromium leaves out. A proxy that refuses a tunnel with 403, one that is rate limiting you with 429, and one whose upstream is down with 502 all produce the identical `ERR_TUNNEL_CONNECTION_FAILED`. This guide shows which proxy behaviour produces which error in Playwright, Puppeteer and curl, reproduced against small controlled proxies rather than collected from forum threads, and then gives you a short procedure to recover the status the browser hides. ## Seeing this in Chrome or Edge without any code? The meaning is the same in a normal browser window. Chrome and Edge share Chromium's network stack, and by default they take their proxy settings from the operating system, so the error tells you that a proxy is configured somewhere and that it refused to open the tunnel (`ERR_TUNNEL_CONNECTION_FAILED`) or could not be reached at all (`ERR_PROXY_CONNECTION_FAILED`). The website itself is not down; the browser never got past the proxy. The usual sources of that configuration are a VPN client that installs a system proxy while connected, a proxy or VPN browser extension, a company policy or PAC script on a managed device, or a proxy that was entered by hand and forgotten. How to fix it, in the order that finds the cause fastest: - Open `chrome://net-internals/#proxy` (or `edge://net-internals/#proxy`) to see the effective proxy settings the browser is using right now. If you did not expect a proxy there, that is the problem. - Disconnect the VPN or disable proxy extensions, reload, and compare. If the page loads, the VPN or extension's proxy was refusing the tunnel or was unreachable. - On a work or school device, the proxy administrator's rules decide which sites are allowed. `ERR_TUNNEL_CONNECTION_FAILED` on an HTTPS site that is blocked by policy is expected behaviour, and only the administrator can change it. - If `http://` pages load but `https://` pages fail, the proxy is refusing `CONNECT` to port 443. That is the tunnel case in the matrix below, and the proxy's own status code says why. The rest of this guide is written for developers who configured the proxy themselves in Playwright or Puppeteer, but every error string means exactly the same thing in the address bar. ## Two errors, two stages For an HTTPS destination through an HTTP proxy, Chromium resolves the proxy hostname, opens a TCP connection to it, sends `CONNECT host:443`, waits for a `2xx` reply, and only then starts the destination TLS handshake inside the tunnel. The two error codes mark two different points on that path: - **`ERR_PROXY_CONNECTION_FAILED`**: the proxy hostname did not resolve, nothing accepted the TCP connection, or the connection to the proxy failed before any HTTP was exchanged. A common self-inflicted variant is writing `https://` in front of a gateway that only speaks plain HTTP, which makes Chromium attempt a TLS handshake with a server that expects cleartext. - **`ERR_TUNNEL_CONNECTION_FAILED`**: the TCP connection worked and the proxy answered the `CONNECT`, but not with a success status. Chromium discards the status code, the reason phrase and any body the proxy sent. Everything else you may see (`ERR_CONNECTION_RESET`, `ERR_INVALID_HTTP_RESPONSE`, `ERR_SOCKS_CONNECTION_FAILED`, a plain navigation timeout) belongs to a different stage and is covered further down. ## What each proxy failure looks like The table records what each client reported for one deliberate proxy behaviour. Playwright used its `proxy` launch option; Puppeteer used raw Chromium flags (`--proxy-server`) with `page.authenticate` for credentials; curl used `-x` with `--proxy-user`. All three talked to the same Chromium 153 build or curl 8.18 on Linux; details are in the method section. | Proxy behaviour | Playwright 1.63 (Chromium 153) | Puppeteer 25 (same Chromium) | curl 8.18 | | --- | --- | --- | --- | | Proxy hostname does not resolve | `ERR_PROXY_CONNECTION_FAILED` | same | `(5) Could not resolve proxy` | | Nothing listens on the proxy port | `ERR_PROXY_CONNECTION_FAILED` | same | `(7) Failed to connect` | | `https://` scheme, but the proxy speaks plain HTTP | `ERR_PROXY_CONNECTION_FAILED` | same | `(35) TLS connect error` | | Proxy accepts TCP and never answers | navigation timeout | navigation timeout | `(28) Connection timed out` | | Proxy accepts TCP and closes at once | `ERR_CONNECTION_RESET` | same | `(56) Proxy CONNECT aborted` or `(56) Recv failure: Connection reset by peer` | | Port answers, but not with HTTP | `ERR_INVALID_HTTP_RESPONSE` | same | `(56) Proxy CONNECT aborted` | | CONNECT answered 403 | `ERR_TUNNEL_CONNECTION_FAILED` | same | `(7) CONNECT tunnel failed, response 403` | | CONNECT answered 429 | `ERR_TUNNEL_CONNECTION_FAILED` | same | `(7) CONNECT tunnel failed, response 429` | | CONNECT answered 502 or 503 | `ERR_TUNNEL_CONNECTION_FAILED` | same | `(7) CONNECT tunnel failed, response 502` or `503` | | CONNECT answered 407, no credentials configured | navigation resolves with status 407, then `ERR_TUNNEL_CONNECTION_FAILED` on the request | `ERR_INVALID_AUTH_CREDENTIALS` | `(7) CONNECT tunnel failed, response 407` | | CONNECT answered 407, wrong credentials | navigation resolves with status 407, then `ERR_TUNNEL_CONNECTION_FAILED` on the request | navigation resolves with status 407 and Chromium's error page, then `ERR_HTTP_RESPONSE_CODE_FAILURE` | `(7) CONNECT tunnel failed, response 407` | | Correct credentials | 200 from the destination | 200 | 200, `http_connect` 200 | | CONNECT answered 200, then the proxy drops the tunnel | `ERR_CONNECTION_CLOSED` or `ERR_CONNECTION_RESET` | `ERR_CONNECTION_RESET` | `(35) Send failure: Broken pipe` | | `socks5://` scheme against an HTTP proxy | `ERR_SOCKS_CONNECTION_FAILED` | same | `(97) Received invalid version in initial SOCKS5 response` | | `socks5://` with a username and password | refused at launch: `Browser does not support socks5 proxy authentication` | not exercised | not exercised | | Plain `http://` destination, proxy rejects with 403 or 407 | no error: the proxy's own 403 or 407 page is the navigation response | same | 403 or 407 with `http_connect` 000 | Three rows deserve a second look. Every non-success `CONNECT` status from 403 to 503 collapses into one browser error, so the browser alone cannot tell you whether you are blocked, throttled or looking at a broken upstream. A 407 is the only status Chromium handles specially, and Playwright and Puppeteer surface it differently. And a plain `http://` destination never produces a tunnel error, because there is no tunnel: the proxy's rejection arrives as an ordinary response with the proxy's status and body, which is why the same script can "work" on an HTTP test page and fail on the HTTPS site you care about. ## Recover the CONNECT status with curl curl keeps the status that Chromium throws away. Run one bounded request against the same gateway, destination and credentials your browser script uses, and print both the destination status and the `CONNECT` status. The command reads `PROXY_URL`, `PROXY_USERNAME` and `PROXY_PASSWORD` from the environment so the password never appears in a shell argument or history entry; curl 8.3 or later is required for the variable expansion. ```sh : "${PROXY_URL:?Set the gateway as http://host:port (no credentials in the URL)}" CHECK_URL=${CHECK_URL:-https://example.com/} curl --disable --silent --show-error --output /dev/null \ --noproxy '' --proxy "$PROXY_URL" --proxy-basic \ --variable %PROXY_USERNAME --variable %PROXY_PASSWORD \ --expand-proxy-user '{{PROXY_USERNAME}}:{{PROXY_PASSWORD}}' \ --max-time 15 \ --write-out 'destination=%{http_code} connect=%{http_connect} exit=%{exitcode}\n' \ "$CHECK_URL" ``` `connect=200` with a destination status means the tunnel works and the browser problem is elsewhere. A non-zero `connect` value is the status Chromium hid: - **407**: the proxy wants credentials it did not accept. Check the account or sub-user, percent-encoding, and whether this gateway authenticates by password or by allowed source IP. The [407 guide](https://ipvolt.com/guides/fix-proxy-error-407) walks through that order and shows the exact symptom in each client. - **403**: the proxy accepted the connection but refuses this tunnel. Typical causes are a destination or port outside the provider's allowed list, an account restriction, or a country or session parameter the gateway rejects. - **429**: concurrency or rate limits at the proxy. Look for a `Retry-After` header in `curl -v` output and reduce parallel browsers before retrying. - **502, 503, 504**: the proxy could not reach or select an upstream exit. Retrying immediately rarely helps; note the time and ask the provider what their gateway logged. `connect=000` with a curl exit code other than 0 means the failure happened before any `CONNECT` reply, which matches the `ERR_PROXY_CONNECTION_FAILED` and reset rows above. The [timeout guide](https://ipvolt.com/guides/proxy-timeout-troubleshooting) shows how to time each stage when the failure is slow rather than immediate. ## Playwright: a 407 does not throw With no proxy credentials, or wrong ones, `page.goto` did not reject in the recorded run. It resolved with a response whose status was 407 and whose `statusText` was `Proxy Authentication Required`, with the proxy's `Proxy-Authenticate` header readable on that response and an empty body; a `requestfailed` event with `ERR_TUNNEL_CONNECTION_FAILED` fired for the same navigation. A script that only awaits `goto` and continues therefore keeps running against an empty page. Check `response.ok()` and treat a 407 as a proxy problem, not a destination problem: ```js import { chromium } from 'playwright'; function required(name) { const value = process.env[name]; if (!value) throw new Error('Missing environment variable: ' + name); return value; } const browser = await chromium.launch({ proxy: { server: required('PROXY_URL'), // http://host:port, no credentials in the URL username: required('PROXY_USERNAME'), password: required('PROXY_PASSWORD'), }, }); try { const page = await browser.newPage(); page.on('requestfailed', (request) => { console.error('request failed:', request.failure()?.errorText, request.url()); }); const response = await page.goto('https://example.com/', { waitUntil: 'domcontentloaded' }); if (!response) throw new Error('No navigation response'); if (response.status() === 407) throw new Error('Proxy rejected the credentials (407)'); if (!response.ok()) throw new Error('Destination answered ' + response.status()); } finally { await browser.close(); } ``` Put proxy credentials in `proxy.username` and `proxy.password`. In the recorded run, credentials supplied through the context's `httpCredentials` option also satisfied the proxy challenge, because Playwright answers Chromium's authentication request from either source. Do not rely on that: `httpCredentials` is meant for the destination, and reusing it for the proxy sends a site login to the proxy operator. Two more Playwright details from the run. Playwright adds `<-loopback>` to the bypass list itself, so a destination on `localhost` or `127.0.0.1` goes through the proxy; raw Chromium does the opposite (see the Puppeteer section). And a `socks5://` server with a username and password is refused before the browser starts, with `Browser does not support socks5 proxy authentication`. Chromium has no SOCKS5 authentication support, so the fix is an HTTP gateway with Basic authentication or IP allow-listing, not a different SOCKS setting. The [HTTP vs SOCKS5 guide](https://ipvolt.com/guides/http-vs-socks5-proxies) covers what changes between the two. ## Puppeteer: authenticate before the first navigation Puppeteer passes the proxy to Chromium as a flag and answers 407 challenges only after `page.authenticate` has been called. Without it, the recorded run produced `net::ERR_INVALID_AUTH_CREDENTIALS`, a code many people never connect with a proxy. With wrong credentials, `goto` resolved with status 407 and Chromium's built-in error page as the body, plus a `requestfailed` event carrying `ERR_HTTP_RESPONSE_CODE_FAILURE`. ```js import puppeteer from 'puppeteer'; function required(name) { const value = process.env[name]; if (!value) throw new Error('Missing environment variable: ' + name); return value; } const browser = await puppeteer.launch({ args: [ '--proxy-server=' + required('PROXY_URL'), // http://host:port '--proxy-bypass-list=<-loopback>', // only if local destinations must use the proxy ], }); try { const page = await browser.newPage(); await page.authenticate({ username: required('PROXY_USERNAME'), password: required('PROXY_PASSWORD'), }); page.on('requestfailed', (request) => { console.error('request failed:', request.failure()?.errorText, request.url()); }); const response = await page.goto('https://example.com/', { waitUntil: 'domcontentloaded' }); if (!response) throw new Error('No navigation response'); if (response.status() === 407) throw new Error('Proxy rejected the credentials (407)'); if (!response.ok()) throw new Error('Destination answered ' + response.status()); } finally { await browser.close(); } ``` Two Chromium defaults matter here. First, Chromium bypasses the proxy for `localhost`, `127.0.0.1` and `[::1]` unless the bypass list contains `<-loopback>`. In the run, a Puppeteer script pointed at a proxy that rejected every tunnel still loaded a local HTTPS page with status 200, because the proxy was never consulted. A test that "passes" against a local server proves nothing about the proxy. Second, a raw Chromium launched with `--proxy-server` routed its own background traffic through the proxy as well: the recorded proxy log shows a `GET` to `clients2.google.com` and a `CONNECT` to `update.googleapis.com:443` before the page navigation. Expect those hostnames in provider logs and metered traffic, and do not mistake their failures for your navigation failing. Playwright's launch flags did not produce that traffic in the same run. ## Errors that are not tunnel errors - **`ERR_CONNECTION_RESET` or `ERR_CONNECTION_CLOSED` right after connecting**: the proxy accepted the TCP connection and dropped it, either before answering `CONNECT` or immediately after a 200. Providers do this when an exit is unavailable or the connection is being rate limited at the socket level. curl reports `Proxy CONNECT aborted` or `Send failure: Broken pipe` for the same behaviour. After a 200, Python prints that close as `SSLEOFError`, and curl on OpenSSL prints `Send failure: Broken pipe` or, if the proxy read the ClientHello first, `unexpected eof while reading`. [SSL EOF behind a proxy](/guides/fix-ssl-unexpected-eof-proxy) says what that means for the request. - **`ERR_INVALID_HTTP_RESPONSE`**: something answered on that port, but not in HTTP. Usually the port number belongs to a SOCKS listener, a TLS-only listener or a different service. - **`ERR_SOCKS_CONNECTION_FAILED`**: you configured `socks5://` and the server spoke HTTP. Swap the scheme to match the gateway's documented protocol before changing anything else. - **A navigation timeout with no net error**: the proxy accepted the connection and never replied. Raising the timeout will not help; verify the port and protocol with curl, which times out with `(28)` in the same situation. - **`ERR_PROXY_CONNECTION_FAILED` on a gateway that works in curl**: compare the scheme. Chromium attempts TLS for `https://` proxies, and most gateways are plain `http://` endpoints that carry HTTPS destinations inside the tunnel. ## A diagnostic order 1. Reproduce with curl using the same gateway, destination and credentials, and read `http_connect`. This converts the browser's one-word error into the proxy's actual status in under a minute. 2. Confirm the proxy scheme (`http://`, `https://` or `socks5://`) against the provider's current instructions. Two of the three `ERR_PROXY_CONNECTION_FAILED` rows above are scheme mistakes. 3. Put credentials where the tool expects them: `proxy.username` and `proxy.password` in Playwright, `page.authenticate` before the first navigation in Puppeteer. Check `response.status() === 407` explicitly in both. 4. Test an HTTPS destination, not an HTTP one. HTTP destinations skip `CONNECT` and hide tunnel problems behind ordinary proxy responses. 5. Check bypass rules. Local and internal destinations bypass the proxy in raw Chromium, and corporate or environment proxy settings can override what you passed. 6. Report with the client versions, UTC time, gateway host and port, destination hostname and the curl `http_connect` value. Leave passwords, credential-bearing URLs and raw traces out; the [407 guide](https://ipvolt.com/guides/fix-proxy-error-407) has a sanitised report template. ## Method and downloads ipvolt ran the reproduction on 17 September 2026 on a Linux host with Node.js 24.20.0, Playwright 1.63.0 (Chromium 153.0.8010.12, headless), puppeteer-core 25.11.0 driving the same Chromium build, and curl 8.18.0. Each "proxy" was a small Node.js server on 127.0.0.1 with exactly one behaviour; the destination was a local HTTPS server with a throwaway self-signed certificate, so the browser cases ignored destination certificate errors, which does not affect how Chromium talks to the proxy. Firefox and WebKit were not exercised, and no commercial gateway was involved: the table describes Chromium's reaction to a proxy behaviour, not any provider's policy. The [lab archive](https://ipvolt.com/downloads/chromium-proxy-tunnel-errors/chromium-proxy-tunnel-errors.zip) contains the [lab script](https://ipvolt.com/downloads/chromium-proxy-tunnel-errors/tunnel-errors-lab.mjs), the [package manifest](https://ipvolt.com/downloads/chromium-proxy-tunnel-errors/package.json), the [README](https://ipvolt.com/downloads/chromium-proxy-tunnel-errors/README.md) and the [recorded results](https://ipvolt.com/downloads/chromium-proxy-tunnel-errors/results.json), including the proxy-side log that shows whether each client reached the proxy and whether credentials arrived. It runs on loopback only and needs no proxy account. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). These examples are client diagnostics, not documentation of an ipvolt endpoint. ## Sources & further reading - [Chromium network error list (net_error_list.h)](https://chromium.googlesource.com/chromium/src/+/main/net/base/net_error_list.h) - [Chromium proxy support and bypass rules (proxy.md)](https://chromium.googlesource.com/chromium/src/+/main/net/docs/proxy.md) - [Playwright: HTTP proxy configuration](https://playwright.dev/docs/network#http-proxy) - [Puppeteer: page.authenticate](https://pptr.dev/api/puppeteer.page.authenticate) - [curl: --write-out variables including http_connect](https://curl.se/docs/manpage.html#-w) - [RFC 9110: the CONNECT method](https://www.rfc-editor.org/rfc/rfc9110.html#name-connect) - [RFC 9110: 407 Proxy Authentication Required](https://www.rfc-editor.org/rfc/rfc9110.html#name-407-proxy-authentication-req) ## Related guides - [Configure a proxy in Playwright](https://ipvolt.com/guides/playwright-proxy-setup.md) - [Fix proxy error 407 without guessing](https://ipvolt.com/guides/fix-proxy-error-407.md) - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md) - [HTTP vs SOCKS5 proxies: choose by the connection](https://ipvolt.com/guides/http-vs-socks5-proxies.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 88 of 138: Fix Node.js TypeError: fetch failed behind a proxy URL: https://ipvolt.com/guides/fix-node-fetch-failed-proxy Markdown: https://ipvolt.com/guides/fix-node-fetch-failed-proxy.md # Fix Node.js TypeError: fetch failed behind a proxy Source: https://ipvolt.com/guides/fix-node-fetch-failed-proxy Markdown: https://ipvolt.com/guides/fix-node-fetch-failed-proxy.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Fix Node.js TypeError: fetch failed behind a proxy](https://ipvolt.com/guides/fix-node-fetch-failed-proxy.md) Category: Troubleshooting Reviewed: 2026-09-24 Published: 2026-09-24 Reading time: 22 minutes Author: ipvolt TypeError: fetch failed hides the real error in err.cause. Find yours: ENOTFOUND, UND_ERR_CONNECT_TIMEOUT, invalid onError method or a proxy 403/407/502. `TypeError: fetch failed` is not the error itself. It is the wrapper that Node.js's built-in `fetch` (undici) puts around every network-level failure. The reason is in `err.cause`, and sometimes one level deeper. Behind a proxy, the causes fall into four groups: - **The proxy was never used.** Built-in `fetch` ignores `HTTPS_PROXY` until you opt in with `NODE_USE_ENV_PROXY=1`, `--use-env-proxy` or `http.setGlobalProxyFromEnv()`, and Node 26 ignores a global dispatcher set by undici 5, 6, or 7 before 7.27.0. You see `getaddrinfo ENOTFOUND`, a connect error that names the destination's address, or a normal response that the proxy never logged. - **Version skew around undici 8.** An undici 5 or 6 dispatcher passed per request to Node 26's `fetch`, or an undici 8 dispatcher passed to the `fetch` of Node 22 or 24, fails with `invalid onError method` or `invalid onRequestStart method` before any byte reaches the proxy. - **The proxy refused the request.** `Proxy response (NNN) !== 200 when HTTP Tunneling` sits two levels down, with the proxy's status, such as 403, 407, 429 or 502. Plain `http://` URLs on undici 8.7 and later differ. - **An unreachable or failing proxy.** `ECONNREFUSED`, `ETIMEDOUT`, `UND_ERR_CONNECT_TIMEOUT` or `ENOTFOUND` naming the proxy, `UND_ERR_PRX_CONN`, `ECONNRESET`, a TLS error, or no error at all. If the cause is `invalid onError method` on Node.js 26, [fetch failed: invalid onError method on Node.js 26](/guides/node-26-invalid-onerror-method) finds the old undici copy and picks the fix. Print the whole chain, find the deepest string in the tables below and apply the fix for that layer. Except for the one row marked as reported, every error string in the tables was observed in 1,965 loopback lab cells that ipvolt ran on 23 and 24 September 2026 with Node.js v22.23.3, v24.21.0 and v26.10.0 and npm undici 5.29.0 to 8.11.0. A 4xx or 5xx from the destination never produces `fetch failed`; it resolves as a `Response`. The browser's `TypeError: Failed to fetch` is a different error, raised for network and CORS failures whose details JavaScript cannot see. ## What "TypeError: fetch failed" means in Node.js undici rejects network errors with `new TypeError('fetch failed', { cause: response.error })`. The [same line](https://github.com/nodejs/undici/blob/v8.10.2/lib/web/fetch/index.js#L272) is in the first and the latest undici bundled by each of Node 22, 24 and 26 (six releases, from 6.11.1 to 8.10.2). The cause can be an undici error with a stable `code` such as `UND_ERR_INVALID_ARG`, a Node.js system error such as `ECONNREFUSED`, or a `DOMException` with the message `Request was cancelled.` that wraps the real error one level further down, as every rejected CONNECT did in the lab. Your own `AbortSignal.timeout()` is the exception: it rejects with a bare `TimeoutError` that has no `fetch failed` wrapper and no cause. ## Print the whole cause chain Several common ways of logging the error stop before the deepest string. With the lab's 407 proxy on all three runtimes, `err.message` showed only `fetch failed`, `err.cause.message` stopped at `Request was cancelled.`, and `JSON.stringify(err)` printed `{}`. `console.log(err)` did reach the 407, but with stack traces and without masking anything. Walk the chain instead with [print-cause.mjs](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/print-cause.mjs), the printer that recorded every cell in the lab: ```js // print-cause.mjs: walk err.cause and report name, code and message at each depth. // Reads only name, code, message, cause and an AggregateError's errors (never headers, // bodies or stacks). Masks URL userinfo, Bearer tokens and key:value or key=value pairs // whose key names a credential. Regex masking is not exhaustive: review before sharing. const KEY = String.raw`[\w-]*(?:authorization|cookie|token|secret|passw(?:or)?d|api[-_]?key)[\w-]*`; const mask = (s) => String(s) .replace(/\/\/[^/\s]*@/g, '//***@') .replace(/\bBearer\s+[\w.~+/-]+=*/gi, 'Bearer ***') .replace(new RegExp(String.raw`(["']?\b${KEY}["']?\s*[:=]\s*)(["']?)(?:(?:Basic|Bearer|Digest)\s+)?[^\s"'&,;]+`, 'gi'), '$1$2***'); export function causeChain(err, maxDepth = 10) { const chain = []; for (let e = err, depth = 0; e != null && depth < maxDepth; e = e.cause, depth++) { const entry = { depth, name: e.name ?? typeof e, code: typeof e.code === 'string' ? e.code : undefined, message: mask(e.message ?? e).slice(0, 300) }; if (Array.isArray(e.errors)) entry.errors = e.errors.slice(0, 5).map((x) => `${x?.code ?? x?.name}: ${mask(x?.message ?? x).slice(0, 200)}`); chain.push(entry); } return chain; } export function printCauseChain(err, log = console.error) { for (const { depth, name, code, message, errors } of causeChain(err)) { log(`${' '.repeat(depth)}[${depth}] ${name}${code ? ` (${code})` : ''}: ${message}${errors ? ` [${errors.join('; ')}]` : ''}`); } } ``` Call it in the `catch` block, for example `try { await fetch(url) } catch (err) { printCauseChain(err); process.exitCode = 1; }`. Don't rethrow `err` and leave it uncaught: Node then prints the whole error itself, including an unmasked `[cause]`, as the lab confirmed with a throwaway password. This is the output for the lab's 407 proxy on Node v26.10.0 with `NODE_USE_ENV_PROXY=1`: ```text [0] TypeError: fetch failed [1] Error: Request was cancelled. [2] AbortError (UND_ERR_ABORTED): Proxy response (407) !== 200 when HTTP Tunneling ``` Read the output before you share it: anything the masks don't match, such as `user:password@host` without a scheme in front, passes through. If your code branches on the error, match `err.code`, not `instanceof`. undici's [Errors reference](https://github.com/nodejs/undici/blob/v8.11.0/docs/docs/api/Errors.md) recommends this because "the bundled (global) dispatcher may come from a different undici version than the one you import directly". For `UND_ERR_INVALID_ARG`, check the message too: in the lab it meant version skew or a proxy 407 on a plain `http://` URL. ## Find your error: string, depth, layer and fix Depth 0 is `TypeError: fetch failed`, and each string sits at depth 1, unless a row says otherwise. "Proxy logged nothing" means the lab proxy saw no connection for that fetch. ### It failed before reaching the proxy | What you see | Layer | Fix | | --- | --- | --- | | `invalid onError method` (`UND_ERR_INVALID_ARG`), proxy logged nothing | An undici 5 or 6 dispatcher handed to Node 26's `fetch` | An undici 7 or 8 dispatcher, undici's own `fetch`, or no dispatcher plus `NODE_USE_ENV_PROXY=1` | | `invalid onRequestStart method` (`UND_ERR_INVALID_ARG`), proxy logged nothing | An undici 8 dispatcher handed to the `fetch` of Node 22 or 24 | `Dispatcher1Wrapper`, undici 8's own `fetch` or `setGlobalDispatcher()`, or an undici 7 agent | | `getaddrinfo ENOTFOUND` naming the destination, proxy logged nothing | The proxy was never used; the direct DNS lookup failed | Turn on the env-proxy opt-in. For a global dispatcher, upgrade undici to 7.27.0+ or 8.0.1+ | | `getaddrinfo ENOTFOUND` naming the proxy's host | The proxy's host name does not resolve on this machine | Check the host in the proxy URL, and the DNS or VPN that should resolve it | | `connect ECONNREFUSED` or `connect ETIMEDOUT` with the destination's address, proxy logged nothing | The proxy was never used; the direct connection failed | As above | | `Connect Timeout Error` (`UND_ERR_CONNECT_TIMEOUT`) listing the destination's addresses, reported in [undici#4960](https://github.com/nodejs/undici/issues/4960) | The same, reported by undici's connect timeout | As above | | No error and a normal response, proxy logged nothing | The proxy was silently bypassed | As above | | `Setting the TLS ServerName to an IP address is not permitted` (`ERR_INVALID_ARG_VALUE`), on Node 26 | An `https://` proxy URL with an IP address, which Node 25 and later refuse | `http://` for a plain-HTTP proxy, or a host name the HTTPS proxy's certificate covers | ### It failed at the proxy or beyond it | What you see | Layer | Fix | | --- | --- | --- | | Depth 2 `Proxy response (NNN) !== 200 when HTTP Tunneling` under depth 1 `Request was cancelled.` | The proxy refused the CONNECT with status NNN | Read NNN: 407 is credentials ([fix proxy error 407](/guides/fix-proxy-error-407)), 403 its policy, 429 its rate limit, 502 to 504 trouble at or beyond the proxy | | `Proxy Authentication Required (407)` (`UND_ERR_INVALID_ARG`) | A 407 for a plain `http://` URL that undici 8.7 or later forwarded without CONNECT | The same credentials fix; this `UND_ERR_INVALID_ARG` is not version skew | | No error, but `response.status` is 403, 429, 502 or 503, and the origin never logged the request | The proxy's own error for a forwarded `http://` URL (undici 8.7 and later) | Check the body and headers for the proxy's signature | | `connect ECONNREFUSED` plus the proxy's address | Nothing listens at the proxy's host and port | Check the host, the port and that the proxy is running | | `AggregateError` (`ECONNREFUSED`) with an empty message and one refused address per IP family | The same, for a proxy host name such as `localhost` | As above | | `connect ETIMEDOUT` plus the proxy's address | The TCP handshake with the proxy never completed | Check the route and firewalls to the proxy | | `Connect Timeout Error` (`UND_ERR_CONNECT_TIMEOUT`) with the proxy's address | The same fault, reported by undici's connect timeout | As above | | `ERR_SSL_WRONG_VERSION_NUMBER`, with `wrong version number` in the message | The proxy URL says `https://`, but the proxy speaks plain HTTP | Use `http://` in the proxy URL | | `Proxy Connection failed` (`UND_ERR_PRX_CONN`) over depth 2 `other side closed` | The proxy closed the connection without answering CONNECT (undici 8.6 and later) | Check the port, the protocol and whether the proxy supports CONNECT | | `other side closed` (`UND_ERR_SOCKET`) for an `http://` URL | The proxy closed a forwarded request without answering (undici 8.7 and later) | Check the port and the protocol, then the proxy's log | | No error, and the fetch never settles, while the proxy logs CONNECT after CONNECT | The same fault on undici 8.5 and older: a reconnect loop | A caller deadline turns it into a `TimeoutError`; undici 8.6 or later turns it into `UND_ERR_PRX_CONN` | | `Client network socket disconnected before secure TLS connection was established` (`ECONNRESET`) | The proxy answered 200, then dropped the tunnel | Look past the proxy: its upstream or the destination | | `SELF_SIGNED_CERT_IN_CHAIN` or `UNABLE_TO_VERIFY_LEAF_SIGNATURE` | A TLS-inspecting proxy presented a certificate from a CA that Node doesn't trust | Trust that CA with `NODE_EXTRA_CA_CERTS`, or with `--use-system-ca` if it is in the OS trust store | | No error for about five minutes, then depth 1 `Headers Timeout Error` (`UND_ERR_HEADERS_TIMEOUT`) | The proxy accepted CONNECT and never answered | Set your own deadline | | Depth 0 `TimeoutError: The operation was aborted due to timeout`, no cause | Your `AbortSignal.timeout()` fired | Check the proxy log for the pending stage | In every cell that got as far as the injected proxy behavior, 449 in the main matrix and 803 in the checks suite, the layer that the lab derived from the strings and proxy counts alone matched that behavior. ## HTTPS_PROXY is set but fetch ignores it (NODE_USE_ENV_PROXY) With `HTTPS_PROXY` set and no opt-in, all three runtimes in the lab connected directly, and `HTTP_PROXY` with `http://` URLs behaved the same way; a destination reachable without the proxy returned 200 while the proxy logged nothing. Node's [startup code](https://github.com/nodejs/node/blob/v26.10.0/lib/internal/process/pre_execution.js#L314-L333) installs a proxy dispatcher only when the opt-in is on and one of `HTTP_PROXY`, `HTTPS_PROXY`, `http_proxy` or `https_proxy` is set. `ALL_PROXY` doesn't count. | Opt-in | Documented since | Lab: v22.23.3 / v24.21.0 / v26.10.0 | | --- | --- | --- | | [`NODE_USE_ENV_PROXY=1`](https://nodejs.org/api/cli.html#node_use_env_proxy1) | v24.0.0, v22.21.0 | proxied on all three | | [`node --use-env-proxy`](https://nodejs.org/api/cli.html#--use-env-proxy) | v24.5.0, v22.21.0 | proxied on all three | | [`http.setGlobalProxyFromEnv()`](https://nodejs.org/api/http.html#httpsetglobalproxyfromenvproxyenv) | v24.14.0, v25.4.0 | not a function on v22.23.3; proxied on the other two | | npm undici `setGlobalDispatcher(new EnvHttpProxyAgent())` | exported by 6.28.1 and every undici 7 and 8 in the lab | proxied, except on v26.10.0 with 6.28.1, 7.16.0 or 7.26.0, which went direct | - Older releases don't have the opt-in; use a dispatcher or undici's own `fetch` there. - Include the scheme. With the opt-in on, a value without `http://`, such as `127.0.0.1:` or `localhost:`, made all three runtimes exit at startup with `TypeError: Invalid URL` or `Invalid URL protocol`, before any application code ran. Only `http://` and `https://` proxy URLs are documented; SOCKS5 is still an open item in Node's [proxy tracking issue](https://github.com/nodejs/node/issues/57872). - Node parses the variables "during startup", per the CLI docs, so setting `process.env.HTTPS_PROXY` from code later does not help. `http.setGlobalProxyFromEnv()` is the runtime alternative. - On v22.23.3, the opt-in printed `[UNDICI-EHPA] Warning: EnvHttpProxyAgent is experimental`, a stability notice, not an error. - With no `NO_PROXY` set, even `https://127.0.0.1` went through the proxy. What `NO_PROXY` exempts differs between clients; see the [NO_PROXY matching matrix](/blog/no-proxy-matching-tested). - A per-request `dispatcher` takes over from the opt-in for its request: with `HTTPS_PROXY` pointing at a dead port and the agent at the working proxy, every request that ran used the agent. In the proxy log, a plain `http://` URL on undici 8.7 and later, including the env proxy of Node 26.5 and later, shows no CONNECT, only the request itself in absolute form, such as `GET http://origin.test/…`. For the same variables in curl and Python, see [proxy environment variables](/guides/proxy-environment-variables); for an explicit `ProxyAgent`, [use a proxy with Node.js fetch](/guides/nodejs-fetch-proxy). ## invalid onError method: an older undici dispatcher on Node 26 [undici 8.0.0](https://github.com/nodejs/undici/releases/tag/v8.0.0) removed the legacy handler wrappers and renamed handler callbacks, for example `onError` to `onResponseError` ([migration guide](https://github.com/nodejs/undici/blob/v8.11.0/docs/docs/best-practices/migrating-from-v7-to-v8.md)). Every Node 26 release bundles undici 8, so its `fetch` gives dispatchers a handler with only the new callbacks. In undici 6, the first failed check, such as `invalid onConnect method`, goes to the [dispatch error path](https://github.com/nodejs/undici/blob/v6.28.1/lib/dispatcher/dispatcher-base.js#L168-L196), which calls `handler.onError`; that method no longer exists, so undici throws `invalid onError method` and the original message is lost. npm undici 5.29.0 and 6.28.1 `ProxyAgent`s passed as `dispatcher` to v26.10.0's `fetch` failed in all 18 cells, before any connection, and adding `NODE_USE_ENV_PROXY=1` did not help: ```text [0] TypeError: fetch failed [1] InvalidArgumentError (UND_ERR_INVALID_ARG): invalid onError method ``` [xen-orchestra#10411](https://github.com/vatesfr/xen-orchestra/issues/10411) reports `UND_ERR_INVALID_ARG` for an undici 6.28.1 `EnvHttpProxyAgent` passed to Node 26's `fetch`. The global route fails more quietly. On v26.10.0, `setGlobalDispatcher()` from npm undici 5.29.0 (with a `ProxyAgent`; that release has no `EnvHttpProxyAgent`), 6.28.1, 7.16.0 or 7.26.0 (with a `ProxyAgent` or an `EnvHttpProxyAgent`) had no effect on the built-in `fetch`. Requests went direct and ended in `ENOTFOUND`, or in a 200 with zero CONNECTs, while the same code proxied on v22.23.3 and v24.21.0. These versions, like the other undici 7 tags before 7.27.0 whose `lib/global.js` was checked (7.0.0, 7.10.0 and 7.25.0), store the global dispatcher only under `Symbol.for('undici.globalDispatcher.1')`, which v26.10.0's `fetch` ignored. undici 7.27.0, released on 2026-06-01 with [PR #5319](https://github.com/nodejs/undici/pull/5319), writes both `.1` and `.2`, as do 7.29.1 and 8.11.0; with those three the global dispatcher proxied on all three runtimes. undici 6.28.1's `EnvHttpProxyAgent` still printed its experimental warning on v26.10.0, so the warning does not prove the agent is in use. ## invalid onRequestStart method: an undici 8 dispatcher on Node 22 or 24 An npm undici 8.11.0 `ProxyAgent` passed per request to the built-in `fetch` of v22.23.3 or v24.21.0 failed in all 18 cells with `InvalidArgumentError (UND_ERR_INVALID_ARG): invalid onRequestStart method` at depth 1, again before any connection. The `fetch` in Node 22 and 24 builds a legacy handler, and undici 8 [rejects any handler](https://github.com/nodejs/undici/blob/v8.10.2/lib/core/util.js#L567-L605) without `onRequestStart`. [shadcn-vue#1959](https://github.com/unovue/shadcn-vue/issues/1959) reports the same string from a CLI that bundles undici 8.10.2 on Node 24. On v22.23.3 and v24.21.0, wrapping the agent in `Dispatcher1Wrapper`, undici 8's documented bridge for legacy consumers, reached the proxy: ```js import { Dispatcher1Wrapper, ProxyAgent } from 'undici'; // undici 8 const dispatcher = new Dispatcher1Wrapper(new ProxyAgent(proxyUrl)); const response = await fetch(url, { dispatcher }); ``` So did `setGlobalDispatcher(new ProxyAgent(proxyUrl))` from undici 8.11.0, which also stores a wrapped copy in the legacy slot that built-in `fetch` reads. undici 8.0.0 did not, so on Node 24 and 25 built-in `fetch` ignored it; [PR #4962](https://github.com/nodejs/undici/pull/4962) fixed that in 8.0.1 on 2026-04-03. ## Pick a fix: match undici to process.versions.undici Check the runtime first with `node -p process.versions.undici` ([Node.js docs](https://nodejs.org/api/globals.html#custom-dispatcher)). According to the [Node source tree](https://github.com/nodejs/node/blob/v26.10.0/src/undici_version.h) at every release tag, every 22.x release bundles undici 6, every 24.x release 7 and every 26.x release 8. In the lab, a per-request `dispatcher` from npm undici 5.29.0 or 6.28.1 reached the proxy on v22.23.3 and v24.21.0 but failed on v26.10.0; one from undici 7.16.0, 7.26.0, 7.27.0 or 7.29.1 reached it on all three; and one from 8.11.0 reached it only on v26.10.0. The fixes, and what each one costs: 1. **Use undici's own `fetch` with its own dispatcher.** It worked with the four main npm versions on every runtime in the lab. The costs: one more dependency, and body classes such as `FormData` must come from the same package ([undici docs](https://github.com/nodejs/undici/blob/v8.11.0/docs/docs/best-practices/undici-vs-builtin-fetch.md)). 2. **Drop the custom dispatcher and use the runtime opt-in.** It proxied on every runtime that has it, but it is process-wide, covers HTTP(S) proxies only, and `NO_PROXY` follows the bundled undici. [Corepack 0.35.0](https://github.com/nodejs/corepack/releases/tag/v0.35.0) took this route. 3. **Match the major.** An npm undici with the same major as `process.versions.undici` reached the proxy on all three runtimes. A per-request undici 7 agent was accepted by all three too, but that is a snapshot, not a promise about future Node lines. 4. **`setGlobalDispatcher()` from undici 7.27.0 or later 7.x, or from 8.0.1 and later.** With 7.27.0, 7.29.1 and 8.11.0, it proxied on all three runtimes, for every `fetch` in the process. With undici 5, 6, or 7 before 7.27.0 on Node 26, it is ignored, so upgrade undici to 7.27.0+ or 8.0.1+. Prefer the latest 7.x: on 24 September 2026, `npm audit` flagged 7.27.0 as well. 5. **`Dispatcher1Wrapper` (undici 8).** It proxied per request on all three runtimes. 6. **[`install()`](https://github.com/nodejs/undici/blob/v8.11.0/docs/docs/api/GlobalInstallation.md) (undici 7.11.0 and later).** It replaces `globalThis.fetch` and related globals with the npm copy. Documented only; the lab did not run it. ## Proxy response (NNN) !== 200 when HTTP Tunneling When the proxy answers CONNECT with anything but 200, the proxy's status appears only at depth 2: ```text [0] TypeError: fetch failed [1] Error: Request was cancelled. [2] AbortError (UND_ERR_ABORTED): Proxy response (403) !== 200 when HTTP Tunneling ``` In the lab, every wiring that reached a proxy answering CONNECT with 403, 407, 429, 502 or 503 produced this chain with that status, 49 `https://` cells per status. Under [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110.html#section-9.3.6), any answer other than a 2xx means the tunnel was never formed. undici [discards](https://github.com/nodejs/undici/blob/v8.10.2/lib/dispatcher/proxy-agent.js#L229-L233) the rest of the answer, including `Retry-After` and the body. To see them, run curl through the same proxy, for example `curl -v -x http://PROXY_HOST:PORT https://DESTINATION/ -o /dev/null`. Against the lab's 429 proxy, curl 8.7.1 and 8.22.0 printed its `Retry-After: 30`. The [curl baseline](/guides/curl-proxy-setup) covers that setup. | Status | What the proxy is saying | Where to look | | --- | --- | --- | | 407 | It wants proxy credentials | [Fix proxy error 407](/guides/fix-proxy-error-407) | | 403 | Its policy refuses the request; RFC 9110 asks proxies to limit CONNECT to known ports or allowed targets | The proxy's allow rules for this destination and port | | 429 | A rate limit; the status alone doesn't say whose ([RFC 6585](https://www.rfc-editor.org/rfc/rfc6585#section-4)) | Slow down; read `Retry-After` with `curl -v` | | 502 or 504 | Its upstream sent a bad answer, or none in time | Retry within a budget; check the destination from the proxy's side | | 503 | It is temporarily unable to handle the request | Retry later, honoring any `Retry-After` | undici builds the same message from any non-200 status. [Proxy errors explained](/blog/proxy-status-codes-407-429-502) covers each status in more depth. A plain `http://` URL depends on which undici owns the agent. undici 8.6 and older, including the env proxy of Node 22, 24 and 26.0 to 26.4, send `CONNECT origin.test:80` and fail with the same chain (in the lab, every undici 7.29.1 and older path, 33 cells per status). undici 8.7 and later, including the env proxy of Node 26.5 and later, forward the request itself without CONNECT ([PR #5116](https://github.com/nodejs/undici/pull/5116)). Of those forwarded requests (16 cells per status), a 407 came back one level down as `InvalidArgumentError (UND_ERR_INVALID_ARG): Proxy Authentication Required (407)`, the same code that version skew uses. A 403, 429, 502 or 503 did not throw at all: `fetch` resolved with the proxy's status and body, and the origin never saw the request. ## ECONNREFUSED, ETIMEDOUT or ENOTFOUND: whose address is it? `connect ECONNREFUSED` followed by the proxy's IP and port (49 cells) means nothing is listening there. For a proxy host name such as `localhost`, Node tries each address and reports an `AggregateError` with an empty message instead (49 cells): ```text [0] TypeError: fetch failed [1] AggregateError (ECONNREFUSED): [ECONNREFUSED: connect ECONNREFUSED ::1:; ECONNREFUSED: connect ECONNREFUSED 127.0.0.1:] ``` If the address is the destination's, the request went direct: with `HTTPS_PROXY` set and no opt-in, a refused destination produced `connect ECONNREFUSED 127.0.0.1:` on all three runtimes. `getaddrinfo ENOTFOUND` works the same way: read the host name. With the proxy URL `http://proxy.invalid:3128`, a reserved name that never resolves, every wiring that used the proxy failed with depth 1 `getaddrinfo ENOTFOUND proxy.invalid` (49 cells), the same shape as a bypass's `getaddrinfo ENOTFOUND origin.test`. `connect ETIMEDOUT` followed by the proxy's address (77 cells) means the TCP handshake with the proxy never completed; the lab used a listener whose accept queue was full. macOS usually gave up after about 7.8 seconds, before undici's default connect timeout. A never-accepting destination behind a bypassed proxy produced the same string with the destination's address. ## UND_ERR_CONNECT_TIMEOUT: proxy or destination? undici's `connectTimeout` defaults to 10 seconds ([Client docs](https://github.com/nodejs/undici/blob/v8.11.0/docs/docs/api/Client.md)), and on macOS loopback the OS timeout usually came first. The published run therefore shows `UND_ERR_CONNECT_TIMEOUT` only with `connectTimeout: 3000` on undici 8.11.0 agents, after about 3.5 seconds (13 cells): ```text [0] TypeError: fetch failed [1] ConnectTimeoutError (UND_ERR_CONNECT_TIMEOUT): Connect Timeout Error (attempted address: 127.0.0.1:, timeout: 3000ms) ``` undici 5.29.0, 6.28.1 and 7.29.1 `ProxyAgent`s given the same option still ended at the OS timeout (28 cells), because they build the proxy connection from `proxyTls` options only. On Linux or a real network, undici's 10-second timer may win more often; the lab did not test that. undici 8.10.2 and 8.11.0 also report `Connect Timeout Error` when every address of a host name fails and one timed out, whichever timer fired, with the configured timeout in the message and the `AggregateError` at depth 2 ([connect.js](https://github.com/nodejs/undici/blob/v8.10.2/lib/core/connect.js#L167-L190)); the lab used single addresses and never produced that form. Read the address in the message. The proxy's address means the proxy is unreachable; the destination's means the request never used the proxy, as in [undici#4960](https://github.com/nodejs/undici/issues/4960), where the message listed six destination addresses. undici 6 and later print `attempted address:` or `attempted addresses:`; undici 5 prints a bare `Connect Timeout Error` with no address, so compare the proxy's log instead. For deadlines and retry budgets, see [proxy timeout troubleshooting](/guides/proxy-timeout-troubleshooting). ## ERR_SSL_WRONG_VERSION_NUMBER: an https:// proxy URL for a plain proxy A plain-HTTP forward proxy still carries `https://` destinations inside the CONNECT tunnel, but a proxy URL that starts with `https://` makes the client open TLS to the proxy itself. In the lab, a plain-HTTP proxy answered that handshake with an HTTP 400, and every wiring that reached it failed with depth 1 `Error (ERR_SSL_WRONG_VERSION_NUMBER)` and an OpenSSL message containing `SSL routines:tls_validate_record_header:wrong version number` (85 cells). With an IP address in the `https://` proxy URL, 13 wirings on v26.10.0 failed before connecting with depth 1 `TypeError (ERR_INVALID_ARG_VALUE): The property 'options.servername' Setting the TLS ServerName to an IP address is not permitted.. Received '127.0.0.1'`. Node made an IP-address TLS server name an error in v25.0.0 ([DEP0123](https://nodejs.org/api/deprecations.html#dep0123-setting-the-tls-servername-to-an-ip-address)). The fix for both is `http://` in the proxy URL, unless the proxy really serves TLS on that port. ## UND_ERR_PRX_CONN: the proxy closed before answering CONNECT One fixture accepted TCP, read the CONNECT and closed without replying. The outcome depended on which undici owned the proxy agent: - **undici 8.6 and later** (in the lab, every npm 8.11.0 agent that reached the proxy and the built-in env proxy of v26.10.0): depth 1 `ProxyConnectionError (UND_ERR_PRX_CONN): Proxy Connection failed` over depth 2 `SocketError (UND_ERR_SOCKET): other side closed`, after one CONNECT (16 cells). - **undici 8.5 and older** (in the lab, every npm 5, 6 and 7 agent that reached the proxy and the built-in env proxy of Node 22 and 24): no error. The client reconnected at once until the harness stopped it at 25 CONNECTs (33 cells). From the application, that loop looks like a hang: the `fetch` never settles. With `AbortSignal.timeout(2000)` and no stop, the looping clients rejected after 2 seconds with a bare `TimeoutError`, and the proxy logged 18,600 to 20,548 CONNECTs for that single request in the published run (9 cells, on loopback). For a plain `http://` URL, undici 8.7 and later send no CONNECT, so the same fault surfaced as depth 1 `SocketError (UND_ERR_SOCKET): other side closed` (16 cells), while undici 7 and older looped as above (33 cells). [PR #5441](https://github.com/nodejs/undici/pull/5441) added `ProxyConnectionError` to fail these requests instead of looping ([issue #3897](https://github.com/nodejs/undici/issues/3897)). The class first shipped in undici 8.6.0, although the 8.11.0 Errors reference labels it v8.10.1, and v26.5.0 is the first Node 26 release whose bundled undici includes it. ## ECONNRESET after CONNECT 200: the tunnel dropped When the proxy answered 200 and then closed before sending any tunnel bytes, every wiring that reached it (49 cells) reported `Client network socket disconnected before secure TLS connection was established` (`ECONNRESET`) at depth 1. The CONNECT succeeded, so look past the proxy's front door: its upstream, the exit, the destination, or the proxy dropping the tunnel. PR #5441 covers only tunnel setup, so this case does not become `UND_ERR_PRX_CONN`. Python prints the same close as `SSLEOFError`. curl on OpenSSL prints `Send failure: Broken pipe` if the proxy closes before reading the ClientHello, and `unexpected eof while reading` if it closes after. [SSL EOF occurred in violation of protocol behind a proxy](/guides/fix-ssl-unexpected-eof-proxy) has what that means for the request and what a retry re-sends. ## SELF_SIGNED_CERT_IN_CHAIN behind a TLS-inspecting proxy Behind a TLS-inspecting proxy whose CA Node doesn't trust, the chain ends in a certificate error. The lab's stand-in answered CONNECT with 200, then presented its own certificate for the destination from a throwaway CA. Every wiring that reached it failed at depth 1 on all three runtimes, with `self-signed certificate in certificate chain` (`SELF_SIGNED_CERT_IN_CHAIN`) when the proxy sent its CA certificate along (49 cells) and `unable to verify the first certificate` (`UNABLE_TO_VERIFY_LEAF_SIGNATURE`) when it sent only its own certificate (49 cells). Pointing [`NODE_EXTRA_CA_CERTS`](https://nodejs.org/api/cli.html#node_extra_ca_certsfile) at a file that held that CA fixed all 98 cells; Node reads it only at process start. If the CA is already in the operating system's trust store, Node's [`--use-system-ca`](https://nodejs.org/api/cli.html#--use-system-ca) flag (documented since v22.15.0 and v23.8.0) or `NODE_USE_SYSTEM_CA=1` (since v22.19.0 and v24.6.0) makes Node trust that store too ([enterprise network configuration](https://nodejs.org/learn/http/enterprise-network-configuration)); the lab did not test these. Don't disable verification with `NODE_TLS_REJECT_UNAUTHORIZED=0`. ## No error for five minutes: set your own deadline A proxy that accepted CONNECT and never answered produced no error within the harness's 15-second limit (49 cells). In the published long run, all 49 of those cells failed after 301 to 302 seconds with `HeadersTimeoutError (UND_ERR_HEADERS_TIMEOUT): Headers Timeout Error`, which matches undici's documented 300-second `headersTimeout` default. With `signal: AbortSignal.timeout(2000)`, the same wirings rejected after about 2 seconds with a bare `TimeoutError`. Pass a signal on every proxied request. ## When the failing code is a tool you did not write CLIs, SDKs and MCP servers often ship their own undici and hand its agent to the built-in `fetch` or install it with `setGlobalDispatcher()`. The skew appears when either side moves: an older tool on Node 26, or a tool that adopted undici 8 on Node 22 or 24. 1. Run `node -p process.versions.undici` with the same `node` binary the tool uses. 2. Find the tool's copies with `npm explain undici`. In the lab, `npm ls undici` printed `(empty)` for copies installed under an npm alias (`npm:undici@…`) that `npm explain` listed. A copy compiled into the tool's bundle shows up in neither; check the tool's changelog or issue tracker. 3. Upgrade the tool first. If its docs support Node's opt-in, use `NODE_USE_ENV_PROXY=1`. Otherwise, run it temporarily on a Node line that accepts its copy (see the fixes above), and report the printed chain upstream. These are reported examples that ipvolt did not reproduce: - [vercel/vercel#17629](https://github.com/vercel/vercel/issues/17629), open on 2026-09-23: the Vercel CLI's bundled undici 5.29.0 fails with `invalid onError method` on Node 26.8.2 when a proxy variable is set, and works on Node 24.21.0. - [nodejs/corepack#834](https://github.com/nodejs/corepack/issues/834): a bundled undici 6 `ProxyAgent` failed on Node 26; Corepack 0.35.0 fixed it by requiring `NODE_USE_ENV_PROXY=1`. - [openclaw#155840](https://github.com/openclaw/openclaw/issues/155840): `invalid onRequestStart method` from an undici 8 dispatcher passed to a dependency's undici 7 WebSocket; the skew is not limited to `fetch`. For help choosing the next diagnostic inside an MCP-compatible coding agent, [Proxy Toolkit MCP](/mcp) accepts a sanitized error description. Keep credentials, private URLs and full logs out of tool arguments. Its suggestions do not prove which route your application used; confirm that with the cause chain and the proxy's own observations. ## Method, limitations and downloads ipvolt ran these checks locally on 23 and 24 September 2026 on macOS 15.7.4 (arm64), with the official Node.js v22.23.3, v24.21.0 and v26.10.0 tarballs and npm undici 5.29.0, 6.28.1, 7.29.1 and 8.11.0, plus 7.16.0, 7.26.0 and 7.27.0 for the global-dispatcher checks. Each cell ran one `fetch` in its own child process through a single-behavior loopback proxy that counted connections and requests. Most cells requested the reserved name `origin.test` ([RFC 6761](https://www.rfc-editor.org/rfc/rfc6761.html#section-6.2)), which only the lab proxy resolved. The main matrix had 591 cells, the extra suite 282 (`http://` URLs, a `localhost` proxy URL, unreachable destinations) and the checks suite 1,029; a separate 63-cell run let the never-answering proxy run for 330 seconds. The [README](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/README.md) has the full method, per-suite results and run history. A clean rerun from only the final archive, following the README, classified all 591 main, 282 extra, 1,029 checks and 63 long-run cells the same way as the published results. Expect a rerun to differ on a few never-completing-handshake cells, where the OS and undici connect timeouts race, and on the loop-deadline checks when they run back to back: a looping cell leaves thousands of sockets in TIME_WAIT, so the next one can record zero CONNECTs until the ports drain about 40 seconds later. The lab did not cover Linux or real networks, real HTTPS or SOCKS proxies, proxies that accept credentials, 504, `NO_PROXY` matching, `http.request`, Deno, Bun or real third-party tools. The results show how these Node.js and undici versions report each injected behavior, not how any proxy provider behaves. The lockfile pins old undici versions on purpose, and `npm ci` reports them as a high-severity vulnerability; don't copy these pins into an application. All files are under `https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/`: - [fix-node-fetch-failed-proxy-lab.zip](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/fix-node-fetch-failed-proxy-lab.zip) holds all of the files below. - [README.md](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/README.md) explains how to run the lab and read a cell; [print-cause.mjs](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/print-cause.mjs) is the printer. - [run-matrix.mjs](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/run-matrix.mjs), [run-checks.mjs](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/run-checks.mjs), [cell.mjs](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/cell.mjs), [cause-forms.mjs](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/cause-forms.mjs) and [compare.mjs](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/compare.mjs) are the harness. - [get-runtimes.mjs](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/get-runtimes.mjs), [runtimes.json](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/runtimes.json), [package.json](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/package.json) and [package-lock.json](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/package-lock.json) pin the runtimes and packages. - [results.json](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/results.json), [results.csv](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/results.csv), [results-extra.json](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/results-extra.json), [results-extra.csv](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/results-extra.csv), [results-long-hang.json](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/results-long-hang.json), [results-long-hang.csv](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/results-long-hang.csv), [results-checks.json](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/results-checks.json) and [results-checks.csv](https://ipvolt.com/downloads/fix-node-fetch-failed-proxy/results-checks.csv) hold every cell's cause chain and proxy counts. To reproduce the results, unzip the archive and follow the README: `npm ci`, `node get-runtimes.mjs`, then each suite and `node compare.mjs` against a copy of the published file. No proxy account is needed. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources & further reading - [Node.js HTTP: Built-in Proxy Support and http.setGlobalProxyFromEnv()](https://nodejs.org/api/http.html#built-in-proxy-support) - [Node.js CLI: NODE_USE_ENV_PROXY=1 and --use-env-proxy](https://nodejs.org/api/cli.html#node_use_env_proxy1) - [Node.js globals: fetch with a custom dispatcher and process.versions.undici](https://nodejs.org/api/globals.html#custom-dispatcher) - [Node.js Learn: Enterprise network configuration](https://nodejs.org/learn/http/enterprise-network-configuration) - [Node.js deprecations: DEP0123, setting the TLS ServerName to an IP address](https://nodejs.org/api/deprecations.html#dep0123-setting-the-tls-servername-to-an-ip-address) - [undici 8.11.0: Errors reference](https://github.com/nodejs/undici/blob/v8.11.0/docs/docs/api/Errors.md) - [undici 8.11.0: ProxyAgent (CONNECT for https://, forwarding for http://)](https://github.com/nodejs/undici/blob/v8.11.0/docs/docs/api/ProxyAgent.md) - [undici: Migrating from undici 7 to 8](https://github.com/nodejs/undici/blob/v8.11.0/docs/docs/best-practices/migrating-from-v7-to-v8.md) - [undici: Undici module vs. Node.js built-in fetch](https://github.com/nodejs/undici/blob/v8.11.0/docs/docs/best-practices/undici-vs-builtin-fetch.md) - [undici PR #4962: mirror the legacy global dispatcher for built-in fetch (v8.0.1)](https://github.com/nodejs/undici/pull/4962) - [undici PR #5319: setGlobalDispatcher() writes both global-dispatcher slots, for Node 26 (v7.27.0)](https://github.com/nodejs/undici/pull/5319) - [undici PR #5116: auto-detect HTTP proxy tunneling (v8.7.0)](https://github.com/nodejs/undici/pull/5116) - [undici PR #5441: fail instead of looping when the proxy closes during CONNECT setup (UND_ERR_PRX_CONN, v8.6.0)](https://github.com/nodejs/undici/pull/5441) - [RFC 9110: CONNECT and status codes 403, 407, 502, 503 and 504](https://www.rfc-editor.org/rfc/rfc9110.html#section-9.3.6) - [RFC 6585: section 4, 429 Too Many Requests](https://www.rfc-editor.org/rfc/rfc6585#section-4) ## Related guides - [fetch failed: invalid onError method on Node 26 (undici fix)](https://ipvolt.com/guides/node-26-invalid-onerror-method.md) - [Axios proxy setup: routing, auth and NO_PROXY](https://ipvolt.com/guides/axios-proxy-setup.md) - [Use a proxy with Node.js fetch](https://ipvolt.com/guides/nodejs-fetch-proxy.md) - [Node.js fetch Ignores HTTPS_PROXY: Fix UND_ERR_CONNECT_TIMEOUT in One Line](https://ipvolt.com/guides/node-fetch-ignores-https-proxy.md) - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md) - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md) - [Fix proxy error 407 without guessing](https://ipvolt.com/guides/fix-proxy-error-407.md) - [SSL EOF occurred in violation of protocol behind a proxy: was the request sent?](https://ipvolt.com/guides/fix-ssl-unexpected-eof-proxy.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 89 of 138: How to test an Australian proxy: networks and nbn checks URL: https://ipvolt.com/guides/australia-proxies Markdown: https://ipvolt.com/guides/australia-proxies.md # How to test an Australian proxy: networks and nbn checks Source: https://ipvolt.com/guides/australia-proxies Markdown: https://ipvolt.com/guides/australia-proxies.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Countries](https://ipvolt.com/guides/countries.md) / [How to test an Australian proxy: networks and nbn checks](https://ipvolt.com/guides/australia-proxies.md) Category: Country Reviewed: 2026-09-27 Published: 2026-09-27 Reading time: 6 minutes Author: ipvolt Choose the evidence an Australian proxy test needs: country or city, Telstra/Optus/TPG network labels, nbn provider layers and session requirements. For an overview of Australian proxy use cases and mobile carriers, see [Australia proxies](/proxies/australia); this guide covers how to test one. For an Australian proxy test, start with the condition your application reads. If it needs an IP classified as Australian, request country `AU`. Add a city, named network or session condition only when it changes the expected result. Then keep the supplier’s description separate from what your destination observes. Australian network labels need particular care: Vodafone is operated by TPG Telecom, TPG has access to some Optus sites, and nbn access is delivered through retail-provider arrangements. The distinctions below help turn an offer into requirements you can actually check. ## Decide what an Australian exit must establish Write the expected application result and the fields that determine it before choosing a sample. A country-level check and a Sydney-specific check need different evidence. | Required condition | Evidence to retain | What leaves it unverified | | --- | --- | --- | | Country `AU` | IP seen at your destination, timestamp, and the country result from the classifier your application uses | Only a supplier’s “Australia” label, or a missing result | | A particular city | Required city, chosen classifier’s city result and any accuracy radius relevant to your rule | Country `AU` without the required city information | | A named IP network or mobile classification | Expected field/value, observed IP, lookup result and source/version | A retail brand copied into the result, or a lookup product without the needed field | | Independent mobile radio paths | The intended independence condition and applicable technical evidence about the supplied access paths | Two brand names without evidence that the required paths differ | | Address continuity | Defined journey, reconnect rule and timestamped IPs at declared checkpoints | “Sticky” without a duration or reconnect explanation | | Exclusive public IPv4 use | Supplier terms defining the address covered, sharing policy and duration | The same address at every checkpoint | MaxMind documents that mobile IPs can span broad areas and that it omits city-level data when it cannot support that precision. Its city data is not a street address. If your required city is missing, leave that condition unverified; use country fallback only if your application’s rule allows it. These are MaxMind’s documented limits, not a measured accuracy result for Australia. [MaxMind geolocation accuracy](https://support.maxmind.com/knowledge-base/articles/maxmind-geolocation-accuracy) Record the exact field as well as the lookup product. MaxMind’s API distinguishes country, registered country, ISP, autonomous-system number and connection type; some fields are unavailable in particular products. A registered-country value or an ISP name should not silently replace the field your application uses. [MaxMind response fields](https://dev.maxmind.com/geoip/docs/web-services/responses/) ## Read Telstra, Optus and Vodafone/TPG labels The ACCC names **Telstra, Optus and TPG Telecom** as Australia’s three national mobile network operators. TPG says it owns and operates the **Vodafone** mobile network. Treat Vodafone and TPG as related labels in that operator family, not two independent operators for your sample plan. [ACCC Mobile Infrastructure Report 2026](https://www.accc.gov.au/by-industry/telecommunications-and-internet/mobile-services-regulation/mobile-infrastructure-report/mobile-infrastructure-report-2026), [TPG’s network description](https://www.tpgtelecom.com.au/about-us/our-network) Retail branding is another layer: ACMA explains that most phone companies lease service from the major networks. Ask which retail brand and underlying network a supplier means. An observed IP-network result remains a separate field. [ACMA mobile-service guidance](https://www.acma.gov.au/choose-your-mobile-service-carefully) The ACCC report also says TPG’s network access combines its own sites with sites available through the **Optus–TPG Multi-Operator Core Network arrangement**. The report was published on 22 September 2026, using infrastructure data referenced to 31 January 2026. Two offers labelled Optus and Vodafone therefore do not, by those labels alone, establish independent regional radio infrastructure. This matters when independent access paths are a test requirement; it does not establish that their public IPs or application results are identical. [ACCC’s sharing and date scope](https://www.accc.gov.au/by-industry/telecommunications-and-internet/mobile-services-regulation/mobile-infrastructure-report/mobile-infrastructure-report-2026) For a rule based only on an IP-network classification, test that classification. If the requirement is actual mobile access or separate radio paths, request evidence for that additional condition rather than treating an IP lookup as its proof. ## Separate nbn access, the retailer and the public IP nbn describes itself as a wholesaler relying on retail service providers to serve end customers. Its Ethernet product carries traffic at Layer 2 to a point of interconnect, and providers can use direct, wholesale or white-label pathways. An “nbn proxy” label therefore leaves several questions open. [nbn provider roles and pathways](https://www.nbnco.com.au/rsps/become-an-nbn-provider) Keep three fields: **declared access network**, **declared retail provider**, and **observed public IP/network**. Request evidence for whichever layer your test requires. Do not manufacture an ISP or IP-network result from the access label. Residential access also does not establish an unshared public IPv4. Aussie Broadband says CGNAT is typically enabled on its broadband services and public IPs are often shared; its static-IP services are automatically opted out. That is one retailer’s published policy, not the sharing terms of a proxy pool. If exclusive use matters, obtain the applicable commitment from the proxy supplier. [Aussie Broadband’s CGNAT policy](https://www.aussiebroadband.com.au/help-centre/internet/port-forwarding-and-cgnat/) ## Record a bounded sample Use this procedure with an endpoint you are authorized to use and an owned test destination. It is a proposed evaluation method; this guide has not executed a supplier trial. 1. **Set the conditions.** Record the application rule, expected output, required country/city/network fields, journey checkpoints and allowed fallbacks. Keep supplier declarations in their own fields. 2. **Keep application inputs fixed.** Retain the same URL, fixture, account/cookies, locale, timezone and location-permission state while comparing exits. If your destination sits behind a gateway, identify the trusted server record that exposes the connecting client IP. 3. **Save every checkpoint.** Retain timestamp, observed public IP, classification source/version, required field values, application output and errors. Recheck required classifications when the IP changes. Do not drop failed requests from the record. 4. **Decide each condition separately.** Use *pass*, *mismatch* or *unverified*. Missing required evidence is unverified; a contradictory observed value is a mismatch. State the observed window and checkpoint count. A finite sample does not establish future continuity or unsampled intervals. The [curl setup guide](/guides/curl-proxy-setup) covers request configuration; [rotating versus sticky sessions](/guides/rotating-vs-sticky-proxies) helps specify session behaviour. For a browser-clock failure, use the separate [Australian Playwright timezone diagnostic](/guides/playwright-australia-timezones). A clock-setting test answers a different question from IP geography. ## Worked decision: “Australian nbn, sticky” **Hypothetical example:** your application requires `AU` from its chosen classifier and the same public IPv4 at minutes 0, 5, 10 and 15 of a journey. It requires no city, named provider, mobile access or exclusivity. The supplier’s reply, “Australian nbn, sticky,” leaves both required conditions unverified. Suppose your later record contains the same observed IP and an `AU` result at all four checkpoints, with the expected application output. Those country and checkpoint conditions pass for that record. Missing city data does not invalidate this brief. The record still establishes neither continuous stability between checkpoints nor exclusive use. Now change the brief to require two independent regional mobile radio paths. An nbn label does not answer it. Nor does a replacement offer of “Optus and Vodafone” resolve independence by itself, given the documented shared-access relationship. Leave that requirement unverified until the supplier provides applicable path evidence. The numbers and outcomes here are invented to demonstrate the decision, not an Australian endpoint measurement. ## Method and next step This guide synthesizes regulator, operator and technical documentation checked on 27 September 2026. It measured no Australian endpoint, carrier inventory, latency or success rate. The acceptance matrix and hypothetical case help specify a sample; they do not certify a supplier. ipvolt sells mobile proxies in Australia: the [Australia proxy page](/proxies/australia) has the carriers and prices. ## Sources & further reading - [Major mobile networks and retail service roles](https://www.acma.gov.au/choose-your-mobile-service-carefully) - [Mobile Infrastructure Report 2026: operator, sharing and date scope](https://www.accc.gov.au/by-industry/telecommunications-and-internet/mobile-services-regulation/mobile-infrastructure-report/mobile-infrastructure-report-2026) - [TPG description of Vodafone network operation](https://www.tpgtelecom.com.au/about-us/our-network) - [nbn wholesale role, Ethernet and provider pathways](https://www.nbnco.com.au/rsps/become-an-nbn-provider) - [CGNAT and static-IP policy](https://www.aussiebroadband.com.au/help-centre/internet/port-forwarding-and-cgnat/) - [Geolocation accuracy and precision limits](https://support.maxmind.com/knowledge-base/articles/maxmind-geolocation-accuracy) - [GeoIP/GeoLite API response field semantics](https://dev.maxmind.com/geoip/docs/web-services/responses/) ## Related guides - [Mobile vs residential proxies: build a useful evaluation](https://ipvolt.com/guides/mobile-vs-residential-proxies.md) - [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md) - [Test Australian time zones in Playwright](https://ipvolt.com/guides/playwright-australia-timezones.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile proxies in Australia from $19 a day. Residential proxies from $2.20/GB, in prepaid packs. [See which countries and carriers are on sale.](https://ipvolt.com/pricing) [Australia mobile proxies: carriers and prices](https://ipvolt.com/proxies/australia) [Mobile proxies in Australia on Vodafone from $19 a day](https://ipvolt.com/dashboard/mobile?country=AU&plan=day&carrier=Vodafone%20Australia) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 90 of 138: Canada proxies: location, networks and session checks URL: https://ipvolt.com/guides/canada-proxies Markdown: https://ipvolt.com/guides/canada-proxies.md # Canada proxies: location, networks and session checks Source: https://ipvolt.com/guides/canada-proxies Markdown: https://ipvolt.com/guides/canada-proxies.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Countries](https://ipvolt.com/guides/countries.md) / [Canada proxies: location, networks and session checks](https://ipvolt.com/guides/canada-proxies.md) Category: Country Reviewed: 2026-09-27 Published: 2026-09-27 Reading time: 8 minutes Author: ipvolt Evaluate Canada proxies with a country, carrier and session acceptance matrix. Separate Rogers, Bell, TELUS and Quebecor brands from the evidence you need. For Canadian web tests, first decide whether the application needs a **Canadian country result, a specific province or city, or a particular network**. Write a separate acceptance condition for each requirement. A Toronto label does not establish French-language behaviour, a cellular connection or delivery eligibility. This guide helps you evaluate a Canadian proxy sample before relying on it. Its network distinctions come from CRTC sources; its acceptance matrix and worked example are an evaluation method. No Canadian proxy provider or storefront was tested. ## Choose the location the application actually uses Use country-level targeting when the application only distinguishes Canada from other countries. Request Ontario, Quebec, Toronto or Montreal only when the named rule uses that level of **IP-derived** location. Write down the observable result that would confirm the rule: a region decision in your application log, for example, or an exposed country selector with a documented configuration mapping. A supplier's location label, an IP database result and the target's decision are three different pieces of evidence. Preserve all three when they disagree. MaxMind documents variable accuracy, missing finer location fields and mobile IPs used across broad areas; it does not describe its IP data as precise enough to identify a street address. These are MaxMind's documented limits, not a measured Canadian proxy accuracy rate. [MaxMind geolocation accuracy](https://support.maxmind.com/knowledge-base/articles/maxmind-geolocation-accuracy). For a city requirement, record the checker and date, city/subdivision fields and any supplied accuracy radius. A missing city remains missing. If the application does not expose its location decision, report that gap instead of treating a separate checker as proof that the application recognized Toronto. ## Read Canadian carrier names at the right layer Canadian retail brands are not a count of independent networks. The CRTC's brand definitions place these examples in the following groups; a 2026 decision identifies Freedom Mobile and Videotron as Quebecor subsidiaries. | Group | Related retail names | What to clarify in a proxy request | | --- | --- | --- | | Rogers | Rogers, Fido, Chatr | A Rogers/Fido pair does not establish two different provider groups. | | Bell | Bell, Virgin, Lucky Mobile | Specify whether you need the retail brand, a mobile connection or an observed egress network. | | TELUS | TELUS, Koodo, Public Mobile | A different retail name alone is insufficient evidence of different access infrastructure. | | Quebecor | Videotron, Freedom Mobile; Fizz is a Videotron flanker brand | Ask which service and actual access path the sample uses. | Sources: [CRTC brand definitions](https://crtc.gc.ca/eng/publications/reports/PolicyMonitoring/comm.htm), [CRTC 2026-84, background](https://crtc.gc.ca/eng/archive/2026/2026-84.htm). This is a set of useful group examples, not an exhaustive list or ipvolt inventory. **Bell and TELUS also share radio-access infrastructure.** CRTC decision 2025-245 describes their shared radio-access network and distinguishes it from each company's commercial identity. Its discussion of roaming and MVNO access further shows why a retail service can use another carrier's radio network. A Bell/TELUS pair therefore does not, from names alone, establish independent radio infrastructure. It also does not establish that the samples have identical public IPs or Internet routes. [CRTC shared-network decision](https://crtc.gc.ca/eng/archive/2025/2025-245.htm). Decide which distinction matters before requesting “carrier diversity”: - **Different provider groups:** record the retail brand and its parent group. - **A specific cellular access path:** request relevant operator/access documentation and, where available, redacted device or modem evidence tied to the sampled egress. A company-name lookup alone does not establish the radio connection. - **Different Internet egress networks:** record the observed public IP, ASN and lookup source/date for each sample. An autonomous system describes IP routing; it does not measure a SIM, tower or radio technology. [RFC 1930, section 3](https://www.rfc-editor.org/rfc/rfc1930.html#section-3). Keep a missing layer **unverified**. Do not fill it from a familiar brand name. This approach also applies to “residential” and “ISP” offers: have the supplier define the access and hosting arrangement, then request evidence for the part your test requires. ## Set the acceptance conditions before the sample Select the rows relevant to your job. These are proposed checks, not universal performance guarantees. | Required condition | Record before and during the sample | Decision boundary | | --- | --- | --- | | Canadian country behaviour | Named rule; fixed browser inputs; dated exit-country evidence; target's region result | Accept this condition only when the agreed target behaviour matches. A checker-only result leaves target recognition unverified. | | Province or city targeting | Why the target reads that precision; exact region; checker/date; target decision | Preserve missing or conflicting results. Do not silently downgrade a required city to country. | | Mobile or named-network access | Required brand/group, radio access or egress network; supplier's definition; evidence references | A retail name or ASN alone does not satisfy a required mobile-access proof. | | Stable session | Duration, request schedule, permitted rotation and reconnect behaviour; observed IP at each check | An unexpected address change fails an unchanged-address condition. Equal sampled addresses do not prove exclusivity or uninterrupted stability between checks. | | English/French experience | Browser language, explicit URL, stored choices and relevant application settings | Compare language separately while holding the exit fixed. An IP label alone is insufficient. | | Delivery to a Canadian address | Approved full-address reference, configured delivery rule, cart/stock/checkout controls | Judge the configured address outcome separately from IP geography. | For routing setup, use the [curl proxy guide](/guides/curl-proxy-setup) with your authorized endpoint. Then perform the target check with the same client configuration. Record the IP family, protocol, client version, concurrency and request budget; the observed result applies to those conditions and that sample. Keep planned checks and actual results separate. Record every attempt, including timeouts, address changes, missing location data and unexpected application responses. If retrying, retain the first attempt and describe the retry rule. Report both matches and the full attempt count, plus any unverified required conditions. ## A Canadian sample decision, worked through **Hypothetical example — all outcomes below are invented.** A team needs a Canadian mobile connection for a browser workflow, with the same exit at six checks over 15 minutes. The application's location rule only reads country. The proposed checks are at minutes 0, 3, 6, 9, 12 and 15; this is an example schedule, not a recommended universal sample size. The supplier labels sample A “Fido, Toronto” and sample B “Rogers, Montreal.” Neither sample includes evidence of its cellular access path. | Invented observation | Sample A | Sample B | | --- | --- | --- | | Target identifies Canada | 6 of 6 attempts | 6 of 6 attempts | | Observed exit at the six checks | Same address at all six | Address changes between the third and fourth checks | | Required cellular-access evidence | Missing | Missing | | Decision | Country and sampled address conditions match; mobile requirement remains unverified | Country matches; unchanged-address condition fails; mobile requirement remains unverified | Neither is an accepted overall mobile sample. Sample A needs the missing access evidence; sample B also needs its rotation or reconnect behaviour resolved and a new recorded run. The Toronto/Montreal difference is not a failure of this **country-only** rule. Six Canadian results cannot cancel a failed session condition. If the team also wants two provider groups, these labels do not supply that comparison: Fido belongs to the Rogers group. It must revise the supplier request and establish the required network distinction. Merely replacing one label with Bell or TELUS would still require clarity about whether the comparison concerns provider groups, shared radio infrastructure or observed Internet egress. ## Keep French and postal delivery controls separate For a Canadian storefront, record language and delivery requirements without converting them automatically into Montreal or Toronto proxy requirements. Shopify, for example, documents browser language, market entry and saved choices alongside IP localization; the shipping address determines the final checkout experience. That is platform-specific behaviour to verify against the store's configuration. [Shopify localization](https://help.shopify.com/en/manual/markets/getting-started/localization). Canada Post divides a postal code into a three-character **Forward Sortation Area** and a finer **Local Delivery Unit**. Shopify's local-delivery documentation gives `M5V*` as an example postal zone. For a store actually using that rule, compare approved complete addresses inside and outside the zone with the same exit and cart conditions. Eligibility also depends on address verification, stock, fulfillment location and checkout path. A Toronto IP cannot supply that evidence. [Canada Post postal-code structure](https://www.canadapost-postescanada.ca/cpc/en/support/articles/addressing-guidelines/postal-codes.page), [Shopify local-delivery conditions](https://help.shopify.com/en/manual/fulfillment/setup/delivery-methods/local-delivery). For the full configuration snapshot, paired visits and record checker, use the separate [Shopify Canada localization guide](/guides/shopify-canada-localization). ## Take a precise brief to the provider Use the existing [Canada request brief in JSON](/downloads/canada-exit-request.json) or [CSV](/downloads/canada-exit-request.csv). Both are blank templates; their `not_run` result is intentional. Fill the named rule, minimum IP precision, client/protocol, session duration, volume and acceptance window before the sample. In `network_type_or_origin_requirement_if_material`, state whether you need a retail group, a cellular access path or a particular egress network, and the evidence you will accept. Keep those evidence references with the observation record. Confirm available targeting, permitted use, rotation and replacement terms with the provider; the template supplies no commercial terms. Use **accept** only when all required conditions have enough evidence and match the agreed criterion. Record a **mismatch** when an observed result violates it. Leave a required but unmeasured condition **unverified** and state the next check. These are human decisions; the request JSON/CSV does not automatically validate a provider. The source review and matrix were prepared on 27 September 2026. They do not establish proxy supply, speed, reputation or service quality. The guide and downloads are available without signup. ipvolt doesn't sell mobile proxies in Canada today. ## Sources & further reading - [Communications Market Reports — current trends methodology](https://crtc.gc.ca/eng/publications/reports/PolicyMonitoring/comm.htm) - [Telecom Decision CRTC 2025-245 — wholesale roaming footprint](https://crtc.gc.ca/eng/archive/2025/2025-245.htm) - [Telecom Decision CRTC 2026-84 — Quebecor application](https://crtc.gc.ca/eng/archive/2026/2026-84.htm) - [Geolocation accuracy](https://support.maxmind.com/knowledge-base/articles/maxmind-geolocation-accuracy) - [RFC 1930 — Guidelines for creation, selection, and registration of an Autonomous System](https://www.rfc-editor.org/rfc/rfc1930.html) - [Addressing guidelines — Postal codes](https://www.canadapost-postescanada.ca/cpc/en/support/articles/addressing-guidelines/postal-codes.page) - [Shopify market localization](https://help.shopify.com/en/manual/markets/getting-started/localization) - [Setting up local delivery for online orders](https://help.shopify.com/en/manual/fulfillment/setup/delivery-methods/local-delivery) ## Related guides - [Test Shopify Canada localization](https://ipvolt.com/guides/shopify-canada-localization.md) - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) - [How to test an Australian proxy: networks and nbn checks](https://ipvolt.com/guides/australia-proxies.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Residential proxies are on sale from $2.20/GB. The dashboard lists the countries available now. ipvolt doesn't sell mobile proxies in Canada today. [See which countries and carriers are on sale.](https://ipvolt.com/pricing) [Explore Canada proxy workflows](https://ipvolt.com/proxies/canada) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 91 of 138: Test Australian time zones in Playwright URL: https://ipvolt.com/guides/playwright-australia-timezones Markdown: https://ipvolt.com/guides/playwright-australia-timezones.md # Test Australian time zones in Playwright Source: https://ipvolt.com/guides/playwright-australia-timezones Markdown: https://ipvolt.com/guides/playwright-australia-timezones.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Test Australian time zones in Playwright](https://ipvolt.com/guides/playwright-australia-timezones.md) Category: Integration Reviewed: 2026-09-27 Published: 2026-09-27 Reading time: 6 minutes Author: ipvolt Run 12 Australian browser-clock checks in Playwright, including Lord Howe’s 30-minute change. Separate fixed UTC inputs, browser time zones and the Node runner. Set Playwright’s browser `timezoneId`, fix an explicit UTC instant, then assert the date your page displays. Keep the Node runner’s time zone separate: changing the browser setting does not change the runner. Playwright documents that distinction in its [locale and time-zone controls](https://playwright.dev/docs/emulation#locale--timezone). The downloadable check below gives you 12 repeatable Australian cases: Sydney and Brisbane in two seasons, Broken Hill’s half-hour offset, and Lord Howe’s 30-minute daylight-saving change. It serves its own small page on `127.0.0.1`, reads the clock rendered in Chromium and saves the assertions as JSON. No proxy or credentials are needed. To test the real page through an Australian IP, see [how to test an Australian proxy](/guides/australia-proxies). ## Run the clock check Use Node.js 24. In a macOS or Linux shell: ```sh mkdir australia-clock-demo cd australia-clock-demo curl --fail --silent --show-error --output australia-clock-check.mjs https://ipvolt.com/downloads/australia-clock-check.mjs npm install --no-audit --no-fund --save-exact playwright@1.63.0 npx playwright install chromium TZ=UTC node australia-clock-check.mjs > results-utc.json ``` The [script](/downloads/australia-clock-check.mjs) and [README](/downloads/australia-clock-README.md) are available directly. Compare your output with the [reference JSON](/downloads/australia-clock-results.json), which includes every assertion and the environment, or the [reference CSV](/downloads/australia-clock-results.csv), which contains selected row fields. A successful run exits `0` and reports `summary.allPassed: true`, with `total: 12` and `passed: 12`. That includes the expected clock relationships and the request/error checks. Exit `1` with result JSON means an assertion failed. A launch or dependency error on standard error is a setup failure; if Chromium cannot start on Linux, check Playwright’s [browser system dependencies](https://playwright.dev/docs/browsers#install-system-dependencies). For each row, the script creates a fresh browser context, sets its `timezoneId`, and calls `page.clock.setFixedTime(new Date(test.utc))` before loading the page. The UTC input ends in `Z`, so it identifies the same instant in either runner environment. `setFixedTime` fixes the values returned by `Date.now()` and `new Date()` while timers continue normally; this fixture checks rendered dates. [Playwright’s fixed-time API](https://playwright.dev/docs/api/class-clock#clock-set-fixed-time) ## Keep the Australian exceptions in your test cases These eight rows use midnight UTC on **15 January 2026** and **15 July 2026**. Offsets below are east of UTC. The JSON expresses them as minutes, with the opposite sign to JavaScript’s `getTimezoneOffset()`. | Browser `timezoneId` | January local time / UTC offset | July local time / UTC offset | | --- | --- | --- | | `Australia/Sydney` | 11:00 / +11:00 | 10:00 / +10:00 | | `Australia/Brisbane` | 10:00 / +10:00 | 10:00 / +10:00 | | `Australia/Broken_Hill` | 10:30 / +10:30 | 09:30 / +09:30 | | `Australia/Lord_Howe` | 11:00 / +11:00 | 10:30 / +10:30 | Sydney and Brisbane agree in July but differ by an hour in January. Broken Hill and Lord Howe also prevent “NSW” from becoming a single clock expectation. NSW’s [time definitions and exceptions](https://dcj.nsw.gov.au/about-us/daylight-saving/definitions-of-time-and-how-time-is-regulated.html) describe these offsets and Queensland’s lack of daylight saving. The [reference results](/downloads/australia-clock-results.json) record what this Chromium run rendered at the declared instants. The remaining four rows bracket the modelled **4 October 2026** changes. Each pair advances UTC by one second: | Browser zone | UTC snapshots on 3 October 2026 | Local snapshots on 4 October 2026 | Offset change | | --- | --- | --- | --- | | `Australia/Lord_Howe` | 15:29:59 → 15:30:00 | 01:59:59 → 02:30:00 | +10:30 → +11:00 | | `Australia/Sydney` | 15:59:59 → 16:00:00 | 01:59:59 → 03:00:00 | +10:00 → +11:00 | These are **synthetic fixed-time snapshots**, executed on 26 September 2026 UTC. The October inputs simulate future instants under the rules checked that day; they do not record a live transition or test a timer running across it. The [NSW seasonal dates](https://www.nsw.gov.au/about-nsw/daylight-saving) and [IANA Australasian rules](https://data.iana.org/time-zones/tzdb/australasia) support the date and offset expectations. Lord Howe’s change is 30 minutes, and it occurs 30 minutes earlier in UTC than Sydney’s change in this pair. ## Change the runner without changing the browser result Run the same file with Perth as the Node runner’s time zone: ```sh TZ=Australia/Perth node australia-clock-check.mjs > results-perth.json ``` Compare the 12 `rows[].browser` objects with `results-utc.json`. They should match. The `runner` objects should differ: the UTC run reports offset `0`, while Perth reports `480` minutes east of UTC. Node’s [`TZ` environment variable](https://nodejs.org/docs/latest-v24.x/api/cli.html#tz) controls the runner. Both recorded runs passed all 12 rows, with identical browser readings. Whole JSON files will differ because they also retain execution timestamps and runner metadata. This comparison helps catch a test expectation accidentally calculated in the runner’s local zone. ## Check that the assertions reject a mistake The script includes three deliberately wrong modes. Run each command separately if your shell or CI job stops after a nonzero exit: ```sh TZ=UTC node australia-clock-check.mjs one-nsw-clock > wrong-nsw.json TZ=UTC node australia-clock-check.mjs one-hour-dst > wrong-dst.json TZ=UTC node australia-clock-check.mjs omit-browser-timezone > wrong-browser-zone.json ``` | Mode | Deliberate mistake | Recorded failing rows | | --- | --- | --- | | `one-nsw-clock` | Expect Sydney’s offset at the same instant for Broken Hill and Lord Howe. | 5 of 12 | | `one-hour-dst` | Expect Lord Howe’s +10:30 standard offset to increase by a full hour. | 2 of 12 | | `omit-browser-timezone` | Remove the browser setting while retaining the Australian expectations under the UTC runner. | 12 of 12 | Each mode should exit `1`. The first two deliberately change expected values; the third removes a browser control. They demonstrate detection of those specific mistakes. In `wrong-nsw.json`, the five failed IDs are Broken Hill in January and July, Lord Howe in July, and both Lord Howe boundary snapshots. In `wrong-dst.json`, Lord Howe in January and the after-change snapshot reject the invented +11:30 offset. For an unexpected failure in the normal run, inspect `summary.failed` and that row’s `assertions`: | Failed check | What to inspect next | | --- | --- | | `fixedInstant` | Confirm the explicit UTC input and that fixed time is set before the page reads its clock. | | `requestedTimezone` | Confirm the page belongs to the context with the requested `timezoneId`. | | `expectedOffset` or `expectedWallTime` | Check the row’s date, zone, offset sign and current rules before changing the expectation. | | `renderedEqualsSampled` | Inspect page errors and any difference between the rendered clock and the later browser reading. | If every row passes but `summary.allPassed` is false, also inspect `relationshipsMinutes`, `requests`, `blockedRequests` and `pageErrors`. The fixture requires the declared offset relationships, exactly 12 requests to its loopback page, and no blocked page requests or page errors. ## Apply the controls to your own page Choose a date display or schedule whose expected behaviour you can state. Keep the explicit UTC input and browser `timezoneId`, then replace the fixture’s visible-clock assertion with an assertion against that element in your own test. The download itself accepts no external target URL. Hold other inputs constant for the first comparison: locale, saved preferences, application configuration and test data. If the application intentionally formats a schedule in a fixed business zone, assert that behaviour. A server-generated timestamp or account-level time-zone preference needs its own setup; browser emulation alone does not establish either value. Start with the relevant January/July pair, then add a boundary case your application supports. Preserve the failed input and JSON environment record when investigating a discrepancy. Changing the expected output merely to match a browser run would remove the independent check. If the application also makes a decision from the request’s IP location, use a separate exit-location test. The [Australia proxies page](/proxies/australia) explains how to choose the location evidence that rule needs. ## Method and limits The recorded runs used Node.js **24.20.0**, Playwright **1.63.0** and Chromium **153.0.8010.12** on macOS arm64. After dependency installation, each run made 12 requests to its own loopback page, with zero off-origin page attempts and zero page errors. Expected offsets came from the primary sources above; the script compared the page’s rendered clock with a second browser reading. This covers one browser engine and OS in 12 declared cases. It does not establish timer progression, repeated times when clocks move backward, every Australian territory, your application’s behaviour or Australian IP geography. The checked IANA source was [version **2026d**](https://data.iana.org/time-zones/tzdb/version). The results’ `nodeTz: 2026a` describes Node’s time-zone data; Chromium’s internal database version was not measured. Retain version information and recheck rules when upgrading or choosing new dates. ipvolt sells mobile proxies in Australia: the [Australia proxy page](/proxies/australia) has the carriers and prices. ## Sources & further reading - [Browser locale and timezone; separate runner](https://playwright.dev/docs/emulation#locale--timezone) - [Clock setFixedTime API](https://playwright.dev/docs/api/class-clock#clock-set-fixed-time) - [Browser installation and system dependencies](https://playwright.dev/docs/browsers#install-system-dependencies) - [Time definitions and NSW exceptions](https://dcj.nsw.gov.au/about-us/daylight-saving/definitions-of-time-and-how-time-is-regulated.html) - [Current daylight-saving dates](https://www.nsw.gov.au/about-nsw/daylight-saving) - [Australasian zone rules](https://data.iana.org/time-zones/tzdb/australasia) - [Live directory version](https://data.iana.org/time-zones/tzdb/version) - [Node.js TZ environment variable](https://nodejs.org/docs/latest-v24.x/api/cli.html#tz) ## Related guides - [How to test an Australian proxy: networks and nbn checks](https://ipvolt.com/guides/australia-proxies.md) - [Configure a proxy in Playwright](https://ipvolt.com/guides/playwright-proxy-setup.md) - [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md) - [Mobile vs residential proxies: build a useful evaluation](https://ipvolt.com/guides/mobile-vs-residential-proxies.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile proxies in Australia from $19 a day. Residential proxies from $2.20/GB, in prepaid packs. [Mobile proxies in Australia on Vodafone from $19 a day](https://ipvolt.com/dashboard/mobile?country=AU&plan=day&carrier=Vodafone%20Australia) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 92 of 138: Test Shopify Canada localization URL: https://ipvolt.com/guides/shopify-canada-localization Markdown: https://ipvolt.com/guides/shopify-canada-localization.md # Test Shopify Canada localization Source: https://ipvolt.com/guides/shopify-canada-localization Markdown: https://ipvolt.com/guides/shopify-canada-localization.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Test Shopify Canada localization](https://ipvolt.com/guides/shopify-canada-localization.md) Category: Integration Reviewed: 2026-09-27 Published: 2026-09-27 Reading time: 9 minutes Author: ipvolt Use a configuration snapshot and paired visits to test Shopify Canada localization. Separate IP, URL, language, saved choice and shipping-address effects. Start with your Shopify Online Store’s configuration, then compare a Canadian and non-Canadian first visit to the **same neutral URL**. Keep language, browser state and the product fixed. An explicit Canada URL answers a different question, so test it separately. The downloadable worksheet provides six comparison pairs and twelve empty visit records. Choose the pairs relevant to your problem; you do not need to run all six. The local checker catches missing declarations and specified control mistakes. No Shopify or proxy behaviour has been measured in these files. Download the [JSON worksheet](/downloads/canada-localization/shopify-canada-worksheet.json), [Python checker](/downloads/canada-localization/validate_shopify_canada.py) and [README](/downloads/canada-localization/README.md). For a spreadsheet view, keep the [configuration CSV](/downloads/canada-localization/shopify-canada-configuration.csv) and [visits CSV](/downloads/canada-localization/shopify-canada-visits.csv) together. The checker reads JSON; editing the CSV does not update it. ## Capture the configuration before the visit Save a copy of the JSON and fill `configuration` from the store you control. Give the snapshot an ID, UTC timestamp and private evidence reference. Record: - Active markets and currencies; whether market URLs use shared, dedicated or mixed domains. - Actual country and language redirection settings, published languages by market, selectors and saved-choice behaviour. - Shipping rules and any third-party routing, or `none`. - Product/cart fixture, browser version, viewport, time zone and a short test window. Use a signed-out browser with location permission denied. An account or granted coordinates would introduce additional inputs into this protocol. Keep configuration and stock stable during the pair; record a new snapshot when they change. Read the shipping setup actually present in your store. Shopify is gradually moving shipping profiles and rates to shipping options by market. Its state/province sub-region markets are currently **early access**, with independent customization limited to shipping options. Neither feature is a prerequisite for this worksheet. [Shipping setup](https://help.shopify.com/en/manual/fulfillment/setup/shipping-rates/setting-up-shipping-rates), [market types](https://help.shopify.com/en/manual/markets/getting-started/market-types). For each relevant pair, set `applicable` to `true`, write the `expected_rule` and its evidence, and give both visits an `expected_outcome` before execution. Retain unused pairs as `applicable: false` with an `inapplicable_reason`. A correct result may be unchanged when the configured rule maps both inputs to the same experience. ## Run the same-URL IP comparison first Map `neutral_entry_url` to the agreed first-visit entry for testing location selection. Do not substitute a preselected Canada domain or path. If your setup has no suitable common entry, mark this pair inapplicable and explain why. Fill `exits.CA` and `exits.control` from your authorized IP observations. The control must be outside Canada. Record the checking service or target, UTC timestamp, observed country and an `egress_id`: a private reference or digest identifying the observed exit address. A separate IP checker’s country result does not establish Shopify’s own location decision; Shopify warns that IP geolocation can be inaccurate. [Localization considerations](https://help.shopify.com/en/manual/markets/getting-started/localization). | Visit | Entry | Exit | Language | Browser state | Shipping address | | --- | --- | --- | --- | --- | --- | | `ip-A` | Same neutral URL | Observed CA | `en-CA` | Fresh, signed out | None entered | | `ip-B` | Same neutral URL | Observed non-CA control | `en-CA` | Separate fresh context, signed out | None entered | Open a new isolated context for each visit, without reused storage state, cart or old profile. Record the first landing before entering an address, then close the context. Shopify documents automatic redirection as first-page behaviour, so navigating around in an existing session is a different comparison. [First-page redirection](https://help.shopify.com/en/manual/markets/getting-started/localization). Record final URL, selected country, market, language and currency separately. Shared-domain markets can change displayed content without changing the URL; dedicated market domains can redirect it. URL change alone is therefore an unsuitable universal pass condition. [Domain-dependent redirection](https://help.shopify.com/en/manual/international/automatic-redirection). For market evidence, capture the relevant selector state and configuration mapping, or an authorized storefront diagnostic. A country and a market need not map one-to-one: a market can include multiple countries. CAD or HTTP 200 alone does not establish which market was selected. Shopify’s [Liquid localization object](https://shopify.dev/docs/api/liquid/objects/localization) exposes selected country, language and the applicable country-region market; the download supplies no tested Liquid instrumentation. [Country and region market scope](https://help.shopify.com/en/manual/markets/getting-started/market-types). ## Add the comparison that matches the symptom Keep the snapshot, product/cart and browser settings fixed. Each fresh visit gets its own context; the saved-choice comparison deliberately retains only the prepared choice. | Pair | Change between visits | Keep fixed | What it helps diagnose | | --- | --- | --- | --- | | `url` | Neutral entry → configured Canada entry | CA exit, `en-CA`, fresh contexts | Interaction between entry URL and configured redirection. | | `language` | Browser preference `en-CA` → `fr-CA` | Canada entry, CA exit, fresh contexts | Whether the configured French experience appears. | | `saved` | Fresh context → deliberately retained manual choice | Canada entry, CA exit, `fr-CA` | Whether the recorded selector choice is respected on return. | | `province` | Approved Ontario → Quebec delivery address | Canada entry, CA exit, `en-CA`, equivalent fresh carts | Delivery outcomes for those two destinations. | | `cross_border` | Approved non-CA → Ontario delivery address | Control-market entry, non-CA exit, `en-CA`, equivalent fresh carts | Checkout changes after the destination changes. | If the neutral and Canada entries are identical on a shared domain, the `url` contrast is inapplicable. The `ip` pair can still inspect content at that shared entry. For distinct URLs, observe the interaction in your setup instead of assuming a universal URL-versus-IP precedence order. For the language pair, verify the browser’s actual language preference. French redirection requires language redirection to be active and French to be added, assigned to the relevant market, translated and published. Shopify illustrates a configured `.ca` storefront redirecting to `.ca/fr`; that is a documentation example, not a URL pattern to impose on every store. [Language requirements](https://help.shopify.com/en/manual/international/automatic-redirection). For `saved-B`, start clean, manually choose the intended country and English using the store’s selectors, then revisit in that same context. Record the exact steps. Importing an unrelated old profile adds unknown state. Shopify documents retention of manual choices on later visits. [Saved selector preferences](https://help.shopify.com/en/manual/markets/getting-started/localization). For the address pairs, reference approved **complete test addresses** kept privately. Reset cart and checkout between visits and stop at your authorized observation point without placing an order. Ontario versus Quebec compares two destinations; it does not isolate province from postal, street or radius rules. For local delivery, also preserve inventory, fulfillment and checkout conditions. [Local-delivery eligibility](https://help.shopify.com/en/manual/fulfillment/setup/delivery-methods/local-delivery). Inspect the checkout experience again after entering the address. Shopify documents shipping destination as determining the final experience, including an example of a US visitor entering a Canadian address. A successful first landing therefore does not finish the cross-border comparison. [Checkout localization](https://help.shopify.com/en/manual/markets/getting-started/localization). ## Interpret what changed—and what did not Write actual inputs and observations into each visit, then set `observation.status` to `observed`. Preserve the final URL, selected country, market evidence, language, currency, UTC time and evidence reference. Include delivery options for address comparisons, recording `none` if absent. Use `match`, `mismatch` or `inconclusive` against the expectation you wrote before the visit. If one of `selected_country`, `market`, `market_evidence`, `language` or `currency` is unavailable, record `unavailable`, choose `inconclusive` and explain the gap. `final_url` still requires an observed HTTP(S) URL; without it the record remains incomplete. Keep failed and inconclusive records. **Invented interpretation example:** suppose a recorded shared-domain configuration assigns Canadian visitors to a Canada market and US visitors to a US market. Both visits finish at the same URL. Authorized market evidence identifies Canada for `ip-A` and the US for `ip-B`. That would match the declared rule even without a redirect. If the only evidence were a CAD price, market selection would remain inconclusive. This example contains no observed merchant result. If both inputs should select the same market, identical output can match. If the declared rule predicts different markets but both observations identify the same one, retain the mismatch and inspect settings, actual entry, fresh state and Shopify’s location decision. A different URL plus a different language cannot isolate the exit’s effect. Compare `actual_inputs` with the plan. If the exit rotates, the product changes or an old session is reused, restore the control and repeat the pair. Preserve the original record. Use a new worksheet record when a later pair uses a different observed egress ID; the earlier IP evidence does not cover the new address. ## Check the record locally Place the checker beside the JSON. Python 3.10 or later uses only the standard library: ```sh python3 validate_shopify_canada.py shopify-canada-worksheet.json ``` The blank download returns `INCOMPLETE_RECORD` and exit `2`. A filled plan can return `PLAN_COMPLETE` with exit `0`: only its declarations and paired inputs passed the local checks. This is not a Shopify pass. After entering observations: ```sh python3 validate_shopify_canada.py shopify-canada-worksheet.json --observations ``` `RECORD_COMPLETE` means the declared observation fields and controls passed the checker. It can contain `mismatch` and `inconclusive` outcomes; it does not verify that the store works or that the observations are true. To export the visit view after editing JSON: ```sh python3 validate_shopify_canada.py shopify-canada-worksheet.json --export-csv shopify-canada-visits.csv ``` Keep the configuration with that export. Read the returned `errors` when the checker reports an incomplete record; do not fill missing observations with expected values just to make the command succeed. ## Method and scope The worksheet was derived from the linked Shopify documentation, checked on 26 September 2026 UTC. Its checker passed **28 of 28 offline tests with invented records** on Python **3.14.7**, macOS **15.7.4 arm64**. Those tests include missing market evidence, changed egress, mixed IP/language inputs, signed-in state, granted location permission and an address entered during the first-visit IP pair. Python 3.10 syntax was checked; runtime execution used 3.14.7. These results establish the tested record checks. No Shopify store, browser, proxy, checkout or address eligibility was tested. The protocol targets a configured Shopify Online Store; headless storefronts, B2B and custom routing need their own rules. The checker cannot establish IP-location accuracy, hidden app behaviour, tax correctness or actual delivery eligibility. For a network exit requirement, the [Canada proxies page](/proxies/canada) sets out what to specify. The guide and downloads are available without signup. ipvolt doesn't sell mobile proxies in Canada today. ## Sources & further reading - [Shopify market localization](https://help.shopify.com/en/manual/markets/getting-started/localization) - [Shopify domain and language redirection](https://help.shopify.com/en/manual/international/automatic-redirection) - [Shopify market types and early-access sub-region markets](https://help.shopify.com/en/manual/markets/getting-started/market-types) - [Shopify shipping configuration](https://help.shopify.com/en/manual/fulfillment/setup/shipping-rates/setting-up-shipping-rates) - [Shopify local-delivery eligibility](https://help.shopify.com/en/manual/fulfillment/setup/delivery-methods/local-delivery) - [Shopify Liquid localization object](https://shopify.dev/docs/api/liquid/objects/localization) ## Related guides - [Canada proxies: location, networks and session checks](https://ipvolt.com/guides/canada-proxies.md) - [Configure a proxy in Playwright](https://ipvolt.com/guides/playwright-proxy-setup.md) - [France proxies: networks, regions and local testing](https://ipvolt.com/guides/france-proxies.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Residential proxies are on sale from $2.20/GB. The dashboard lists the countries available now. ipvolt doesn't sell mobile proxies in Canada today. [See which countries and carriers are on sale.](https://ipvolt.com/pricing) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 93 of 138: curl --compressed: which clients skip compression URL: https://ipvolt.com/guides/curl-compressed-accept-encoding Markdown: https://ipvolt.com/guides/curl-compressed-accept-encoding.md # curl --compressed: which clients skip compression Source: https://ipvolt.com/guides/curl-compressed-accept-encoding Markdown: https://ipvolt.com/guides/curl-compressed-accept-encoding.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [curl --compressed: which clients skip compression](https://ipvolt.com/guides/curl-compressed-accept-encoding.md) Category: Integration Reviewed: 2026-09-27 Published: 2026-09-27 Reading time: 20 minutes Author: ipvolt curl, Wget 1.x, urllib, node:http, PHP curl, Guzzle and java.net.http.HttpClient send no Accept-Encoding (or identity) by default. Tested fixes and byte checks. curl sends no `Accept-Encoding` header unless you pass `--compressed`. GNU Wget 1.x and Python's `urllib.request` send `Accept-Encoding: identity`, and Node's `node:http`, PHP's ext-curl, Guzzle and Java's `java.net.http.HttpClient` send no header at all. A server that compresses only when asked then returns the full, uncompressed text, and every one of those bytes crosses your proxy. Requests, httpx, aiohttp, Scrapy, Node's built-in `fetch`, axios, got, Go and browsers already ask for compression: for them there is nothing to switch on, and at most an optional br decoder trims a little more from some pages. Each default below was recorded by a local lab that ipvolt ran on 27 September 2026, with the versions listed under each table. The results are synthetic: a server and a proxy on 127.0.0.1 served a local test page, so no byte count here comes from a public site or a provider bill. ## Who asks for compression by default ### Sends no Accept-Encoding, or identity A server that compresses only when asked sends these clients uncompressed text. No header: curl, node:http, node:https, PHP ext-curl, Guzzle, Laravel Http, Java HttpClient. `identity`: Wget, urllib, http.client. | Client | Fix | |---|---| | curl | Add `--compressed` | | Wget | Add `--compression=auto` | | urllib, http.client | Use Requests or httpx | | node:http, node:https | Use `fetch`, got or axios | | PHP ext-curl | Set `CURLOPT_ACCEPT_ENCODING` to `''` | | Guzzle, Laravel Http | Set `decode_content` to `'gzip'` | | Java HttpClient | Send `Accept-Encoding: gzip`, unzip with `GZIPInputStream` | Versions run: curl 8.7.1, 8.22.0; Wget 1.25.0; urllib.request, http.client (Python 3.13.15, 3.14.7); node:http, node:https (Node.js 22.23.3, 24.21.0, 26.10.0); PHP 8.5.8 ext-curl (libcurl 8.20.0); Guzzle 8.2.0, Laravel Http 13.33.0; Java 25.0.4.1 HttpClient. - curl: a hand-set `-H 'Accept-Encoding: gzip'` is sent, but the body stays compressed. - Wget: with `--compression=auto` it sent `gzip` and decoded the reply. - urllib.request and http.client return compressed bodies as they arrived. - node:http and node:https return compressed bodies as they arrived. - PHP ext-curl: with `CURLOPT_ACCEPT_ENCODING` set to `''`, this libcurl sent `deflate, gzip, br, zstd`. A hand-set header is sent but not decoded. - Laravel Http: `withOptions(['decode_content' => 'gzip'])`. - Java HttpClient never decodes: wrap the body in `GZIPInputStream` when the reply is gzip. ### Already asks for compression Nothing to change: these clients ask for compression and decode the reply. | Client | Header sent | |---|---| | Requests | Python 3.13.15: `gzip, deflate`; Python 3.14.7: `gzip, deflate, zstd` | | httpx | `gzip, deflate` | | aiohttp | Python 3.13.15: `gzip, deflate`; Python 3.14.7: `gzip, deflate, zstd` | | Scrapy | `gzip, deflate, br, zstd` | | Node.js built-in fetch | Node.js 22.23.3/24.21.0: `br, gzip, deflate`; Node.js 26.10.0: `br, gzip, deflate, zstd` | | Go net/http | `gzip` | Versions run: Requests 2.34.2; httpx 0.28.1; aiohttp 3.14.3; Scrapy 2.19.0; built-in fetch (Node.js 22.23.3, 24.21.0, 26.10.0); Go 1.27.1 net/http. - Requests: `brotli` adds br; on Python 3.13, `backports.zstd` adds zstd. - httpx: `brotli` adds br and `zstandard` adds zstd. - aiohttp: `Brotli` adds br; on Python 3.13, `backports.zstd` adds zstd. - Built-in fetch over `http://`: `gzip, deflate`. - Go: setting the header yourself turns decoding off. If your client already asks for compression, confirm it with the byte check below, and read the section on copied browser headers before you add any header by hand. Compression is worth nothing for images, video and other payloads that are already compressed, whichever client you use. Every row is a lab run, not a reading of the source: 567 recorded cells, none marked source-read. [tables.md](https://ipvolt.com/downloads/accept-encoding-defaults/tables.md) lists the records behind each row. "Wget" here means GNU Wget 1.x. GNU Wget2 asks for every coding it was built with by default ([wget.c](https://gitlab.com/gnuwget/wget2/-/blob/v2.3.0/src/wget.c#L4306-4331)), and Fedora 40 and later install wget2 as the `wget` command ([Fedora change](https://fedoraproject.org/wiki/Changes/Wget2asWget)); that is source-read, and the lab did not run Wget2. ## curl: no header until you pass --compressed Plain `curl URL` sends no `Accept-Encoding` at all. In libcurl, [`CURLOPT_ACCEPT_ENCODING`](https://curl.se/libcurl/c/CURLOPT_ACCEPT_ENCODING.html) defaults to NULL, which "makes libcurl not send an `Accept-Encoding:` header and not decompress received contents automatically", and the curl tool changes it only for `--compressed`. Neither curl build in the lab sent the header, directly, through an `http://` proxy or through CONNECT. [curl#11091](https://github.com/curl/curl/issues/11091) shows the same thing with an `nc` capture of curl 7.88.1. `--compressed` asks for every coding your build can decode, then decodes the reply: - The macOS system curl 8.7.1, built with zlib only, sent `deflate, gzip`. - Homebrew curl 8.22.0, built with brotli and zstd, sent `deflate, gzip, br, zstd`. To see what yours will ask for, read the `Features:` line of `curl -V`: `libz` means gzip and deflate, `brotli` adds br, and `zstd` adds zstd. Three details decide whether it helps: - It is "a request, not an order; the server may or may not deliver data compressed" ([man page](https://curl.se/docs/manpage.html#--compressed)). curl reports no error when a server ignores it and has no switch to fail in that case ([curl#7516](https://github.com/curl/curl/issues/7516)), so check the bytes as shown below. - A hand-set `-H 'Accept-Encoding: gzip'` is sent, but curl does not decode the reply. In the lab, curl output the 17,750-byte gzip stream instead of the 100,129-byte page. Use `--compressed`, not a header. - `--no-compressed` turns it off again, for example after a `--compressed` line in `.curlrc`. When the lab server sent br or zstd that the macOS build cannot decode, `curl --compressed` stopped with exit code 61: ```text curl: (61) Unrecognized content encoding type. libcurl understands deflate, gzip content encodings. ``` Decompression has a cost of its own. The man page warns that "even tiny transfers might be expanded and generate a huge amount of bytes" and suggests `--max-filesize`. That option stops a transfer that grows through `--compressed` decompression only "Since 8.20.0" ([man page](https://curl.se/docs/manpage.html#--max-filesize)), so it does not protect the macOS system curl 8.7.1. That limit is documented; the lab did not test it. Without `--compressed`, a server that compresses anyway leaves you with raw gzip bytes, as in [curl#2836](https://github.com/curl/curl/issues/2836); that is the familiar "binary output" case, and `--compressed` fixes it. For the proxy flags themselves, see [use a proxy with curl](/guides/curl-proxy-setup). ## Python: urllib sends identity; Requests, httpx, aiohttp and Scrapy compress - **urllib.request and http.client** send `Accept-Encoding: identity` on CPython 3.13.15 and 3.14.7. http.client adds it unless you set your own, with the comment "we don't support encodings such as x-gzip or x-deflate" ([client.py](https://github.com/python/cpython/blob/v3.14.7/Lib/http/client.py#L1296-L1299)), and neither module decodes a reply. In the lab, urllib.request returned gzip, br and zstd replies as they arrived; http.client, which urllib.request sends its requests through, ran only with its default header, so for http.client this rests on the source. Setting the header yourself only gets you compressed bytes to decode by hand, so switch clients instead. A script that must stay on the standard library can send `Accept-Encoding: gzip` and, when the reply carries `Content-Encoding: gzip`, decode the body with [`gzip.decompress()`](https://docs.python.org/3.14/library/gzip.html#gzip.decompress); that route was not run in the lab. - **Requests 2.34.2** (with urllib3 2.8.0) takes its default from urllib3 ([utils.py](https://github.com/psf/requests/blob/v2.34.2/src/requests/utils.py#L91-L93)): `gzip, deflate` on Python 3.13.15 and `gzip, deflate, zstd` on 3.14.7, where urllib3 uses the standard library's [`compression.zstd`](https://docs.python.org/3.14/library/compression.zstd.html). Installing `brotli` adds br; on 3.13, `backports.zstd` adds zstd. Since urllib3 2.6.0, the separate `zstandard` package no longer enables zstd ([request.py](https://github.com/urllib3/urllib3/blob/2.8.0/src/urllib3/util/request.py#L22-L41); source-read, not run). The proxy side is in [configure Python Requests](/guides/python-requests-proxy). - **urllib3 on its own**, through `urllib3.request()` or a `PoolManager`, adds no compression header. Its request path passes through to http.client ([connection.py](https://github.com/urllib3/urllib3/blob/2.8.0/src/urllib3/connection.py#L525-L531)), which by the source means `identity`. This is source-read; the lab ran Requests, not urllib3 alone. - **aiohttp 3.14.3** sends `gzip, deflate` on 3.13.15 and `gzip, deflate, zstd` on 3.14.7; `Brotli` adds br, and on 3.13 `backports.zstd` adds zstd. It is the only Python client here that raises an exception on a coding it cannot decode; the exact message is below. - **Scrapy 2.19.0** sends `gzip, deflate, br, zstd` on both. Since Scrapy 2.18.0, brotli and Zstandard support are required, "so `br` and `zstd` are always included in the `Accept-Encoding` header of requests" ([release notes](https://github.com/scrapy/scrapy/blob/2.19.0/docs/news.rst)). ### httpx and zstd on Python 3.14 httpx 0.28.1 sends `gzip, deflate` on both Pythons. It adds br with `brotli` and zstd only with the third-party `zstandard` package; unlike Requests and aiohttp, it does not use the standard-library zstd of Python 3.14 ([_decoders.py](https://github.com/encode/httpx/blob/0.28.1/httpx/_decoders.py#L381-L393)). The [HTTPX documentation](https://www.python-httpx.org/) installs both decoders with `pip install "httpx[brotli,zstd]"`. None of that is needed for compression itself, since gzip is always requested. It matters when a server sends a coding httpx cannot decode: httpx returns the compressed bytes and raises nothing. On Python 3.14.7 without `zstandard`, a zstd reply reached the caller as the 19,298-byte zstd stream. Proxy configuration is in the [HTTPX async proxy guide](/guides/httpx-async-proxy). ## Node.js: built-in fetch compresses, node:http does not Built-in `fetch` (undici) chooses the header by URL scheme and release line ([source, v26.10.0](https://github.com/nodejs/node/blob/v26.10.0/deps/undici/src/lib/web/fetch/index.js#L1562-L1576); [v24.21.0](https://github.com/nodejs/node/blob/v24.21.0/deps/undici/src/lib/web/fetch/index.js#L1514-L1528)): - `https://` URLs: `br, gzip, deflate` on Node.js 22.23.3 and 24.21.0, and `br, gzip, deflate, zstd` on 26.10.0. - `http://` URLs: `gzip, deflate` on all three. - Any request with a `Range` header: `identity` on all three. All three decoded gzip and br. zstd is where they differ, including zstd a server sends unasked: - Node.js 22.23.3 `fetch` has no zstd decoder and returned the compressed bytes with no error ([source](https://github.com/nodejs/node/blob/v22.23.3/deps/undici/src/lib/web/fetch/index.js#L2149-L2170)). - Node.js 24.21.0 `fetch` decoded zstd it had not asked for. A body made of four concatenated zstd frames came back as the first frame only: 25,033 of 100,129 bytes, with no error. axios 1.20.0 and got 16.0.0 also returned only the first frame on Node.js 22.23.3 and 24.21.0. - Node.js 26.10.0 decoded all four frames with `fetch`, axios and got. `node:http` and `node:https` send no `Accept-Encoding` on any of the three releases and never decode; Node's core HTTP client does not set the header ([_http_client.js](https://github.com/nodejs/node/blob/v26.10.0/lib/_http_client.js)). Node's [zlib documentation](https://nodejs.org/api/zlib.html#compressing-http-requests-and-responses) shows the manual route: set the header yourself and pipe the response through a decompressor. Switching to `fetch`, got or axios is less code. ### Built-in fetch vs the node-fetch package The npm package `node-fetch` is a separate client with its own defaults ([node-fetch#1556](https://github.com/node-fetch/node-fetch/discussions/1556)). On Node.js 24.21.0, node-fetch 3.3.2 sent `gzip, deflate, br` and node-fetch 2.7.0 sent `gzip,deflate`, and both decoded the reply. axios 1.20.0 sends `gzip, compress, deflate, br` and adds zstd only with `transitional: { advertiseZstdAcceptEncoding: true }` ([http.js](https://github.com/axios/axios/blob/v1.20.0/lib/adapters/http.js#L54-L57)). got 16.0.0 sent `gzip, deflate, br, zstd` on all three releases ([index.ts](https://github.com/sindresorhus/got/blob/v16.0.0/source/core/index.ts#L2248-L2258)). None of them needs a change. The proxy dispatcher for built-in `fetch` is covered in [use a proxy with Node.js fetch](/guides/nodejs-fetch-proxy). ## Go, Wget, PHP and Java ### Go net/http asks for gzip only Go 1.27.1 sends `Accept-Encoding: gzip`, decodes the reply and removes `Content-Encoding` and `Content-Length` from the response it gives you ([transport.go](https://github.com/golang/go/blob/go1.27.1/src/net/http/transport.go#L199-L207)). It sends no header for `HEAD` requests, for requests with a `Range` header, or with `DisableCompression: true`. Two consequences: - Setting `Accept-Encoding` yourself turns the decoding off: "if the user explicitly requested gzip it is not automatically uncompressed". With `req.Header.Set("Accept-Encoding", "gzip")`, the lab's Go client received the 17,750-byte gzip stream. - net/http has no br or zstd decoder. A server that sent them unasked delivered raw bytes. ### GNU Wget 1.x sends identity Wget 1.25.0 sends `Accept-Encoding: identity`. For `--compression`, the manual says of "none": "This is the default" ([manual](https://www.gnu.org/software/wget/manual/wget.html#HTTP-Options)); the same page's `.wgetrc` list still calls `auto` the default, but the lab run matches `none`. With `--compression=auto`, Wget sent `gzip` and decoded gzip, and nothing else: br or zstd sent unasked arrived raw. Wget2 differs, as noted above. ### PHP: Guzzle, Laravel Http and ext-curl send no Accept-Encoding - **PHP ext-curl** (PHP 8.5.8 with libcurl 8.20.0) sends nothing, because `CURLOPT_ACCEPT_ENCODING` "Defaults to null" ([PHP manual](https://www.php.net/manual/en/curl.constants.php)). `CURLOPT_ACCEPT_ENCODING => ''` asks for every coding the linked libcurl supports, `deflate, gzip, br, zstd` in this build, and decodes. An `Accept-Encoding` line in `CURLOPT_HTTPHEADER` is sent but not decoded. - **Guzzle 8.2.0** removes the header on purpose. Its cURL handler turns on every decoder, then adds an empty `Accept-Encoding:` line to stop curl sending one, with the comment that this "will be interpreted as 'Accept-Encoding: *'" ([CurlFactory.php](https://github.com/guzzle/guzzle/blob/8.2.0/src/Handler/CurlFactory.php#L2609-L2622)). The same code is in every tag checked from 6.5.0 to 8.2.0 (source-read). Give [`decode_content`](https://docs.guzzlephp.org/en/stable/request-options.html#decode-content) a string, such as `'decode_content' => 'gzip'`, and Guzzle sends it as the header ([Client.php](https://github.com/guzzle/guzzle/blob/8.2.0/src/Client.php#L1582-L1586)); `'gzip, deflate, br, zstd'` also worked with the cURL handler. By default the cURL handler still decodes gzip, br or zstd that a server sends unasked. Guzzle's `StreamHandler`, which uses PHP streams instead of ext-curl, decoded gzip but returned br and zstd raw. - **Laravel Http** (illuminate/http 13.33.0) builds a plain Guzzle client and inherits all of this ([PendingRequest.php](https://github.com/laravel/framework/blob/v13.33.0/src/Illuminate/Http/Client/PendingRequest.php)). Both `withOptions(['decode_content' => 'gzip'])` and `withHeaders(['Accept-Encoding' => 'gzip'])` sent `gzip` and decoded the reply. ### Java HttpClient never decodes `java.net.http.HttpClient` on Temurin 25.0.4.1 sent no `Accept-Encoding` and did not decode a gzip reply that the server sent unasked. To get compression, send `Accept-Encoding: gzip` yourself and read the body through `java.util.zip.GZIPInputStream` when the response carries `Content-Encoding: gzip`, as the lab's [Java client](https://ipvolt.com/downloads/accept-encoding-defaults/harness/clients/php-java/JavaHttpClientLab.java) does. No other Java client was run. ## Accept-Encoding: identity, no header, and garbled output [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-accept-encoding) separates three request states: - **No header** (curl, node:http, ext-curl, Guzzle, Java): "any content coding is considered acceptable by the user agent". - **`identity`** (urllib, Wget 1.x): "a synonym for 'no encoding'". - **An empty value**: "the user agent does not want any content coding in response". So the standard allows a server to compress a reply to a request with no header, and "compress only when asked" is server practice, not an RFC rule. Server and CDN documentation describes that practice. Cloudflare picks gzip, Brotli, Zstandard or no compression "depending on" the values in the request's `accept-encoding` header, the plan and any matching compression rule ([Cloudflare](https://developers.cloudflare.com/speed/optimization/content/compression/), page updated 17 April 2026). Apache's mod_deflate sends `Vary: Accept-Encoding` so that compressed content is not "sent to a client that will not understand it" ([mod_deflate](https://httpd.apache.org/docs/2.4/mod/mod_deflate.html)). Guzzle's comment relies on the RFC reading; with servers that follow that practice, a missing header gets the uncompressed body. The lab server followed the same practice. How often real servers compress unasked was not measured. Some do. nginx's `gzip_static always` serves the gzipped file "without checking if the client supports it" ([nginx](https://nginx.org/en/docs/http/ngx_http_gzip_static_module.html)), and curl#2836 reports a real host that did it. When the lab server sent gzip unasked, curl without `--compressed`, Wget, urllib, `node:http`, PHP ext-curl, Java and Go with `DisableCompression` all handed the caller the 17,750-byte gzip stream; Guzzle and Laravel Http decoded it. If a response from one of those clients looks like binary garbage, check its `Content-Encoding` first. ## Verify the bytes on your own target For a client without a byte-count snippet here, run the curl comparison below against the same URL through the same proxy, and compare its `Content-Encoding` with your client's. This measures curl's response; a different coding or server response is not a byte measurement of your client. The curl, Requests, httpx and `node-fetch-bytes.mjs` snippets below print wire body bytes: the response body as it crossed the network, before any decoding. Response headers, TLS records, the CONNECT exchange and retries are not included, so this is not what a provider bills. In eight lab pairs ([tables.md](https://ipvolt.com/downloads/accept-encoding-defaults/tables.md) lists them), the same client fetched the test page over CONNECT with and without compression, and those extras added 2,343 to 3,520 bytes per response on the proxy's client leg. They lowered the ratio, for example from 5.19× on the body to 4.56× on the proxy leg for curl 8.22.0, but not the saving: in each of those pairs, the proxy leg shrank by the body difference plus 87 bytes. To meter a whole run through your proxy and convert it at your own rate, use [Scrapescope](/guides/scraper-bandwidth-report). The Go snippet prints the decoded size and `resp.Uncompressed`, which says whether Go decoded the reply, and the linked `node-fetch-verify.mjs` prints the header `fetch` sent; neither prints wire bytes. Each snippet ran unchanged in the lab except that `https://example.com/` became a loopback URL, and the outputs shown are from those runs; the Go snippet was also compiled with one lab file that trusts the lab's CA, described in the method section. Set `PROXY_URL` to your proxy. If you need to trust a private CA, use the client's own setting, such as `--cacert`, `NODE_EXTRA_CA_CERTS` or Go's `tls.Config.RootCAs`; never turn certificate verification off. ### Verify with curl ```sh # Wire body bytes and the Content-Encoding the server chose (curl 7.84.0+ for %header{}). curl -sS -o /dev/null -x "$PROXY_URL" \ -w '%{size_download} %header{content-encoding}\n' https://example.com/ curl -sS -o /dev/null -x "$PROXY_URL" --compressed \ -w '%{size_download} %header{content-encoding}\n' https://example.com/ ``` With Homebrew curl 8.22.0 against the lab's test page, the first line printed `100129` and no coding, and the second `19298 zstd`; the macOS system curl 8.7.1 printed `17750 gzip` on the second line. curl's `size_download` is "the size of the body/data that was transferred, excluding headers", and `%header{}` needs curl 7.84.0 or later ([write-out](https://curl.se/docs/manpage.html#-w)). The ratio for that page is the first number divided by the second. ### Verify with Requests and httpx ```python import os import requests proxies = {"http": os.environ["PROXY_URL"], "https": os.environ["PROXY_URL"]} with requests.get("https://example.com/", proxies=proxies, stream=True) as r: wire = r.raw.read(decode_content=False) # body bytes as sent, still encoded print(r.headers.get("content-encoding"), len(wire)) ``` Requests printed `gzip 17750` on Python 3.13.15 and `zstd 19298` on 3.14.7. For httpx, `r.num_bytes_downloaded` counts the bytes as read and `len(r.content)` the decoded body: ```python import os import httpx with httpx.Client(proxy=os.environ["PROXY_URL"]) as client: r = client.get("https://example.com/") # wire body bytes (as received) vs decoded bytes your code sees print(r.headers.get("content-encoding"), r.num_bytes_downloaded, len(r.content)) ``` It printed `gzip 17750 100129` on Python 3.14.7, and `zstd 19298 100129` with `zstandard` installed. urllib never decodes, so the length of what you read from it is already the wire body. ### Verify with Node.js For built-in `fetch`, Node's resource timing entry for the URL gives the wire body size: ```js // Wire body bytes of a built-in fetch, from Node's resource timing entry for the URL. // Run: NODE_USE_ENV_PROXY=1 HTTPS_PROXY="$PROXY_URL" node node-fetch-bytes.mjs import { setImmediate } from 'node:timers/promises'; const url = new URL('https://example.com/'); const res = await fetch(url); const body = await res.arrayBuffer(); // already decoded by fetch // Node adds the entry after the body has been read, so give the event loop a turn. let entry; for (let turn = 0; !entry && turn < 100; turn++) { await setImmediate(); entry = performance.getEntriesByType('resource').findLast((e) => e.name === url.href); } performance.clearResourceTimings(); // the buffer stops at 250 entries unless you clear it // encodedBodySize: the body as it crossed the network, before decoding (no headers, TLS or CONNECT) console.log('content-encoding', res.headers.get('content-encoding'), 'wire body bytes', entry?.encodedBodySize, 'decoded bytes', body.byteLength); ``` Through the lab's CONNECT proxy it printed `content-encoding br wire body bytes 18451 decoded bytes 100129` on Node.js 22.23.3 and 24.21.0, and `content-encoding zstd wire body bytes 19298 decoded bytes 100129` on 26.10.0, each matching what the lab server sent. In 18 further lab cells on the three releases (direct `http://`, direct `https://` and through the CONNECT proxy, each with and without compression), `encodedBodySize` equalled the body bytes the server sent every time; [tables.md](https://ipvolt.com/downloads/accept-encoding-defaults/tables.md) lists the readings. The entry never existed straight after the body was read, only after one event-loop turn, which is why the snippet waits. The snippet then clears the entries, because Node's resource timing buffer holds only 250 by default ([observe.js](https://github.com/nodejs/node/blob/v26.10.0/lib/internal/perf/observe.js#L103)). Do not use `transferSize` instead: it was `encodedBodySize` plus a fixed 300 bytes in every cell, while through the proxy the client leg carried 3,431 to 3,520 bytes more than the body. [node-fetch-verify.mjs](https://ipvolt.com/downloads/accept-encoding-defaults/harness/snippets/node-fetch-verify.mjs) prints the header `fetch` sent (`sent accept-encoding: br, gzip, deflate, zstd` on Node.js 26.10.0). For `node:https`, which never decodes, [node-http-verify.mjs](https://ipvolt.com/downloads/accept-encoding-defaults/harness/snippets/node-http-verify.mjs) counts the body as it arrives, which is the wire body. ### Verify with Go ```go // Did Go ask for gzip and decode it for you? resp.Uncompressed says so. // Run: go run go-verify.go (with PROXY_URL set in the environment) package main import ( "fmt" "io" "net/http" "net/url" "os" ) func main() { proxy, err := url.Parse(os.Getenv("PROXY_URL")) if err != nil { panic(err) } t := http.DefaultTransport.(*http.Transport).Clone() t.Proxy = http.ProxyURL(proxy) resp, err := (&http.Client{Transport: t}).Get("https://example.com/") if err != nil { panic(err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { panic(err) } // true: Go sent "Accept-Encoding: gzip" itself, received gzip and decoded it, // then removed Content-Encoding and set ContentLength to -1. fmt.Printf("uncompressed=%v content-encoding=%q content-length=%d decoded-bytes=%d\n", resp.Uncompressed, resp.Header.Get("Content-Encoding"), resp.ContentLength, len(body)) } ``` With Go 1.27.1 it printed `uncompressed=true content-encoding="" content-length=-1 decoded-bytes=100129`. `resp.Uncompressed` only says that Go decoded the reply ([response.go](https://github.com/golang/go/blob/go1.27.1/src/net/http/response.go#L93-L100)); the response no longer carries its wire size. To count wire bytes, set the header yourself, which leaves the body compressed, measure it, then decode it with `compress/gzip`. ## Through a proxy: CONNECT vs absolute-form For an `https://` URL, the client opens a CONNECT tunnel and sends its request inside TLS. With end-to-end TLS and no TLS interception, the proxy cannot read or change `Accept-Encoding`; it relays the encrypted response. The lab recorder did not parse headers inside CONNECT tunnels. For an `http://` URL, most clients send the request itself to the proxy in absolute form, as in `GET http://host/path`, so the proxy reads every header: the lab proxy saw curl 8.22.0's `deflate, gzip, br, zstd` with `--compressed`, Wget's `identity` and Go's `gzip`. An intermediary on that path could also rewrite the header or the body. The lab proxy did neither, and no real proxy was tested. Two clients behaved differently with `http://` URLs: - Node.js 22.23.3 and 24.21.0 built-in `fetch`, with `NODE_USE_ENV_PROXY=1`, tunnelled `http://` URLs through CONNECT. The lab recorder did not parse the inner header, but that HTTP request was still plaintext and inspectable: [CONNECT itself does not encrypt traffic](https://www.rfc-editor.org/rfc/rfc9110.html#name-connect). Node.js 26.10.0 sent absolute form. - Guzzle's `StreamHandler` sent an origin-form request line to the proxy unless `request_fulluri` was set, and the lab proxy rejected it with a 400. What counts toward a bill is each provider's rule. Decodo, for example, documents download traffic as "every byte received from the target website, including response headers and cookies", says that for HTTPS "the bytes tunneled through the proxy also count toward proxy traffic usage", and gives an example in which its own test endpoint took 0.85 kB of download over `http://` against 3.96 kB over `https://` ([Decodo help](https://help.decodo.com/docs/proxy-traffic), read 26 September 2026, page modified 23 April 2026). Decodo does not say whether it counts compressed or decoded bytes. For HTTPS with end-to-end TLS inside CONNECT, the proxy counts the encrypted bytes crossing the tunnel, including the compressed response and TLS overhead; that is an inference, not Decodo's statement. Scraping APIs and unblockers that send the request to the target for you choose their own headers and meter in their own way, so check your provider's documentation. ## Copying a browser's Accept-Encoding You may be tempted to paste a browser's `Accept-Encoding: gzip, deflate, br, zstd` into a scraper. That asks the server for codings your client may not decode, and in several clients a hand-set header also switches decoding off. With exactly that header, the lab server chose zstd: - curl (both builds), urllib, `node:http`, Go, PHP ext-curl, Java `HttpClient` and Guzzle's `StreamHandler` returned the compressed bytes: a normal response with an unreadable body. - Requests and httpx did the same whenever the matching decoder was missing. On Python 3.13, bare Requests returned both zstd and br raw. On 3.14 it decoded zstd but returned br raw when the server sent br. httpx without `zstandard` returned zstd raw on both Pythons, with no exception. - Node.js 22.23.3 `fetch` returned zstd raw; 24.21.0 and 26.10.0 decoded it. - Guzzle's cURL handler decoded both zstd and br. - aiohttp raised an exception whenever it lacked the decoder: br without `Brotli`, and zstd on Python 3.13 without `backports.zstd`. On 3.14 it decoded zstd. The fix is to let the client write the header. If you want br or zstd, install the decoder package your client uses, such as `brotli`, `backports.zstd` on Python 3.13 or `httpx[brotli,zstd]`; the client then adds the token itself. ### aiohttp 3.14.3: `` Can not decode content-encoding: brotli (br). Please install `Brotli` `` When a server sends br and the `Brotli` package is missing, aiohttp 3.14.3 raises the first of these, on Python 3.13.15 and 3.14.7 alike. The second is the zstd version, raised on Python 3.13.15 without `backports.zstd` (loopback URLs shortened): ```text aiohttp.client_exceptions.ClientResponseError: 400, message='Can not decode content-encoding: brotli (br). Please install `Brotli`', url='…' aiohttp.client_exceptions.ClientResponseError: 400, message='Can not decode content-encoding: zstandard (zstd). Please install `backports.zstd`', url='…' ``` The 400 is aiohttp's own status for a response it cannot decode; the lab server had answered 200 ([http_parser.py](https://github.com/aio-libs/aiohttp/blob/v3.14.3/aiohttp/http_parser.py#L1147-L1159)). Installing `Brotli`, or `backports.zstd` for the second, fixed it in the lab: aiohttp then decoded br, and zstd including a body of four zstd frames. The shorter `Can not decode content-encoding: br` comes from a different path in the same file: a decoder is installed, but the body failed to decompress. ### Servers that mishandle advertised zstd Advertising a coding can itself break a request. OpenSearch 2.19.0 hung when a request's `Accept-Encoding` included zstd, as it does from curl builds with zstd support. It was fixed for 2.19.1 and 3.0.0 ([OpenSearch#17339](https://github.com/opensearch-project/OpenSearch/issues/17339)). If one host times out only for zstd-capable clients, a request that asks for gzip only will show whether zstd negotiation is the problem. ## Where compression does not help - **Payloads that are already compressed**, such as images, video and archives. "Media files such as images that are already compressed do not benefit from HTTP compression" ([Web Almanac 2021](https://almanac.httparchive.org/en/2021/compression)). - **Responses a server or CDN leaves uncompressed.** Cloudflare, for example, documents compressing only 200, 403 and 404 responses, with a minimum size of 48 bytes for gzip and 50 bytes for Brotli and Zstandard ([Cloudflare](https://developers.cloudflare.com/speed/optimization/content/compression/)). - **Range and HEAD requests.** Go sends no header for either, and Node.js `fetch` sends `identity` whenever a `Range` header is set. - **Uploads.** `--compressed` and its equivalents work on downloads; for request bodies "there is no standard way to do compression" ([Everything curl](https://everything.curl.dev/http/modify/compression.html)). - **Browser automation.** Browsers negotiate compression themselves: MDN gives `gzip, deflate, br, zstd` as the typical browser value ([MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Accept-Encoding)), and Chrome has decoded zstd by default since version 123 ([Chrome Platform Status](https://chromestatus.com/feature/6186023867908096)), so in Playwright or Puppeteer the bytes to cut are in what the browser downloads, not in this header. For pages you fetch again and again, conditional requests are a separate lever: a `304 Not Modified` response carries no body at all ([RFC 9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-304-not-modified); [ETag monitoring](/blog/etag-monitoring-cache-control)). ## What it is worth Only clients in the first table have compression to switch on. For them: saved $ ≈ pages × uncompressed text bytes per page × (1 − 1/ratio) ÷ 10⁹ × your $ per GB Take the ratio from the verify step on your own pages, as bytes without compression divided by bytes with it, and the rate from your own plan. Compression lowers the bill only when you pay per byte. On a flat plan priced by Mbps or threads the price stays the same, though more compressed pages fit through the channel. [What unlimited residential proxies cost per GB](/blog/unlimited-residential-proxies-cost-per-gb) compares the two ways of billing. An invented example, not a measurement: 100,000 pages of 100 KB (100,000 bytes) of HTML are 10 GB uncompressed. At a ratio of 4, compression saves 7.5 GB; at a ratio of 10, it saves 9.0 GB. At an invented rate of $3 to $8 per GB, that is about $22.50 to $72 for one crawl of those pages. For a client that already asks for compression, switching it on saves nothing, because it is already on. An optional br decoder for Requests, httpx or aiohttp can trim a little more on some pages: on the lab's 23 documentation pages, br bodies totalled 277,665 bytes against 325,873 for gzip, about 15% fewer, but on the synthetic page br was larger than gzip (18,451 against 17,750 bytes). The lab's own ratios are not a forecast. The synthetic test page shrank 5.64× with gzip and 5.19× with zstd. In this corpus of 23 CPython 3.14.7 documentation pages, the uncompressed bodies were 6.67× their gzip size, 6.61× their zstd size and 7.83× their br size. Those numbers describe those files only. The formula counts body bytes; in the lab, headers, TLS and the CONNECT exchange barely changed with compression, as the verify section shows. How a provider turns bytes into a bill (GB or GiB, minimums, failed requests) is covered by [Scrapescope](/guides/scraper-bandwidth-report). The result is an estimate, not a provider bill. ## Method, limits and downloads ipvolt ran the recorded matrix of 567 cells once on 27 September 2026 on macOS 15.7.4 (Apple M4 Pro, arm64): setup from 02:43 to 02:44 UTC, then the whole matrix from 02:44 to 02:45 UTC. A Python server on 127.0.0.1 served a 100,129-byte synthetic HTML page, and for some cells 23 pages of the CPython 3.14.7 documentation, behind a counting forward proxy on 127.0.0.1 that handled both absolute-form and CONNECT requests. With no header, the server sent the page uncompressed; otherwise it picked from the codings the client listed, preferring zstd, then br, gzip and deflate. Forced modes sent gzip, br, zstd, four zstd frames or no compression regardless of the request. Every HTTPS cell trusted a throwaway local CA through the client's own setting, and 21 control cells without that CA all failed certificate verification. The Go snippet was compiled with one lab file that put that CA in `http.DefaultTransport`'s `RootCAs` before the snippet cloned it (its text is `LAB_TRUST_GO` in [snippets.py](https://ipvolt.com/downloads/accept-encoding-defaults/harness/nodego/snippets.py)), so trust did not depend on `SSL_CERT_FILE`: go1.27.1 on macOS honours that variable unless `GODEBUG=x509sslcertoverrideplatform=0` is set, as it is by default in a module declaring go 1.26. A second run from the published archive, in an empty directory with every download fetched afresh, matched all 567 records on every compared field (`compare.py --strict`). Versions: curl 8.7.1 (macOS, LibreSSL) and 8.22.0 (Homebrew, OpenSSL 3.6.4, brotli, zstd); GNU Wget 1.25.0; CPython 3.13.15 and 3.14.7 with Requests 2.34.2 (urllib3 2.8.0), httpx 0.28.1, aiohttp 3.14.3 and Scrapy 2.19.0; Node.js 22.23.3, 24.21.0 and 26.10.0 from nodejs.org, checksums verified, with axios 1.20.0, got 16.0.0 and node-fetch 3.3.2 and 2.7.0; Go 1.27.1; PHP 8.5.8 (static build, libcurl 8.20.0) with Guzzle 8.2.0 and illuminate/http 13.33.0; Temurin JDK 25.0.4.1. The lab did not cover HTTP/2 or HTTP/3 (the server offered HTTP/1.1 only), Linux or Windows builds, browsers, Wget2, urllib3 on its own, curl_cffi, Apache HttpClient, OkHttp, Symfony HttpClient, .NET HttpClient, Rust reqwest, Ruby Net::HTTP or Faraday, other PHP or libcurl builds, or Java releases after 25. Defaults change between releases. These were the versions installed or current when the lab ran: the macOS system curl 8.7.1 is older than curl 8.22.0, PHP's static build was three patch releases behind php.net's 8.5.11, and Java 25 is the newest LTS release, not the newest feature release. Rerun the lab before you rely on a row. All files are under `https://ipvolt.com/downloads/accept-encoding-defaults/`: - [accept-encoding-lab.zip](https://ipvolt.com/downloads/accept-encoding-defaults/accept-encoding-lab.zip) holds everything below; its checksum is in [accept-encoding-lab.zip.sha256](https://ipvolt.com/downloads/accept-encoding-defaults/accept-encoding-lab.zip.sha256). - [README.md](https://ipvolt.com/downloads/accept-encoding-defaults/README.md) explains how to run the lab, compare a rerun and read a record. - [results.json](https://ipvolt.com/downloads/accept-encoding-defaults/results.json) and [results.csv](https://ipvolt.com/downloads/accept-encoding-defaults/results.csv) hold all 567 records; [tables.md](https://ipvolt.com/downloads/accept-encoding-defaults/tables.md) has every table, including the decode matrix and the exact error text. - [environment.txt](https://ipvolt.com/downloads/accept-encoding-defaults/environment.txt) records the OS and every version output, [corpus-manifest.txt](https://ipvolt.com/downloads/accept-encoding-defaults/corpus-manifest.txt) the documentation pages, and [SHA256SUMS](https://ipvolt.com/downloads/accept-encoding-defaults/SHA256SUMS) the checksum of every other file in the archive. - The verify snippets: [curl-verify.sh](https://ipvolt.com/downloads/accept-encoding-defaults/harness/snippets/curl-verify.sh), [requests-verify.py](https://ipvolt.com/downloads/accept-encoding-defaults/harness/snippets/requests-verify.py), [httpx-verify.py](https://ipvolt.com/downloads/accept-encoding-defaults/harness/snippets/httpx-verify.py), [node-fetch-bytes.mjs](https://ipvolt.com/downloads/accept-encoding-defaults/harness/snippets/node-fetch-bytes.mjs), [node-fetch-verify.mjs](https://ipvolt.com/downloads/accept-encoding-defaults/harness/snippets/node-fetch-verify.mjs), [node-http-verify.mjs](https://ipvolt.com/downloads/accept-encoding-defaults/harness/snippets/node-http-verify.mjs) and [go-verify.go](https://ipvolt.com/downloads/accept-encoding-defaults/harness/snippets/go-verify.go). - [render_tables.py](https://ipvolt.com/downloads/accept-encoding-defaults/render_tables.py) regenerates the tables from `results.json` or from your own run's `harness/out/results.json`, and [compare.py](https://ipvolt.com/downloads/accept-encoding-defaults/compare.py) compares your rerun with the published one. To reproduce the whole run, unzip the archive, run `./setup.sh` and then `./run.sh` in `harness/`, then `python3 ../compare.py ../results.json out/results.json`. The README lists what setup downloads and what each group of cells needs. No proxy account is needed. ipvolt, which publishes this guide, sells mobile proxies and residential proxies from $2.20/GB. The measurements use a local test proxy; the advice applies to any provider or none. ## Sources & further reading - [RFC 9110: CONNECT tunnels and the HTTPS scheme](https://www.rfc-editor.org/rfc/rfc9110.html#name-connect) - [Python 3.14 gzip: gzip.decompress and multi-member streams](https://docs.python.org/3.14/library/gzip.html#gzip.decompress) - [Node.js 26.10.0: resource timing buffer limit](https://github.com/nodejs/node/blob/v26.10.0/lib/internal/perf/observe.js#L103) - [RFC 9110 section 12.5.3: Accept-Encoding (no header, identity, empty value)](https://www.rfc-editor.org/rfc/rfc9110.html#name-accept-encoding) - [RFC 9110 section 15.4.5: 304 Not Modified (no content)](https://www.rfc-editor.org/rfc/rfc9110.html#name-304-not-modified) - [curl man page: --compressed (the page describes 8.23.0; this text is unchanged since the tested 8.22.0)](https://curl.se/docs/manpage.html#--compressed) - [curl man page: --max-filesize and decompression (since 8.20.0)](https://curl.se/docs/manpage.html#--max-filesize) - [curl man page: -w, %{size_download} and %header{} (added in 7.84.0)](https://curl.se/docs/manpage.html#-w) - [libcurl: CURLOPT_ACCEPT_ENCODING (default NULL, no header and no decoding)](https://curl.se/libcurl/c/CURLOPT_ACCEPT_ENCODING.html) - [curl issue #11091: no Accept-Encoding by default, captured with nc](https://github.com/curl/curl/issues/11091) - [curl issue #7516: curl can only ask for compression](https://github.com/curl/curl/issues/7516) - [curl issue #2836: raw gzip output when a server compresses unasked](https://github.com/curl/curl/issues/2836) - [Everything curl: HTTP compression applies to downloads](https://everything.curl.dev/http/modify/compression.html) - [CPython 3.14.7 http.client: Accept-Encoding identity](https://github.com/python/cpython/blob/v3.14.7/Lib/http/client.py#L1296-L1299) - [urllib3 2.8.0 util/request.py: gzip, deflate, br and zstd tokens](https://github.com/urllib3/urllib3/blob/2.8.0/src/urllib3/util/request.py#L22-L41) - [urllib3 2.8.0 connection.py: the request path adds no compression header](https://github.com/urllib3/urllib3/blob/2.8.0/src/urllib3/connection.py#L525-L531) - [Requests 2.34.2 utils.py: default Accept-Encoding](https://github.com/psf/requests/blob/v2.34.2/src/requests/utils.py#L91-L93) - [httpx 0.28.1 _decoders.py: br needs brotli, zstd needs zstandard](https://github.com/encode/httpx/blob/0.28.1/httpx/_decoders.py#L381-L393) - [HTTPX documentation: optional brotli and zstd decoders](https://www.python-httpx.org/) - [aiohttp 3.14.3 http_parser.py: Can not decode content-encoding](https://github.com/aio-libs/aiohttp/blob/v3.14.3/aiohttp/http_parser.py#L1147-L1159) - [Scrapy 2.19.0 release notes: br and zstd required since 2.18.0](https://github.com/scrapy/scrapy/blob/2.19.0/docs/news.rst) - [Python 3.14: compression.zstd](https://docs.python.org/3.14/library/compression.zstd.html) - [Node.js 26.10.0 bundled undici fetch: Accept-Encoding by scheme and Range](https://github.com/nodejs/node/blob/v26.10.0/deps/undici/src/lib/web/fetch/index.js#L1562-L1576) - [Node.js 24.21.0 bundled undici fetch](https://github.com/nodejs/node/blob/v24.21.0/deps/undici/src/lib/web/fetch/index.js#L1514-L1528) - [Node.js 22.23.3 bundled undici fetch: no zstd decoder](https://github.com/nodejs/node/blob/v22.23.3/deps/undici/src/lib/web/fetch/index.js#L2149-L2170) - [Node.js 26.10.0 core HTTP client (no Accept-Encoding)](https://github.com/nodejs/node/blob/v26.10.0/lib/_http_client.js) - [Node.js zlib: compressing HTTP requests and responses](https://nodejs.org/api/zlib.html#compressing-http-requests-and-responses) - [node-fetch discussion #1556: default gzip, deflate, br](https://github.com/node-fetch/node-fetch/discussions/1556) - [axios 1.20.0 http adapter: default Accept-Encoding and zstd opt-in](https://github.com/axios/axios/blob/v1.20.0/lib/adapters/http.js#L54-L57) - [got 16.0.0 core: default accept-encoding](https://github.com/sindresorhus/got/blob/v16.0.0/source/core/index.ts#L2248-L2258) - [Go 1.27.1 net/http transport.go: DisableCompression and automatic gzip](https://github.com/golang/go/blob/go1.27.1/src/net/http/transport.go#L199-L207) - [Go 1.27.1 net/http response.go: Response.Uncompressed](https://github.com/golang/go/blob/go1.27.1/src/net/http/response.go#L93-L100) - [GNU Wget manual: --compression (none is the default)](https://www.gnu.org/software/wget/manual/wget.html#HTTP-Options) - [GNU Wget2 2.3.0 wget.c: default Accept-Encoding](https://gitlab.com/gnuwget/wget2/-/blob/v2.3.0/src/wget.c#L4306-4331) - [Fedora change: Wget2 as wget](https://fedoraproject.org/wiki/Changes/Wget2asWget) - [PHP manual: cURL constants, CURLOPT_ACCEPT_ENCODING](https://www.php.net/manual/en/curl.constants.php) - [Guzzle 8.2.0 CurlFactory.php: Accept-Encoding suppressed by default](https://github.com/guzzle/guzzle/blob/8.2.0/src/Handler/CurlFactory.php#L2609-L2622) - [Guzzle 8.2.0 Client.php: a string decode_content becomes the header](https://github.com/guzzle/guzzle/blob/8.2.0/src/Client.php#L1582-L1586) - [Guzzle request options: decode_content](https://docs.guzzlephp.org/en/stable/request-options.html#decode-content) - [Laravel 13.33.0 PendingRequest.php: a plain Guzzle client](https://github.com/laravel/framework/blob/v13.33.0/src/Illuminate/Http/Client/PendingRequest.php) - [Cloudflare: Content compression](https://developers.cloudflare.com/speed/optimization/content/compression/) - [Apache HTTP Server 2.4: mod_deflate and proxy servers](https://httpd.apache.org/docs/2.4/mod/mod_deflate.html) - [nginx: ngx_http_gzip_static_module (gzip_static always)](https://nginx.org/en/docs/http/ngx_http_gzip_static_module.html) - [OpenSearch issue #17339: REST API hangs with Accept-Encoding zstd](https://github.com/opensearch-project/OpenSearch/issues/17339) - [MDN: Accept-Encoding](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Accept-Encoding) - [Chrome Platform Status: Zstd Content-Encoding (Chrome 123)](https://chromestatus.com/feature/6186023867908096) - [Web Almanac 2021: Compression](https://almanac.httparchive.org/en/2021/compression) - [Decodo help: how proxy traffic is calculated (vendor documentation)](https://help.decodo.com/docs/proxy-traffic) ## Related guides - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) - [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md) - [Use a proxy with Node.js fetch](https://ipvolt.com/guides/nodejs-fetch-proxy.md) - [HTTPX async proxies: setup and PoolTimeout diagnosis](https://ipvolt.com/guides/httpx-async-proxy.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 94 of 138: Axios proxy setup: routing, auth and NO_PROXY URL: https://ipvolt.com/guides/axios-proxy-setup Markdown: https://ipvolt.com/guides/axios-proxy-setup.md # Axios proxy setup: routing, auth and NO_PROXY Source: https://ipvolt.com/guides/axios-proxy-setup Markdown: https://ipvolt.com/guides/axios-proxy-setup.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Axios proxy setup: routing, auth and NO_PROXY](https://ipvolt.com/guides/axios-proxy-setup.md) Category: Integration Reviewed: 2026-09-28 Published: 2026-09-28 Reading time: 8 minutes Author: ipvolt Configure Axios proxies in Node.js, separate explicit settings from environment and agent routing, and reproduce authentication and TLS checks. For Axios in Node.js, start with the HTTP adapter and an explicit `proxy` object. Keep proxy credentials in `proxy.auth`, verify the route, and only then add environment variables or custom agents. Those layers can change the connection: in our local test, `proxy: false` still used a proxy when a custom Node agent had `proxyEnv` configured. Is a proxy you already configured being skipped, or failing? [Axios proxy not working: 16 causes and fixes](/guides/fix-axios-proxy-not-working) goes through them by symptom, including Axios 1.21, where `proxy: false` now bypasses such an agent. This guide uses **Axios 1.20.0 and Node.js 24.20.0**. Its 15 routing cases and four recipe checks are synthetic loopback tests, not measurements of an external proxy service. Browser Axios and the Axios fetch adapter are different paths; the `proxy` option belongs to Node's HTTP adapter. See [Axios configuration](https://axios.rest/pages/advanced/request-config) and the [pinned HTTP adapter](https://github.com/axios/axios/blob/v1.20.0/lib/adapters/http.js). ## Run one explicit proxy check Use [proxy-check.mjs](https://ipvolt.com/downloads/axios-proxy-setup/proxy-check.mjs), [package.json](https://ipvolt.com/downloads/axios-proxy-setup/package.json) and the [lockfile](https://ipvolt.com/downloads/axios-proxy-setup/package-lock.json) together. In a new directory, with Node 24.20.0 or later in the Node 24 line: ```sh for file in package.json package-lock.json proxy-check.mjs; do curl --fail --silent --show-error \ "https://ipvolt.com/downloads/axios-proxy-setup/$file" -o "$file" || exit 1 done npm ci --ignore-scripts --no-audit --no-fund ``` Have your secret manager supply `PROXY_HOST`, `PROXY_PORT`, `PROXY_USER` and `PROXY_PASSWORD`, then run `node proxy-check.mjs`. `PROXY_HOST` is a hostname without a scheme or credentials. `PROXY_PROTOCOL` defaults to `http`; use `https` only for a provider-documented TLS proxy endpoint. It describes the connection **to the proxy**, not the destination. Do not put real passwords into shell history or a coding-agent prompt. The checker builds this configuration using separate credential fields: ```js const proxy = { protocol: process.env.PROXY_PROTOCOL || 'http', host: process.env.PROXY_HOST, port: Number(process.env.PROXY_PORT), auth: { username: process.env.PROXY_USER, password: process.env.PROXY_PASSWORD, }, }; ``` This excerpt shows the shape; the downloadable script validates its inputs and performs the request. It selects `adapter: 'http'`, disables redirects, caps the response at 4 KiB, and has a 5-second Axios timeout plus a 6-second abort signal. It checks that the returned JSON contains a valid IP address and prints only the result, status and an IP or error code. It does not print Axios's raw error or request configuration, which can contain credentials. Running the script sends a request through your proxy to the third-party [ipify IPv4 JSON endpoint](https://www.ipify.org/) by default. That service observes the request's public source address. Set a credential-free HTTPS `CHECK_URL` for an approved endpoint returning the same `{ "ip": "..." }` shape. An observed IP is one route check; it does not verify a country, carrier, residential classification or performance guarantee. We tested the checker with controlled local responses, not public ipify. Basic credentials sent to an ordinary HTTP proxy are not encrypted on the client-to-proxy connection merely because the destination is HTTPS. Use a TLS proxy endpoint when supported and keep certificate verification enabled. The lab tests an HTTP proxy tunnelling to a trusted HTTPS origin; it does not test TLS transport to the proxy itself. ## Choose which layer owns routing These observations use the pinned fixture with native environment-proxy startup flags disabled. “Direct” means the fixture proxy received nothing; “proxied” means it recorded a request or CONNECT. The raw [results](https://ipvolt.com/downloads/axios-proxy-setup/results.json) retain those observations. | Configuration | Observed route | What to check | | --- | --- | --- | | HTTP adapter, explicit `proxy`, conflicting environment and `NO_PROXY` | Explicit proxy | Start here for a reproducible baseline. | | HTTP adapter, no explicit proxy, matching `HTTP_PROXY` or `HTTPS_PROXY` | Environment proxy | Inspect the process environment as well as application code. | | Environment-selected proxy, matching `NO_PROXY` entry | Direct | Success alone does not prove proxy use. | | `proxy: false`, ordinary agent | Direct | Axios environment selection is disabled in this case. | | Ordinary custom `http.Agent`, no explicit proxy | Axios environment proxy | Supplying an agent does not automatically remove Axios's environment handling. | | Custom `http.Agent({ proxyEnv: ... })`, plus `proxy: false` | Agent's proxy | The agent still controls routing. | | Fetch adapter, Axios `proxy` object | Direct | HTTP-adapter options do not configure this adapter. | For environment-driven routing, `HTTP_PROXY` applies to an HTTP destination and `HTTPS_PROXY` to an HTTPS destination. The value's scheme still describes the proxy: `HTTPS_PROXY=http://gateway:port` can select an HTTP proxy for an HTTPS destination. The [environment variables guide](/guides/proxy-environment-variables) explains inheritance. The existing [NO_PROXY matrix](/blog/no-proxy-matching-tested) covers its own named clients and versions, not this Axios experiment. The native agent row is the exception to a blanket reading of “false disables proxies.” [Node's built-in proxy support](https://nodejs.org/download/release/v24.20.0/docs/api/http.html#built-in-proxy-support) can give an agent its own routing configuration. In the fixture, `proxy: false` plus that agent still used its proxy; replacing it with a plain agent made the control request direct. We did not test every startup flag or third-party agent. Inspect the agent supplied to your process rather than treating an Axios setting as a network-wide guarantee. For native Node `fetch`, use the [Undici dispatcher guide](/guides/nodejs-fetch-proxy). An Axios `proxy` object and a fetch dispatcher are different interfaces. ## HTTPS and authentication: find the failing layer Axios 1.20.0's HTTP adapter established a CONNECT tunnel for the lab's HTTPS destination. A trusted local CA allowed the request through; removing that trust produced `DEPTH_ZERO_SELF_SIGNED_CERT`. The proxy saw CONNECT but the HTTPS origin received no application request in the rejected-certificate case. Advice that Axios always needs a separate tunnelling package does not describe this tested version. Use `proxy.auth` for proxy credentials; top-level Axios `auth` is destination authentication. In the successful CONNECT case, the fixture origin received no `Proxy-Authorization` header. The proxy received that credential at the tunnel step. This is scoped to the tested configuration, not arbitrary intercepting proxies or redirects. Wrong credentials produced status `407` and code `ERR_BAD_REQUEST` for both the plain HTTP case and the checker’s HTTPS CONNECT case. The rejected CONNECT reached the proxy but produced no origin request. A raw Axios error can include its credential-bearing configuration: retain a sanitized code and available status instead of logging the whole object. | Observation | Next check | | --- | --- | | Proxy receives nothing, destination succeeds | Explicit versus inherited settings, `NO_PROXY`, selected adapter and agent ownership. | | Proxy rejects authentication | Gateway, authentication method and account scope; follow the [407 guide](/guides/fix-proxy-error-407). | | CONNECT succeeds, then certificate verification fails | Origin trust chain and hostname; keep TLS verification enabled. | | Request reaches a stalled origin and times out | Request deadline and origin behaviour; a longer timeout does not establish the cause. | | HTTP 200 with an unexpected body | Validate the response shape before accepting the check. | The stalled HTTP origin produced `ECONNABORTED` with a 100 ms fixture timeout. That establishes a local failure branch, not a useful production timeout or latency benchmark. The reusable checker uses larger bounded deadlines and never retries automatically. ## Reproduce the routing matrix Download [lab.mjs](https://ipvolt.com/downloads/axios-proxy-setup/lab.mjs) alongside the checker and pinned package files, then run: ```sh curl --fail --silent --show-error \ https://ipvolt.com/downloads/axios-proxy-setup/lab.mjs -o lab.mjs node lab.mjs local-results.json ``` The [README](https://ipvolt.com/downloads/axios-proxy-setup/README.md) documents prerequisites and cases. The fixture needs OpenSSL, binds random IPv4 loopback ports, generates a temporary local certificate, and uses invented credentials. Unset native environment-proxy startup flags first; the harness rejects those flags because they alter its baseline. Dependency installation contacts the package registry; fixture requests stay on loopback. Recorded on 28 September 2026 with Node 24.20.0, Axios 1.20.0 and macOS arm64: **15 routing cases and four recipe checks passed**. The checks cover routing, authentication, trusted and untrusted local HTTPS, adapter scope, timeout, valid IP output and unexpected-body rejection. They do not measure provider inventory, anonymity, geography or throughput, and do not test SOCKS, browser Axios, redirects or TLS transport to the proxy. Rerun the fixture after changing Axios, Node, an adapter or an agent. For optional diagnostic help inside a coding agent, [Proxy Toolkit MCP](/mcp) accepts sanitized error descriptions. Keep credentials and private URLs out of its arguments and verify suggested changes with a bounded request. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources & further reading - [Axios: request configuration](https://axios.rest/pages/advanced/request-config) - [Axios 1.20.0: HTTP adapter source](https://github.com/axios/axios/blob/v1.20.0/lib/adapters/http.js) - [Node.js 24.20.0: built-in proxy support](https://nodejs.org/download/release/v24.20.0/docs/api/http.html#built-in-proxy-support) - [ipify: public IP address API](https://www.ipify.org/) ## Related guides - [Axios Proxy Not Working: 16 Causes and Fixes (Tested)](https://ipvolt.com/guides/fix-axios-proxy-not-working.md) - [Use a proxy with Node.js fetch](https://ipvolt.com/guides/nodejs-fetch-proxy.md) - [Fix Node.js TypeError: fetch failed behind a proxy](https://ipvolt.com/guides/fix-node-fetch-failed-proxy.md) - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md) - [Fix proxy error 407 without guessing](https://ipvolt.com/guides/fix-proxy-error-407.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 95 of 138: Node.js fetch Ignores HTTPS_PROXY: Fix UND_ERR_CONNECT_TIMEOUT in One Line URL: https://ipvolt.com/guides/node-fetch-ignores-https-proxy Markdown: https://ipvolt.com/guides/node-fetch-ignores-https-proxy.md # Node.js fetch Ignores HTTPS_PROXY: Fix UND_ERR_CONNECT_TIMEOUT in One Line Source: https://ipvolt.com/guides/node-fetch-ignores-https-proxy Markdown: https://ipvolt.com/guides/node-fetch-ignores-https-proxy.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Node.js fetch Ignores HTTPS_PROXY: Fix UND_ERR_CONNECT_TIMEOUT in One Line](https://ipvolt.com/guides/node-fetch-ignores-https-proxy.md) Category: Troubleshooting Published: 2026-10-02 Reading time: 11 minutes Author: ipvolt Node's built-in fetch skips HTTPS_PROXY, so requests hit UND_ERR_CONNECT_TIMEOUT while curl works. Set NODE_USE_ENV_PROXY=1 on Node 22.21+ and 24+. Your script sets `HTTPS_PROXY`, calls `fetch()`, waits ten seconds and dies with this: ```text node:internal/modules/run_main:107 triggerUncaughtException( ^ [TypeError: fetch failed] { [cause]: ConnectTimeoutError: Connect Timeout Error (attempted address: shop.example.de:443, timeout: 10000ms) at onConnectTimeout (node:internal/deps/undici/undici:1991:23) at Immediate._onImmediate (node:internal/deps/undici/undici:1972:11) at process.processImmediate (node:internal/timers:574:21) { code: 'UND_ERR_CONNECT_TIMEOUT' } } Node.js v24.21.0 ``` curl, run in the same shell with the same `HTTPS_PROXY`, gets through: ```sh curl -sS -o /dev/null -w '%{http_code}\n' https://shop.example.de/p/espressomuehle-k2 # 200 ``` Nothing is wrong with the proxy. Node's built-in `fetch` doesn't read `HTTP_PROXY` or `HTTPS_PROXY` unless you tell it to, so it tried to reach the shop directly. The short fix, on Node 22.21 or later and on Node 24 and later: ```sh NODE_USE_ENV_PROXY=1 node price-check.mjs ``` If you pass an undici dispatcher on Node.js 26 and get `invalid onError method` instead of a timeout, see [fetch failed: invalid onError method on Node.js 26](/guides/node-26-invalid-onerror-method). On older releases, including Node 20, you need an undici dispatcher instead. Both are below, along with the traps around them. Every command and output on this page was run on 2 October 2026 against a logging test proxy, on the Node versions listed in [How this was tested](#how-this-was-tested). ## The script that times out The running example is a small job that checks the price of one product on a German shop every hour, through a residential proxy. `shop.example.de` stands in for the real shop: ```js // price-check.mjs: log one product's price every hour. const PRODUCT_URL = 'https://shop.example.de/p/espressomuehle-k2'; const ONE_HOUR = 60 * 60 * 1000; async function checkPrice() { const res = await fetch(PRODUCT_URL, { signal: AbortSignal.timeout(30_000) }); if (!res.ok) throw new Error(`HTTP ${res.status}`); const html = await res.text(); const price = html.match(/itemprop="price" content="([\d.]+)"/)?.[1]; console.log(new Date().toISOString(), price ? `${price} EUR` : 'price not found'); } await checkPrice(); setInterval(() => checkPrice().catch((err) => console.error(err)), ONE_HOUR); ``` The proxy comes from the environment, the way curl, Python Requests and most CLI tools expect it. `proxy.example.net`, `USERNAME` and `PASSWORD` are placeholders for your provider's gateway and credentials; percent-encode any reserved characters in them, and load the real values from your secret manager rather than typing them into shell history: ```sh export HTTPS_PROXY='http://USERNAME:PASSWORD@proxy.example.net:8080' node price-check.mjs ``` On every Node version tested, from 20.20.2 to 26.10.0, this run never contacted the proxy. It failed after about 10.6 seconds with the error above. Node 20 and 22 print the same `[cause]`, under a `TypeError: fetch failed` line with a stack trace instead of the bracketed form. ## Why Node's fetch ignores HTTPS_PROXY Node's built-in `fetch` is [undici](https://github.com/nodejs/undici). Its default dispatcher opens a direct connection to whatever host the URL names. Proxy variables are only read when you opt in: [PR #57165](https://github.com/nodejs/node/pull/57165) added that support in 2025 behind `NODE_USE_ENV_PROXY`, and its description calls the opt-in a first step, with turning it on by default left for later. So the request goes straight to `shop.example.de:443`. In a network where only the proxy may reach the internet, the connection attempt gets no answer, and undici gives up after its 10-second connect timeout with `UND_ERR_CONNECT_TIMEOUT`. Read the address in the message: `attempted address: shop.example.de:443` is the shop, so the proxy was never used. If the message names your proxy's host instead, the proxy itself is unreachable, which is a different problem; [Fix Node.js TypeError: fetch failed behind a proxy](/guides/fix-node-fetch-failed-proxy) decodes that and the other cause strings. Where direct traffic is allowed, there is no error at all. In the test, with no opt-in, a fetch to a host the machine could reach directly returned 200 and the proxy logged nothing. For a price check, that means the shop sees your server's own address instead of the proxy's. ## The one-line fix: NODE_USE_ENV_PROXY=1 or --use-env-proxy Turn on Node's built-in proxy support for the process: ```sh NODE_USE_ENV_PROXY=1 node price-check.mjs # 2026-10-02T12:35:44.149Z 49.90 EUR ``` The command-line flag does the same thing, and it also works in `NODE_OPTIONS`: ```sh node --use-env-proxy price-check.mjs NODE_OPTIONS=--use-env-proxy node price-check.mjs ``` With either one, every tested release that supports it sent `CONNECT shop.example.de:443` to the proxy, with the credentials from the URL, and printed the price. The two switches arrived in different releases: | Opt-in | Added in (Node.js docs) | Test result | | --- | --- | --- | | [`NODE_USE_ENV_PROXY=1`](https://nodejs.org/api/cli.html#node_use_env_proxy1) | v24.0.0, v22.21.0 | Proxied on 22.21.0, 22.23.3, 24.0.0, 24.4.1, 24.5.0, 24.21.0 and 26.10.0. Silently ignored on 20.20.2 and 22.20.0, which timed out as before | | [`--use-env-proxy`](https://nodejs.org/api/cli.html#--use-env-proxy) | v24.5.0, v22.21.0 | Proxied on 22.21.0, 22.23.3, 24.5.0, 24.21.0 and 26.10.0. Node 20.20.2, 22.20.0, 24.0.0 and 24.4.1 refused to start: `bad option: --use-env-proxy` | | `NODE_OPTIONS=--use-env-proxy` | Listed among the options allowed in `NODE_OPTIONS` | Same as the flag. Older releases exit with `--use-env-proxy is not allowed in NODE_OPTIONS` | The [Enterprise network configuration](https://nodejs.org/learn/http/enterprise-network-configuration) guide adds that the same switch routes `node:http` and `node:https` requests from v22.21.0 and v24.5.0. That matched the test: `https.get` used the proxy on 22.21.0 and 24.5.0, and still went direct on 24.0.0 and 24.4.1, where only `fetch` was covered. Things that tripped the test, so they don't trip you: - **Set the variables before Node starts.** Node reads them at startup. A script that assigned `process.env.HTTPS_PROXY` itself and then called `fetch` went direct on every version. - **Keep the scheme in the proxy URL.** With `HTTPS_PROXY=127.0.0.1:3128`, the process exited before running any code with `TypeError: Invalid URL` (`ERR_INVALID_URL`). With credentials but no scheme, it exited with an `Invalid URL protocol` error (`UND_ERR_INVALID_ARG`). - **Set HTTPS_PROXY for https:// URLs.** With only `HTTP_PROXY` set, `fetch` still used it for the HTTPS shop on 22.23.3, 24.21.0 and 26.10.0, but `https.get` went direct. `HTTPS_PROXY` covers both. - **Put the opt-in on the command line, not in an `--env-file`.** Node read `HTTPS_PROXY` from a `.env` file, but `NODE_USE_ENV_PROXY=1` in the same file had no effect on 22.21.0, 22.23.3, 24.5.0, 24.21.0 or 26.10.0. It only worked from the file on 24.0.0 and 24.4.1. With the proxy in `.env` and the flag on the command line, every release that has the flag used the proxy: ```sh node --env-file=.env --use-env-proxy price-check.mjs ``` - **Expect a warning on Node 22.** 22.21.0 and 22.23.3 printed `[UNDICI-EHPA] Warning: EnvHttpProxyAgent is experimental, expect them to change at any time.` The request still went through the proxy. - **A 407 is a credentials problem, not this one.** With a wrong password, the error two levels down was `Proxy response (407) !== 200 when HTTP Tunneling`. [Fix proxy error 407](/guides/fix-proxy-error-407) covers it. ## Node 20 and older: route fetch through an undici dispatcher Node 20 has no built-in opt-in, and it reached end-of-life on 30 April 2026 according to the [Node.js release schedule](https://github.com/nodejs/Release/blob/main/schedule.json). The same applies to 22.20 and earlier. Upgrading is the real fix. Until then, install undici from npm and set its `EnvHttpProxyAgent` as the global dispatcher. It reads `HTTP_PROXY`, `HTTPS_PROXY` and `NO_PROXY`, in either case, like the built-in support does: ```sh npm install undici@7 ``` ```js // proxy-setup.mjs: send the built-in fetch through HTTP(S)_PROXY on older Node. import { EnvHttpProxyAgent, setGlobalDispatcher } from 'undici'; setGlobalDispatcher(new EnvHttpProxyAgent()); ``` Load it before the script, so `price-check.mjs` stays unchanged: ```sh node --import ./proxy-setup.mjs price-check.mjs ``` With undici 7.30.0, this used the proxy on all nine tested releases, from 20.20.2 to 26.10.0. If you'd rather keep the proxy to one call, pass the agent as a per-request `dispatcher`: ```js import { EnvHttpProxyAgent } from 'undici'; const dispatcher = new EnvHttpProxyAgent(); const res = await fetch('https://shop.example.de/p/espressomuehle-k2', { dispatcher }); console.log(res.status); ``` `ProxyAgent` takes one proxy URL and sends every request through it. Unlike `EnvHttpProxyAgent`, it doesn't read `NO_PROXY`: ```js import { ProxyAgent } from 'undici'; const dispatcher = new ProxyAgent(process.env.HTTPS_PROXY); const res = await fetch('https://shop.example.de/p/espressomuehle-k2', { dispatcher }); console.log(res.status); ``` Both printed `200` through the proxy on every tested release, with the credentials taken from the URL. Pick the undici major with care. undici 7 requires Node 20.18.1 or later, according to its `package.json`. With undici 6.29.0 instead, all three wirings worked on Node 20, 22 and 24, but not on 26.10.0: the global dispatcher was ignored and the request went direct, and a per-request undici 6 dispatcher failed with `UND_ERR_INVALID_ARG`. undici 8 dispatchers have the opposite problem on Node 22 and 24, as recorded in [the fetch failed guide](/guides/fix-node-fetch-failed-proxy), which explains that version skew. On Node 22.21 and later, and on 24 and later, `NODE_USE_ENV_PROXY=1` needs no dependency at all. ## A common wrong turn: https-proxy-agent Search for a Node proxy and you'll find `https-proxy-agent`. It is an agent for `node:http`, `node:https` and libraries built on them. The built-in `fetch` has no `agent` option and silently ignores one: ```js import { HttpsProxyAgent } from 'https-proxy-agent'; const agent = new HttpsProxyAgent(process.env.HTTPS_PROXY); const res = await fetch('https://shop.example.de/p/espressomuehle-k2', { agent }); console.log(res.status); ``` There was no warning on any tested version. The request went direct and failed with `UND_ERR_CONNECT_TIMEOUT` after about 10.6 seconds, exactly as if the agent weren't there. The same agent (https-proxy-agent 9.1.0) works where it belongs. Both of these printed 200 through the proxy on all nine releases: ```js import https from 'node:https'; import { HttpsProxyAgent } from 'https-proxy-agent'; const agent = new HttpsProxyAgent(process.env.HTTPS_PROXY); https.get('https://shop.example.de/p/espressomuehle-k2', { agent }, (res) => { console.log(res.statusCode); res.resume(); }); ``` ```js import fetch from 'node-fetch'; import { HttpsProxyAgent } from 'https-proxy-agent'; const agent = new HttpsProxyAgent(process.env.HTTPS_PROXY); const res = await fetch('https://shop.example.de/p/espressomuehle-k2', { agent }); console.log(res.status); ``` The second one uses the `node-fetch` package (3.3.2), not the built-in `fetch`. If you're on the built-in one, use `NODE_USE_ENV_PROXY` or an undici dispatcher. ## NO_PROXY, and the empty lower-case variable trap Once the opt-in is on, `NO_PROXY` lists the hosts that skip the proxy. A price-check host usually runs next to things that shouldn't go through a paid residential proxy, such as a local database API or a health check. In the test, without `NO_PROXY`, even a request to `http://127.0.0.1` went through the proxy. These are the routes `fetch` took to `https://shop.example.de/` with different `NO_PROXY` values, on Node 22.23.3, 24.21.0 and 26.10.0 with `NODE_USE_ENV_PROXY=1`, and on Node 20.20.2 with the undici 7.30.0 setup above: | NO_PROXY | Route for shop.example.de | | --- | --- | | `localhost,127.0.0.1` | Proxy | | `shop.example.de`, `.example.de` or `*.example.de` | Direct | | `shop.example.de:443` | Direct | | `shop.example.de:8443` | Proxy (the port doesn't match) | | `*` | Direct | | `example.de` | Direct on 20 (undici 7.30.0), 24.21.0 and 26.10.0; proxy on 22.23.3 | Node's HTTP docs describe `example.com` as an exact host match. `https.get` followed that on 24.21.0 and 26.10.0 and used the proxy, while `fetch` on the same versions treated `example.de` as covering `shop.example.de`. [nodejs/node#65616](https://github.com/nodejs/node/issues/65616) tracks the difference. Names are compared as written, so `NO_PROXY=localhost` didn't exempt `http://127.0.0.1`. List the exact hosts you mean, and include both `localhost` and `127.0.0.1` when you need both. Node's docs say the lower-case variable wins when both cases are set. That gets odd when the lower-case one is set but empty, for example by an `export https_proxy=` left in a shell profile or by an empty value in a CI or container config. [nodejs/node#66202](https://github.com/nodejs/node/issues/66202) reports that `fetch` and `http.request()` read an empty value differently. This script sends the same request both ways: ```js // which-route.mjs: send the same request with https.get and with fetch. import https from 'node:https'; const url = 'https://shop.example.de/p/espressomuehle-k2'; const viaGet = await new Promise((resolve) => { const req = https.get(url, { timeout: 15_000 }, (res) => resolve(res.statusCode)); req.on('timeout', () => req.destroy(Object.assign(new Error('timeout'), { code: 'ETIMEDOUT' }))); req.on('error', (err) => resolve(err.code)); }); const viaFetch = await fetch(url, { signal: AbortSignal.timeout(15_000) }) .then((res) => res.status, (err) => err.cause?.code ?? err.name); console.log({ viaGet, viaFetch }); ``` In the test network, 200 means the request went through the proxy, and a timeout means it went direct. With `NODE_USE_ENV_PROXY=1` on 22.21.0, 22.23.3, 24.5.0, 24.21.0 and 26.10.0: | Environment | `https.get` | `fetch` | | --- | --- | --- | | `HTTPS_PROXY` set | Proxy (200) | Proxy (200) | | `HTTPS_PROXY` set, `https_proxy=''` | Proxy (200) | Direct (`UND_ERR_CONNECT_TIMEOUT`) | | `HTTPS_PROXY` set, `no_proxy=''`, `NO_PROXY='*'` | Direct (`ETIMEDOUT`) | Proxy (200) | `fetch` treats an empty lower-case variable as set, so `https_proxy=''` switches the proxy off for it and `no_proxy=''` cancels `NO_PROXY`. `https.get` treats an empty value as unset and falls back to the upper-case one. The undici 7.30.0 `EnvHttpProxyAgent` on Node 20 behaved like `fetch`. The plain-HTTP version from the issue reproduced the same way. On 2 October 2026 the issue is open and [the proposed fix](https://github.com/nodejs/node/pull/66210) was closed without merging, so don't rely on either reading. Unset the empty variables instead. This prints which proxy variables a process sees, without their values: ```sh node -e "for (const k of ['https_proxy', 'HTTPS_PROXY', 'http_proxy', 'HTTP_PROXY', 'no_proxy', 'NO_PROXY']) console.log(k, process.env[k] === undefined ? 'unset' : process.env[k] === '' ? 'EMPTY' : 'set')" unset https_proxy no_proxy ``` Run the check in the same environment as the job, such as the cron line, systemd unit or container, not just your terminal. For how curl, Python and Node each read these variables, see [proxy environment variables](/guides/proxy-environment-variables). ## Which fix for which Node version | Node.js | Bundled undici (tested release) | What to use | | --- | --- | --- | | 20.x (end-of-life) | 6.24.1 (20.20.2) | undici 7 `EnvHttpProxyAgent` via `--import ./proxy-setup.mjs`, then upgrade | | 22.0 to 22.20 | 6.21.2 (22.20.0) | The undici 7 dispatcher, or update to the latest 22.x | | 22.21 and later | 6.22.0 to 6.28.1 (22.21.0, 22.23.3) | `NODE_USE_ENV_PROXY=1` or `--use-env-proxy` | | 24.0 to 24.4 | 7.8.0 to 7.11.0 (24.0.0, 24.4.1) | `NODE_USE_ENV_PROXY=1`; the flag doesn't exist yet | | 24.5 and later | 7.12.0 to 7.29.1 (24.5.0, 24.21.0) | `NODE_USE_ENV_PROXY=1` or `--use-env-proxy` | | 26.x | 8.10.2 (26.10.0) | `NODE_USE_ENV_PROXY=1` or `--use-env-proxy` | Node 18 and earlier, and the odd-numbered lines, were not tested. Check your version with `node -v`, using the same binary the job runs. ## The price check, end to end The script is the same file as at the top. Only the way it starts changes. On Node 22.21 or later, or 24 and later: ```sh export HTTPS_PROXY='http://USERNAME:PASSWORD@proxy.example.net:8080' export NO_PROXY='localhost,127.0.0.1' NODE_USE_ENV_PROXY=1 node price-check.mjs # 2026-10-02T13:20:12.538Z 49.90 EUR ``` On Node 20, with `undici@7` installed and `proxy-setup.mjs` next to the script: ```sh node --import ./proxy-setup.mjs price-check.mjs # 2026-10-02T13:20:11.398Z 49.90 EUR ``` The process stays running, and `setInterval` repeats the check every hour. In the test, the proxy logged one authenticated `CONNECT shop.example.de:443` for the check, and the shop received the request without the `Proxy-Authorization` header. A 200 alone doesn't prove the route: confirm it in your provider's dashboard or request log, or point the script once at an endpoint you control that reports the caller's IP address. ## How this was tested On 2 October 2026, on an Ubuntu VPS (linux-x64), with the official Node.js tarballs v20.20.2, v22.20.0, v22.21.0, v22.23.3, v24.0.0, v24.4.1, v24.5.0, v24.21.0 and v26.10.0, each checked against its published SHA-256. npm packages: undici 7.30.0 and 6.29.0, https-proxy-agent 9.1.0 and node-fetch 3.3.2. curl 8.18.0. Each case ran as its own process inside a separate Linux network namespace. There, `shop.example.de` resolved to 203.0.113.10, an address reserved for documentation, and every packet to a non-loopback address was dropped, so a direct connection could only time out. The only route to the shop was a loopback forward proxy that required Basic authentication and logged every `CONNECT` and forwarded request. Behind it, a local HTTPS server answered for `shop.example.de` with a certificate from a throwaway CA, which the processes trusted through `NODE_EXTRA_CA_CERTS` and curl through `CURL_CA_BUNDLE`. The test credentials were invented and the placeholders above replaced them. A route counts as "proxy" only when the proxy logged an authenticated request for that host. The test didn't cover macOS or Windows (where environment variable names aren't case-sensitive), HTTPS or SOCKS proxies, a real provider's network, Docker, or Node 18, 23 and 25. Timings come from the namespace and say nothing about a real proxy's speed. ## Related guides - [Proxy environment variables: HTTP_PROXY and NO_PROXY](/guides/proxy-environment-variables) explains how curl, Python Requests and Node each read the variables. - [Fix proxy error 407 without guessing](/guides/fix-proxy-error-407) helps once the proxy is in use but rejects your credentials. - [Fix ERR_TUNNEL_CONNECTION_FAILED](/guides/fix-err-tunnel-connection-failed) covers the same proxy refusals in Playwright and Puppeteer. - [Fix Node.js TypeError: fetch failed behind a proxy](/guides/fix-node-fetch-failed-proxy) decodes every other cause behind `fetch failed`. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources & further reading - [Node.js Learn: Enterprise network configuration](https://nodejs.org/learn/http/enterprise-network-configuration) - [Node.js CLI: NODE_USE_ENV_PROXY=1](https://nodejs.org/api/cli.html#node_use_env_proxy1) - [Node.js CLI: --use-env-proxy](https://nodejs.org/api/cli.html#--use-env-proxy) - [Node.js HTTP: built-in proxy support and the NO_PROXY format](https://nodejs.org/api/http.html#built-in-proxy-support) - [nodejs/node PR #57165: support HTTP[S]_PROXY environment variables in fetch](https://github.com/nodejs/node/pull/57165) - [nodejs/node issue #66202: fetch() and http.request() disagree when a lower-cased proxy variable is empty](https://github.com/nodejs/node/issues/66202) - [nodejs/node issue #65616: NO_PROXY=example.com and subdomains, http.request() vs fetch()](https://github.com/nodejs/node/issues/65616) - [undici 7.30.0: EnvHttpProxyAgent](https://github.com/nodejs/undici/blob/v7.30.0/docs/docs/api/EnvHttpProxyAgent.md) - [undici 7.30.0: ProxyAgent](https://github.com/nodejs/undici/blob/v7.30.0/docs/docs/api/ProxyAgent.md) - [Node.js release schedule (end-of-life dates)](https://github.com/nodejs/Release/blob/main/schedule.json) ## Related guides - [fetch failed: invalid onError method on Node 26 (undici fix)](https://ipvolt.com/guides/node-26-invalid-onerror-method.md) - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md) - [Fix proxy error 407 without guessing](https://ipvolt.com/guides/fix-proxy-error-407.md) - [Fix ERR_TUNNEL_CONNECTION_FAILED in Playwright and Puppeteer](https://ipvolt.com/guides/fix-err-tunnel-connection-failed.md) - [Fix Node.js TypeError: fetch failed behind a proxy](https://ipvolt.com/guides/fix-node-fetch-failed-proxy.md) - [Use a proxy with Node.js fetch](https://ipvolt.com/guides/nodejs-fetch-proxy.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 96 of 138: SSL WRONG_VERSION_NUMBER behind a proxy: which hop failed URL: https://ipvolt.com/guides/fix-ssl-wrong-version-number-proxy Markdown: https://ipvolt.com/guides/fix-ssl-wrong-version-number-proxy.md # SSL WRONG_VERSION_NUMBER behind a proxy: which hop failed Source: https://ipvolt.com/guides/fix-ssl-wrong-version-number-proxy Markdown: https://ipvolt.com/guides/fix-ssl-wrong-version-number-proxy.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [SSL WRONG_VERSION_NUMBER behind a proxy: which hop failed](https://ipvolt.com/guides/fix-ssl-wrong-version-number-proxy.md) Category: Troubleshooting Published: 2026-10-04 Reading time: 8 minutes Author: ipvolt The same SSL wrong version number error comes from two hops behind a proxy. Tell which one failed in curl, Requests and HTTPX, then apply the right fix. `wrong version number` is what OpenSSL reports when it starts a TLS handshake and the first bytes of the reply are not TLS. In practice they are plain HTTP: the client sent a ClientHello to a port that answers in cleartext, and a reply such as `HTTP/1.1 400 Bad Request` cannot be read as a TLS record. No certificate, protocol version or cipher is involved, so `--tlsv1.2`, `--insecure` and `verify=False` change nothing. Behind a proxy that handshake can happen in two places, and most clients print the same text for both: 1. **Proxy hop.** The proxy URL says `https://`, so the client starts TLS with the proxy itself, but the proxy port speaks plain HTTP. 2. **Target hop.** The proxy URL says `http://`, `CONNECT` succeeds, and the client starts TLS through the tunnel with a target port that doesn't speak TLS, such as `https://example.com:80/`. | Client | Case 1: proxy hop | Case 2: target hop | | --- | --- | --- | | curl 8.18.0 | `curl: (35) TLS connect error: error:0A00010B:SSL routines::wrong version number` | The same line | | Requests 2.34.2 | `ProxyError`: `Unable to connect to proxy. Your proxy appears to only use HTTP and not HTTPS, try changing your proxy URL to be HTTP.` | `SSLError`: `[SSL: WRONG_VERSION_NUMBER] wrong version number`, with no hint | | HTTPX 0.28.1 | `ConnectError: [SSL: WRONG_VERSION_NUMBER] wrong version number` | The same line | Only Requests names the hop. With curl and HTTPX you need one more check, described next. The Python rows come from Python 3.12.3 with OpenSSL 3.0.13; newer OpenSSL builds word the same failure differently, and the last table on this page lists every string recorded. ## Tell the two hops apart **Read the proxy URL first.** Case 1 needs an `https://` proxy URL. Print what the process really uses, including variables you didn't set yourself: ```sh env | grep -i _proxy ``` If every proxy URL already starts with `http://`, you are in case 2. **curl: read the CONNECT status.** `%{http_connect}` is the status of the proxy's reply to `CONNECT`. Zero means curl never got that far. ```sh curl --silent --show-error --output /dev/null \ --proxy "$PROXY_URL" \ --write-out 'connect=%{http_connect} exit=%{exitcode}\n' \ https://example.com/ ``` - `connect=000 exit=35`: the handshake with the proxy failed. Case 1. - `connect=200 exit=35`: the tunnel opened and the handshake with the target failed. Case 2. `curl -v` shows the same thing. In case 2 these lines come before the error; in case 1 there is no `CONNECT` line at all: ```text > CONNECT 127.0.0.1:18000 HTTP/1.1 < HTTP/1.1 200 Connection established * CONNECT tunnel established, response 200 * TLS connect error: error:0A00010B:SSL routines::wrong version number ``` Verbose output also prints the `Proxy-Authorization` header, so share the write-out line, not the trace. **Requests: read the exception class.** `requests.exceptions.ProxyError` means the connection to the proxy failed. `requests.exceptions.SSLError` means TLS failed after the tunnel was open. ```python import requests proxy_url = "http://USERNAME:PASSWORD@proxy.example.net:8080" proxies = {"http": proxy_url, "https": proxy_url} try: requests.get("https://example.com/", proxies=proxies, timeout=(10, 20)) except requests.exceptions.ProxyError as error: print("proxy hop:", type(error).__name__) except requests.exceptions.SSLError as error: print("target hop:", type(error).__name__) ``` The hint comes from urllib3, which adds it only when the proxy URL scheme is `https` and the TLS error contains `wrong version number`, `unknown protocol` or `record layer failure`. Older releases were less careful: urllib3 1.26.8 printed the hint for `http://` proxy URLs too ([issue #2564](https://github.com/urllib3/urllib3/issues/2564)). On an old urllib3, trust the proxy URL you printed, not the hint. **HTTPX: change the scheme, or read the httpcore log.** HTTPX raises the same `ConnectError` for both. If the proxy URL is `https://`, change it to `http://` and run again: when the error goes away it was case 1, and when the same error remains it is case 2. For a direct answer, turn on debug logging: ```python import logging logging.basicConfig(level=logging.DEBUG) ``` Case 2 logs a `CONNECT` that returns 200, then a failure in `httpcore.proxy`: ```text DEBUG:httpcore.http11:receive_response_headers.complete return_value=(b'HTTP/1.1', 200, b'Connection established', []) DEBUG:httpcore.proxy:start_tls.failed exception=ConnectError(SSLError(1, '[SSL: RECORD_LAYER_FAILURE] record layer failure (_ssl.c:1081)')) ``` Case 1 logs no `CONNECT`, and the failing line is `httpcore.connection:start_tls.failed`. This log is from Python 3.14.4 with OpenSSL 3.5.5, which is why it says `RECORD_LAYER_FAILURE`. ## Fix case 1: write http:// in the proxy URL The scheme in a proxy URL describes how the client talks to the proxy, not what it fetches through it. An `http://` proxy URL still carries HTTPS traffic: the client sends `CONNECT` in cleartext, then runs TLS with the target inside the tunnel. Use `https://` only when your provider documents a TLS proxy port. curl's `--proxy` documentation treats a missing scheme or `http://` as an HTTP proxy and `https://` as an HTTPS proxy. ```sh curl --proxy http://USERNAME:PASSWORD@proxy.example.net:8080 https://example.com/ ``` ```python import requests proxy_url = "http://USERNAME:PASSWORD@proxy.example.net:8080" response = requests.get( "https://example.com/", proxies={"http": proxy_url, "https": proxy_url}, timeout=(10, 20), ) ``` ```python import httpx with httpx.Client(proxy="http://USERNAME:PASSWORD@proxy.example.net:8080") as client: response = client.get("https://example.com/") ``` ```sh export HTTPS_PROXY=http://USERNAME:PASSWORD@proxy.example.net:8080 export HTTP_PROXY=http://USERNAME:PASSWORD@proxy.example.net:8080 ``` In the lab, the proxy port that failed with `https://` returned 200 in all three clients once the scheme was `http://`, set in code or through `HTTPS_PROXY`. If the error survives the change, an environment variable may still be supplying the old value: Requests and HTTPX both read `HTTPS_PROXY` by default (`trust_env`). [Proxy environment variables](/guides/proxy-environment-variables) covers which variable each client reads, and the [curl](/guides/curl-proxy-setup), [Requests](/guides/python-requests-proxy) and [HTTPX](/guides/httpx-async-proxy) guides have complete setups. ## The trap: the dictionary key is not the proxy's scheme In `proxies={"https": ...}` the key is the scheme of the URL you are requesting. The value is the proxy URL, with its own scheme. The two don't have to match, and for a plain HTTP proxy port they must not: ```python # Case 1: TLS to a proxy port that speaks plain HTTP proxies = {"https": "https://USERNAME:PASSWORD@proxy.example.net:8080"} # Correct: HTTPS targets through an HTTP proxy proxies = {"https": "http://USERNAME:PASSWORD@proxy.example.net:8080"} ``` Environment variables work the same way. The name `HTTPS_PROXY` selects which requests use the proxy, and the value says how to reach it. ## Fix case 2: correct the target URL The proxy is fine. The URL asks for TLS on a port that serves plain HTTP. Typical causes are `https://` combined with port 80 or an internal HTTP port, and a base URL assembled from a scheme and a port that are configured separately. Confirm it by sending plain HTTP through the same tunnel: ```sh curl --silent --show-error --proxy "$PROXY_URL" --proxytunnel \ --write-out 'connect=%{http_connect} status=%{http_code}\n' \ http://example.com:80/ ``` In the lab this printed the page and `connect=200 status=200` for the port that had failed with `https://`, while a port that really speaks TLS gave `curl: (52) Empty reply from server`. An HTTP status here means the port speaks plain HTTP: change the URL to `http://`, or point it at the TLS port. If you are allowed to connect without the proxy, the same URL fails the same way directly, which also clears the proxy. If the URL is right and the error comes and goes, the bytes arriving through the tunnel are not from your target's TLS server. urllib3 issue #2564 reports that pattern with an unstable proxy. Record the `connect=` line with a timestamp and send it to the provider. ## Retries won't fix either case Both cases are configuration errors, and every attempt fails the same way. The `Max retries exceeded` in the Requests message doesn't mean retries ran: the default adapter is configured for zero retries and prints that text anyway. A retry policy only delays the same exception. Fix the URL, and keep retries for failures that can change between attempts. A connection that closes during or after the handshake is one of those failures. After the handshake a retry can re-send work; during it, that attempt was not sent unless TLS early data was on: [SSL EOF occurred in violation of protocol behind a proxy](/guides/fix-ssl-unexpected-eof-proxy) covers when a retry is safe. Inside an MCP-compatible coding agent, the free [Proxy Toolkit MCP](/mcp) diagnoses proxy errors by request phase. Give it the client, the exception and the `connect=` value, without credentials. ## The wording depends on the OpenSSL build The text comes from the TLS library, not from the client, so the same failure reads differently across builds. Each build printed the same string at both hops unless noted: | Build | Error text | | --- | --- | | curl 8.18.0 (OpenSSL 3.5.5), curl 8.17.0 (OpenSSL 3.6.0), curl 8.22.0 (OpenSSL 4.0.2) | `curl: (35) TLS connect error: error:0A00010B:SSL routines::wrong version number` | | curl 8.12.1 (OpenSSL 3.4.1) | `curl: (35) TLS connect error: error:0A0000C6:SSL routines::packet length too long` | | curl 8.7.1 (OpenSSL 3.2.1) | `curl: (35) OpenSSL/3.2.1: error:0A0000C6:SSL routines::packet length too long` | | Python 3.11.3 (OpenSSL 1.1.1s), Python 3.12.3 (OpenSSL 3.0.13) | `[SSL: WRONG_VERSION_NUMBER] wrong version number` | | Python 3.14.4 (OpenSSL 3.5.5) | `[SSL: RECORD_LAYER_FAILURE] record layer failure` | | Node.js 24.20.0 `fetch` (OpenSSL 3.5.7) | `TypeError: fetch failed`, cause code `ERR_SSL_WRONG_VERSION_NUMBER` | | Playwright 1.63.0 (Chromium 153) | Case 1: `net::ERR_PROXY_CONNECTION_FAILED`. Case 2: `net::ERR_SSL_PROTOCOL_ERROR` | So `packet length too long` and `record layer failure` with a proxy in the path are the same two cases. On all three Python builds, Requests raised `ProxyError` with the hint in case 1 and a bare `SSLError` in case 2. `unknown protocol`, the third phrase urllib3 looks for, did not appear on any build tested. Chromium is the one client here that separates the hops by itself; [Fix ERR_TUNNEL_CONNECTION_FAILED](/guides/fix-err-tunnel-connection-failed) covers its proxy errors, and [Node.js fetch failed behind a proxy](/guides/fix-node-fetch-failed-proxy) covers reading the `cause` chain. ## How this was tested On 4 October 2026, on an Ubuntu 26.04 VPS, with everything on `127.0.0.1`: a listener that answers any input with a plaintext `HTTP/1.1 400 Bad Request`, a minimal plain-HTTP `CONNECT` proxy, `python -m http.server` as the plain HTTP target, and the same handler behind a throwaway certificate as a working TLS target. No proxy account and no outbound traffic. Case 1 pointed an `https://` proxy URL at the plaintext listener and at the `CONNECT` proxy. Case 2 used the `CONNECT` proxy with an `https://` URL for the plain HTTP port. A control with the `http://` proxy URL and the TLS target returned 200 in every client. Clients: the curl builds above; Requests 2.34.2 with urllib3 2.8.0 and HTTPX 0.28.1 with httpcore 1.0.9 on the three Python builds; Node.js 24.20.0 `fetch` with `NODE_USE_ENV_PROXY=1`; Playwright 1.63.0 with Chromium 153.0.8010.12. The [lab archive](https://ipvolt.com/downloads/fix-ssl-wrong-version-number-proxy/wrong-version-number-lab.zip) contains the [lab script](https://ipvolt.com/downloads/fix-ssl-wrong-version-number-proxy/lab.py), the client scripts, the [README](https://ipvolt.com/downloads/fix-ssl-wrong-version-number-proxy/README.md) and the [recorded results](https://ipvolt.com/downloads/fix-ssl-wrong-version-number-proxy/results.json). Not tested: macOS and Windows, TLS libraries other than OpenSSL and Chromium's own, SOCKS proxies, real TLS proxy ports and any commercial proxy network. A proxy port that closes the connection or stays silent, with no plaintext reply, was not tested either and may produce a different error. The [SSL EOF guide](/guides/fix-ssl-unexpected-eof-proxy) records what a closing proxy port prints. ## Related guides - [Proxy environment variables: HTTP_PROXY and NO_PROXY](/guides/proxy-environment-variables) explains which variable curl, Requests and Node each read. - [Use a proxy with curl](/guides/curl-proxy-setup) covers `-x`, the `CONNECT` tunnel and curl's exit codes. - [Configure Python Requests](/guides/python-requests-proxy) explains the `proxies` dictionary and `trust_env`. - [HTTPX async proxies](/guides/httpx-async-proxy) covers explicit clients and pool timeouts. - [Fix ERR_TUNNEL_CONNECTION_FAILED](/guides/fix-err-tunnel-connection-failed) covers proxy refusals in Playwright and Puppeteer. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources & further reading - [urllib3: Your proxy appears to only use HTTP and not HTTPS](https://urllib3.readthedocs.io/en/stable/advanced-usage.html#https-proxy-error-http-proxy) - [urllib3 issue #2564: the HTTP-only proxy hint shown for http:// proxy URLs](https://github.com/urllib3/urllib3/issues/2564) - [urllib3 2.8.0 source: _wrap_proxy_error in connection.py](https://github.com/urllib3/urllib3/blob/2.8.0/src/urllib3/connection.py) - [curl: -x, --proxy and the proxy URL scheme](https://curl.se/docs/manpage.html#-x) - [curl: --write-out variables including http_connect](https://curl.se/docs/manpage.html#-w) - [Requests: proxies](https://requests.readthedocs.io/en/latest/user/advanced/#proxies) - [HTTPX: proxies](https://www.python-httpx.org/advanced/proxies/) - [HTTPX: logging](https://www.python-httpx.org/logging/) - [RFC 9110: the CONNECT method](https://www.rfc-editor.org/rfc/rfc9110.html#name-connect) ## Related guides - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md) - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) - [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md) - [HTTPX async proxies: setup and PoolTimeout diagnosis](https://ipvolt.com/guides/httpx-async-proxy.md) - [Fix ERR_TUNNEL_CONNECTION_FAILED in Playwright and Puppeteer](https://ipvolt.com/guides/fix-err-tunnel-connection-failed.md) - [Fix Node.js TypeError: fetch failed behind a proxy](https://ipvolt.com/guides/fix-node-fetch-failed-proxy.md) - [SSL EOF occurred in violation of protocol behind a proxy: was the request sent?](https://ipvolt.com/guides/fix-ssl-unexpected-eof-proxy.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 97 of 138: SSL EOF occurred in violation of protocol behind a proxy: was the request sent? URL: https://ipvolt.com/guides/fix-ssl-unexpected-eof-proxy Markdown: https://ipvolt.com/guides/fix-ssl-unexpected-eof-proxy.md # SSL EOF occurred in violation of protocol behind a proxy: was the request sent? Source: https://ipvolt.com/guides/fix-ssl-unexpected-eof-proxy Markdown: https://ipvolt.com/guides/fix-ssl-unexpected-eof-proxy.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [SSL EOF occurred in violation of protocol behind a proxy: was the request sent?](https://ipvolt.com/guides/fix-ssl-unexpected-eof-proxy.md) Category: Troubleshooting Published: 2026-11-05 Reading time: 22 minutes Author: ipvolt [SSL: UNEXPECTED_EOF_WHILE_READING], SSLEOFError or curl error 0A000126 through a proxy: was the request sent, can you retry, and which side should you check? A failure in the TLS handshake means that attempt was not sent, unless you turned on TLS early data. A failure after the handshake means the outcome is unknown, and the target may already have your request. Either way your last error line describes one attempt, not the whole job. The string says the connection ended while TLS still expected data, and it doesn't say who ended it. No proxy that you know of? [Check that first](#is-a-proxy-in-your-path-at-all): many public reports of these strings involve none. Earlier attempts are a separate question. A mounted `Retry` or `max_retries`, urllib3 used directly, an SDK with built-in retries or a followed redirect can put a POST at the target even when the last line reads as a handshake EOF. Behind an HTTP proxy those retry settings can re-send a POST by themselves, including `Retry(total=3, allowed_methods={"GET"})`. | Your last line | This attempt | | --- | --- | | `SSLError(SSLEOFError(8, '[SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1081)'))`, ``, or that text with no prefix, with a low `_ssl.c` number (we saw 1000 to 1147) | Not sent | | `httpx.ConnectError: [SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1081)` | Not sent | | `ProxyError('Unable to connect to proxy', SSLError(SSLEOFError(8, '[SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1081)')))` | Not sent. If your proxy URL says `https://` and the port speaks plain HTTP, [write `http://`](/guides/fix-ssl-wrong-version-number-proxy) | | `curl: (35) TLS connect error: error:0A000126:SSL routines::unexpected eof while reading`, `curl: (35) Send failure: Broken pipe` or `curl: (35) Recv failure: Connection reset by peer` | Not sent. With `--tls-earlydata`, unknown | | `curl: (56) OpenSSL SSL_read: OpenSSL/3.5.5: error:0A000126:SSL routines::unexpected eof while reading, errno 0` | Unknown | | `ProxyError('Unable to connect to proxy', RemoteDisconnected('Remote end closed connection without response'))` | Unknown | | `SSLEOFError` with a high `_ssl.c` number (we saw 2406 to 3042), or `[SSL: UNEXPECTED_EOF_WHILE_READING] unexpected eof while reading (_ssl.c:2711)` | Unknown | These results are synthetic: our own scripted proxies and target on one machine (the fixture) and named proxy software on loopback. - **Not sent, on a first attempt with no redirect:** a retry can't duplicate anything. - **Not sent after retries or a redirect, or Unknown:** [look for the result at the target](/blog/proxy-retries-duplicate-jobs) before you send a POST again. Give it time: on the fixture a relay that held the request delivered it after the client had printed its error (scripted timing), so an empty lookup straight after the failure proves nothing. With no lookup or idempotency key at the target, the outcome stays unknown: ask its operator, or decide whether a duplicate is worse than a lost request. A followed redirect counts as an earlier attempt: the POST may already sit at the first URL, and the last line can't rule that out. Requests and urllib3 follow them by default and print the next hop, which can be the address you posted to. `urllib.request`, aiohttp, HTTPX's `follow_redirects=True` and `curl -L` print no path. If this endpoint can redirect, treat the POST as unknown, or send it with redirects off. For a safe GET or HEAD a duplicate shouldn't change anything at the target, so go straight to [the comparison below](#target-known-good-direct-which-side-to-look-at). No client-side check can always name the side that closed; the comparison narrows it, and [the table by path](#next-step-by-path) gives the next action. pip ends on `ERROR: No matching distribution found`, so read the `WARNING: Retrying` lines above it. Its `There was a problem confirming the ssl certificate` line blames the certificate, but no certificate was involved. A package download has nothing to duplicate, so a retry is safe, but pip has already retried: next, [check which proxy pip picks up](#is-a-proxy-in-your-path-at-all). The `_ssl.c` numbers change between builds, but [CPython's source](https://github.com/python/cpython/blob/main/Modules/_ssl.c) has kept handshake lines at or below 1176 and read or write lines at or above 1844 from 3.5 to `main`. PyPy prints no number and can swap the wording, so treat its line as unknown. The prefix alone doesn't show the stage: `[SSL: UNEXPECTED_EOF_WHILE_READING]` also printed on a cut upload on Linux, with the headers at the target. Turning off certificate checks doesn't help: `verify=False`, `curl --insecure` and pip's `--trusted-host` printed the same line on the fixture, and `ssl.OP_IGNORE_UNEXPECTED_EOF`, where the build has it, only changed it to `SSLZeroReturnError`. ## Is a proxy in your path at all? ```sh env | grep -i _proxy python3 -c "import urllib.request; print(urllib.request.getproxies())" pip config list ``` The output can hold the proxy password, so don't paste it anywhere. If a proxy shows up that you didn't expect and don't need, remove it (`unset HTTPS_PROXY`, `pip config --user unset global.proxy`), then try a safe request again. The second line [also reads](https://docs.python.org/3/library/urllib.request.html#urllib.request.getproxies) the Windows registry and [a macOS system proxy](https://github.com/NousResearch/hermes-agent/issues/53702). The third covers pip. If nothing is set and you run no local proxy client, this page isn't your main path. Many public reports of these strings involve no proxy. Look here instead: - A large upload or a body limit: [CPython #110467](https://github.com/python/cpython/issues/110467), [UbiOps](https://ubiops.com/docs/troubleshooting/calling-api/sslerror-eof/). - A service refusing your IP: [a Let's Encrypt thread](https://community.letsencrypt.org/t/eof-occurred-in-violation-of-protocol-ssl-c-1131/158369). - An old server with no shared cipher: [urllib3 #3100](https://github.com/urllib3/urllib3/issues/3100), [bpo-45487](https://bugs.python.org/issue45487). - A peer that closes without `close_notify`: [OpenSSL](https://docs.openssl.org/3.5/man3/SSL_CTX_set_options/). - A firewall in the path: [Microsoft Q&A](https://learn.microsoft.com/en-us/answers/questions/1440221/how-to-fix-the-error-eof-occurred-in-violation-of). ## Check the next attempt with a HEAD or GET, never the failed POST A probe describes only the attempt it makes, and it can pass on an intermittent fault. Your last line stays the evidence for the request that failed. Set `PROXY_URL` to the proxy your failing job uses and `TARGET_URL` to the HTTPS address that failed. An empty `PROXY_URL` would turn the proxy off, so these commands stop with an error instead. ```sh curl --silent --show-error --head --output /dev/null --max-time 20 \ --noproxy '' --proxy "${PROXY_URL:?}" \ --write-out 'connect=%{http_connect} exit=%{exitcode} appconnect=%{time_appconnect} http=%{http_code}\n' \ "${TARGET_URL:?}" ``` `connect` is the status of the proxy's reply to `CONNECT` (000 if curl read none). `appconnect` is the seconds until the TLS handshake with the target finished (through a TLS-inspecting proxy, with that proxy). `exit` is curl's exit code: `%{exitcode}` needs curl 7.75 or later; before that, read `$?`. Read `appconnect` before the exit code. On a new connection to an `https://` target with TLS early data off (curl's default), `appconnect` 0 with a non-zero exit meant the attempt that printed it was not sent, on every curl build we ran. A reused connection also reports 0, even with the POST delivered, so use this only on a one-URL run like the one above. Exit 35 on a one-URL HTTP/1.1 run showed 0 unless `-L` or auth negotiation came first. Exit 56 occurred with 0 receipts and with 1 or more (a receipt is one complete request the target read). | Write-out | Meaning | Next | | --- | --- | --- | | `connect=200 exit=35`, `appconnect` 0 | Tunnel opened, handshake through it failed. Not sent | [Compare](#target-known-good-direct-which-side-to-look-at) | | `connect=200 exit=28`, `appconnect` 0 | Tunnel opened, handshake went silent. Not sent | [Timeouts](/guides/proxy-timeout-troubleshooting) | | `connect=000 exit=35`, `https://` proxy URL | TLS to the proxy failed. Not sent | Check the scheme | | `connect=000 exit=7` | Proxy port closed. Not sent | Host and port | | `connect=000 exit=56`, `appconnect` 0, `curl: (56) Proxy CONNECT aborted` or `Recv failure: Connection reset by peer` | Proxy never answered `CONNECT`. Not sent | Proxy's log or provider | | `connect=000 exit=97`, SOCKS5 | Proxy refused or couldn't reach the target. Not sent | Proxy's log or provider | | `connect=502 exit=7` (exit 56 on curl 8.7.1) | Proxy refused the tunnel. Not sent | [Tunnel 502](/guides/fix-proxy-tunnel-502-503), [other codes](/blog/proxy-status-codes-407-429-502) | | `appconnect` above 0, any non-zero exit (we saw 16, 18, 28, 52, 55, 56, 92) | Handshake done, then it ended. Unknown | [Compare](#target-known-good-direct-which-side-to-look-at) | | `connect=200 exit=0`, `appconnect` above 0, any `http` | This attempt got a response, and `http` is its status. It says nothing about the attempt that failed | [Repeat it](#target-known-good-direct-which-side-to-look-at) | Through SOCKS5 `connect` is always `000`, even with the request delivered (120 of 120 calls on loopback), so go by `appconnect` there. No curl? [`ssl_eof_probe.py`](https://ipvolt.com/downloads/fix-ssl-unexpected-eof-proxy/ssl_eof_probe.py) needs only Python and says in words how far one `HEAD` got: `HTTPS_PROXY="$PROXY_URL" python3 ssl_eof_probe.py "$TARGET_URL"`. With no proxy set it stops with an error. We ran it on Linux and macOS, not Windows, and it doesn't test SOCKS5. A wrong scheme can print this string too: an `https://` proxy URL whose handshake closes gives the `ProxyError` with `SSLError` row in the first table. On loopback, 6 of 15 proxy ports with no TLS did this at `connect=000 exit=35` ([rows](https://ipvolt.com/downloads/fix-ssl-unexpected-eof-proxy/real-proxy-tables.md)). If your port has no TLS, [write `http://` in the proxy URL](/guides/fix-ssl-wrong-version-number-proxy), or `socks5h://` if it's a SOCKS5 port. Share the write-out line, not a verbose trace: `curl -v` prints a `Proxy-Authorization: Basic` token that decodes to the password, and `--proxy` shows the password in the process list while curl runs. aiohttp's `ClientHttpProxyError` prints `url='http://USERNAME:PASSWORD@...'` in `str()`. With a well-formed proxy URL, Requests, urllib3, HTTPX and curl's error lines showed no password. A proxy URL a client can't parse is different: with an unencoded `/` in the password, curl printed the whole URL, password included, and Requests, urllib3 and HTTPX printed part or all of it. Requests and urllib3 also print the query string, in the error and in the logging below, so a token in the URL lands in your log. ## ProxyError with RemoteDisconnected('Remote end closed connection without response'): the request may have been sent This is the line you see when a tunnel ends with no response after the handshake. The label `Unable to connect to proxy` can be false: the tunnel had connected, and across 540 single-attempt calls on loopback the target held the complete request in 309, headers only in 179, and nothing in 52. Those count failures we provoked, not rates. urllib3 1.26.20 prints `Cannot connect to proxy.` for this drop and also for a proxy that closes before any tunnel opens, so that line is unknown too. | These read the same way | This attempt | | --- | --- | | `ProxyError('Unable to connect to proxy', ConnectionResetError(104, 'Connection reset by peer'))` | Unknown | | `('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))` | Unknown | | `httpx.RemoteProtocolError: Server disconnected without sending a response.` | Unknown | | `httpx.ReadError` | Unknown | | `Read timed out. (read timeout=3.0)` | Unknown. If your connect and read timeouts differ and the number is the connect one, that case was not sent | | `curl: (52) Empty reply from server` | Unknown | | `curl: (56) Recv failure: Connection reset by peer` | Unknown, unless the write-out shows `appconnect` 0 | Treat this line and `SSLEOFError` as one incident. On the fixture, a job sending GETs while the proxy's exit IP changed saw the in-flight request fail with this `ProxyError`, then `SSLEOFError` on each new tunnel, then 200 (3 of 3 runs on Linux and on macOS). So when a log shows `SSLEOFError`, look one line up. An earlier `ProxyError` is the request that may have landed. To see which side closed it, run the comparison below. Retries can hide that line, and `Max retries exceeded` doesn't show them: it printed after 1 `CONNECT` on a default session and after 4 on `max_retries=3`. Add this before the job's next run: ```python import logging logging.basicConfig(level=logging.WARNING) ``` Then look for a line like this: ```text WARNING:urllib3.connectionpool:Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'RemoteDisconnected('Remote end closed connection without response')': /drop-fin ``` On the fixture a plain script printed no `Retrying` lines and logging printed 3, the first naming `RemoteDisconnected`, and both runs ended on `SSLEOFError` with 1 receipt at the target. Treat any `RemoteDisconnected` or reset line as unknown, whatever the last line says. For a run that already happened with retries on and logging off, treat the earlier attempts as unknown. curl's `--retry-all-errors` re-sends the same way: `--show-error` prints every attempt, and `--silent` alone prints none. ## What each retry setting re-sends Receipts at the target for a POST delivered and then dropped with no response, recorded on the fixture on 5 November 2026, 3 calls per cell. The curl and HTTPX rows come from the named-software run on 4 November (curl flag rows: 18, 12 and 2 calls, left to right). | Setting | HTTP proxy | SOCKS5 (`socks5h://`) | No proxy | | --- | ---: | ---: | ---: | | Requests default session | 1 | 1 | 1 | | `HTTPAdapter(max_retries=3)` | **4** | 1 | 1 | | `Retry(total=3)` | **4** | 1 | 1 | | `Retry(total=3, allowed_methods={"GET"})` | **4** | 1 | 1 | | `Retry(total=3, status_forcelist=[429,500,502,503,504])` | **4** | 1 | 1 | | urllib3 with no `retries` argument | **4** | 1 | 1 | | `Retry(connect=3)` or `Retry(read=3)` | **11** | 1 | 1 | | `Retry(total=3, allowed_methods={"GET", "POST"})`, or `allowed_methods=[]` | **4** | **4** | **4** | | `Retry(total=3, other=0)` | 1 | 1 | 1 | | `HandshakeEOFRetry(total=3, other=0)`, below | 1 | 1 | 1 | | HTTPX default or `HTTPTransport(retries=3)` | 1 | 1 | 1 | | aiohttp default | 1 | not run | 1 | | curl, with or without `--retry 3` | 1 | 1 | 1 | | `curl --retry 3 --retry-all-errors` | **4** | **4** | **4** | `Retry(connect=3)` leaves `total` at its default of 10, and this drop spends `total`. These counts need a close or reset with no response bytes. Other settings and failures: - Zeroing the rest doesn't help: `Retry(total=3, connect=0, read=0, redirect=0, status=0)` still went 4 times through the HTTP proxy. - With `total=None` no retry counter limits it: `Retry(total=None, connect=3, read=3)` was still re-sending there after 15 s, at 374 to 641 receipts, when we stopped it. - A read timeout or a partial status line stayed at 1 on every path. A `100 Continue` and then a close still went 4 times through the HTTP proxy. - A generator body can't be rewound, so its 3 re-sends were empty POSTs. - A delivered PUT or DELETE went 4 times on every path, by design. - With POST in `allowed_methods`, `other=0` stops only the HTTP proxy re-send: through SOCKS5 and with no proxy it still went 4 times. - A loop of your own that catches `requests.exceptions.ConnectionError` re-sends after a drop like this, because `ProxyError` and `SSLError` are subclasses of it. Versions: Requests 2.34.2, urllib3 2.8.0, HTTPX 0.28.1, aiohttp 3.14.5 and curl 8.18.0 on Python 3.14.4 with OpenSSL 3.5.5. urllib3 1.26.20 and `main` at commit `c5347bb` gave the same urllib3 counts, and every release from 1.25.1 to 2.8.0 gave 4 in a separate sweep (`other` needs 1.26). HTTPX passes `retries` to its direct connection pool only, so it does nothing through a proxy. On loopback ([tables](https://ipvolt.com/downloads/fix-ssl-unexpected-eof-proxy/real-proxy-tables.md)), tinyproxy, Squid, gost, proxy.py, mitmproxy in tunnel mode, mihomo, sing-box and Xray gave 4 receipts in 351 of 351 calls across `HTTPAdapter(max_retries=3)`, `Retry(total=3)` and `Retry(total=3, allowed_methods={"GET"})`. Dante and every SOCKS5 port gave 1. When the first attempt was delivered and each retry died in its handshake, those eight ended on `SSLEOFError` with 1 receipt (78 of 78). A retry can also succeed and duplicate: with the proxy killed after delivery and restarted, `Retry(total=3, allowed_methods={"GET"}, backoff_factor=1)` returned HTTP 200 while the target held the POST twice (23 of 23, on those eight plus TLS-inspecting mitmproxy). None of it says how often this happens on a real path, or whether any commercial service behaves this way. Whether upstream intends this is open, so plan for what the installed code does. Requests [documents](https://github.com/psf/requests/blob/v2.34.2/src/requests/adapters.py) that `max_retries` "applies only to failed DNS lookups, socket connections and connection timeouts, never to requests where data has made it to the server", and these counts contradict that. urllib3 [warns](https://urllib3.readthedocs.io/en/2.8.0/reference/urllib3.util.html) of its `other` counter: "These errors might be raised after the request was sent to the server, so the request might have side-effects." The mechanism: behind an HTTP proxy this drop arrives as `ProxyError`, which counts as `other`, and among errors urllib3 [checks the method only for read errors](https://github.com/urllib3/urllib3/blob/2.8.0/src/urllib3/util/retry.py), so `allowed_methods` is never consulted. Through SOCKS5 or with no proxy the same drop is a `ProtocolError`, a read error, and POST stops. On urllib3 2.x `ProxyError` appears because `http.client` closes the connection first and `close()` clears [the flag](https://github.com/urllib3/urllib3/blob/2.8.0/src/urllib3/_base_connection.py) urllib3 uses to tell proxy errors from tunnel errors: keeping the flag in a local patch took this POST from 4 receipts to 1. urllib3 1.26 wraps any socket error behind a proxy as `ProxyError`. On 5 November 2026 we found no maintainer ruling in either project's tracker. A related thread is [urllib3 #1744](https://github.com/urllib3/urllib3/issues/1744), where maintainers called a `ProxyError` hiding a connect failure from `Retry` a bug and fixed the connect side. curl re-sends a POST in other ways too: - Two URLs in one invocation, with the POST lost on the reused connection: 2 receipts with no retry flag on loopback ([52 of 52 calls](https://ipvolt.com/downloads/fix-ssl-unexpected-eof-proxy/real-proxy-facts.json)). TLS-inspecting mitmproxy stayed at 1, and so did a single HTTP/1.1 URL in a fresh process with no `--retry`. If the fresh connection then dies in the handshake, the last line is `curl: (35)` with the POST already at the target. - A long-lived libcurl client: a `curl_cffi` 0.17.0 session with no retry option did the same on the fixture, on all three paths. - `--retry` alone on a timeout or a transient status: `--retry 2` on exit 28 after delivery gave 3 receipts on the fixture and `--retry 3` on 408, 429, 500, 502, 503 or 504 gave 4 with exit 0. A TLS-inspecting proxy can turn the drop into that 502. ## Fixes and what they cost If you can't look up or de-duplicate the POST at the target, use no retries or `Retry(total=3, other=0)`, and add `HandshakeEOFRetry` only if you need retries through an outage. ```python import requests from requests.adapters import HTTPAdapter from urllib3.util import Retry session = requests.Session() session.mount("https://", HTTPAdapter(max_retries=Retry(total=3, other=0))) ``` With urllib3 used directly, pass `retries=False` or `retries=Retry(total=3, other=0)` to the request. `retries=False` also stops it following redirects. | Fix | What it stops | Cost | | --- | --- | --- | | No automatic retry on non-idempotent calls: keep them on a session with no mounted retries, as [RFC 9110 section 9.2.2](https://www.rfc-editor.org/rfc/rfc9110.html#section-9.2.2) asks | Every re-send except a followed 307 or 308, which also needs `allow_redirects=False` | You handle each failure yourself | | `Retry(total=3, other=0)` | The POST re-send after a drop or a corrupted record, on every path | Also stops retrying a handshake EOF (1 `CONNECT` and a failure, where `Retry(total=3)` took 3 and got a 200) and a delivered GET behind an HTTP proxy. Through SOCKS5 or with no proxy that GET still went 4 times | | Idempotency keys | The effect of a duplicate | Works only where the endpoint implements the key. See [what a key does and doesn't do](/blog/proxy-retries-duplicate-jobs) | | `HandshakeEOFRetry(..., other=0)` | Every POST re-send except after a handshake that died or a connect that failed, and a followed 307 or 308, which also needs `allow_redirects=False`. If you add POST to `allowed_methods`, it re-sends through SOCKS5 and with no proxy | Doesn't retry a stalled handshake or a `CONNECT` the proxy refuses or drops. It relies on a private urllib3 method: if a later version stops calling it, handshakes stop being retried with no warning, and no duplicates follow. Rerun the fixture when you upgrade | [`retry_handshake_eof.py`](https://ipvolt.com/downloads/fix-ssl-unexpected-eof-proxy/retry_handshake_eof.py) tests where the error was raised (`do_handshake`), not what it says. Recorded on 5 November 2026 in 15 pairings of OpenSSL 1.1.1s to 4.1.0, LibreSSL 2.8.3 and urllib3 1.26.20 to `main`, it recovered from handshake failures and its retries never re-sent a POST after delivery. In your own retry loop, `died_in_handshake(error)` from the same file tests the last attempt only, so call it with no mounted retries and `allow_redirects=False`. On a default session a 303 or 307 whose next hop died in the handshake made it return True with the POST at the first URL, and a loop that re-sent on True put it there 3 times on the fixture. Simpler tests fail. Matching the `SSLEOFError` class sent a cut upload 4 times on OpenSSL 1.1.1s and 3.0.13 and on PyPy. Matching `UNEXPECTED_EOF` never retried on LibreSSL, OpenSSL 1.1.1s or Python 3.9.25. SOCKS5 isn't a way out. Clean closes and resets stayed at 1, but a corrupted TLS record after a complete POST went 4 times with `Retry(total=3)`, through SOCKS5 and with no proxy, because it counts as `other`. A cut upload also reached the target more than once on some builds, as headers with no complete body. Delivery stays unknown through SOCKS5 too, and not every proxy offers it. ## A retry that waits On the fixture `Retry(total=3)` spent its 4 attempts in under 10 ms, all inside one outage. This version uses the helper above and waits: ```python import requests from requests.adapters import HTTPAdapter from retry_handshake_eof import HandshakeEOFRetry proxy_url = "http://USERNAME:PASSWORD@proxy.example.net:8080" session = requests.Session() session.trust_env = False session.proxies = {"http": proxy_url, "https": proxy_url} retries = HandshakeEOFRetry(total=6, other=0, backoff_factor=1) session.mount("https://", HTTPAdapter(max_retries=retries)) response = session.post("https://example.com/price-checks", json={"sku": "A-100"}, timeout=(10, 20)) print(response.status_code) ``` `trust_env = False` stops an `HTTPS_PROXY` variable overriding `session.proxies`, and it also ignores `REQUESTS_CA_BUNDLE`. Against a 20 s outage on the fixture this attempted at about 0, 0, 2, 6, 14 and 30 s, and the last one got a 200. A GET can use plain `Retry(total=6, backoff_factor=1)`. From a shell, `--retry` alone did not retry exit 35. To retry it, wrap curl in a loop that waits and re-sends only on exit 35 with `appconnect` 0. Run one URL, put `-q` first so `~/.curlrc` can't add flags, and use no redirect flag, `--retry` or `--tls-earlydata`: with any of those, exit 35 can follow a delivered POST. How long to wait depends on the proxy's route out, so measure your own path or ask your provider. ## Target, known-good, direct: which side to look at Set `KNOWN_GOOD_URL` to a small, unrelated HTTPS page you may fetch and the proxy allows. The block sends the same `HEAD` to the target through the proxy, to that page through the proxy, and to the target from your own address: the second line shows whether every tunnel fails, the third whether direct clients fail too. ```sh probe() { curl --silent --show-error --head --output /dev/null --max-time 20 \ --write-out 'connect=%{http_connect} exit=%{exitcode} appconnect=%{time_appconnect} http=%{http_code}\n' "$@" } compare() { probe --noproxy '' --proxy "${PROXY_URL:?}" "${TARGET_URL:?}" probe --noproxy '' --proxy "${PROXY_URL:?}" "${KNOWN_GOOD_URL:?}" probe --noproxy '*' "${TARGET_URL:?}" } compare ``` The third line connects from your own address, so the target sees that address; skip the line if it shouldn't. Each cell is exit/connect/http, so `connect=200 exit=35 appconnect=0.000000 http=000` is 35/200/000. All are from the fixture on three curl builds. | Target via proxy | Known-good via proxy | Target direct | Points at | | --- | --- | --- | --- | | 35/200/000 | 35/200/000 | 0/000/200 | The proxy or its exit IP, or your known-good page. Open that page directly and try a second one: a dead known-good through a proxy that answers 200 first prints this row too | | 35/200/000 | 0/200/200 | 35/000/000 | The target closes your address and the proxy's exit IP, perhaps everyone | | 35/200/000 | 0/200/200 | 7/000/000 | The target is down, or your own route to it is blocked, and this proxy answers 200 before dialling | | 35/200/000 | 0/200/200 | 0/000/200 | **Unresolved:** the target refuses the proxy's exit IP, or the route from that IP to the target fails | Row four's two causes print the same three lines. The third line counts only if this machine may connect directly. In a sandbox or behind a corporate proxy a blocked direct route fails whatever the target does, and exit 7 there looks like row three. If you can't connect directly, or you skip the line, read the first two columns alone: known-good failing is row one, known-good passing is row four. A local client in TUN mode sets no proxy variable, and `--noproxy '*'` still goes through it, so stop the client for the third line (we didn't run TUN mode). All three at exit 35 has no row here: look near you first, at a firewall or your client. Through SOCKS5 read `000` for `200`, and a dead target prints exit 97. If `connect` on the first line isn't 200 through an HTTP proxy, the tunnel never opened, so read that line in [the write-out table](#check-the-next-attempt-with-a-head-or-get-never-the-failed-post). A first column of 52/200/000 or 56/200/000 means the handshake finished and then the connection ended. Read the same rows with that code in place of 35. On the fixture a drop after the handshake printed 52 on curl 8.7.1 and 56 on curl 8.18.0 and 8.23.0, in the patterns of rows one, two and four. After row one or four, go to [Next step by path](#next-step-by-path). After row two the proxy is cleared, so use [the no-proxy list above](#is-a-proxy-in-your-path-at-all). After row three, try the target from another network, then wait for it. Any HTTP status counts as a response here, except that a TLS-inspecting proxy can answer for a target it couldn't reach: mitmproxy answered `connect=200 exit=0 http=502` with the target's handshake dead. If all three lines pass, curl's `HEAD` works now, and either the fault comes and goes or your job differs from this `HEAD`. If the job fails every time, suspect the difference: its TLS library, its proxy setting or its request. Run `ssl_eof_probe.py` with the interpreter your job uses: `HTTPS_PROXY="$PROXY_URL" /path/to/job/python ssl_eof_probe.py "$TARGET_URL"`. If that fails where curl passed, read the error it prints: a certificate error is the trust store, and an EOF points at the TLS build, as in the middlebox row below. If it passes too, look at what your job does that this `HEAD` doesn't: its proxy URL, its body or a long response. If the job fails only sometimes, repeat the first two lines on a slow timer while the job runs, since a connection limit may show only under its load: ```sh while :; do date -u +%FT%TZ probe --noproxy '' --proxy "${PROXY_URL:?}" "${TARGET_URL:?}" probe --noproxy '' --proxy "${PROXY_URL:?}" "${KNOWN_GOOD_URL:?}" sleep 30 done ``` When a line fails, stop the loop, run the third line once and read that row. Send your provider the failing line and its timestamp. Until you catch one, keep logging on so the next failure shows its earlier attempts, and retry only what wasn't sent, [with a wait](#a-retry-that-waits). A `HEAD` has no body in either direction, so it passes where only uploads or long responses die: on the fixture, through a proxy that cut uploads, it gave `exit=0 http=200` while a 5 MB POST failed. If your failing request or its response is large, look for a size limit at the proxy or the target. ## Next step by path | Path | Next action | Tested here | | --- | --- | --- | | Sandbox or corporate egress | Check the host allow-list, the proxy's connection limit and its log: [a denied host can print `SSLEOFError`](https://github.com/docker/sbx-releases/issues/611), and [a 16-connection cap printed both strings](https://github.com/raine/workmux/issues/255) on hosts that were allowed | No. Public reports only | | Local proxy client with rules | Read which rule matched, then try the other route: [one curl line appeared on a host a rule sent direct](https://github.com/blackmatrix7/ios_rule_script/issues/1749). Then check port, scheme and stale settings | mihomo 1.19.33 on loopback: a `MATCH,REJECT` rule or a dead upstream node printed the string with a healthy target (128 of 128). No other client's rules | | TLS-inspecting proxy | This string doesn't point at the root CA: a missing root prints a certificate error (`CERTIFICATE_VERIFY_FAILED`, curl exit 60). Ask the network team | mitmproxy only: HTTP 502 or a timeout when the upstream closed first. The string only when mitmproxy was killed, or on curl when a transfer was cut. Not `ssl-bump` or corporate middleboxes | | Middlebox and a large ClientHello | Add `--curves X25519` to the first curl block on a curl built with OpenSSL 3.5 or later. If only that passes, OpenSSL's larger ClientHello is tripping a device, which OpenSSL [warns](https://docs.openssl.org/3.5/man3/SSL_CTX_set1_curves/) can happen in rare cases. [A developer calls this a device bug](https://github.com/openssl/openssl/discussions/28729), so raise it with whoever runs it, or its [vendor](https://tldr.fail/) | Fixture only: a proxy that closed on a ClientHello over 1,000 bytes. [One report](https://github.com/NousResearch/hermes-agent/issues/106384) suspects this behind `SSLEOFError` | | Exit IP changing, for example a mobile proxy rotating | Live tunnels can die and new ones can fail until the path settles, as the fixture scripted it. Pause, then retry only what wasn't sent, with a wait | Fixture only. No timing here applies to a real network | | Target refuses your exit IP | Stop, or ask the site. It isn't a fault to work around: [one service](https://community.letsencrypt.org/t/eof-occurred-in-violation-of-protocol-ssl-c-1131/158369) did this to a client's IP until its staff lifted the block | Fixture only; that report had no proxy | | Commercial proxy | On a rotating pool each line can leave from a different exit, so use a sticky session if your provider offers one, or repeat the comparison before you trust a row. If failures rise with concurrency, lower it and compare again. Then ask your provider, with a failing write-out line and its timestamp | Nothing here shows what a service does | ## The wording depends on the build | Build | Handshake EOF prints | | --- | --- | | Python on OpenSSL 3.0.13, 3.5.5, 3.5.9, 3.6.5 and 4.1.0 | `[SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol`, low number | | Python on OpenSSL 1.1.1s and LibreSSL 2.8.3 | `EOF occurred in violation of protocol`, low number | | Python 3.9.25 (OpenSSL 3.5.4) | `SSLZeroReturnError(6, 'TLS/SSL connection has been closed (EOF) (_ssl.c:1147)')` | | curl 8.7.1 (LibreSSL 3.3.6) | `curl: (35) LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to`, then the host | | pip 26.3 | `There was a problem confirming the ssl certificate: [SSL: UNEXPECTED_EOF_WHILE_READING]`, then the EOF text | An untrusted chain prints `CERTIFICATE_VERIFY_FAILED` on Linux and `certificate is not trusted` on macOS instead of pip's certificate line. aiohttp 3.14.5 prints `Cannot connect to host` with no EOF text, and sends a delivered GET, HEAD, OPTIONS, PUT or DELETE twice and a POST or PATCH once. Node 24.22.1's `fetch`, in one run, printed `TypeError: fetch failed` with cause `ECONNRESET`: see [Node.js fetch failed behind a proxy](/guides/fix-node-fetch-failed-proxy). Playwright wasn't run: see [Fix ERR_TUNNEL_CONNECTION_FAILED](/guides/fix-err-tunnel-connection-failed). ## How this was tested ipvolt sells dedicated mobile proxies, and its [Terms](/terms) say rotation can briefly interrupt traffic. The tables come from a loopback fixture and from named open-source proxy software on loopback, with default settings apart from the changes its [README](https://ipvolt.com/downloads/fix-ssl-unexpected-eof-proxy/real-proxy-README.md) lists. None of it shows what a commercial service runs or does. ipvolt ran the fixture on 4 and 5 November 2026 on Ubuntu 26.04 and macOS 15.7, and the named software on 4 November on Ubuntu 26.04 (11,816 client calls against an HTTP/1.1 target). These runs leave out Windows, HTTP/3, load, a real proxy's open tunnel going silent with no FIN or RST, and a real proxy that requires a login. Fixture files: [archive](https://ipvolt.com/downloads/fix-ssl-unexpected-eof-proxy/ssl-eof-lab.zip), [README](https://ipvolt.com/downloads/fix-ssl-unexpected-eof-proxy/README.md) and [recorded results](https://ipvolt.com/downloads/fix-ssl-unexpected-eof-proxy/results.json). Named-software files: [archive](https://ipvolt.com/downloads/fix-ssl-unexpected-eof-proxy/ssl-eof-real-proxy.zip) and the [facts](https://ipvolt.com/downloads/fix-ssl-unexpected-eof-proxy/real-proxy-facts.json) behind its counts. [Pricing](/pricing) lists ipvolt's mobile proxies by country and carrier. ## Sources & further reading - [Requests 2.34.2 source: the max_retries docstring in adapters.py](https://github.com/psf/requests/blob/v2.34.2/src/requests/adapters.py) - [urllib3 2.8.0: Retry, including the other parameter and backoff_factor](https://urllib3.readthedocs.io/en/2.8.0/reference/urllib3.util.html) - [urllib3 2.8.0 source: where Retry checks the method, in retry.py](https://github.com/urllib3/urllib3/blob/2.8.0/src/urllib3/util/retry.py) - [urllib3 2.8.0 source: the ProxyError wrap in connectionpool.py](https://github.com/urllib3/urllib3/blob/2.8.0/src/urllib3/connectionpool.py) - [urllib3 1.26.20 source: the older Cannot connect to proxy text](https://github.com/urllib3/urllib3/blob/1.26.20/src/urllib3/connectionpool.py) - [urllib3 main at c5347bb, 2 November 2026](https://github.com/urllib3/urllib3/tree/c5347bbd39203d68d7b0e3ffb83ced3e3b4b9109) - [curl man page: --write-out, --retry, --retry-all-errors, --tls-earlydata and exit codes](https://curl.se/docs/manpage.html) - [HTTPX 0.28.1 source: where the retries setting goes, in default.py](https://github.com/encode/httpx/blob/0.28.1/httpx/_transports/default.py) - [aiohttp 3.14.5 source: the retry on a closed connection, in client.py](https://github.com/aio-libs/aiohttp/blob/v3.14.5/aiohttp/client.py) - [RFC 9110: idempotent methods and automatic retries, section 9.2.2](https://www.rfc-editor.org/rfc/rfc9110.html#section-9.2.2) - [CPython issue #110467: EOF on a write during a large request](https://github.com/python/cpython/issues/110467) - [UbiOps: SSLError during a large upload](https://ubiops.com/docs/troubleshooting/calling-api/sslerror-eof/) - [Let's Encrypt community: a blocked client IP printing this string](https://community.letsencrypt.org/t/eof-occurred-in-violation-of-protocol-ssl-c-1131/158369) - [urllib3 issue #3100: SSLEOFError with no shared cipher](https://github.com/urllib3/urllib3/issues/3100) - [Python issue 45487: SSLEOFError with stricter default ciphers](https://bugs.python.org/issue45487) - [OpenSSL: SSL_OP_IGNORE_UNEXPECTED_EOF and the missing close_notify](https://docs.openssl.org/3.5/man3/SSL_CTX_set_options/) - [Microsoft Q&A: this string through a firewall](https://learn.microsoft.com/en-us/answers/questions/1440221/how-to-fix-the-error-eof-occurred-in-violation-of) - [discuss.python.org: a pip user deleting proxy values from pip.ini and the environment](https://discuss.python.org/t/py-pip-installation-dir-sslerror/63146) - [hermes-agent issue #53702: a macOS system proxy picked up by httpx](https://github.com/NousResearch/hermes-agent/issues/53702) - [docker/sbx-releases issue #611: a denied host surfacing as SSLEOFError](https://github.com/docker/sbx-releases/issues/611) - [workmux issue #255: an egress proxy's connection cap printing both strings](https://github.com/raine/workmux/issues/255) - [lens-sandbox-core issue #87: a proxy that answers 200 before dialling](https://github.com/lensapp/lens-sandbox-core/issues/87) - [ios_rule_script issue #1749: a host a client rule sent direct, with the curl EOF line](https://github.com/blackmatrix7/ios_rule_script/issues/1749) - [OpenSSL 3.5: the larger default ClientHello and the firewall warning](https://docs.openssl.org/3.5/man3/SSL_CTX_set1_curves/) - [OpenSSL discussion #28729: middleboxes and split ClientHellos](https://github.com/openssl/openssl/discussions/28729) - [tldr.fail: buggy middleboxes, and asking the vendor for a patch](https://tldr.fail/) - [hermes-agent issue #106384: a middlebox suspected behind SSLEOFError on OpenSSL 3.5](https://github.com/NousResearch/hermes-agent/issues/106384) - [CPython _ssl.c: the handshake, read and write error lines](https://github.com/python/cpython/blob/main/Modules/_ssl.c) - [Python docs: urllib.request.getproxies, environment then macOS or Windows settings](https://docs.python.org/3/library/urllib.request.html#urllib.request.getproxies) - [urllib3 2.8.0 source: has_connected_to_proxy, in _base_connection.py](https://github.com/urllib3/urllib3/blob/2.8.0/src/urllib3/_base_connection.py) - [urllib3 issue #1744: ProxyError hiding a connect failure from Retry](https://github.com/urllib3/urllib3/issues/1744) ## Related guides - [SSL WRONG_VERSION_NUMBER behind a proxy: which hop failed](https://ipvolt.com/guides/fix-ssl-wrong-version-number-proxy.md) - [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md) - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md) - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md) - [Fix Node.js TypeError: fetch failed behind a proxy](https://ipvolt.com/guides/fix-node-fetch-failed-proxy.md) - [Fix ERR_TUNNEL_CONNECTION_FAILED in Playwright and Puppeteer](https://ipvolt.com/guides/fix-err-tunnel-connection-failed.md) - ["Tunnel connection failed: 502 Bad Gateway" (and 503, 504) behind a proxy](https://ipvolt.com/guides/fix-proxy-tunnel-502-503.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 98 of 138: Fix "Missing dependencies for SOCKS support" in Requests, pip and HTTPX URL: https://ipvolt.com/guides/fix-missing-dependencies-for-socks-support Markdown: https://ipvolt.com/guides/fix-missing-dependencies-for-socks-support.md # Fix "Missing dependencies for SOCKS support" in Requests, pip and HTTPX Source: https://ipvolt.com/guides/fix-missing-dependencies-for-socks-support Markdown: https://ipvolt.com/guides/fix-missing-dependencies-for-socks-support.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Fix "Missing dependencies for SOCKS support" in Requests, pip and HTTPX](https://ipvolt.com/guides/fix-missing-dependencies-for-socks-support.md) Category: Troubleshooting Published: 2026-10-05 Reading time: 7 minutes Author: ipvolt Fix Missing dependencies for SOCKS support, No module named 'socks' and socksio ImportError in pip, Requests and HTTPX: install the extra or clear ALL_PROXY. `Missing dependencies for SOCKS support` means Requests was given a SOCKS proxy URL, such as `socks5://` or `socks5h://`, and could not `import socks`, the module that PySocks installs, in the Python that is running. Requests raises it before opening any connection, so the proxy has not been contacted yet. The proxy URL doesn't have to be in your code: Requests also takes it from `ALL_PROXY` or `all_proxy` in the environment. And pip runs on its own bundled copy of Requests, so with that variable set, `pip install pysocks` stops with the same message. | What you see | Cause | Fix | | --- | --- | --- | | `requests.exceptions.InvalidSchema: Missing dependencies for SOCKS support.` and your code sets a SOCKS proxy | PySocks is not importable from this Python | Fix 1: `python -m pip install "requests[socks]"` | | The same error, and your code sets no proxy | `ALL_PROXY` or another proxy variable holds a SOCKS URL | Fix 2: unset the variable, or install PySocks | | `ERROR: Could not install packages due to an OSError: Missing dependencies for SOCKS support.` | pip read the same variable | Fix 3: clear it for that one command | | `AttributeError: module 'socks' has no attribute 'PROXY_TYPE_SOCKS5'` | Your own `socks.py` or `socks/` package is imported instead of PySocks | Fix 4: rename it | | `ImportError: Using SOCKS proxy, but the 'socksio' package is not installed.` | HTTPX needs socksio, not PySocks | `python -m pip install "httpx[socks]"` | The results below were recorded on 5 October 2026 with Requests 2.34.2, HTTPX 0.28.1, pip 26.2.1, PySocks 1.7.1 and socksio 1.0.0 on Python 3.13.5 and 3.14.4, with a fresh virtual environment for each case. Both Pythons gave the same results. ## Fix 1: install PySocks into the Python that runs your code ```sh python -m pip install "requests[socks]" ``` The extra adds one package, PySocks, whose importable module is named `socks`. Installing `pysocks` by name works too. Use `python -m pip`, not a bare `pip`: it installs into the interpreter that the `python` command starts, while a bare `pip` can belong to another environment. In the lab, with `pip` on `PATH` pointing at a second virtual environment, `pip install "requests[socks]"` printed `Successfully installed PySocks-1.7.1` and the script kept raising the same error. Check the running interpreter: ```sh python -c "import socks, sys; print(sys.executable, socks.__file__)" ``` It prints the interpreter and the file that `import socks` resolved to, which should be `socks.py` inside that interpreter's `site-packages`. `ModuleNotFoundError: No module named 'socks'` means PySocks is missing from this Python. ## Fix 2: you never set a proxy When you pass no `proxies`, Requests builds them from the environment. Its [documentation](https://requests.readthedocs.io/en/latest/user/advanced/#proxies) names `http_proxy`, `https_proxy`, `no_proxy` and `all_proxy`, plus the uppercase variants. List what your process inherits: ```sh env | grep -i _proxy ``` In the lab, a script with no proxy in its code raised the error with only `ALL_PROXY=socks5://127.0.0.1:1080` set, and again with only lowercase `all_proxy`. `HTTP_PROXY` holding a `socks5://` URL did the same. [Requests issue #3516](https://github.com/psf/requests/issues/3516) is this case: the reporter's environment contained `all_proxy`, and the code broke on upgrading to Requests 2.11, where a maintainer says support for `all_proxy` began. If you want the SOCKS proxy, apply fix 1. If you don't, remove the variable where it is set, such as a shell profile or a container image. Four details from the lab: - An empty value counts as unset. `ALL_PROXY=` gave a direct request and status 200. - Lowercase wins. With `all_proxy` set and `ALL_PROXY` emptied, the error remained. Emptying `all_proxy` removed it even with `ALL_PROXY` still set. Clear both. - `ALL_PROXY` is a fallback. With `HTTP_PROXY` also set to an HTTP proxy, a request to an `http://` URL tried that proxy and never touched the SOCKS code. - Code can opt out. `session.trust_env = False` returned 200 with `ALL_PROXY` still set, and so did adding the host to `NO_PROXY`. [Proxy environment variables](/guides/proxy-environment-variables) lists which variables each client reads, and the [Python Requests proxy guide](/guides/python-requests-proxy) covers `trust_env`. ## Fix 3: pip fails with Missing dependencies for SOCKS support pip downloads through a vendored copy of Requests and reads the same variables. With `all_proxy` or `ALL_PROXY` set to a SOCKS URL, in a new virtual environment: ```text $ python -m pip install "requests[socks]" WARNING: There was an error checking the latest version of pip. ERROR: Could not install packages due to an OSError: Missing dependencies for SOCKS support. ``` `pip download` and `pip index versions` ended in a traceback instead, with `pip._vendor.requests.exceptions.InvalidSchema: Missing dependencies for SOCKS support.` as its last line. Clear the variables for that one command: ```sh ALL_PROXY= all_proxy= python -m pip install "requests[socks]" ``` `env -u ALL_PROXY -u all_proxy` in front of the command worked as well. Clearing only `ALL_PROXY` did not, because `all_proxy` was still set. Then decide whether the variable should stay exported. With PySocks installed, Requests used the proxy from `ALL_PROXY` and returned 200 through the lab's SOCKS server. pip did not: pip 26.2.1 stopped with `TypeError: PoolKey.__new__() got an unexpected keyword argument 'key_proxy_ssl_context'`, while pip 25.1.1 installed a package through the same proxy. On pip 26.2.1, keep clearing the variable for pip commands, or set the proxy only for the program that needs it. Python 3.15 adds another pip failure: [Failed building wheel for brotli](/blog/python-3-15-web-scraping). ## Fix 4: AttributeError: module 'socks' has no attribute 'PROXY_TYPE_SOCKS5' Here `import socks` found something, but not PySocks. Python [searches the script's directory first](https://docs.python.org/3/library/sys_path_init.html), or the current directory for `python -c` and `python -m`, and adds `site-packages` last, so a file or folder of yours named `socks` wins. The check from fix 1 shows what was imported: | In the directory Python searches first | PySocks installed | Result | The check prints | | --- | --- | --- | --- | | `socks.py` | Yes | `AttributeError` | your `socks.py` | | `socks/` with `__init__.py` | Yes | `AttributeError` | your `socks/__init__.py` | | `socks/` without `__init__.py` | Yes | Works, status 200 | PySocks in `site-packages` | | `socks/` without `__init__.py` | No | `AttributeError`, not `InvalidSchema` | `None` | Rename the file or folder. In the last row, a plain folder named `socks` turned the missing-dependency error into the `AttributeError`, so after renaming it you still need fix 1. ## HTTPX: Using SOCKS proxy, but the 'socksio' package is not installed HTTPX has its own SOCKS dependency. Without it, HTTPX 0.28.1 raises: ```text ImportError: Using SOCKS proxy, but the 'socksio' package is not installed. Make sure to install httpx using `pip install httpx[socks]`. ``` ```sh python -m pip install "httpx[socks]" ``` That installed socksio 1.0.0, and the same request returned 200 through the proxy. The other fixes carry over: - The error appears with `proxy="socks5://..."` in code and with only `ALL_PROXY` or `all_proxy` in the environment. It is raised when the client is built: under `ALL_PROXY`, `httpx.Client()` with no arguments failed before any request. - An empty `ALL_PROXY` and `trust_env=False` each gave a direct 200. - The two libraries are not interchangeable. HTTPX with only PySocks installed still raised the `ImportError`, and Requests with only socksio still raised `InvalidSchema`. To check the import, replace `socks` with `socksio` in the command from fix 1. The [HTTPX async proxy guide](/guides/httpx-async-proxy) has a complete client setup. ## After it imports: choose socks5:// or socks5h:// on purpose A different error now is progress: with PySocks installed and nothing listening on the proxy port, Requests raised `ConnectionError` with `Connection refused`, a network problem. The scheme is the next decision. In Requests, `socks5://` resolves the hostname on your machine and `socks5h://` sends it to the proxy, while HTTPX sends the hostname with both. [socks5 vs socks5h: what six clients actually send](/blog/socks5-vs-socks5h) has the logged results for each client, and [HTTP vs SOCKS5 proxies](/guides/http-vs-socks5-proxies) helps if you are still choosing a protocol. ## How this was tested On Ubuntu 26.04.1, with everything on `127.0.0.1`: `python -m http.server` as the target and a small SOCKS5 relay that logs every request it receives. Each of the 47 cases ran on both Pythons in a fresh virtual environment, an otherwise empty working directory and an empty home directory, with no proxy variables except the ones named in that case. No proxy account was used; the only outbound traffic was pip talking to PyPI. In every failing case the relay logged no connection. The [lab archive](https://ipvolt.com/downloads/fix-missing-dependencies-for-socks-support/socks-missing-dependencies-lab.zip) contains the [runner](https://ipvolt.com/downloads/fix-missing-dependencies-for-socks-support/run_lab.py), the [SOCKS5 relay](https://ipvolt.com/downloads/fix-missing-dependencies-for-socks-support/socks5_relay.py), the [README](https://ipvolt.com/downloads/fix-missing-dependencies-for-socks-support/README.md) and the [recorded results](https://ipvolt.com/downloads/fix-missing-dependencies-for-socks-support/results.json). Not tested: macOS and Windows, SOCKS4 and authenticated SOCKS proxies, older releases of Requests and HTTPX, and installers other than pip. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources & further reading - [Requests: SOCKS proxies and the requests[socks] extra](https://requests.readthedocs.io/en/latest/user/advanced/#socks) - [Requests: proxies and the proxy environment variables](https://requests.readthedocs.io/en/latest/user/advanced/#proxies) - [psf/requests issue #3516: Missing dependencies for SOCKS support](https://github.com/psf/requests/issues/3516) - [HTTPX: proxies and SOCKS](https://www.python-httpx.org/advanced/proxies/) - [HTTPX: environment variables](https://www.python-httpx.org/environment_variables/) - [PySocks on PyPI](https://pypi.org/project/PySocks/) - [Python: how the sys.path module search path is initialized](https://docs.python.org/3/library/sys_path_init.html) ## Related guides - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md) - [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md) - [HTTPX async proxies: setup and PoolTimeout diagnosis](https://ipvolt.com/guides/httpx-async-proxy.md) - [HTTP vs SOCKS5 proxies: choose by the connection](https://ipvolt.com/guides/http-vs-socks5-proxies.md) - [SSL WRONG_VERSION_NUMBER behind a proxy: which hop failed](https://ipvolt.com/guides/fix-ssl-wrong-version-number-proxy.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 99 of 138: aiohttp proxies in 3.14: auth without BasicAuth, env vars and the errors you'll hit URL: https://ipvolt.com/guides/aiohttp-proxy-setup Markdown: https://ipvolt.com/guides/aiohttp-proxy-setup.md # aiohttp proxies in 3.14: auth without BasicAuth, env vars and the errors you'll hit Source: https://ipvolt.com/guides/aiohttp-proxy-setup Markdown: https://ipvolt.com/guides/aiohttp-proxy-setup.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [aiohttp proxies in 3.14: auth without BasicAuth, env vars and the errors you'll hit](https://ipvolt.com/guides/aiohttp-proxy-setup.md) Category: Integration Published: 2026-10-06 Reading time: 7 minutes Author: ipvolt Set up an HTTP or SOCKS proxy in aiohttp 3.14: replace the deprecated BasicAuth and proxy_auth, turn on trust_env, and read the 407 and Bad status line errors. aiohttp 3.14.0 (1 June 2026) deprecated `BasicAuth` and the `proxy_auth` parameter ([changelog](https://docs.aiohttp.org/en/stable/changes.html), [#12499](https://github.com/aio-libs/aiohttp/pull/12499)). The replacement is a `Proxy-Authorization` header built with `aiohttp.encode_basic_auth()`: ```python import asyncio import aiohttp PROXY = "http://proxy.example.com:8080" PROXY_HEADERS = {"Proxy-Authorization": aiohttp.encode_basic_auth("user", "pass")} async def main() -> None: async with aiohttp.ClientSession(proxy=PROXY) as session: async with session.get("https://example.com/", proxy_headers=PROXY_HEADERS) as response: print(response.status) asyncio.run(main()) ``` In our lab this authenticated every `https://` request with no `DeprecationWarning`. It did not authenticate plain `http://` requests: aiohttp 3.14.4 sent `proxy_headers` only with the `CONNECT` request that opens an HTTPS tunnel, so for an `http://` URL the proxy received no credentials and answered 407. | Credentials passed as | `https://` URL | `http://` URL | Deprecation warnings | | --- | --- | --- | --- | | `proxy_headers={"Proxy-Authorization": aiohttp.encode_basic_auth(...)}` | 200 | 407 | none | | `proxy="http://user:pass@host:port"` | 200 | 200 | none | | `proxy_auth=aiohttp.BasicAuth(...)` | 200 | 200 | two per call | These results were recorded on 6 October 2026 with aiohttp 3.14.4 and aiohttp-socks 0.12.0 on Python 3.14.4, run with `python -W always` against a local proxy that requires Basic authentication. aiohttp 3.14.0 and 3.14.3 gave the same results. ## Migrating from proxy_auth=aiohttp.BasicAuth The old call still works in 3.14.4 for both URL schemes: ```python async with session.get(url, proxy=PROXY, proxy_auth=aiohttp.BasicAuth("user", "pass")) as response: print(response.status) ``` Each call printed two warnings: ```text DeprecationWarning: BasicAuth is deprecated and will be removed in aiohttp 4.0; use aiohttp.encode_basic_auth() with headers={'Authorization': ...} instead DeprecationWarning: The 'proxy_auth' parameter is deprecated and will be removed in v4; pass proxy_headers={'Proxy-Authorization': aiohttp.encode_basic_auth(login, password)} instead ``` The replacement: ```python proxy_headers = {"Proxy-Authorization": aiohttp.encode_basic_auth("user", "pass")} async with session.get(url, proxy=PROXY, proxy_headers=proxy_headers) as response: print(response.status) ``` Check four things before you ship it: - **Plain `http://` URLs lose their credentials.** The [documentation](https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support) shows `proxy_headers` with an `http://` URL. In the lab that request reached the proxy without `Proxy-Authorization`, and without a custom header we added to `proxy_headers`, and came back as 407. [Issue #4422](https://github.com/aio-libs/aiohttp/issues/4422) reported the same against aiohttp 3.6.2. If you fetch `http://` URLs, put the credentials in the proxy URL: `proxy="http://user:pass@host:port"` returned 200 for both schemes with no warning. - **`ClientSession` has no `proxy_headers` argument.** The documentation shows `ClientSession(proxy=..., proxy_headers=...)`. In 3.14.4 it raised `TypeError: ClientSession.__init__() got an unexpected keyword argument 'proxy_headers'`. Set `proxy=` on the session and pass `proxy_headers=` with each request, as in the first example. - **Don't move the header to `headers=`.** For an `https://` URL, request headers travel inside the tunnel. With `Proxy-Authorization` in `headers=`, the lab's destination server received the proxy credentials. - **The default encoding changed.** `encode_basic_auth()` uses UTF-8 and `BasicAuth` used latin1. For the password `päss` the two produced different header values, so pass `encoding="latin1"` if your proxy expects the old bytes. `encode_basic_auth()` is new in 3.14 ([reference](https://docs.aiohttp.org/en/stable/client_reference.html#aiohttp.encode_basic_auth)). On aiohttp 3.13.5 the same code raised `AttributeError: module aiohttp has no attribute encode_basic_auth`. ## Environment variables need trust_env=True A default `ClientSession()` ignores proxy variables. With `HTTP_PROXY` set, the request went straight to the target and the proxy logged nothing. This session used the proxy: ```python async with aiohttp.ClientSession(trust_env=True) as session: async with session.get("http://example.com/") as response: print(response.status) ``` The [documentation](https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support) says aiohttp reads the variables through `urllib.request.getproxies()`, applies them to the HTTP, HTTPS, WS and WSS schemes, lets hosts in `no_proxy` bypass the proxy, and can take proxy credentials from `~/.netrc`. In the lab, with `trust_env=True`: - `HTTP_PROXY` and lowercase `http_proxy` applied to `http://` URLs, and `HTTPS_PROXY` to `https://` URLs. With only `HTTP_PROXY` set, an `https://` request went direct. - `ALL_PROXY` was ignored. - Credentials in the variable's URL authenticated both schemes and printed no warning. - `NO_PROXY=127.0.0.1` sent the request direct. It had no effect on an explicit `proxy=` argument, which also took priority over the variable. - A variable holding an `https://` proxy URL was skipped. aiohttp logged `HTTPS proxies https://127.0.0.1:8888 are not supported, ignoring` and connected directly. [Proxy environment variables](/guides/proxy-environment-variables) compares these rules across other clients. ## ClientHttpProxyError: 407 on https:// URLs When the proxy rejects the `CONNECT` request, aiohttp raises before anything reaches the destination. With a wrong password in the proxy URL: ```text aiohttp.client_exceptions.ClientHttpProxyError: 407, message='Proxy Authentication Required', url='http://user:wrong@127.0.0.1:8888' ``` The password is in the message, so it goes wherever the exception goes: logs, tracebacks, error trackers. With the credentials in `proxy_headers`, or taken from `HTTPS_PROXY`, the same failure printed `url='http://127.0.0.1:8888'`. Keep credentials out of the proxy URL for `https://` traffic. Where you need them in the URL, log `exc.status` and `exc.message` (`407` and `Proxy Authentication Required` in the lab) instead of the exception text. [Fix proxy error 407](/guides/fix-proxy-error-407) gives the order of checks when the credentials look right. ## Status 407 with no exception on http:// URLs For an `http://` URL the proxy's 407 is an ordinary response. Nothing is raised, `response.status` is 407 and the `Proxy-Authenticate` header holds the challenge. Code that only catches exceptions treats this as success. Check `response.status`, or create the session with `raise_for_status=True`. That raised: ```text aiohttp.client_exceptions.ClientResponseError: 407, message='Proxy Authentication Required', url='http://127.0.0.1:8080/' ``` `raise_for_status=True` on the request and `response.raise_for_status()` raised the same error. The class is `ClientResponseError` and the URL is the target, not the proxy. `ClientHttpProxyError` is a subclass of it, so `except aiohttp.ClientResponseError` with a check for `exc.status == 407` covers both schemes. ## Bad status line: b'\x05\x00' from a socks5:// proxy URL aiohttp does not reject `proxy="socks5://..."`. It sends an HTTP request to the SOCKS port and fails on the reply: ```text aiohttp.client_exceptions.ClientResponseError: 400, message="Bad status line:\n Expected HTTP/, RTSP/ or ICE/:\n\n b'\\x05\\x00'\n ^", url='http://127.0.0.1:8080/' ``` `\x05\x00` is the start of the SOCKS5 server's reply, read as if it were an HTTP status line. `socks5h://` failed the same way. The fix is a SOCKS connector, shown below. ## ClientConnectorSSLError from an https:// proxy URL An `https://` proxy URL tells aiohttp to open TLS to the proxy itself. Against the lab proxy, which speaks plain HTTP, the request failed during the handshake: ```text aiohttp.client_exceptions.ClientConnectorSSLError: Cannot connect to host 127.0.0.1:8888 ssl:default [[SSL: RECORD_LAYER_FAILURE] record layer failure (_ssl.c:1081)] ``` The proxy saw a TLS ClientHello and answered with a plaintext 400. The scheme of the proxy URL describes the connection to the proxy, not to the destination: an `http://` proxy URL carries `https://` requests through `CONNECT`. The error text comes from OpenSSL 3.5.5 and may read differently on other versions. ## DeprecationWarning: BasicAuth is deprecated Constructing `aiohttp.BasicAuth(...)` is enough to trigger the first warning, before any request. The `auth=` parameter for website credentials is deprecated too. Its warning names `headers={'Authorization': aiohttp.encode_basic_auth(login, password)}` as the replacement. You may not see either warning. By default Python shows a `DeprecationWarning` only when [the code that triggered it is in `__main__`](https://docs.python.org/3/library/warnings.html#default-warning-filter). In the lab the deprecated call printed its warnings when it was in the script being run and printed nothing when it was in an imported module. `python -W always` printed them in both places. `python -W error` turned the first one into an exception, which finds every call site in a test run. ## SOCKS proxies: use aiohttp-socks ```sh python -m pip install aiohttp-socks ``` ```python import aiohttp from aiohttp_socks import ProxyConnector connector = ProxyConnector.from_url("socks5://127.0.0.1:1080") async with aiohttp.ClientSession(connector=connector) as session: async with session.get("https://example.com/") as response: print(response.status) ``` With [aiohttp-socks](https://pypi.org/project/aiohttp-socks/) 0.12.0 this returned 200 for `http://` and `https://` URLs, and the SOCKS server logged each connection. Two details: - `socks5://` already sends the hostname to the proxy. For `http://localhost:8080/` the server logged a domain name. With `rdns=False` it logged `127.0.0.1`. - `ProxyConnector.from_url("socks5h://...")` raised `ValueError: Invalid scheme component: socks5h`. [socks5 vs socks5h](/blog/socks5-vs-socks5h) shows what each client does with the two schemes. Requests and HTTPX need their own SOCKS packages, covered in [Missing dependencies for SOCKS support](/guides/fix-missing-dependencies-for-socks-support). ## Retries after proxy errors A 407, the SOCKS status-line error and the TLS error above are configuration errors. The same request fails the same way again, so fix the setup instead of retrying. For timeouts and dropped connections, retry only requests that are safe to repeat. A `POST` may have reached the destination before the proxy connection failed. [Proxy retries: one lost response, two created jobs](/blog/proxy-retries-duplicate-jobs) shows that case and what an idempotency key changes. The [SSL EOF guide](/guides/fix-ssl-unexpected-eof-proxy) compares what aiohttp, Requests, HTTPX and curl each re-send. If you use HTTPX for async work, see [HTTPX async proxies](/guides/httpx-async-proxy). For diagnostic help inside a coding agent, [Proxy Toolkit MCP](/mcp) accepts sanitized error descriptions. Keep credentials out of its arguments. ## How this was tested On Ubuntu 26.04.1 with Python 3.14.4 and OpenSSL 3.5.5, everything on `127.0.0.1`: `python -m http.server` as the HTTP and HTTPS targets, a proxy that requires Basic authentication and logs every request with its header names, a SOCKS5 server that logs each destination, and an HTTPS target that reports the headers it received. Each of the 67 cases ran in a new interpreter with a clean environment. No proxy account was used. The [lab archive](https://ipvolt.com/downloads/aiohttp-proxy-setup/aiohttp-proxy-lab.zip) contains the [runner](https://ipvolt.com/downloads/aiohttp-proxy-setup/run_lab.py), the [cases](https://ipvolt.com/downloads/aiohttp-proxy-setup/cases.py), the [proxy](https://ipvolt.com/downloads/aiohttp-proxy-setup/auth_proxy.py), the [SOCKS5 server](https://ipvolt.com/downloads/aiohttp-proxy-setup/socks5_server.py), the [README](https://ipvolt.com/downloads/aiohttp-proxy-setup/README.md) and the [recorded results](https://ipvolt.com/downloads/aiohttp-proxy-setup/results.json). Not tested: macOS and Windows, Digest and NTLM proxy authentication, authenticated SOCKS proxies, WebSocket requests, `~/.netrc` credentials and proxies reached over TLS. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources & further reading - [aiohttp changelog: 3.14.0](https://docs.aiohttp.org/en/stable/changes.html) - [aiohttp pull request #12499: Deprecate auth. Add encode_basic_auth](https://github.com/aio-libs/aiohttp/pull/12499) - [aiohttp Advanced Client Usage: proxy support and trust_env](https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support) - [aiohttp Client Reference: encode_basic_auth and proxy_headers](https://docs.aiohttp.org/en/stable/client_reference.html#aiohttp.encode_basic_auth) - [aiohttp issue #4422: proxy_headers not passed to proxy](https://github.com/aio-libs/aiohttp/issues/4422) - [aiohttp-socks on PyPI](https://pypi.org/project/aiohttp-socks/) - [Python warnings: the default warning filter](https://docs.python.org/3/library/warnings.html#default-warning-filter) ## Related guides - [Fix proxy error 407 without guessing](https://ipvolt.com/guides/fix-proxy-error-407.md) - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md) - [HTTPX async proxies: setup and PoolTimeout diagnosis](https://ipvolt.com/guides/httpx-async-proxy.md) - [Fix "Missing dependencies for SOCKS support" in Requests, pip and HTTPX](https://ipvolt.com/guides/fix-missing-dependencies-for-socks-support.md) - [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Residential from $2.20 per GB. Mobile from $9 a day. [Buy residential](https://ipvolt.com/dashboard/residential) [Buy mobile](https://ipvolt.com/dashboard/mobile) --- Document 100 of 138: Scrapy proxies in 2.19: auth, rotation and the errors you'll hit URL: https://ipvolt.com/guides/scrapy-proxy-setup Markdown: https://ipvolt.com/guides/scrapy-proxy-setup.md # Scrapy proxies in 2.19: auth, rotation and the errors you'll hit Source: https://ipvolt.com/guides/scrapy-proxy-setup Markdown: https://ipvolt.com/guides/scrapy-proxy-setup.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Scrapy proxies in 2.19: auth, rotation and the errors you'll hit](https://ipvolt.com/guides/scrapy-proxy-setup.md) Category: Integration Published: 2026-10-07 Reading time: 8 minutes Author: ipvolt Scrapy 2.19 proxy setup: credentials in meta["proxy"], per-request rotation, HTTP_PROXY, and fixes for TunnelError 407, ignored 407 responses and socks5. Put the credentials in the proxy URL and pass it as `meta["proxy"]`: ```python import scrapy PROXY = "http://user:pass@proxy.example.com:8080" class ExampleSpider(scrapy.Spider): name = "example" async def start(self): yield scrapy.Request("https://example.com/", meta={"proxy": PROXY}) def parse(self, response): self.logger.info("%s via %s", response.status, response.meta["proxy"]) ``` `HttpProxyMiddleware` is on by default (`HTTPPROXY_ENABLED = True`). It moves the user and password from the URL into a `Proxy-Authorization` header ([documentation](https://docs.scrapy.org/en/latest/topics/downloader-middleware.html#module-scrapy.downloadermiddlewares.httpproxy)), so `response.meta["proxy"]` holds the URL without credentials. In our lab this authenticated `https://` and `http://` requests against a local proxy that requires Basic authentication. Everything below was recorded on 7 October 2026 with Scrapy 2.19.0, Twisted 26.4.0 and Python 3.14.4. Three details before the errors: - **Percent-encode the password.** `p@ss:w/rd` worked as `p%40ss%3Aw%2Frd`. Unencoded, the request failed with `ValueError: Port could not be cast to integer value as 'w'`. - **Requests made in a callback do not inherit the proxy.** A request created with `response.follow()` went direct. A redirect kept the proxy. Set `meta["proxy"]` on every request, or in a downloader middleware as shown below. - **Use `async def start()`.** A spider that defined only `start_requests()` opened, sent nothing and closed with `finish_reason: finished` and no warning. Scrapy 2.16.0 removed the method: it "is removed and no longer called" ([release notes](https://docs.scrapy.org/en/latest/news.html#release-2-16-0)). [`Spider.start()`](https://docs.scrapy.org/en/latest/topics/spiders.html#scrapy.Spider.start) replaces it. [Scrapy crawls 0 pages after upgrading](/guides/scrapy-start-requests-not-called) has the migration, spider middlewares included. ## Rotating proxies: set meta["proxy"] per request Rotation is a downloader middleware that runs before `HttpProxyMiddleware` (order 750) and sets a proxy URL with credentials: ```python from itertools import cycle PROXIES = cycle([ "http://user:pass@proxy-a.example.com:8080", "http://user:pass@proxy-b.example.com:8080", ]) class RotateProxyMiddleware: def process_request(self, request): request.meta["proxy"] = next(PROXIES) ``` ```python DOWNLOADER_MIDDLEWARES = {"myproject.middlewares.RotateProxyMiddleware": 740} ``` In the lab a redirected request passed through this middleware twice, went to two proxies and authenticated at both. The version that fails sets a URL without credentials and writes the header itself: ```python request.meta["proxy"] = next(PROXIES) # "http://proxy-a.example.com:8080" request.headers["Proxy-Authorization"] = "Basic dXNlcjpwYXNz" ``` The first request reached proxy A with the header. The target answered 301 and the redirected request went through the middlewares again. The rotation chose proxy B and set the header again, yet proxy B received the request with no `Proxy-Authorization` and answered 407. A retried `https://` request lost the header the same way. `HttpProxyMiddleware` records which proxy URL a hand-set header was sent with. When a later pass over the same request has a different proxy URL without credentials, it deletes the header. The [2.6.2 release notes](https://docs.scrapy.org/en/latest/news.html#release-2-6-2) give the reason: rotation middlewares changed the proxy and left the old header in place, so one proxy's credentials went to another. Since [2.7.1](https://docs.scrapy.org/en/latest/news.html#release-2-7-1) a hand-set header is kept only "for as long as that proxy URL remains the same". Credentials in the URL always replace it. Two more results from the same code: - On the first pass the header is not tied to a proxy yet. A middleware that changed `meta["proxy"]` from A to B before `HttpProxyMiddleware` ran sent the hand-set header to proxy B. - With no proxy at all, the header was removed before the request reached the target. ## Environment variables: HTTP_PROXY is used by default Scrapy reads the proxy variables when the crawl starts, and no setting is needed to turn that on. With `HTTP_PROXY=http://user:pass@127.0.0.1:8888` and no `meta["proxy"]`, the lab request went through the proxy and authenticated. - `HTTP_PROXY` and lowercase `http_proxy` applied to `http://` URLs, and `HTTPS_PROXY` to `https://` URLs. With only `HTTP_PROXY` set, an `https://` request went direct. `ALL_PROXY` was ignored. - `NO_PROXY=127.0.0.1` sent the request direct. `meta["proxy"]` took priority over the variables and ignored `NO_PROXY`, as the documentation says. - `meta={"proxy": None}` sent one request direct with the variable set. - `HTTPPROXY_ENABLED = False` stopped Scrapy from reading the variables. It also stopped the credential handling: `meta["proxy"] = "http://user:pass@127.0.0.1:8888"` then raised `ValueError: invalid hostname: user:pass@127.0.0.1` for an `http://` URL and the 407 `TunnelError` for `https://`. To ignore the environment and keep `meta["proxy"]` working, replace the middleware with a subclass that discards what it read: ```python from scrapy.downloadermiddlewares.httpproxy import HttpProxyMiddleware class ExplicitProxyMiddleware(HttpProxyMiddleware): def __init__(self, auth_encoding="latin-1"): super().__init__(auth_encoding) self.proxies = {} ``` ```python DOWNLOADER_MIDDLEWARES = { "scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware": None, "myproject.middlewares.ExplicitProxyMiddleware": 750, } ``` `proxies` is not a documented attribute, so test this again after an upgrade. aiohttp does the opposite: it ignores the variables unless you pass `trust_env=True` ([aiohttp proxies in 3.14](/guides/aiohttp-proxy-setup)). [Proxy environment variables](/guides/proxy-environment-variables) compares other clients. ## TunnelError: Could not open CONNECT tunnel with proxy ```text scrapy.core.downloader.handlers.http11.TunnelError: Could not open CONNECT tunnel with proxy 127.0.0.1:8888 [{'status': 407, 'reason': b'Proxy Authentication Required'}] ``` The proxy rejected the `CONNECT` request for an `https://` URL. The message was identical with no credentials and with a wrong password, and it does not contain the credentials, so it cannot tell you which of the two you have. Check the URL in `meta["proxy"]` on the failing request, then follow the order of checks in [Fix proxy error 407](/guides/fix-proxy-error-407). - `TunnelError` is in `RETRY_EXCEPTIONS`. With default settings the lab proxy received the rejected `CONNECT` three times. The log showed `Retrying (failed 1 times)`, then `(failed 2 times)`, then `Gave up retrying`. With `"dont_retry": True` in `meta` the proxy received one. - `handle_httpstatus_list` changes nothing here. There is no response, only the exception, so handle it in an `errback`. ## Ignoring response 407: HTTP status code is not handled or not allowed ```text Ignoring response <407 http://127.0.0.1:8080/>: HTTP status code is not handled or not allowed ``` For an `http://` URL the proxy's 407 is an ordinary response, and `HttpErrorMiddleware` drops it. The callback was never called, this INFO line was the only sign, and the crawl closed with `finish_reason: finished`. With an `errback` the line is not logged and the errback receives `scrapy.spidermiddlewares.httperror.HttpError: Ignoring non-200 response`. Scrapy did not retry the request. To get the response in the callback, allow the status for the request: ```python yield scrapy.Request(url, meta={"proxy": PROXY, "handle_httpstatus_list": [407]}) ``` The spider attribute `handle_httpstatus_list = [407]` and the setting `HTTPERROR_ALLOWED_CODES = [407]` did the same ([HttpErrorMiddleware](https://docs.scrapy.org/en/latest/topics/spider-middleware.html#module-scrapy.spidermiddlewares.httperror)). The callback then received status 407 with `Proxy-Authenticate: Basic realm="lab"`. Without any of them, the crawl stats count the dropped responses under `httperror/response_ignored_status_count/407`. ## UnsupportedURLSchemeError: Unsupported scheme: b'socks5' ```text scrapy.exceptions.UnsupportedURLSchemeError: Unsupported scheme: b'socks5' ``` Scrapy's default download handler has no SOCKS support. With `meta["proxy"] = "socks5://127.0.0.1:1080"`, an `http://` request raised this error once, with no retry. `socks5h://` raised `Unsupported scheme: b'socks5h'`, and a SOCKS URL in `HTTP_PROXY` raised the same error. An `https://` request did not raise it. Scrapy sent `CONNECT 127.0.0.1:8443` as plain HTTP to the SOCKS port, the lab's SOCKS server closed the connection, and Scrapy waited for the download timeout three times before it reported `DownloadTimeoutError: Getting https://127.0.0.1:8443/ took longer than 15.0 seconds.` The lab set `DOWNLOAD_TIMEOUT` to 15. The default is 180. There are two ways out: - Use an HTTP proxy endpoint if your provider has one. Everything above then applies. - Switch to `HttpxDownloadHandler`. It ships with Scrapy, and the [documentation](https://docs.scrapy.org/en/latest/topics/download-handlers.html#httpx-handler) lists it as supporting SOCKS5 and marks it experimental and not yet recommended for production. ```sh python -m pip install "scrapy[httpx]" ``` ```python DOWNLOAD_HANDLERS = { "http": "scrapy.core.downloader.handlers._httpx.HttpxDownloadHandler", "https": "scrapy.core.downloader.handlers._httpx.HttpxDownloadHandler", } ``` With this handler `socks5://` returned 200 for both schemes. For `http://localhost:8080/` the SOCKS server logged a domain name, so the handler sends the hostname to the proxy. `socks5h://` worked too. [socks5 vs socks5h](/blog/socks5-vs-socks5h) shows what other clients do with the two schemes. Its errors read differently: a rejected `CONNECT` surfaced as `scrapy.exceptions.DownloadConnectionRefusedError: 407 Proxy Authentication Required`. ## Retries: RetryMiddleware repeats POST requests `RetryMiddleware` retried a `POST` the way it retries a `GET`. In the lab a `POST` went through the proxy to a target that read the request and closed the connection without answering. Scrapy logged `Retrying (failed 1 times)` and sent it again. The target received the same body twice and the callback saw one 201. For a request that is not safe to repeat, set `"dont_retry": True` in `meta` ([RetryMiddleware](https://docs.scrapy.org/en/latest/topics/downloader-middleware.html#module-scrapy.downloadermiddlewares.retry)). The target then received one `POST` and the errback got `scrapy.exceptions.DownloadFailedError`. [Proxy retries: one lost response, two created jobs](/blog/proxy-retries-duplicate-jobs) shows what an idempotency key changes. Each retry is another request through the proxy. [How many GB of proxies do you need](/blog/how-many-gb-of-proxies-do-i-need) measures what an HTML-only fetch uses. For diagnostic help inside a coding agent, [Proxy Toolkit MCP](/mcp) accepts sanitized error descriptions. Keep credentials out of its arguments. ## How this was tested On Ubuntu 26.04.1 with Python 3.14.4, Scrapy 2.19.0, Twisted 26.4.0 and httpx2 2.13.1, everything on `127.0.0.1`: `python -m http.server` as the HTTP and HTTPS targets, three proxies that require Basic authentication and log every request with its header names, a SOCKS5 server that logs each destination, and a target that loses the response to the first `POST`. Each of the 62 cases ran `scrapy runspider` in a new interpreter with a clean environment. No proxy account was used. On Python 3.15.0, `pip install scrapy` fails without a C compiler because brotli had no cp315 wheel on 14 October 2026; [Python 3.15 for web scraping](/blog/python-3-15-web-scraping) has the tested fixes. The [lab archive](https://ipvolt.com/downloads/scrapy-proxy-setup/scrapy-proxy-lab.zip) contains the [runner](https://ipvolt.com/downloads/scrapy-proxy-setup/run_lab.py), the [cases](https://ipvolt.com/downloads/scrapy-proxy-setup/cases.py), the [proxy](https://ipvolt.com/downloads/scrapy-proxy-setup/auth_proxy.py), the [SOCKS5 server](https://ipvolt.com/downloads/scrapy-proxy-setup/socks5_server.py), the [README](https://ipvolt.com/downloads/scrapy-proxy-setup/README.md) and the [recorded results](https://ipvolt.com/downloads/scrapy-proxy-setup/results.json). Not tested: macOS and Windows, Digest and NTLM proxy authentication, authenticated SOCKS proxies, proxies reached over TLS, HTTP/2 and Scrapy's aiohttp-based download handler. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources & further reading - [Scrapy documentation: HttpProxyMiddleware and HTTPPROXY_ENABLED](https://docs.scrapy.org/en/latest/topics/downloader-middleware.html#module-scrapy.downloadermiddlewares.httpproxy) - [Scrapy documentation: Request.meta special keys (proxy, dont_retry, handle_httpstatus_list)](https://docs.scrapy.org/en/latest/topics/request-response.html#topics-request-meta) - [Scrapy documentation: HttpErrorMiddleware and HTTPERROR_ALLOWED_CODES](https://docs.scrapy.org/en/latest/topics/spider-middleware.html#module-scrapy.spidermiddlewares.httperror) - [Scrapy documentation: RetryMiddleware](https://docs.scrapy.org/en/latest/topics/downloader-middleware.html#module-scrapy.downloadermiddlewares.retry) - [Scrapy documentation: Spider.start()](https://docs.scrapy.org/en/latest/topics/spiders.html#scrapy.Spider.start) - [Scrapy documentation: HttpxDownloadHandler](https://docs.scrapy.org/en/latest/topics/download-handlers.html#httpx-handler) - [Scrapy release notes: 2.16.0, start_requests() removed](https://docs.scrapy.org/en/latest/news.html#release-2-16-0) - [Scrapy release notes: 2.6.2, Proxy-Authorization security fix](https://docs.scrapy.org/en/latest/news.html#release-2-6-2) - [Scrapy release notes: 2.7.1, explicit Proxy-Authorization header](https://docs.scrapy.org/en/latest/news.html#release-2-7-1) ## Related guides - [Fix proxy error 407 without guessing](https://ipvolt.com/guides/fix-proxy-error-407.md) - [Scrapy crawls 0 pages after upgrading: start_requests() is no longer called](https://ipvolt.com/guides/scrapy-start-requests-not-called.md) - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md) - [aiohttp proxies in 3.14: auth without BasicAuth, env vars and the errors you'll hit](https://ipvolt.com/guides/aiohttp-proxy-setup.md) - [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md) - [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Residential from $2.20 per GB. Mobile from $9 a day. [Buy residential](https://ipvolt.com/dashboard/residential) [Buy mobile](https://ipvolt.com/dashboard/mobile) --- Document 101 of 138: Scrapy crawls 0 pages after upgrading: start_requests() is no longer called URL: https://ipvolt.com/guides/scrapy-start-requests-not-called Markdown: https://ipvolt.com/guides/scrapy-start-requests-not-called.md # Scrapy crawls 0 pages after upgrading: start_requests() is no longer called Source: https://ipvolt.com/guides/scrapy-start-requests-not-called Markdown: https://ipvolt.com/guides/scrapy-start-requests-not-called.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Scrapy crawls 0 pages after upgrading: start_requests() is no longer called](https://ipvolt.com/guides/scrapy-start-requests-not-called.md) Category: Troubleshooting Published: 2026-10-10 Reading time: 6 minutes Author: ipvolt Scrapy 2.16 removed Spider.start_requests(): the spider logs Crawled 0 pages and closes as finished with no warning. Fix: async def start(). Tested on 2.19. After an upgrade to Scrapy 2.16 or later, a spider that defines only `start_requests()` opens, sends no request and closes as if it had finished: ```text 2026-10-09 12:33:33 [scrapy.core.engine] INFO: Spider opened 2026-10-09 12:33:33 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min) 2026-10-09 12:33:33 [scrapy.core.engine] INFO: Closing spider (finished) 2026-10-09 12:33:33 [scrapy.core.engine] INFO: Spider closed (finished) ``` These are the engine and logstats lines of a Scrapy 2.19.0 run. The log had no WARNING or ERROR line, the exit code was 0 and `parse()` never ran. The stats dump had `'finish_reason': 'finished'` and no `downloader/request_count` key. The cause: Scrapy 2.16.0 (19 May 2026) removed `Spider.start_requests()`, deprecated since 2.13.0. The [release notes](https://docs.scrapy.org/en/latest/news.html#release-2-16-0) say it "is removed and no longer called" ([pull request #7490](https://github.com/scrapy/scrapy/pull/7490)). The fix is to rename the method to `async def start()`: ```python # Before: Scrapy 2.16 and later never call this def start_requests(self): yield scrapy.Request("https://example.com/", callback=self.parse) ``` ```python # After async def start(self): yield scrapy.Request("https://example.com/", callback=self.parse) ``` With that one change the same spider crawled its page on Scrapy 2.16.0 and 2.19.0. | What you see on 2.16+ | Cause | Fix | | --- | --- | --- | | `Crawled 0 pages`, then `Spider closed (finished)`, no warning | The spider defines only `start_requests()` | Rename it to `async def start()` | | The crawl runs, but a middleware no longer changes the first requests | A spider middleware defines only `process_start_requests()` | Add `async def process_start()` | | `TypeError: Middleware ... doesn't support asynchronous spider output`, exit code 1 | A spider middleware has a synchronous `process_spider_output()` | Make it an async generator | Everything below was recorded on 9 October 2026 with Scrapy 2.19.0, Twisted 26.4.0 and Python 3.14.4, and repeated on Scrapy 2.16.0, 2.15.2 and 2.12.0. A spider that only sets `start_urls` and defines neither method is not affected: it crawled on all four. ## Migrate start_requests() to async def start() [`Spider.start()`](https://docs.scrapy.org/en/latest/topics/spiders.html#scrapy.Spider.start) is an asynchronous generator: `async def` with `yield`. The requests you yield stay the same. Two slips give a different symptom, an ERROR line and still no request: ```text TypeError: e1_start_not_async.LabSpider.start() must be an asynchronous generator, i.e. an async def method with yield statements, got ``` That is `def start()` without `async`. An `async def start()` that returns a list ends with `got `. In both cases Scrapy 2.19.0 closed the spider with `'finish_reason': 'start_error'` and the exit code was still 0. If the spider overrode `start_requests()` to add headers or meta to `start_urls`, keep the loop: ```python async def start(self): for url in self.start_urls: yield scrapy.Request( url, headers={"Accept-Language": "en-AU"}, meta={"page": 1}, dont_filter=True, ) ``` The default `start()` is the same loop with `dont_filter=True` and nothing else, so keep that argument. In the lab the callback read the header from `response.request.headers` and `page` from `response.meta`. A proxy goes in `meta` as before: ```python async def start(self): yield scrapy.Request( "https://example.com/", meta={"proxy": "http://user:pass@proxy.example.com:8080"}, ) ``` The lab's `http://` request arrived at a local proxy that requires Basic authentication, with valid credentials. [Scrapy proxies in 2.19](/guides/scrapy-proxy-setup) covers rotation and the proxy environment variables, and [Fix proxy error 407](/guides/fix-proxy-error-407) covers a proxy that rejects the credentials. ## Support Scrapy below 2.13 and 2.16+ with both methods Code that has to run on both sides of the change defines both methods. The release notes put it this way: "Use start() instead, or both to maintain support for lower Scrapy versions." ```python async def start(self): for request in self.start_requests(): yield request def start_requests(self): yield scrapy.Request("https://example.com/", callback=self.parse) ``` Scrapy 2.12.0 called `start_requests()`, and 2.15.2, 2.16.0 and 2.19.0 called `start()`. Each crawled the page, and 2.15.2 logged no deprecation warning. The opposite mistake is just as quiet: a spider with only `async def start()` sent no request on 2.12.0 and closed as finished. ## Spider middlewares: process_start_requests() is skipped without a warning The same release removed support for `process_start_requests()` in spider middlewares. The lab middleware set `meta["tagged"] = True` on each start request. On 2.19.0, under a migrated spider, the page was crawled, the callback logged `tagged=None` and the log had no warning: the method was never called. Scrapy 2.15.2 stopped the same pair with a `ValueError`, so the upgrade turned an error into silence. Replace it with [`process_start()`](https://docs.scrapy.org/en/latest/topics/spider-middleware.html#scrapy.spidermiddlewares.SpiderMiddleware.process_start): ```python class TagStartMiddleware: async def process_start(self, start): async for item_or_request in start: if isinstance(item_or_request, scrapy.Request): item_or_request.meta["tagged"] = True yield item_or_request ``` With this the callback logged `tagged=True` on 2.15.2, 2.16.0 and 2.19.0. To support Scrapy below 2.13 too, keep `process_start_requests()` next to it. With both methods in the middleware and both in the spider, the request was tagged on all four versions. ## TypeError: Middleware doesn't support asynchronous spider output A synchronous `process_spider_output()` fails loudly. The crawl stops before `Spider opened`, with exit code 1: ```text TypeError: Middleware d2_mw_sync_output.StampMiddleware doesn't support asynchronous spider output. Its process_spider_output() method should be an async generator function or it should additionally define a process_spider_output_async() method. ``` `d2_mw_sync_output.StampMiddleware` is the lab's middleware, and yours is named in its place. Scrapy 2.15.2 ran the same middleware with a warning that it "will stop working in a future version of Scrapy". Make the method an async generator: ```python class StampMiddleware: async def process_spider_output(self, response, result): async for item_or_request in result: if isinstance(item_or_request, dict): item_or_request["stamped"] = True yield item_or_request ``` The signature has no `spider` parameter. With one, 2.19.0 still ran the middleware and logged `ScrapyDeprecationWarning: StampMiddleware.process_spider_output() requires a spider argument`. A middleware that already has a synchronous `process_spider_output()` and a `process_spider_output_async()` loaded without the error, and 2.19.0 ran the async one. If the class in the message comes from an installed package, look for a release of that package that supports your Scrapy version. ## Check which Scrapy version you are running ```sh scrapy version python -m pip show scrapy ``` In the lab the first printed `Scrapy 2.19.0` and the second `Version: 2.19.0`. The first line of the crawl log names it too: `Scrapy 2.19.0 started (bot: scrapybot)`. Run the commands in the environment that runs the crawl, such as the virtual environment, the container image or the CI job. A `requirements.txt` line that says only `scrapy` installs the newest release on the next build. If you cannot migrate today, hold the last release line that still calls `start_requests()`: ```text scrapy>=2.15,<2.16 ``` In the lab that resolved to 2.15.2, which crawled the unchanged spider and logged a `ScrapyDeprecationWarning` that names the spider class and says the method "will stop being called in a future version of Scrapy". Treat the pin as temporary: the release notes list security bug fixes in [2.17.0](https://docs.scrapy.org/en/latest/news.html#release-2-17-0). After migrating, pin the version you tested. On Python 3.15 without a C compiler, `pip install --only-binary brotli scrapy` quietly installed Scrapy 2.17.0 instead of 2.19.0; [Python 3.15 for web scraping](/blog/python-3-15-web-scraping) shows how to catch that. ## Catch a zero-request crawl in CI With exit code 0 and `finish_reason` `finished`, a job that only checks whether the crawl succeeded passes. Assert on the request count: ```python from scrapy.crawler import CrawlerProcess from myproject.spiders.quotes import QuotesSpider def test_spider_sends_requests(): process = CrawlerProcess(settings={"LOG_LEVEL": "WARNING"}) crawler = process.create_crawler(QuotesSpider) process.crawl(crawler) process.start() assert crawler.stats.get_value("downloader/request_count", 0) > 0 ``` On 2.16.0 and 2.19.0 this failed for the `start_requests()` spider with `AssertionError: assert 0 > 0` and passed after the rename. On 2.15.2 it passed for both. The lab ran one crawl per pytest process against a local `python -m http.server`, so point yours at a fixture or a page you are allowed to fetch. For a scheduled job, read the same number from the stats dump at the end of the log. A run that sent requests has a `'downloader/request_count'` entry, and the failed run had none. ## How this was tested On Ubuntu 26.04.1 with Python 3.14.4, everything on `127.0.0.1`: `python -m http.server` as the target and a forward proxy that requires Basic authentication. Four virtual environments held Scrapy 2.19.0 and 2.16.0 with Twisted 26.4.0, 2.15.2 with Twisted 25.5.0, and 2.12.0 with Twisted 24.11.0. Each of the 17 spiders ran on each version with `scrapy runspider` in a new interpreter with a clean environment: 68 runs, plus 8 pytest runs. No proxy account was used. The [lab archive](https://ipvolt.com/downloads/scrapy-start-requests-not-called/scrapy-start-requests-lab.zip) contains the [runner](https://ipvolt.com/downloads/scrapy-start-requests-not-called/run_lab.py), the spiders, the [pytest check](https://ipvolt.com/downloads/scrapy-start-requests-not-called/ci/test_crawl.py), the [README](https://ipvolt.com/downloads/scrapy-start-requests-not-called/README.md) with a table of every result, and the [recorded results](https://ipvolt.com/downloads/scrapy-start-requests-not-called/results.json). Not tested: macOS and Windows, Scrapy 2.13, 2.14, 2.17 and 2.18, `CrawlSpider` rules and third-party middlewares. Once the spider sends requests again, each one counts against a proxy plan. [How many GB of proxies do you need](/blog/how-many-gb-of-proxies-do-i-need) measures what an HTML-only fetch uses. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources & further reading - [Scrapy release notes: 2.16.0, deprecation removals](https://docs.scrapy.org/en/latest/news.html#release-2-16-0) - [Scrapy documentation: Spider.start()](https://docs.scrapy.org/en/latest/topics/spiders.html#scrapy.Spider.start) - [Scrapy documentation: SpiderMiddleware.process_start()](https://docs.scrapy.org/en/latest/topics/spider-middleware.html#scrapy.spidermiddlewares.SpiderMiddleware.process_start) - [Scrapy documentation: SpiderMiddleware.process_spider_output()](https://docs.scrapy.org/en/latest/topics/spider-middleware.html#scrapy.spidermiddlewares.SpiderMiddleware.process_spider_output) - [scrapy/scrapy pull request #7490: Drop start_requests() support](https://github.com/scrapy/scrapy/pull/7490) - [scrapy/scrapy pull request #7504: Remove support for sync process_spider_output()](https://github.com/scrapy/scrapy/pull/7504) - [Scrapy release notes: 2.17.0, security bug fixes](https://docs.scrapy.org/en/latest/news.html#release-2-17-0) ## Related guides - [Scrapy proxies in 2.19: auth, rotation and the errors you'll hit](https://ipvolt.com/guides/scrapy-proxy-setup.md) - [Fix proxy error 407 without guessing](https://ipvolt.com/guides/fix-proxy-error-407.md) - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md) - [aiohttp proxies in 3.14: auth without BasicAuth, env vars and the errors you'll hit](https://ipvolt.com/guides/aiohttp-proxy-setup.md) - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Residential from $2.20 per GB. Mobile from $9 a day. [Buy residential](https://ipvolt.com/dashboard/residential) [Buy mobile](https://ipvolt.com/dashboard/mobile) --- Document 102 of 138: curl_cffi proxies: auth, the 407 that ProxyError misses, and SOCKS URL: https://ipvolt.com/guides/curl-cffi-proxy-setup Markdown: https://ipvolt.com/guides/curl-cffi-proxy-setup.md # curl_cffi proxies: auth, the 407 that ProxyError misses, and SOCKS Source: https://ipvolt.com/guides/curl-cffi-proxy-setup Markdown: https://ipvolt.com/guides/curl-cffi-proxy-setup.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [curl_cffi proxies: auth, the 407 that ProxyError misses, and SOCKS](https://ipvolt.com/guides/curl-cffi-proxy-setup.md) Category: Integration Published: 2026-10-10 Reading time: 8 minutes Author: ipvolt curl_cffi proxy setup on 0.16.3: credentials with impersonate, why a CONNECT 407 raises ConnectionError and not ProxyError, HTTP_PROXY rules, socks5h. Put the credentials in the proxy URL and pass it as `proxy`: ```python from curl_cffi import requests PROXY = "http://user:pass@proxy.example.com:8080" with requests.Session(impersonate="chrome", proxy=PROXY) as session: response = session.get("https://example.com/") print(response.status_code) ``` To catch proxy failures, catch `ProxyError` and `ConnectionError`, and check `status_code` for 407. In curl_cffi 0.16 a proxy that rejects `CONNECT` raises `ConnectionError`, not `ProxyError`. In our lab this authenticated `https://` and `http://` requests against a local proxy that requires Basic authentication. Everything below was recorded on 10 October 2026 with curl_cffi 0.16.3 (libcurl 8.21.0) on Python 3.14.4. `impersonate` selects the browser profile curl_cffi copies for its TLS and HTTP/2 settings. Every result below was the same with and without it. Three details before the errors: - **Use `proxy` or `proxies`, not both.** `proxies={"http": PROXY, "https": PROXY}` worked the same on a request and on a `Session`. The key is the scheme of the URL you request: with only an `"https"` key, an `http://` request went direct. Passing both arguments raised `TypeError: Cannot specify both 'proxy' and 'proxies'`. - **Percent-encode the password in the URL.** `p@ss:w/rd` worked as `p%40ss%3Aw%2Frd`. Unencoded, the request raised `ProxyError` with `curl: (5) Unsupported proxy syntax`. `proxy_auth=("user", "p@ss:w/rd")` next to a proxy URL without credentials also worked and needs no encoding. - **Write `http://` for an HTTP proxy, for `https://` URLs too.** The scheme describes the connection to the proxy. An `https://` proxy URL pointed at the lab's plain HTTP proxy raised `SSLError` with `curl: (35) TLS connect error` and `WRONG_VERSION_NUMBER`. [SSL WRONG_VERSION_NUMBER behind a proxy](/guides/fix-ssl-wrong-version-number-proxy) covers that message. ## CONNECT tunnel failed, response 407: ConnectionError, not ProxyError ```text curl_cffi.requests.exceptions.ConnectionError: Failed to perform, curl: (7) CONNECT tunnel failed, response 407. See https://curl.se/libcurl/c/libcurl-errors.html first for more details. ``` For an `https://` URL curl_cffi first sends `CONNECT` to the proxy. The lab proxy answered 407 and the request raised this error. The message was identical with no credentials and with a wrong password. - `isinstance(error, ProxyError)` is `False`. `ProxyError` and `ConnectionError` are siblings under `RequestException`, so `except ProxyError` does not catch it. - `error.code` is 7. - `error.response` is a `Response` whose `status_code` is 0, not 407. The status is only in the message. - Code 7 is not specific to a 407. When the lab proxy could not reach the target it answered 502, and the message was `curl: (7) CONNECT tunnel failed, response 502`. With nothing listening on the proxy port it was `curl: (7) Failed to connect to 127.0.0.1:8443 over proxy 127.0.0.1 after 0 ms: Could not connect to server`. The class follows the curl error code, and that code changed between releases. We ran the same request on twelve of them: | curl_cffi | libcurl | Rejected `CONNECT` | SOCKS failure | | --- | --- | --- | --- | | 0.16.0 to 0.16.3 | 8.21.0 | `ConnectionError`, curl code 7 | `ProxyError`, curl code 97 | | 0.7.4 to 0.15.0 | 8.7.0 to 8.15.0 | `ProxyError`, curl code 56 | `ProxyError`, curl code 97 | Up to 0.15.0 the message was `curl: (56) CONNECT tunnel failed, response 407`. The curl command line moved from exit code 56 to 7 in 8.18.0. [Fix proxy error 407](/guides/fix-proxy-error-407) has that table and the order of checks for the credentials. This block handles a rejected `CONNECT` on both sides of the change, a SOCKS failure and a 407 response: ```python import re from curl_cffi.requests.exceptions import ConnectionError, ProxyError CONNECT_STATUS = re.compile(r"CONNECT tunnel failed, response (\d{3})") class ProxyFailure(Exception): pass def fetch(session, url): try: response = session.get(url) except ProxyError as error: raise ProxyFailure(f"proxy error, curl {error.code}") from error except ConnectionError as error: rejected = CONNECT_STATUS.search(str(error)) if error.code == 7 and rejected: raise ProxyFailure(f"proxy answered CONNECT with {rejected[1]}") from error raise if response.status_code == 407: raise ProxyFailure("proxy answered 407") return response ``` In the lab it reported `proxy answered CONNECT with 407`, `proxy answered CONNECT with 502`, `proxy answered 407` for an `http://` URL and `proxy error, curl 97` for a SOCKS failure. It re-raised the `ConnectionError` for a closed proxy port. ## 407 on http:// URLs: a response, not an exception For an `http://` URL there is no tunnel. curl_cffi sends the full URL to the proxy in a plain `GET`, as it has since 0.7.0b7 ([issue #326](https://github.com/lexiforest/curl_cffi/issues/326)), and the proxy's 407 comes back as the response. No exception was raised. `response.status_code` was 407, `response.ok` was `False` and the headers carried `Proxy-Authenticate: Basic realm="lab"`. Code that only catches exceptions treats this as a successful request with an empty body. `response.raise_for_status()` raised `curl_cffi.requests.exceptions.HTTPError: HTTP Error 407: Proxy Authentication Required`. On that exception `error.response.status_code` is 407. ## Environment variables: http_proxy is read, HTTP_PROXY is not With no proxy in the code, libcurl picks one from the environment: - For an `http://` URL, uppercase `HTTP_PROXY` was ignored and the request went direct. Lowercase `http_proxy` sent it through the proxy. - For an `https://` URL, `HTTPS_PROXY` and `https_proxy` were both used. `http_proxy` alone left an `https://` request direct. - `ALL_PROXY` and `all_proxy` applied to both schemes. - `NO_PROXY=127.0.0.1` and lowercase `no_proxy` sent the request direct. libcurl documents the exception: the variables are also checked in uppercase, "except the http_proxy one which is only used lowercase" ([libcurl environment variables](https://curl.se/libcurl/c/libcurl-env.html)). The reason is CGI: a server turns a `Proxy:` request header into an `HTTP_PROXY` variable for the script ([Everything curl](https://everything.curl.dev/usingcurl/proxies/env.html)). Scrapy reads uppercase `HTTP_PROXY` ([Scrapy proxies in 2.19](/guides/scrapy-proxy-setup)), and aiohttp reads no variable unless you pass `trust_env=True` ([aiohttp proxies in 3.14](/guides/aiohttp-proxy-setup)). [Proxy environment variables](/guides/proxy-environment-variables) compares more clients. Two results are easy to miss: - **`NO_PROXY` overrides the `proxy` argument.** With `NO_PROXY=127.0.0.1` set, `requests.get(url, proxy=PROXY)` went direct for both schemes. Adding `curl_options={CurlOpt.NOPROXY: ""}` sent it through the proxy again. Against `http_proxy` the argument won. - **`trust_env=False` did not turn the variables off.** A `Session(trust_env=False)` still used `http_proxy` and `HTTPS_PROXY`. So did `proxy=""`. Two settings did send the request direct with the variables set: ```python from curl_cffi import CurlOpt, requests requests.get("https://example.com/", proxies={"all": ""}) requests.get("https://example.com/", curl_options={CurlOpt.NOPROXY: "*"}) ``` Both also work as `Session` arguments. An empty proxy string "explicitly disables the use of a proxy, even if there is an environment variable set for it" ([CURLOPT_PROXY](https://curl.se/libcurl/c/CURLOPT_PROXY.html)). ## SOCKS: socks5:// resolves locally, socks5h:// sends the hostname The lab requested `http://dnsprobe.example:8080/`, a name that exists only in the hosts file as `127.0.0.2`, through a SOCKS5 server that logs each destination: - With `socks5://127.0.0.1:1080` the server logged `CONNECT atyp=IPv4 dest=127.0.0.2:8080`. curl_cffi resolved the name itself. - With `socks5h://127.0.0.1:1080` it logged `CONNECT atyp=DOMAIN dest=dnsprobe.example:8080`. The proxy received the hostname. An `https://` URL gave the same two results. This is curl's own convention ([Use a proxy with curl](/guides/curl-proxy-setup)). [socks5 vs socks5h](/blog/socks5-vs-socks5h) lists clients that do not follow it. A failed SOCKS handshake is the case that does raise `ProxyError`: ```text curl_cffi.requests.exceptions.ProxyError: Failed to perform, curl: (97) cannot complete SOCKS5 connection to 127.0.0.1. (1). See https://curl.se/libcurl/c/libcurl-errors.html first for more details. ``` `error.code` is 97. The last number in parentheses is the reply code the SOCKS server sent: the lab server answered 1, general failure. When the target port was closed and the server answered 5, the message ended in `(5)`. A scheme that does not match the port fails in other ways: - `socks5://` pointed at the HTTP proxy port raised `ProxyError` with `curl: (97) Received invalid version in initial SOCKS5 response.` - `http://` pointed at the SOCKS port raised `ProxyError` with `curl: (56) Proxy CONNECT aborted` for an `https://` URL. - With nothing listening on the SOCKS port, the error was the `ConnectionError` with code 7 again. ## AsyncSession: the same setup, the same errors ```python import asyncio from curl_cffi import AsyncSession PROXY = "http://user:pass@proxy.example.com:8080" async def main(): async with AsyncSession(impersonate="chrome", proxy=PROXY) as session: response = await session.get("https://example.com/") print(response.status_code) asyncio.run(main()) ``` Every async case matched its sync twin. A rejected `CONNECT` raised the same `ConnectionError` with code 7. An `http://` URL returned the 407 as a response. A SOCKS failure raised `ProxyError` with code 97. `socks5://` and `socks5h://` sent the same address types, and `HTTP_PROXY` was ignored while `http_proxy` was used. ## Retries: retry repeats POST requests curl_cffi does not retry by default. The lab sent a `POST` through the proxy to a target that reads the request and closes the connection without answering. The call raised `ConnectionError` with `curl: (52) Empty reply from server`, and the target had received one `POST`. With `requests.Session(proxy=PROXY, retry=1)` the same call returned 201, and the target had received the body twice. `retry` repeated the `POST` the way it repeats a `GET`. `retry=2` on a rejected `CONNECT` sent three `CONNECT` requests and raised the same error, with `Session` and with `AsyncSession`. A retry does not fix wrong credentials. Keep `retry` at 0 for requests that are not safe to repeat, or send an idempotency key. [Proxy retries: one lost response, two created jobs](/blog/proxy-retries-duplicate-jobs) shows what a key changes. For diagnostic help inside a coding agent, [Proxy Toolkit MCP](/mcp) accepts sanitized error descriptions. Keep credentials out of its arguments. ## How this was tested On Ubuntu 26.04.1 with Python 3.14.4 and curl_cffi 0.16.3 (libcurl 8.21.0-IMPERSONATE with BoringSSL), everything on loopback: `python -m http.server` as the HTTP and HTTPS targets, three proxies that require Basic authentication and log every request, a SOCKS5 server that logs each destination and one that answers every request with reply code 1, and a target that loses the response to the first `POST`. `dnsprobe.example` existed only in a private copy of the hosts file. Each of the 86 cases ran in a new interpreter with a clean environment. The version comparison installed twelve releases from 0.7.4 to 0.16.3. No proxy account was used. The [lab archive](https://ipvolt.com/downloads/curl-cffi-proxy-setup/curl-cffi-proxy-lab.zip) contains the [runner](https://ipvolt.com/downloads/curl-cffi-proxy-setup/run_lab.py), the [cases](https://ipvolt.com/downloads/curl-cffi-proxy-setup/cases.py), the [proxy](https://ipvolt.com/downloads/curl-cffi-proxy-setup/auth_proxy.py), the [SOCKS5 server](https://ipvolt.com/downloads/curl-cffi-proxy-setup/socks5_server.py), the [README](https://ipvolt.com/downloads/curl-cffi-proxy-setup/README.md), the [recorded results](https://ipvolt.com/downloads/curl-cffi-proxy-setup/results.json) and the [version comparison](https://ipvolt.com/downloads/curl-cffi-proxy-setup/versions.json). Not tested: macOS and Windows, Digest and NTLM proxy authentication, authenticated SOCKS proxies, proxies reached over TLS, HTTP/3 and WebSockets. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources & further reading - [curl_cffi documentation: Proxies](https://curl-cffi.readthedocs.io/en/latest/advanced.html#proxies) - [curl_cffi API reference: Session (proxy, proxies, proxy_auth, trust_env, retry)](https://curl-cffi.readthedocs.io/en/latest/api.html#curl_cffi.requests.Session) - [curl_cffi API reference: AsyncSession](https://curl-cffi.readthedocs.io/en/latest/api.html#curl_cffi.requests.AsyncSession) - [curl_cffi API reference: Exceptions and warnings (ProxyError, ConnectionError)](https://curl-cffi.readthedocs.io/en/latest/api.html#exceptions-and-warnings) - [curl_cffi documentation: Using CURLOPT_* in requests API (curl_options)](https://curl-cffi.readthedocs.io/en/latest/advanced.html#using-curlopt-in-requests-api) - [curl_cffi issue #326: CONNECT was sent for http:// URLs, changed in 0.7.0b7](https://github.com/lexiforest/curl_cffi/issues/326) - [libcurl: CURLOPT_PROXY (schemes, the empty string, socks5h)](https://curl.se/libcurl/c/CURLOPT_PROXY.html) - [libcurl: CURLOPT_NOPROXY and the no_proxy variable](https://curl.se/libcurl/c/CURLOPT_NOPROXY.html) - [libcurl environment variables: http_proxy is only used lowercase](https://curl.se/libcurl/c/libcurl-env.html) - [Everything curl: proxy environment variables and the CGI reason](https://everything.curl.dev/usingcurl/proxies/env.html) - [libcurl error codes: CURLE_COULDNT_CONNECT (7), CURLE_RECV_ERROR (56), CURLE_PROXY (97)](https://curl.se/libcurl/c/libcurl-errors.html) ## Related guides - [Fix proxy error 407 without guessing](https://ipvolt.com/guides/fix-proxy-error-407.md) - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md) - [aiohttp proxies in 3.14: auth without BasicAuth, env vars and the errors you'll hit](https://ipvolt.com/guides/aiohttp-proxy-setup.md) - [Scrapy proxies in 2.19: auth, rotation and the errors you'll hit](https://ipvolt.com/guides/scrapy-proxy-setup.md) - [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Residential from $2.20 per GB. Mobile from $9 a day. [Buy residential](https://ipvolt.com/dashboard/residential) [Buy mobile](https://ipvolt.com/dashboard/mobile) --- Document 103 of 138: Block Images, Fonts and Media in Playwright to Cut Proxy Bandwidth URL: https://ipvolt.com/guides/playwright-block-images-save-bandwidth Markdown: https://ipvolt.com/guides/playwright-block-images-save-bandwidth.md # Block Images, Fonts and Media in Playwright to Cut Proxy Bandwidth Source: https://ipvolt.com/guides/playwright-block-images-save-bandwidth Markdown: https://ipvolt.com/guides/playwright-block-images-save-bandwidth.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Block Images, Fonts and Media in Playwright to Cut Proxy Bandwidth](https://ipvolt.com/guides/playwright-block-images-save-bandwidth.md) Category: Integration Published: 2026-10-09 Reading time: 7 minutes Author: ipvolt Block images, fonts and media in Playwright with route() in Python and Node.js, for a whole browser context or by host, plus cache and service worker caveats. ## The starting point Abort the heavy requests a scraping job does not need, for every page in a browser context, then measure whether the run really moved fewer bytes. ## Measure the job before you block anything Images, fonts and video can make up much of what a page downloads, and many scraping jobs never read them. Blocking them with request interception is a common way to reduce proxy traffic. Whether it helps your job depends on your pages, so start with a measurement: run the job once as it is and record where the bytes go. [scrapescope](/guides/scraper-bandwidth-report) is a free, open-source local meter that reports bytes per host and per resource type for a Playwright run and models the effect of blocking images, media and fonts. The examples below use Playwright 1.63 and the placeholder https://example.com/. Point TARGET_URL at a page you are allowed to automate, and keep proxy settings and credentials in your own launch or context options; none are needed to try the blocking itself. ## Block by resource type in Python Playwright labels every request with the resource type the rendering engine perceived: document, stylesheet, image, media, font, script, texttrack, xhr, fetch, eventsource, websocket, manifest or other. Register one route for all URLs on the browser context and abort the three heavy types; every other request continues unchanged. Save as block_resources.py and run python block_resources.py after pip install playwright and playwright install chromium. The context also blocks service workers, for the reason explained further down. ### block_resources.py · Playwright for Python ```python import os from playwright.sync_api import Route, sync_playwright TARGET_URL = os.environ.get("TARGET_URL", "https://example.com/") BLOCKED_TYPES = {"image", "media", "font"} def block_heavy(route: Route) -> None: if route.request.resource_type in BLOCKED_TYPES: route.abort() else: route.continue_() with sync_playwright() as p: browser = p.chromium.launch() try: context = browser.new_context(service_workers="block") context.route("**/*", block_heavy) page = context.new_page() response = page.goto(TARGET_URL, wait_until="load") print({"status": response.status if response else None}) context.close() finally: browser.close() ``` ## Block by resource type in Node.js The Node.js version is the same route with the same three types. route.request().resourceType() returns the type, route.abort() fails the request before it leaves the browser, and route.continue() sends everything else as it was. Save as block-resources.mjs and run node block-resources.mjs after npm install playwright and npx playwright install chromium. ### block-resources.mjs · Playwright Chromium ```javascript import { chromium } from 'playwright'; const TARGET_URL = process.env.TARGET_URL ?? 'https://example.com/'; const BLOCKED_TYPES = new Set(['image', 'media', 'font']); const browser = await chromium.launch(); try { const context = await browser.newContext({ serviceWorkers: 'block' }); await context.route('**/*', route => BLOCKED_TYPES.has(route.request().resourceType()) ? route.abort() : route.continue()); const page = await context.newPage(); const response = await page.goto(TARGET_URL, { waitUntil: 'load' }); console.log({ status: response?.status() }); await context.close(); } finally { await browser.close(); } ``` ## Apply it to every page in the browser context A route on the browser context applies to requests made by any page in that context: pages you open later, second tabs and popups a page opens with window.open(). A route on a single page applies to that page only, so a popup or a new tab would load its images and fonts again. Register the context route before the first page loads, and put it in one helper so every job uses the same rule. When a request matches both, page routes take precedence over browser context routes, and when several page routes match, the most recently registered one wins. Keep one blocking route per context to avoid surprises. ### context-wide.mjs · one route for every page ```javascript import { chromium } from 'playwright'; const TARGET_URL = process.env.TARGET_URL ?? 'https://example.com/'; const BLOCKED_TYPES = new Set(['image', 'media', 'font']); // One route on the context covers every page the context opens, including // tabs opened later and popups. Register it before the first page loads. async function blockHeavyResources(context) { await context.route('**/*', route => BLOCKED_TYPES.has(route.request().resourceType()) ? route.abort() : route.continue()); } const browser = await chromium.launch(); try { const context = await browser.newContext({ serviceWorkers: 'block' }); await blockHeavyResources(context); const first = await context.newPage(); const second = await context.newPage(); await Promise.all([ first.goto(TARGET_URL, { waitUntil: 'load' }), second.goto(TARGET_URL, { waitUntil: 'load' }), ]); console.log({ pages: context.pages().length }); await context.close(); } finally { await browser.close(); } ``` ## Block specific heavy hosts by URL pattern Sometimes one host is the problem: a video CDN, an ad server or a font service. route() also takes a URL pattern, so you can abort everything from those hosts and leave the resource types alone. A glob such as https://media.example.net/** matches every URL on one host; a regular expression can list several. The hosts below are placeholders; take the real names from your measurement rather than from a generic blocklist. ### block_hosts.py · abort named hosts ```python import os import re from playwright.sync_api import sync_playwright TARGET_URL = os.environ.get("TARGET_URL", "https://example.com/") # A glob covers every URL on one host; a regular expression can cover several. HEAVY_HOST = "https://media.example.net/**" HEAVY_HOSTS = re.compile(r"^https://(video\.example\.org|fonts\.example\.com)/") with sync_playwright() as p: browser = p.chromium.launch() try: context = browser.new_context(service_workers="block") context.route(HEAVY_HOST, lambda route: route.abort()) context.route(HEAVY_HOSTS, lambda route: route.abort()) page = context.new_page() response = page.goto(TARGET_URL, wait_until="load") print({"status": response.status if response else None}) context.close() finally: browser.close() ``` ## Routing turns off the HTTP cache Playwright's API reference states for both page.route() and browserContext.route(): "Enabling routing disables http cache." Once any route is registered, stylesheets, scripts and other repeated assets that the browser would normally reuse from its cache are downloaded again for each page. On a job that loads many pages in one context, that extra transfer can offset part of what blocking removes, or all of it. This is why a single-page test is not enough: measure the whole run. ## Block service workers while you intercept Requests that a page's service worker handles can bypass your routes: the API reference notes that browserContext.route() will not intercept requests intercepted by Service Worker, and recommends disabling service workers when using request interception by setting serviceWorkers to 'block'. That is the service_workers="block" (Python) and serviceWorkers: 'block' (Node.js) context option in every example above. A site that depends on a service worker, for example to cache content for offline use, can behave differently once it cannot register one. ## Blocking can change what the page does Blocking images, media and fonts can break extraction, change how a page behaves or attract anti-bot scrutiny. A page may wait for an image before rendering the data you read, lazy-load content only after media events, or treat a browser that never downloads images as unusual. Check that the values you extract are unchanged after enabling the route, and keep blocking within what the site's terms allow. ## Measure again and compare Run the same job twice through the same provider, once without the route and once with it, and compare the two runs. A second measured run is the evidence; a model or an estimate is a prediction. [scrapescope](/guides/scraper-bandwidth-report) can compare two reports side by side in its viewer, including bytes per host and per resource type, so you can see what the route removed and what the lost HTTP cache added back. ## Before you ship - Measure the job once without blocking before changing anything. - Register the route on the browser context, before the first page loads. - Block service workers in the context options while routes are active. - Confirm that the extracted values are unchanged after blocking. - Compare a second measured run through the same provider before relying on the change. ## Sources & further reading - [Playwright: browserContext.route() (routing notes, v1.63)](https://playwright.dev/docs/api/class-browsercontext#browser-context-route) - [Playwright: page.route()](https://playwright.dev/docs/api/class-page#page-route) - [Playwright: request.resourceType()](https://playwright.dev/docs/api/class-request#request-resource-type) - [Playwright: the serviceWorkers context option](https://playwright.dev/docs/api/class-browser#browser-new-context-option-service-workers) - [Playwright for Python: browser_context.route()](https://playwright.dev/python/docs/api/class-browsercontext#browser-context-route) - [Playwright issue 1090: routes and service workers](https://github.com/microsoft/playwright/issues/1090) ## Related guides - [Configure a proxy in Playwright](https://ipvolt.com/guides/playwright-proxy-setup.md) - [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md) - [Fix ERR_TUNNEL_CONNECTION_FAILED in Playwright and Puppeteer](https://ipvolt.com/guides/fix-err-tunnel-connection-failed.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Residential from $2.20 per GB. Mobile from $9 a day. [Buy residential](https://ipvolt.com/dashboard/residential) [Buy mobile](https://ipvolt.com/dashboard/mobile) --- Document 104 of 138: Japan proxies: IP location and mobile network checks URL: https://ipvolt.com/guides/japan-proxies Markdown: https://ipvolt.com/guides/japan-proxies.md # Japan proxies: IP location and mobile network checks Source: https://ipvolt.com/guides/japan-proxies Markdown: https://ipvolt.com/guides/japan-proxies.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Countries](https://ipvolt.com/guides/countries.md) / [Japan proxies: IP location and mobile network checks](https://ipvolt.com/guides/japan-proxies.md) Category: Country Published: 2026-10-06 Reading time: 7 minutes Author: ipvolt Evaluate Japan proxies with separate IP-location, egress and mobile-access evidence. Work through au/UQ branding and Rakuten roaming before accepting a sample. For web QA through a Japan IP proxy, specify what your application must see: country `JP`, a required city, or a particular public IP network. Add a mobile-access condition only when the job depends on it. Then evaluate each requirement separately; a list of Japanese carrier brands cannot fill the missing evidence. This guide helps you turn an offer into a sample decision. It covers IP routing proxies, with a worked mobile-network example. No Japanese proxy endpoint or provider was tested. ## Choose the evidence your Japan test needs Write the application rule before requesting “Tokyo residential” or “Japan mobile.” If the rule only reads country, a city or cellular requirement adds a condition the application does not use. For access-type definitions, see [mobile versus residential proxies](/guides/mobile-vs-residential-proxies). | Requirement | Evidence to keep | What cannot replace it | | --- | --- | --- | | Country `JP` | Public exit IP, timestamp, selected country classifier and the application's country decision | The seller's Japan label | | Tokyo, Osaka or another city | Required city, dated classifier result and available accuracy radius; application decision if it uses that location | A country match or a registered company address | | A particular public IP network | Observed exit IP and ASN/network result with lookup source and date | The SIM or retail brand | | A particular serving mobile network | Dated access evidence tied to the sample, including serving operator and roaming state where relevant | A coverage map or an ASN alone | JPNIC WHOIS describes allocated or assigned address space and the responsible entities, plus ASN registration information. That is registration evidence. A Japanese registration or Tokyo contact address does not measure the sampled exit's location. [JPNIC WHOIS information](https://www.nic.ad.jp/en/db/whois/). MaxMind says mobile IPs may be used over broad areas and finer location data may be absent. Record missing city data as **unverified** when city is required; do not silently substitute `JP`. These are MaxMind's documented limits, not a measured accuracy rate for Japan. [MaxMind geolocation accuracy](https://support.maxmind.com/knowledge-base/articles/maxmind-geolocation-accuracy). ## Translate Japanese brands into the right request These operator descriptions change how you count candidate networks. They do not establish proxy inventory, resale permission or the access path of a supplied endpoint. | Names in an offer | What the operator documents | What to request | | --- | --- | --- | | NTT DOCOMO / ahamo | ahamo's FAQ says it is usable in DOCOMO 4G/5G service areas. [ahamo coverage FAQ](https://faq.ahamo.com/faq/show/5?site_domain=default) | Do not count the two labels as evidence of two different mobile networks. Specify the layer you need to differ. | | au / UQ mobile | KDDI says UQ mobile uses the same communication network as au. [KDDI's UQ description](https://newsroom.kddi.com/english/news/detail/kddi_nr-584_3897.html) | An au/UQ pair cannot establish different serving operators from its brand names. | | SoftBank / Y!mobile | Y!mobile describes using the same network as SoftBank. [Y!mobile network description](https://www.ymobile.jp/area/feature/) | Request evidence of the actual access and egress; changing these labels does not establish network diversity. | | Rakuten Mobile | KDDI describes supplemental au LTE roaming for Rakuten and a progressively shrinking roaming area. [KDDI's current roaming information](https://www.kddi.com/corporate/kddi/public/roaming/) | Specify whether the sample must use Rakuten's own network or whether partner access is acceptable. | The Rakuten distinction needs a date. KDDI's page showed a **30 September 2026** area update when checked on 6 October 2026, and cautions that its calculated map can differ from actual radio conditions. A Rakuten label or coverage screenshot therefore leaves the sample's serving network unverified. Agree in advance which device or modem record you will accept and how it will be tied to the sampled exit and time. [KDDI's scope and map limitations](https://www.kddi.com/corporate/kddi/public/roaming/). Keep public egress separate. An autonomous system describes IP routing policy; it is not a measurement of the serving radio network. Consequently, au partner access does not tell you which ASN your destination will observe. Record that result independently. [RFC 1930, section 3](https://www.rfc-editor.org/rfc/rfc1930.html#section-3). ## Worked decision: three brands, how many usable paths? **Hypothetical example: every sample and result below is invented.** A QA team needs two different serving mobile operators. Each sample must also return `JP` in the application's selected classifier and retain its own exit address at minutes 0, 5 and 10. There is no city requirement. This is an illustrative schedule, not a universal sample size. | Fictional evidence | Sample A | Sample B | Sample C | | --- | --- | --- | --- | | Seller's label | au | UQ mobile | Rakuten Mobile | | Application country result | JP at 3/3 attempts | JP at 3/3 attempts | JP at 3/3 attempts | | Exit within the sample | Unchanged at all three checks | Unchanged at all three checks | Unchanged at all three checks | | Timestamped serving-network evidence tied to the exit | au at all three checks | au at all three checks | Missing | The country and recorded-address conditions match for each sample. **A+B fails the different-serving-operator condition:** both records identify au. **A+C remains unverified:** the Rakuten label does not fill C's missing access evidence. Passing country checks cannot cancel that gap. The next evidence changes the purchase decision: - **C is confirmed on au partner access at all three checks:** A+C still fails the different-serving-operator condition. - **C is confirmed on Rakuten's own network at all three checks:** A+C matches the stated operator condition for those checkpoints. The team can accept that bounded record if all other agreed requirements also match. - **C has only a brand label or coverage map:** keep the condition unverified and request a sample with the necessary access evidence. This narrower result does not establish separate towers, backhaul or failure independence, nor continuous state between checks. If those are required, define and obtain evidence for them too. If the job instead requires **different egress ASNs**, this record cannot answer it: it contains no ASN observations. If the job only needs `JP`, the carrier comparison is unnecessary. ## Run and record the agreed sample The following is a proposed procedure for your authorized endpoint and test destination; it was not executed for this guide. 1. **Freeze the brief.** Record required country/city/network fields, client version, protocol, IP family, request budget, session checkpoints and reconnect rule. Agree the source and format of access evidence and how each record will be linked to a sample. Have the provider define any “mobile,” “residential” or “sticky” claim that matters to the brief. Use the [curl proxy setup guide](/guides/curl-proxy-setup) for connection configuration. 2. **Hold application inputs constant.** Keep the destination, account/cookies, language and other relevant settings fixed while comparing exits. Use the destination's trusted record of the public client IP. Preserve the seller's declarations in separate fields. 3. **Save every attempt.** Record time, exit IP, required classifier values and source/version, application output, errors and applicable access-evidence reference. Recheck required evidence after an address change or reconnect. Retain failures and any retry history in the denominator. 4. **Decide per condition.** A contradictory observed value is a **mismatch**. Missing required evidence is **unverified**. Accept the sample only when every required condition has matching evidence. Report the checkpoint count and observed window; address continuity at checkpoints does not prove exclusive use or future stability. For session terms, use [rotating versus sticky proxies](/guides/rotating-vs-sticky-proxies). Take unresolved conditions back to the provider as exact requests: for example, “Rakuten own-network access tied to each recorded sample,” rather than “another Japanese carrier.” For a separate application check after obtaining a page, see [Japanese price parsing](/blog/japanese-price-parsing). Its offline example preserves yen currency evidence and tax labels; an IP-location result alone does not validate a price record. ## Method and access ipvolt prepared this guide with agent-assisted source research and synthesis on 6 October 2026. Its original contribution is the brand/access/egress decision and hypothetical worked case. It measured no Japan endpoint, supply, speed or success rate. The full evaluation method is available without signup. ipvolt doesn't sell mobile proxies in Japan today. ## Sources & further reading - [利用できるエリアを教えてください。 (FAQ 5)](https://faq.ahamo.com/faq/show/5?site_domain=default) - [UQ mobile launches Komi-Komi Plan Value and Toku-Toku Plan 2](https://newsroom.kddi.com/english/news/detail/kddi_nr-584_3897.html) - [ネットワークの特長](https://www.ymobile.jp/area/feature/) - [楽天モバイル株式会社サービスへのローミング提供について](https://www.kddi.com/corporate/kddi/public/roaming/) - [WHOIS](https://www.nic.ad.jp/en/db/whois/) - [Geolocation accuracy](https://support.maxmind.com/knowledge-base/articles/maxmind-geolocation-accuracy) - [RFC 1930: Guidelines for creation, selection, and registration of an Autonomous System](https://www.rfc-editor.org/rfc/rfc1930.html) ## Related guides - [Mobile vs residential proxies: build a useful evaluation](https://ipvolt.com/guides/mobile-vs-residential-proxies.md) - [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md) - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Residential proxies are on sale from $2.20/GB. The dashboard lists the countries available now. ipvolt doesn't sell mobile proxies in Japan today. [See which countries and carriers are on sale.](https://ipvolt.com/pricing) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 105 of 138: Git proxy setup: HTTPS, config scope and safe removal URL: https://ipvolt.com/guides/git-proxy-setup Markdown: https://ipvolt.com/guides/git-proxy-setup.md # Git proxy setup: HTTPS, config scope and safe removal Source: https://ipvolt.com/guides/git-proxy-setup Markdown: https://ipvolt.com/guides/git-proxy-setup.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Git proxy setup: HTTPS, config scope and safe removal](https://ipvolt.com/guides/git-proxy-setup.md) Category: Integration Published: 2026-10-13 Reading time: 8 minutes Author: ipvolt Configure a Git HTTP or HTTPS proxy, diagnose 407 and certificate failures, and remove the correct setting. Includes a tested routing fixture. For an HTTP or HTTPS Git remote, start with a one-command `http.proxy` setting. Before making it permanent, check the remote transport and any URL-specific or remote-specific settings. **Clearing the general setting can leave a more specific proxy active.** Examples use illustrative endpoints. Our downloadable lab uses loopback, invented credentials and a temporary repository. Its ten checks ran on Git 2.50.1 (Apple Git-155), Python 3.14.8 and macOS 15.7.4 on 12 October 2026. It verifies routing and repository contents; it does not measure a proxy provider or test HTTPS, SSH or push. ## Check the remote transport Inside an existing repository, inspect the remote locally: ```sh git remote get-url origin ``` An `https://` or `http://` URL uses Git's HTTP transport. A remote such as `git@github.com:OWNER/REPO.git` or `ssh://git@HOST/REPO.git` uses SSH. `http.proxy` does not configure the SSH connection; follow your organization's SSH routing instructions for that transport. For a new clone, inspect the URL you intend to clone. Keep embedded credentials out of shared output. [Git command and SSH documentation](https://git-scm.com/docs/git#Documentation/git.txt-GITSSHCOMMAND). ## Try a proxy for one command Have your environment supply `GIT_PROXY_URL` and `GIT_REPO_URL`. The latter is an HTTP/HTTPS remote you are authorized to access. The proxy value is its documented gateway URL, such as `http://proxy.example:8080`: ```sh git -c http.proxy="$GIT_PROXY_URL" \ -c http.lowSpeedLimit=1 -c http.lowSpeedTime=20 \ ls-remote "$GIT_REPO_URL" ``` This leaves no persistent proxy entry. The low-speed options bound a stalled transfer; they are not a total command deadline. A refs response confirms a repository response, but success alone does not establish the route. To clone, replace `ls-remote` with `clone` and choose a new destination directory. An HTTPS remote can use an HTTP gateway: the proxy URL's scheme describes the connection **to the gateway**. Use an `https://` gateway only when it supports TLS. [Git HTTP options](https://raw.githubusercontent.com/git/git/v2.56.0/Documentation/config/http.adoc), [libcurl proxy protocols](https://curl.se/libcurl/c/CURLOPT_PROXY.html). Proxy and repository credentials serve different purposes. Git documents obtaining a password through its credential mechanism when the proxy URL supplies a username without a password. Follow the gateway's supported authentication method. Keep real credential-bearing URLs out of shared configuration and redact diagnostic output. [Git credentials](https://git-scm.com/docs/gitcredentials). ## Save the narrowest useful setting Choose one setting after the temporary check works. These commands use a credential-free illustrative gateway: | Intended reach | Configuration | Where to run it | | --- | --- | --- | | One HTTPS host | `git config --global 'http.https://github.com/.proxy' 'http://proxy.example:8080'` | Any directory | | One existing repository | `git config --local http.proxy 'http://proxy.example:8080'` | Inside that repository | | One named remote | `git config --local remote.origin.proxy 'http://proxy.example:8080'` | Inside that repository | | All HTTP/HTTPS remotes for this user | `git config --global http.proxy 'http://proxy.example:8080'` | Any directory | A repository-local setting needs an existing repository; use command or URL-scoped user configuration for the first clone. URL matching and ordinary config precedence are separate decisions. A named remote adds another override. [Git configuration scopes](https://git-scm.com/docs/git-config#_scopes), [remote proxy options](https://raw.githubusercontent.com/git/git/v2.56.0/Documentation/config/remote.adoc). ## What the routing fixture showed The [lab script](https://ipvolt.com/downloads/git-proxy-setup/git_proxy_lab.py) creates a bare repository, HTTP origin and authenticated forwarding proxy. Successful clone/fetch cases verify the expected commit and exact file payload; direct cases require zero proxy requests. The [recorded results](https://ipvolt.com/downloads/git-proxy-setup/results.json) retain commands, requests, failures and versions. | Controlled configuration | Observed result | What the result helps you decide | | --- | --- | --- | | One-command `http.proxy` | Proxy; repository verified | Start with this control | | Matching URL-specific proxy | Proxy; repository verified | Inspect the matching URL key | | URL entry for a different path | Direct; repository verified | Scoped entries have limited reach | | Correct remote proxy over a broken general proxy | Proxy; fetch verified | Inspect the named remote | | Empty remote proxy | Direct; fetch verified | Remote-level disable worked | | Empty command general proxy, only a general user entry present | Direct; repository verified | This cleared the general setting | | Empty command general proxy, matching URL entry present | **Proxy; repository verified** | The general empty value did not clear the URL match | | Empty matching URL entry over a general proxy | Direct; repository verified | Address the matching entry itself | | Matching `no_proxy=127.0.0.1` | Direct; repository verified | Check inherited bypass rules | | Wrong invented proxy password | Exit128/HTTP407; no origin request | Resolve gateway authentication first | All ten cases met their acceptance criteria, including the deliberately rejected authentication case. Nine clone/fetch operations succeeded and verified their repository contents. These observations apply to the recorded local Git/libcurl environment. Download the script and [README](https://ipvolt.com/downloads/git-proxy-setup/README.md) into a new directory, then run: ```sh python3 git_proxy_lab.py > local-results.json ``` The fixture requires Git with `GIT_CONFIG_GLOBAL` (introduced in Git2.32) and Python with `ThreadingHTTPServer` (introduced in Python3.7), with no Python packages. These feature requirements are documented; only the recorded Git2.50.1/Python3.14.8 environment was executed. See [Git2.32 release notes](https://raw.githubusercontent.com/git/git/v2.32.0/Documentation/RelNotes/2.32.0.txt) and [Python HTTP server documentation](https://docs.python.org/3/library/http.server.html). It uses IPv4 loopback, dedicated Git config files and a baseline cleared of inherited proxy variables. Temporary repositories are removed afterward. Its dumb HTTP transport does not test smart HTTP, CONNECT, certificates, SOCKS, production authentication systems or SSH. Certificate advice below comes from documentation. The documentation was checked against Git2.56.0 sources; the executed binary was Apple Git2.50.1. ## Find and remove the active setting Inspect locally: configuration values can contain credentials. ```sh git config --show-origin --show-scope --get-regexp \ '^(http\..*proxy|remote\..*\.proxy)$' git config --get-urlmatch http.proxy "$GIT_REPO_URL" ``` The first command locates general, URL-specific and remote-specific entries. The second reports HTTP URL matching; it does not incorporate the named remote or prove actual network routing. Also inspect the actual process's proxy/bypass variables using the [environment variables guide](/guides/proxy-environment-variables). Remove only the intended key and scope. For the example host entry: ```sh git config --global --unset-all 'http.https://github.com/.proxy' ``` For the example named remote, run inside its repository: ```sh git config --local --unset-all remote.origin.proxy ``` For the general user entry, use `git config --global --unset-all http.proxy`. A nonexistent key yields a nonzero status. Removal can expose a remaining setting, so inspect again and repeat your route check. Our fixture explains why clearing `http.proxy` alone can leave the matching URL proxy active. ## Diagnose the failing layer | Symptom | Next useful check | | --- | --- | | Cannot resolve proxy or connection refused | Selected gateway hostname, port and network access | | HTTP407 | Gateway account and supported authentication; use the [407 checklist](/guides/fix-proxy-error-407) | | Repository authentication failure after connection succeeds | Repository permissions and repository credential helper | | Certificate verification failure | Issuer, hostname and approved CA trust for the failing TLS connection | | SSH remote still fails | SSH-specific routing and transport policy | | Success without proxy evidence | URL/remote settings, environment bypass and gateway logs | For an approved corporate interception CA, Git exposes `http.sslCAInfo`; TLS to an HTTPS proxy has a separate `http.proxySSLCAInfo`. Obtain trust material from your administrator and keep verification enabled. These are separate connections, and the HTTP lab does not test either. Windows Schannel may use its certificate store rather than a supplied CA file; follow the platform-specific policy. [Git TLS options](https://raw.githubusercontent.com/git/git/v2.56.0/Documentation/config/http.adoc). For a gateway baseline outside Git, use the [bounded curl check](/guides/curl-proxy-setup#request). A successful curl request does not establish which route Git selects. For a timeout, identify the stalled stage before increasing limits; see [proxy timeout troubleshooting](/guides/proxy-timeout-troubleshooting). ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources & further reading - [Git HTTP options](https://raw.githubusercontent.com/git/git/v2.56.0/Documentation/config/http.adoc) - [Git configuration](https://git-scm.com/docs/git-config) - [Git remote options](https://raw.githubusercontent.com/git/git/v2.56.0/Documentation/config/remote.adoc) ## Related guides - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md) - [Fix proxy error 407 without guessing](https://ipvolt.com/guides/fix-proxy-error-407.md) - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md) - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 106 of 138: npm proxy settings: npmrc, precedence and install failures URL: https://ipvolt.com/guides/npm-proxy-settings Markdown: https://ipvolt.com/guides/npm-proxy-settings.md # npm proxy settings: npmrc, precedence and install failures Source: https://ipvolt.com/guides/npm-proxy-settings Markdown: https://ipvolt.com/guides/npm-proxy-settings.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [npm proxy settings: npmrc, precedence and install failures](https://ipvolt.com/guides/npm-proxy-settings.md) Category: Integration Published: 2026-10-13 Reading time: 9 minutes Author: ipvolt Set npm proxy and https-proxy, resolve npmrc and environment conflicts, verify package downloads, and fix trust or routing without disabling TLS checks. For npm registry traffic, inspect **both `proxy` and `https-proxy`**, choose one approved gateway, and test the package download as well as registry access. A successful `npm ping` is insufficient to prove an installation will work. In our controlled test, ping and package metadata succeeded while the tarball request failed. This guide's observations use **npm11.19.1, Node26.10.0 and macOS15.7.4**, recorded on 12 October 2026. Nine routing cases and four configuration-edit checks passed their stated acceptance criteria. The fixtures use an HTTP registry and forwarding proxies on loopback; they do not test HTTPS, certificates, proxy authentication or a commercial service. If `npm install undici` works but your Node.js 26 code then fails with `invalid onError method`, that is an undici version mismatch, not an npm setting: see [fetch failed: invalid onError method on Node.js 26](/guides/node-26-invalid-onerror-method). ## Distinguish the gateway from the registry `registry` identifies the service supplying package metadata. `proxy` and `https-proxy` configure the network gateway used to reach it. A Nexus “npm proxy repository” is a repository manager/cache exposed as an npm registry; it is a different layer from a forward HTTP proxy. Use your organization's registry URL and gateway as separate inputs. [Sonatype npm configuration](https://help.sonatype.com/en/configuring-npm.html), [npm configuration](https://docs.npmjs.com/cli/v11/using-npm/config/). Start inside the project where the failure occurs: ```sh node --version npm --version npm config get registry npm config get proxy https-proxy noproxy npm config get userconfig globalconfig ``` Inspect this output locally; proxy URLs can contain credentials. The registry URL is not evidence of the network route. Neither are `null` proxy values: our raw `HTTP_PROXY` case still used a proxy while npm displayed `null` for both configuration keys. ## Test registry access, metadata and the archive After inspecting the failing project, choose four explicit inputs: `NPM_PROXY_URL` for the approved gateway, `NPM_REGISTRY_URL` for the approved registry, `NPM_PACKAGE` for an unscoped package pinned as `NAME@VERSION`, and `NPM_USERCONFIG` for an approved absolute npmrc path. The userconfig path reported above is a starting point; ensure the chosen file supplies any required registry authentication. No tokens need to be copied into the diagnostic directory. For a private or scoped package, the approved configuration must preserve the appropriate registry and registry-scoped authentication. An `@scope:registry` entry is a distinct setting: do not assume the default `--registry` overrides it. Confirm the metadata's archive URL and the actual registry used. The basic commands below choose an unscoped package to isolate the gateway check. [npmrc scope and authentication](https://docs.npmjs.com/cli/v11/configuring-npm/npmrc/). An HTTP gateway may be used for an HTTPS registry; the gateway URL's scheme identifies its own connection protocol. Keep actual secrets out of shell-history literals and shared logs. Environment substitution does not conceal the expanded argument from local process inspection. Run all three checks in one new directory outside existing projects. Keep the same registry, approved config and proxy values, with a new cache path for each request stage: ```sh npm_proxy_check_dir="$(mktemp -d)" cd "$npm_proxy_check_dir" || exit 1 npm ping --proxy="$NPM_PROXY_URL" --https-proxy="$NPM_PROXY_URL" \ --registry="$NPM_REGISTRY_URL" --userconfig="$NPM_USERCONFIG" \ --cache="$npm_proxy_check_dir/cache-ping" \ --fetch-retries=0 --fetch-timeout=10000 npm view "$NPM_PACKAGE" version dist.tarball --json \ --proxy="$NPM_PROXY_URL" --https-proxy="$NPM_PROXY_URL" \ --registry="$NPM_REGISTRY_URL" --userconfig="$NPM_USERCONFIG" \ --cache="$npm_proxy_check_dir/cache-view" \ --fetch-retries=0 --fetch-timeout=10000 ``` `ping` probes the registry; `view` reads metadata, including the archive URL. Neither downloads and verifies the package archive. [npm ping](https://docs.npmjs.com/cli/v11/commands/npm-ping/), [npm view](https://docs.npmjs.com/cli/v11/commands/npm-view/). For the third check, stay in that diagnostic directory and use the same inputs: ```sh npm install "$NPM_PACKAGE" --ignore-scripts --no-audit --no-fund \ --no-package-lock --save=false \ --proxy="$NPM_PROXY_URL" --https-proxy="$NPM_PROXY_URL" \ --registry="$NPM_REGISTRY_URL" --userconfig="$NPM_USERCONFIG" \ --cache="$npm_proxy_check_dir/cache-install" \ --fetch-retries=0 --fetch-timeout=10000 ``` Inspect the installed package's expected name, version and contents. Our fixture checks exact payload files, rather than accepting an HTTP200 or successful metadata response. The fresh installation cache prevents a previously cached archive from silently satisfying this check. Also verify the gateway's request logs when available: a valid package alone does not prove which route carried it. Keep the diagnostic output for review and remove the temporary directory when finished. The install disables package installation scripts. It checks registry-package retrieval, not every dependency or a project's complete installation behavior. `fetch-timeout` and disabled fetch retries bound individual fetch behavior; they are not a ten-second deadline for the whole installation. [npm install](https://docs.npmjs.com/cli/v11/commands/npm-install/), [npm fetch options](https://docs.npmjs.com/cli/v11/using-npm/config/). ## Resolve configuration conflicts before saving settings For the **same key**, npm's documented priority runs from command options to `npm_config_*` environment values, then project, user and global configuration. The project's `.npmrc` can keep overriding a new user setting. Project configuration is not read in global install mode. [Pinned npm configuration hierarchy](https://github.com/npm/cli/blob/v11.19.1/workspaces/config/README.md), [npmrc files](https://docs.npmjs.com/cli/v11/configuring-npm/npmrc/). That hierarchy does not settle conflicts between different keys. In our npm11.19.1 case, a user `https-proxy=A` remained active despite a command `--proxy=B`. Both values survived configuration resolution, and the registry fetch implementation selected `httpsProxy || proxy`—even for our HTTP registry. Inspect and align both keys when you intend one gateway. [Pinned registry fetch implementation](https://raw.githubusercontent.com/npm/cli/v11.19.1/node_modules/npm-registry-fetch/lib/index.js). After the temporary test works, save credential-free illustrative values to the intended file: ```sh npm config set proxy=http://proxy.example:8080 \ https-proxy=http://proxy.example:8080 --location=user ``` Use `--location=project` from the relevant project if that is the desired scope. Keep credentials out of committed `.npmrc` files. npmrc supports environment substitutions for values; a configuration lookup can still display the expanded value. Registry tokens also have their own registry scope and are not proxy credentials. [npmrc authentication and substitutions](https://docs.npmjs.com/cli/v11/configuring-npm/npmrc/). ## What our routing fixture showed The [routing lab](https://ipvolt.com/downloads/npm-proxy-settings/npm-proxy-lab.mjs) creates a fake registry and proxies A/B, serves a real generated package archive and records each actual request. The [results](https://ipvolt.com/downloads/npm-proxy-settings/results.json) include exact command arguments, configuration and payload acceptance. | Controlled conflict | Observed route/outcome | Diagnostic value | | --- | --- | --- | | No proxy settings/environment | Direct; payload verified | Baseline | | User npmrc sets both keys A | A; payload verified | User config works in this fixture | | Project B over user A, both keys | B; payload verified | Inspect the project file | | `npm_config_proxy` and `npm_config_https_proxy` A over project B | A; payload verified | Inspect process configuration environment | | Command sets both keys B over config environment A | B; payload verified | Compare like keys at the same layer | | Only raw `HTTP_PROXY=A`, displayed values null | A; payload verified | npm config output is incomplete route evidence | | Raw `NO_PROXY=127.0.0.1` plus user proxy A, displayed noproxy empty | Direct; payload verified | A raw bypass can remain active | | B allows ping and metadata, rejects archive | Ping/view succeed; install failsE502, package absent | Check the archive request separately | | User `https-proxy=A`, project/command `proxy=B` | A; payload verified | Command priority for one key does not erase the other | Eight installations verified the expected package payload. The ninth was an intentional failure with no installed payload; all nine cases met their defined acceptance criteria. Raw environment fallback comes from the tested agent implementation. The bypass observation covers only the exact IPv4 loopback hostname, not wildcard, CIDR or every client. [Pinned npm agent](https://raw.githubusercontent.com/npm/agent/v4.0.2/lib/proxy.js). ## Remove values from the intended file Inspect the project `.npmrc` and the user/global paths reported earlier. If you meant to remove the example user settings: ```sh npm config delete proxy https-proxy --location=user ``` A project entry can still win. Remove project settings only when that is intended, from the project directory: ```sh npm config delete proxy https-proxy --location=project ``` Our four separate configuration-edit checks show that deleting user keys preserved the project's values; deleting the project keys then removed the effective pair in that isolated configuration. npm's documentation says deletion removes keys from all files, but the pinned npm11.19.1 implementation and our experiment act on the selected location. Use explicit scope and verify the result. [Pinned deletion implementation](https://raw.githubusercontent.com/npm/cli/v11.19.1/lib/commands/config.js), [npm config documentation](https://docs.npmjs.com/cli/v11/commands/npm-config/). Also inspect the actual process's `npm_config_proxy`, `npm_config_https_proxy`, `HTTP_PROXY`, `HTTPS_PROXY` and bypass variables. Removing file entries does not remove environment values. The [environment variables guide](/guides/proxy-environment-variables) explains how inherited settings differ by client. ## Diagnose remaining failures | Failure stage | Next check | | --- | --- | | No gateway connection | Host/port, selected config and process bypass settings | | Registry access succeeds, archive fails | `dist.tarball` host/path, gateway policy and archive request; account for cache | | Proxy407 | Gateway authentication; use the [407 guide](/guides/fix-proxy-error-407) | | Registry authentication error | Token, registry and scope; keep this separate from gateway credentials | | Certificate verification error | Approved CA trust and hostname for the actual failing connection | | Git dependency or install-script download fails | Use [Git proxy setup](/guides/git-proxy-setup) for HTTP(S) Git downloads; check each install script's client separately. npm registry settings do not establish those routes | For corporate CA trust, npm documents `cafile` and `strict-ssl`. Obtain the approved CA bundle from your administrator and keep `strict-ssl` enabled. The HTTP fixtures do not verify any HTTPS or corporate trust fix. [npm certificate configuration](https://docs.npmjs.com/cli/v11/using-npm/config/). ## Reproduce the two experiments Download the two scripts and [README](https://ipvolt.com/downloads/npm-proxy-settings/README.md) into one directory, then run with Node and npm installed: ```sh node npm-proxy-lab.mjs ./local-results.json node npm-config-edit-check.mjs ./local-config-results.json ``` The [configuration script](https://ipvolt.com/downloads/npm-proxy-settings/npm-config-edit-check.mjs) and [config results](https://ipvolt.com/downloads/npm-proxy-settings/config-edit-results.json) accompany the routing evidence. They use explicit temporary user/global config paths and caches, preserve your original user configuration and confine network requests to loopback. The recorded environment was npm11.19.1/Node26.10.0; the current v11 docs display a newer version, so rerun before generalizing to another release. No extra npm packages are required to run these fixtures. HTTPS/CONNECT, proxy credentials, private registry authentication, Git dependencies, existing lockfiles and lifecycle downloads remain outside the experiment. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources & further reading - [npm config](https://docs.npmjs.com/cli/v11/using-npm/config/) - [npmrc](https://docs.npmjs.com/cli/v11/configuring-npm/npmrc/) - [Pinned npm registry fetch](https://raw.githubusercontent.com/npm/cli/v11.19.1/node_modules/npm-registry-fetch/lib/index.js) ## Related guides - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md) - [Fix proxy error 407 without guessing](https://ipvolt.com/guides/fix-proxy-error-407.md) - [Use a proxy with Node.js fetch](https://ipvolt.com/guides/nodejs-fetch-proxy.md) - [Git proxy setup: HTTPS, config scope and safe removal](https://ipvolt.com/guides/git-proxy-setup.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 107 of 138: "Tunnel connection failed: 502 Bad Gateway" (and 503, 504) behind a proxy URL: https://ipvolt.com/guides/fix-proxy-tunnel-502-503 Markdown: https://ipvolt.com/guides/fix-proxy-tunnel-502-503.md # "Tunnel connection failed: 502 Bad Gateway" (and 503, 504) behind a proxy Source: https://ipvolt.com/guides/fix-proxy-tunnel-502-503 Markdown: https://ipvolt.com/guides/fix-proxy-tunnel-502-503.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / ["Tunnel connection failed: 502 Bad Gateway" (and 503, 504) behind a proxy](https://ipvolt.com/guides/fix-proxy-tunnel-502-503.md) Category: Troubleshooting Published: 2026-11-05 Reading time: 7 minutes Author: ipvolt A 502, 503 or 504 during CONNECT comes from the proxy; a 502 after the tunnel opens comes from the site. How to tell them apart in each client and fix both. A `502 Bad Gateway`, `503 Service Unavailable` or `504 Gateway Timeout` that arrives while the client is opening the proxy tunnel comes from the proxy: the tunnel never opened and the website never saw your request. A `502` that arrives after the tunnel opened comes from the website, or from something in front of it. Same number, different owner, different fix. Every error string and number below comes from a loopback lab run on 5 November 2026, linked at the end. ## Which side sent the 502 For an `https://` URL the client first asks the proxy for a tunnel with `CONNECT host:443` ([RFC 9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-connect)). If the proxy answers anything but 2xx, there is no tunnel and most clients raise an exception. If the tunnel opens and the website answers 502, you get an ordinary response. | Client | Proxy refused the tunnel | Website answered 502 | | --- | --- | --- | | curl 8.5.0 | exit 56, `curl: (56) CONNECT tunnel failed, response 502` | exit 0, `%{http_code}` is 502, `%{http_connect}` is 200 | | curl 8.18.0 | exit 7, `curl: (7) CONNECT tunnel failed, response 502` | exit 0, `%{http_code}` is 502, `%{http_connect}` is 200 | | Requests 2.34 | `requests.exceptions.ProxyError` with `Tunnel connection failed: 502 Bad Gateway` | `Response` with `status_code == 502` | | HTTPX 0.28 | `httpx.ProxyError: 502 Bad Gateway` | `Response` with `status_code == 502` | | aiohttp 3.14 | `ClientHttpProxyError: 502, message='Bad Gateway'` | response with `status == 502` | | Playwright 1.63 | `page.goto: net::ERR_TUNNEL_CONNECTION_FAILED` | `page.goto` resolves, `status()` is 502 | | Node.js 24 fetch | `TypeError: fetch failed`, and `err.cause.cause.message` is `Proxy response (502) !== 200 when HTTP Tunneling` | `response.status` is 502 | 503 and 504 follow the same pattern with their own number, for example `Tunnel connection failed: 503 Service Unavailable` or `curl: (7) CONNECT tunnel failed, response 504`. Chromium reported `net::ERR_TUNNEL_CONNECTION_FAILED` for all three, without the status; the [ERR_TUNNEL_CONNECTION_FAILED guide](/guides/fix-err-tunnel-connection-failed) covers that family. Requests says `Max retries exceeded` although it retries nothing by default: the lab proxy received one CONNECT per request. Node hides the status two levels down, so log the whole cause chain. Two cases break the rule. For a plain `http://` URL there is no tunnel, so curl, Requests, HTTPX, aiohttp and Playwright return the proxy's own 502 as a response; compare its `Server` header and body with the site's usual ones. Node's fetch tunnels `http://` URLs too, so there it stays an exception. And a proxy that closes the connection without a status gives no number at all: curl printed `curl: (56) Proxy CONNECT aborted`, Requests raised `ConnectionError` with `RemoteDisconnected('Remote end closed connection without response')`, HTTPX `RemoteProtocolError: Server disconnected without sending a response.` and Chromium `net::ERR_EMPTY_RESPONSE`. ## Check with one curl request Print both status codes for the failing URL through the same proxy: ```sh curl --disable -sS -o /dev/null -x "$PROXY_URL" \ -w 'connect=%{http_connect} http=%{http_code} exit=%{exitcode}\n' \ https://example.com/ ``` - `connect=502 http=000`: the proxy refused the tunnel; see the causes below. - `connect=200 http=502`: the website answered 502; see [when the website sent it](#when-the-website-sent-it). - `connect=000` with `Proxy CONNECT aborted`: the proxy closed the connection without a status. Check the port first. ## Causes on the proxy side **The site is unreachable from the exit (502).** The proxy's onward connection failed; in the lab a refused one became `502 Bad Gateway` in every client. Request the URL without the proxy and through another exit or country. If only one exit fails, the site is down or blocking that network from there, so switch exits. If every exit fails, check the host and port in your CONNECT line. **The exit is offline or rotating (503, sometimes 502).** The gateway has nowhere to send the request. Retry idempotent requests with backoff, as below, and check the exit's status in your provider's dashboard. **The proxy gave up waiting (504).** The proxy's deadline for reaching the site expired. The lab proxy waited 3 seconds, and every client failed after 3.0 to 3.5 seconds. Keep your client timeout longer than the proxy's deadline, or you see your own timeout instead of the 504; the [proxy timeout guide](/guides/proxy-timeout-troubleshooting) separates the two. **Wrong port or protocol.** We pointed every client, as an HTTP proxy, at a port that speaks only SOCKS5 (pproxy 2.7.9). The server closed the connection without a reply, so there was no 502 at all: curl 8.5.0 and 8.18.0 printed `curl: (56) Proxy CONNECT aborted`, aiohttp raised `ServerDisconnectedError`, and Node's fetch did not settle until its 10-second timeout fired. Copy the scheme, host and port from your provider's setup page. An `https://` proxy URL on a plain HTTP port fails differently; see [SSL WRONG_VERSION_NUMBER behind a proxy](/guides/fix-ssl-wrong-version-number-proxy). **Provider capacity.** A gateway that is out of capacity can answer 502 or 503 to new tunnels. Reduce concurrency, back off and send your provider the failure times in UTC. At the same step, a 407 is about authentication ([fix proxy error 407](/guides/fix-proxy-error-407)) and a 403 is a deliberate refusal ([CONNECT tunnel failed, response 403](/blog/connect-tunnel-failed-403)). ## Mobile proxies and IP rotation On a mobile proxy the exit is a device on a carrier network. While it changes IP there can be a moment with no working exit; depending on the gateway, the client then sees a 502 or 503 on CONNECT or a closed connection, reported as above. We did not measure a live rotation, so this guide gives no durations. If you start the rotation yourself, pause requests until a cheap test request succeeds. The lab simulated an exit that is offline for 4 seconds, with one Requests call per second. Seconds 0 to 3 failed with `Tunnel connection failed: 503 Service Unavailable`; from second 4 every request returned 200. The 4 seconds are the lab's setting: this shows the shape of a rotation, not its length. Built-in retries treat the two sides differently. `curl --retry 2` sent the CONNECT to the failing proxy once and stopped, but asked the website three times for its 502; with `--retry-all-errors` it repeated the CONNECT too. urllib3's `Retry(total=2, status_forcelist=[502, 503, 504])` repeated both. Node's fetch retried nothing after a status, but when the proxy closed the connection without one it reconnected 160,357 times in 10 seconds, until an `AbortSignal.timeout` stopped it. Always pass a signal. Retry GET requests only. A failed CONNECT never reached the site, but a 502 from the site can arrive after the site did the work, and a retried POST then runs twice; see [one lost response, two created jobs](/blog/proxy-retries-duplicate-jobs). This helper retries a GET after a proxy or site 502, 503 or 504 with capped, jittered backoff and stops on anything else, such as a 407: ```python import random, re, time import requests RETRYABLE = {502, 503, 504} TUNNEL_STATUS = re.compile(r"Tunnel connection failed: (\d{3})") def get_with_retry(session, url, attempts=5, base_delay=1.0, max_delay=8.0, **kwargs): for attempt in range(1, attempts + 1): try: response = session.get(url, **kwargs) except requests.exceptions.ProxyError as exc: match = TUNNEL_STATUS.search(str(exc)) # Requests reports the CONNECT status only as text if match is None or int(match.group(1)) not in RETRYABLE or attempt == attempts: raise else: if response.status_code not in RETRYABLE or attempt == attempts: return response time.sleep(min(max_delay, base_delay * 2 ** (attempt - 1)) * random.uniform(0.5, 1.0)) ``` In the recorded run it got through the 4-second offline window on its fourth attempt, after 5.7 seconds. Against a site that kept answering 502 it gave up after five attempts and 9.9 seconds and returned the 502. ## When the website sent it If the tunnel opened, the proxy did its job: the 502 came from the website's gateway, load balancer or CDN, which got no usable answer from the application behind it. Changing proxies or rotating the IP does not fix that. Request the URL without the proxy; if that fails too, wait and retry GETs with the helper above. If it fails only through the proxy, the site may be serving errors to that network; compare body and headers with a direct request before changing exits. ## Reproduce the lab The [download folder](/downloads/fix-proxy-tunnel-502-503/README.md) holds `lab.mjs` (a proxy on `127.0.0.1` that answers CONNECT with 502, 503 or 504 or hangs up, and a TLS origin that answers 502 itself), one script per client, `wrong_port.mjs`, `node_checks.mjs` and `retry_get.py` with the helper above. [results.json](/downloads/fix-proxy-tunnel-502-503/results.json) records the versions: curl 8.5.0 and 8.18.0, Python 3.14.4, Requests 2.34.2, urllib3 2.8.0, HTTPX 0.28.1, aiohttp 3.14.5, Node.js 24.22.1 with undici 7.30.1, and Playwright 1.63.0 with Chromium 153. Not tested: macOS and Windows, SOCKS and HTTPS proxies, and real provider gateways. Inside a coding agent, [Proxy Toolkit MCP](/mcp) offers error diagnostics; give it the client and the sanitized error, never credentials. ipvolt [mobile proxies](/pricing) are dedicated devices on carrier networks; you rotate the IP on demand or on a schedule, so a rotation never takes you by surprise. ## Sources & further reading - [RFC 9110: CONNECT](https://www.rfc-editor.org/rfc/rfc9110.html#name-connect) - [RFC 9110: 502 Bad Gateway](https://www.rfc-editor.org/rfc/rfc9110.html#name-502-bad-gateway) - [RFC 9110: 503 Service Unavailable](https://www.rfc-editor.org/rfc/rfc9110.html#name-503-service-unavailable) - [RFC 9110: 504 Gateway Timeout](https://www.rfc-editor.org/rfc/rfc9110.html#name-504-gateway-timeout) - [curl manual: --retry](https://curl.se/docs/manpage.html#--retry) - [curl manual: --retry-all-errors](https://curl.se/docs/manpage.html#--retry-all-errors) - [urllib3 documentation: Retry](https://urllib3.readthedocs.io/en/stable/reference/urllib3.util.html#urllib3.util.Retry) - [Requests documentation: proxies](https://requests.readthedocs.io/en/latest/user/advanced/#proxies) - [HTTPX documentation: proxies](https://www.python-httpx.org/advanced/proxies/) - [aiohttp documentation: proxy support](https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support) - [Playwright: HTTP proxy](https://playwright.dev/docs/network#http-proxy) - [Node.js CLI documentation: NODE_USE_ENV_PROXY](https://nodejs.org/api/cli.html#node_use_env_proxy1) - [pproxy on PyPI](https://pypi.org/project/pproxy/) ## Related guides - [Fix proxy error 407 without guessing](https://ipvolt.com/guides/fix-proxy-error-407.md) - [Fix ERR_TUNNEL_CONNECTION_FAILED in Playwright and Puppeteer](https://ipvolt.com/guides/fix-err-tunnel-connection-failed.md) - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md) - [SSL WRONG_VERSION_NUMBER behind a proxy: which hop failed](https://ipvolt.com/guides/fix-ssl-wrong-version-number-proxy.md) - [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md) - [Mobile vs residential proxies: build a useful evaluation](https://ipvolt.com/guides/mobile-vs-residential-proxies.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 108 of 138: fetch failed: invalid onError method on Node 26 (undici fix) URL: https://ipvolt.com/guides/node-26-invalid-onerror-method Markdown: https://ipvolt.com/guides/node-26-invalid-onerror-method.md # fetch failed: invalid onError method on Node 26 (undici fix) Source: https://ipvolt.com/guides/node-26-invalid-onerror-method Markdown: https://ipvolt.com/guides/node-26-invalid-onerror-method.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [fetch failed: invalid onError method on Node 26 (undici fix)](https://ipvolt.com/guides/node-26-invalid-onerror-method.md) Category: Troubleshooting Published: 2026-11-07 Reading time: 9 minutes Author: ipvolt Node.js 26 fetch fails with invalid onError method (UND_ERR_INVALID_ARG) when given an undici 5 or 6 Agent or ProxyAgent. Fix: use undici's own fetch. On Node.js 26, `fetch()` fails with `TypeError: fetch failed` and the cause `invalid onError method` (`UND_ERR_INVALID_ARG`) when it is given a dispatcher built by an older npm `undici`: a plain `Agent`, a keep-alive agent, an SSRF guard, a client library's bundled agent or, most often, a proxy agent. The request never leaves the process. Every version, error string and result below comes from a lab run on 7 November 2026 or from the linked documentation and issues. ## Quick fix ```sh node -p "process.versions.undici" npm ls undici ``` If the first command prints 8.x and the second lists `undici@5` or `undici@6`, that copy is the likely source. The fix that worked with every undici version on both Node lines in our tests is to import `fetch` from the package that builds the dispatcher: `import { fetch, ProxyAgent } from 'undici'` (Fix A below). If the dispatcher only exists to read `HTTPS_PROXY`, remove it and start Node with `--use-env-proxy`. Tested on Node.js 26.13.0 (bundled undici 8.12.2) and 24.22.2 (bundled undici 7.30.1) with npm undici 5.29.0, 6.29.1, 7.30.2 and 8.12.4, on macOS 26.5.1 arm64, 7 November 2026. The scripts and all 166 recorded cases are in the [lab folder](/downloads/node-26-invalid-onerror-method/README.md). ## The error: UND_ERR_INVALID_ARG in err.cause This is the complete output of the minimal reproduction shown further down, which passes an npm undici 6.29.1 `Agent` to the built-in `fetch` on Node.js 26.13.0. The lab path is shortened to `/lab`: ```text node:internal/modules/run_main:111 triggerUncaughtException( ^ [TypeError: fetch failed] { [cause]: InvalidArgumentError: invalid onError method at Agent.dispatch (/lab/u6/node_modules/undici/lib/dispatcher/dispatcher-base.js:198:15) at node:internal/deps/undici/undici:15144:57 at new Promise () at dispatchWithProtocolPreference (node:internal/deps/undici/undici:15144:18) at dispatch (node:internal/deps/undici/undici:15142:16) at httpNetworkFetch (node:internal/deps/undici/undici:15040:73) at httpNetworkOrCacheFetch (node:internal/deps/undici/undici:14912:39) at httpFetch (node:internal/deps/undici/undici:14729:43) at schemeFetch (node:internal/deps/undici/undici:14637:18) at mainFetch (node:internal/deps/undici/undici:14481:30) { code: 'UND_ERR_INVALID_ARG', Symbol(undici.error.UND_ERR): true, Symbol(undici.error.UND_ERR_INVALID_ARG): true } } Node.js v26.13.0 ``` The first `at` line names the copy of undici that threw: here `/lab/u6/node_modules/undici`. With a `ProxyAgent` the trace gains one line, `at ProxyAgent.dispatch`, and the message is the same. The same script on Node.js 24.22.2 printed `200`. Code that catches the error and logs only `err.message` prints just `fetch failed`; the reason is in `err.cause`. ## Why Node 26 rejects older undici dispatchers The built-in `fetch` is a copy of undici bundled into Node, and `process.versions.undici` tells you which one. The `dispatcher` option hands each request to the object you pass, so two undici versions have to agree on how they talk to each other. undici 8 renamed the handler callbacks a dispatcher calls, for example `onError` to `onResponseError` ([migration guide](https://undici.nodejs.org/best-practices/migrating-from-v7-to-v8)). Node 26's `fetch` passes a handler with only the new callbacks. An undici 5 or 6 dispatcher checks for the old `onError`, finds none and throws before it opens a connection. undici 7 dispatchers accepted the new callbacks in our tests. The minimal reproduction: ```js import { Agent } from 'undici'; const res = await fetch('https://example.com/', { dispatcher: new Agent() }); console.log(res.status); ``` The same `Agent`, `ProxyAgent` and `EnvHttpProxyAgent` cases, passed per request to the built-in `fetch`: | npm undici | Node.js 26.13.0 (undici 8.12.2) | Node.js 24.22.2 (undici 7.30.1) | | --- | --- | --- | | 5.29.0 | `invalid onError method` | works | | 6.29.1 | `invalid onError method` | works | | 7.30.2 | works | works | | 8.12.4 | works | `invalid onRequestStart method` | undici 5.29.0 has no `EnvHttpProxyAgent`; every other cell held for all three agent types. Older releases behaved the same on Node 26: `Agent` and `ProxyAgent` from 5.0.0, 5.28.4, 6.0.0 and 6.21.0 failed with `invalid onError method`, and from the eight 7.x releases we tried, 7.0.0 to 7.28.0, they worked. The last row is the same mismatch in reverse: Node 24's `fetch` passes a handler without `onRequestStart`, and an undici 8 dispatcher rejects it. ## Find what's bundling an old undici Run both commands with the same `node` and in the same project as the failing code: ```sh node -p "process.versions.undici" npm ls undici ``` The first printed `8.12.2` on Node 26.13.0 and `7.30.1` on Node 24.22.2. In a test project with its own undici 8 and `cheerio@1.0.0`, the second printed: ```text my-app@1.0.0 /lab/npm-ls-demo/my-app ├─┬ cheerio@1.0.0 │ └── undici@6.29.1 └── undici@8.12.4 ``` The top-level `undici@8.12.4` is the project's own copy. `cheerio@1.0.0` brings its own `undici@6.29.1`. A 5.x or 6.x entry is a candidate, not proof: it fails only if a dispatcher it builds is passed to the built-in `fetch`. The stack trace settles it, because its first `at` line shows the path of the copy that threw. A tool that compiles undici into a single file does not appear in `npm ls` at all; the Corepack trace in [corepack#834](https://github.com/nodejs/corepack/issues/834) points into `corepack.cjs`. ## Fixes A and B: pair fetch with its own undici ### Fix A: use undici's own fetch Import `fetch` from the same package as the dispatcher, so both halves always come from one version: ```js import { fetch, ProxyAgent } from 'undici'; const dispatcher = new ProxyAgent(process.env.HTTPS_PROXY); const res = await fetch('https://example.com/', { dispatcher }); console.log(res.status); ``` In the lab this worked with undici 5.29.0, 6.29.1, 7.30.2 and 8.12.4 on both Node 26.13.0 and 24.22.2, with `Agent` and `ProxyAgent`, and with `EnvHttpProxyAgent` where the version has one; every proxied request reached the proxy. Use it in libraries, CLIs and anything that runs on more than one Node line. Keep `FormData` and other body classes from the same package as `fetch` ([undici docs](https://undici.nodejs.org/best-practices/undici-vs-builtin-fetch)). The Serverless and career-ops fixes and the open Vercel CLI pull request linked below take this route. ### Fix B: match the major to process.versions.undici ```sh npm install undici@8 ``` With undici 8.12.4, the built-in `fetch` on Node 26.13.0 accepted `Agent`, `ProxyAgent` and `EnvHttpProxyAgent`. On Node 24.22.2 the same dispatchers failed with `invalid onRequestStart method`, so this fix ties your code to one Node line. undici 8 needs Node.js 22.19.0 or later ([migration guide](https://undici.nodejs.org/best-practices/migrating-from-v7-to-v8)). undici 7.30.2 worked on both lines in the lab, and Redocly CLI and the Qdrant client moved to undici 7; that is a snapshot of two Node releases, not a promise about the next one. ## Behind a proxy: ProxyAgent, EnvHttpProxyAgent, setGlobalDispatcher `ProxyAgent` and `EnvHttpProxyAgent` from undici 5 or 6 fail exactly like a plain `Agent`. Adding `NODE_USE_ENV_PROXY=1` does not help while your code still passes the old dispatcher: an undici 6.29.1 `ProxyAgent` failed with `invalid onError method` on Node 26.13.0 with the variable set. `setGlobalDispatcher()` fails more quietly. On Node 26.13.0, a global `ProxyAgent` from undici 5.29.0, 6.29.1 or the 7.x releases we tried before 7.27.0 (7.0.0 to 7.26.0), and a global `EnvHttpProxyAgent` from 6.29.1, did not throw. The built-in `fetch` ignored them and connected directly. Against `https://example.com`, an undici 6.29.1 global `ProxyAgent` got a `200` while the proxy logged nothing, so the request left from our own IP; on Node 24.22.2 the same script went through the proxy. undici 7.27.0, 7.28.0, 7.30.2 and 8.12.4 worked globally. None of the older versions writes `Symbol.for('undici.globalDispatcher.2')`, where undici 8 [keeps its global dispatcher](https://undici.nodejs.org/best-practices/migrating-from-v7-to-v8); 7.27.0 and later do. ### Fix C: let Node read the proxy variables If the dispatcher only exists to send traffic through `HTTPS_PROXY`, remove it and let Node do it: ```sh export HTTPS_PROXY=http://USER:PASS@proxy.example:8080 export NO_PROXY=localhost,127.0.0.1 node --use-env-proxy app.mjs ``` `NODE_USE_ENV_PROXY=1`, the `--use-env-proxy` flag and `NODE_OPTIONS=--use-env-proxy` all worked on Node 26.13.0 and 24.22.2, for `fetch` and for `https.get`. The opt-in arrived for `fetch` first, in [this Node commit](https://github.com/nodejs/node/commit/ada34bd0ea); the [Node docs](https://nodejs.org/api/cli.html#--use-env-proxy) list `NODE_USE_ENV_PROXY` from 24.0.0 and `--use-env-proxy` from 24.5.0, and both from 22.21.0. What the lab showed: - **Read at startup only.** Setting `process.env.NODE_USE_ENV_PROXY = '1'` inside the script did nothing. To switch on at runtime, call `http.setGlobalProxyFromEnv()` ([added in 24.14.0 and 25.4.0](https://nodejs.org/api/http.html#httpsetglobalproxyfromenvproxyenv)); it proxied both `fetch` and `https.get`. - **HTTP_PROXY alone.** With only `HTTP_PROXY` set, `fetch` used it for an `https://` URL, but `https.get` connected directly. Set `HTTPS_PROXY`. - **NO_PROXY.** `target.test`, `.test`, `*.test`, `*`, `target.test:8443` and lowercase `no_proxy` all bypassed the proxy; `target.test:9999` did not, because the port differs. With `NO_PROXY` unset, requests to `localhost` and `127.0.0.1` went through the proxy; `NO_PROXY=localhost,127.0.0.1` sent them direct. Node 26's `fetch` negotiated HTTP/2 with the lab's target, inside the CONNECT tunnel too, where Node 24 used HTTP/1.1. The proxy saw the same `CONNECT` line either way, and no request failed because of it. ## Vercel CLI, Corepack, Redocly and other tools you don't control Checked on 7 November 2026: - **Vercel CLI.** [vercel#17629](https://github.com/vercel/vercel/issues/17629) is open: with any proxy variable set, versions 59.18.0 and 59.23.1 fail on Node 26.8.2 with `invalid onError method` from a bundled undici 5.29.0 and work on Node 24.21.0. The fix, [vercel#17634](https://github.com/vercel/vercel/pull/17634), is not merged. Until a release has it, run the CLI on Node 24. - **Corepack.** [corepack#834](https://github.com/nodejs/corepack/issues/834) reports a bundled undici 6 `ProxyAgent` failing on Node 26.0.0 and 26.1.0. [Corepack 0.35.0](https://github.com/nodejs/corepack/releases/tag/v0.35.0) dropped undici and uses Node's proxy support, so set `NODE_USE_ENV_PROXY=1`; the reporter confirmed that combination works. The Node 26.13.0 tarball we installed has no `corepack` binary (24.22.2 has one), so check which version you installed with `corepack --version`. - **Redocly CLI.** [redocly-cli#3232](https://github.com/Redocly/redocly-cli/issues/3232) covers `login`, `push` and the other Reunite commands. [2.62.2](https://github.com/Redocly/redocly-cli/releases/tag/%40redocly/cli%402.62.2) fixed them on Node 26 and moved to undici 7.30.0. - **Serverless Framework.** [4.44.0](https://github.com/serverless/serverless/releases/tag/sf-core%404.44.0) fixed the npm package's proxied download on Node 26 ([#13918](https://github.com/serverless/serverless/pull/13918)), and [4.45.0](https://github.com/serverless/serverless/releases/tag/sf-core%404.45.0) fixed its API requests through a proxy on Node 26. - **Client libraries, no proxy involved.** [SocratiCode#154](https://github.com/giancarloerra/SocratiCode/issues/154): `@qdrant/js-client-rest` before 1.19 hands an undici 6 `Agent` to the built-in `fetch`, and 1.19.0 moved to undici 7. [almyty#702](https://github.com/almyty-inc/almyty/pull/702): an SSRF-pinning `Agent` from undici 6.27.0 failed on Node 26.9.0 and its custom DNS lookup never ran; the fix raised undici to ^8.11.0. [career-ops#4808](https://github.com/career-ops-hq/career-ops/issues/4808): proxy egress with an undici 6 `EnvHttpProxyAgent` failed on Node 26; v1.36.0 pairs it with undici's own `fetch`, the same approach as the earlier [#4787](https://github.com/career-ops-hq/career-ops/pull/4787). For any other tool: upgrade it, run it on Node 24 meanwhile, and report the error with its `cause` and the first `at` line. ## Check it really goes through the proxy A response with status 200 does not prove the proxy carried it: an ignored global dispatcher or a `NO_PROXY` match sends the request direct, and a reachable site still answers 200. Look at the proxy's own log first; in the lab every proxied request left one `CONNECT` line with the host and port, and the bypassed ones left none. Without access to the proxy log, ask an IP-echo service: ```js const res = await fetch('https://api.ipify.org?format=json'); console.log(await res.json()); ``` Run it once through your proxy setup, for example with `HTTPS_PROXY` set and `node --use-env-proxy`, and once without it. If both print the same IP, the request went around the proxy. ## FAQ ### Does undici 7 cause "invalid onError method" on Node.js 26? Not in our tests. `Agent` and `ProxyAgent` from every 7.x release we tried, 7.0.0 to 7.30.2, worked when passed per request, and so did `EnvHttpProxyAgent` from 7.30.2. `setGlobalDispatcher()` from 7.x before 7.27.0 was ignored without an error. ### Why does it work on Node 24 and fail on Node 26? Node 24.22.2 bundles undici 7.30.1, which accepted undici 5 and 6 dispatchers. Node 26.13.0 bundles undici 8.12.2, which sends only the new callbacks. ### Does NODE_USE_ENV_PROXY=1 fix it? Only after you remove the old dispatcher. With an undici 6 `ProxyAgent` still passed to `fetch`, Node 26 failed the same way with the variable set. ### I see "invalid onRequestStart method" instead. Is it the same problem? Yes, in reverse: an undici 8 dispatcher passed to the `fetch` of an older Node line; we saw it on Node 24.22.2. Fix A works there too. ## Related guides - [Fix Node.js TypeError: fetch failed behind a proxy](/guides/fix-node-fetch-failed-proxy) reads every cause in the chain, not only this one. - [Use a proxy with Node.js fetch](/guides/nodejs-fetch-proxy) sets up a `ProxyAgent` with authentication and a deadline. - [Node.js fetch ignores HTTPS_PROXY](/guides/node-fetch-ignores-https-proxy) covers the timeout you get without the opt-in. - [Proxy environment variables](/guides/proxy-environment-variables) compares how curl, Requests and Node read them. - [npm proxy settings](/guides/npm-proxy-settings) gets `npm install undici` through a proxy. **Test the fix through a real carrier IP.** An ipvolt [mobile proxy](/pricing) is a dedicated device on a carrier network, from $9 a day. Put its URL in `HTTPS_PROXY` and run the IP check above with `--use-env-proxy`. ## Sources & further reading - [undici: Migrating from undici 7 to 8 (handler callbacks, global dispatcher)](https://undici.nodejs.org/best-practices/migrating-from-v7-to-v8) - [undici: Undici module vs. Node.js built-in fetch](https://undici.nodejs.org/best-practices/undici-vs-builtin-fetch) - [Node.js CLI: --use-env-proxy](https://nodejs.org/api/cli.html#--use-env-proxy) - [Node.js CLI: NODE_USE_ENV_PROXY=1](https://nodejs.org/api/cli.html#node_use_env_proxy1) - [Node.js HTTP: Built-in proxy support and NO_PROXY format](https://nodejs.org/api/http.html#built-in-proxy-support) - [Node.js HTTP: http.setGlobalProxyFromEnv()](https://nodejs.org/api/http.html#httpsetglobalproxyfromenvproxyenv) - [Node.js commit ada34bd: proxy support for fetch under NODE_USE_ENV_PROXY](https://github.com/nodejs/node/commit/ada34bd0ea) - [vercel/vercel#17629: CLI fails on Node.js 26 with a proxy variable set](https://github.com/vercel/vercel/issues/17629) - [vercel/vercel#17634: route the CLI through its bundled undici fetch](https://github.com/vercel/vercel/pull/17634) - [nodejs/corepack#834: bundled undici 6 ProxyAgent on Node.js 26](https://github.com/nodejs/corepack/issues/834) - [Corepack 0.35.0 release notes](https://github.com/nodejs/corepack/releases/tag/v0.35.0) - [Redocly/redocly-cli#3232: Reunite commands fail on Node.js 26](https://github.com/Redocly/redocly-cli/issues/3232) - [Redocly CLI 2.62.2 release notes](https://github.com/Redocly/redocly-cli/releases/tag/%40redocly/cli%402.62.2) - [serverless/serverless#13918: proxied binary downloads on Node.js 26](https://github.com/serverless/serverless/pull/13918) - [Serverless Framework 4.44.0 release notes](https://github.com/serverless/serverless/releases/tag/sf-core%404.44.0) - [Serverless Framework 4.45.0 release notes](https://github.com/serverless/serverless/releases/tag/sf-core%404.45.0) - [giancarloerra/SocratiCode#154: Qdrant client before 1.19 on Node.js 26](https://github.com/giancarloerra/SocratiCode/issues/154) - [almyty-inc/almyty#702: SSRF-pinning agent and undici 8](https://github.com/almyty-inc/almyty/pull/702) - [career-ops-hq/career-ops#4808: proxy egress fails on Node.js 26](https://github.com/career-ops-hq/career-ops/issues/4808) - [career-ops-hq/career-ops#4787: drive the proxy agent with undici's own fetch](https://github.com/career-ops-hq/career-ops/pull/4787) ## Related guides - [Fix Node.js TypeError: fetch failed behind a proxy](https://ipvolt.com/guides/fix-node-fetch-failed-proxy.md) - [Use a proxy with Node.js fetch](https://ipvolt.com/guides/nodejs-fetch-proxy.md) - [Node.js fetch Ignores HTTPS_PROXY: Fix UND_ERR_CONNECT_TIMEOUT in One Line](https://ipvolt.com/guides/node-fetch-ignores-https-proxy.md) - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md) - [npm proxy settings: npmrc, precedence and install failures](https://ipvolt.com/guides/npm-proxy-settings.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 109 of 138: Axios Proxy Not Working: 16 Causes and Fixes (Tested) URL: https://ipvolt.com/guides/fix-axios-proxy-not-working Markdown: https://ipvolt.com/guides/fix-axios-proxy-not-working.md # Axios Proxy Not Working: 16 Causes and Fixes (Tested) Source: https://ipvolt.com/guides/fix-axios-proxy-not-working Markdown: https://ipvolt.com/guides/fix-axios-proxy-not-working.md [Home](https://ipvolt.com/index.md) / [Guides](https://ipvolt.com/guides.md) / [Axios Proxy Not Working: 16 Causes and Fixes (Tested)](https://ipvolt.com/guides/fix-axios-proxy-not-working.md) Category: Troubleshooting Published: 2026-11-11 Reading time: 15 minutes Author: ipvolt Axios skips your proxy or fails through it in Node.js? 16 causes with tested fixes: proxy: false in 1.21, HTTP/2, CONNECT, 407, NO_PROXY, redirects, SOCKS5. When an Axios request in Node.js skips the proxy, or fails on its way through one, the cause is one of the 16 below, and most of them depend on the Axios version. Axios 1.21.0 and 1.21.1 ignore a `proxyEnv` agent when `proxy: false` is set. `httpVersion: 2` and the fetch adapter go direct on every version that has them. Releases before 1.16.1 never open a CONNECT tunnel for an `https://` URL. Each cause comes with the output we recorded and a fix we ran. Tested on Node.js 24.22.2 and 26.13.0 with Axios 1.12.2, 1.19.0, 1.20.0, 1.21.0 and 1.21.1, plus 1.13.6, 1.15.0, 1.16.0, 1.16.1 and 1.18.1 to find where behaviour changed, https-proxy-agent 9.1.0 and socks-proxy-agent 10.1.0, on macOS 26.5.1 arm64, 11 November 2026. The lab is a logging proxy and an HTTPS target on 127.0.0.1. "Bypassed" means the target answered and the proxy logged nothing. The scripts, the [results table](/downloads/fix-axios-proxy-not-working/RESULTS.md) and all 1,290 records are in the [lab folder](/downloads/fix-axios-proxy-not-working/README.md). To set a proxy up for the first time, start with [Axios proxy setup](/guides/axios-proxy-setup); this page is for a setup that doesn't behave. ## Quick check: is the request using the proxy? ```js import axios from 'axios'; // Use the same client and options as the code you are debugging. const res = await axios.get('https://api.ipify.org?format=json', { proxy: { protocol: 'http', host: 'proxy.example', port: 8080 }, }); console.log(res.data); ``` Run it with the options of the failing code, then once more with no proxy at all. If both runs print the same IP, the request went around the proxy. A `200` proves nothing: every bypass on this page returned `200`. If you can read the proxy's own log, look there first. In the lab each proxied `https://` request left one `CONNECT` line, and each bypassed one left none. ## Find your symptom | What you see | Go to | | --- | --- | | Status `200`, but the IP is your own and the proxy logs nothing | [The request ignores the proxy](#the-request-ignores-the-proxy-with-no-error) | | `400`, `socket hang up`, `wrong version number`, `ENOTFOUND undefined`, or a request that never returns | [HTTPS through an HTTP proxy fails](#https-through-an-http-proxy-fails) | | `Request failed with status code 407` | [407 and authentication errors](#407-and-authentication-errors) | | `HTTPS_PROXY` is set but ignored, or a host is skipped that shouldn't be | [Environment variables and NO_PROXY](#environment-variables-arent-picked-up-or-noproxy-matches-wrongly) | | The first request is proxied and the redirect is not | [Redirects leave the proxy](#redirects-leave-the-proxy) | | `protocol mismatch`, or a SOCKS proxy that can't resolve the host | [SOCKS5 proxies](#socks5-proxies) | ## The request ignores the proxy, with no error ### 1. proxy: false next to a proxyEnv agent (Axios 1.21.0 and later) ```js import https from 'node:https'; import axios from 'axios'; const agent = new https.Agent({ proxyEnv: { https_proxy: 'http://proxy.example:8080' } }); const res = await axios.get('https://example.com/', { proxy: false, httpsAgent: agent }); console.log(res.status); ``` On Axios 1.20.0 the lab proxy carried this request. On 1.21.0 the same script printed: ```text 200 # proxy log: (nothing) # target log: GET /ip HTTP/1.1 direct ``` Since 1.21.0, `proxy: false` means "connect directly" even when the agent has its own proxy settings: Axios replaces the agent with a copy that has no `proxyEnv` ([#11402](https://github.com/axios/axios/issues/11402), closed on 5 November 2026; the change is [PR #11242](https://github.com/axios/axios/pull/11242), commit [2498c23](https://github.com/axios/axios/commit/2498c233438eb72c9a9ee8540ded19c6ef4224fa)). The same happened in the lab with Node's own switch: `NODE_USE_ENV_PROXY=1` or `--use-env-proxy` plus `proxy: false` went through the proxy up to 1.20.0 and direct on 1.21.0 and 1.21.1. **Fix:** remove `proxy: false` from requests that use such an agent. The reporter of #11402 confirmed it, and in the lab the script without it went through the proxy on all ten versions. Axios leaves environment proxying to an agent that has `proxyEnv` ([request config docs](https://axios.rest/pages/advanced/request-config)). Keep `proxy: false` next to a third-party agent such as `HttpsProxyAgent`: that pair worked on every version (cause 5). ### 2. httpVersion: 2 ```js import axios from 'axios'; // HTTPS_PROXY=http://proxy.example:8080 is set in the environment. const res = await axios.get('https://example.com/', { httpVersion: 2 }); console.log(res.status); ``` On Axios 1.21.1: ```text 200 # proxy log: (nothing) # target log: GET /ip HTTP/2.0 direct ``` | Axios | `proxy` object | `HTTPS_PROXY` | `proxy: false` + `HttpsProxyAgent` | | --- | --- | --- | --- | | 1.13.6, 1.15.0, 1.16.0 | `ERR_HTTP2_ERROR` | `ERR_HTTP2_ERROR` | bypassed silently | | 1.16.1, 1.18.1, 1.19.0 | bypassed silently | bypassed silently | bypassed silently | | 1.20.0, 1.21.0, 1.21.1 | `ERR_NOT_SUPPORT` | bypassed silently | bypassed silently | Axios 1.12.2 has no HTTP/2 support and ignored the option. The security advisory [GHSA-3pq3-5fj3-cg6v](https://github.com/axios/axios/security/advisories/GHSA-3pq3-5fj3-cg6v) (CVE-2026-101898, [GitLab entry](https://advisories.gitlab.com/npm/axios/CVE-2026-101898/)) covers 1.13.0 up to, but not including, 1.20.0: the HTTP/2 path connects on its own and drops the proxy. The lab reproduced the silent bypass on 1.16.1 to 1.19.0. On 1.13.6, 1.15.0 and 1.16.0 the request failed with `Protocol error` after sending HTTP/2 bytes to the proxy, so there it was loud, not silent. The fix in 1.20.0 rejects an explicit `proxy` object with `HTTP/2 requests with a proxy are not supported`. It does not cover the environment: [PR #11141](https://github.com/axios/axios/pull/11141) says HTTP/2 stays direct when the proxy comes only from environment variables or an agent, and the [docs](https://axios.rest/pages/advanced/request-config) say HTTP/2 requests cannot be proxied. `NODE_USE_ENV_PROXY=1` went direct too. **Fix:** remove `httpVersion: 2` from every request that must use the proxy. The same request without it went through the proxy over HTTP/1.1 on 1.16.1 and later. ### 3. The fetch adapter With `adapter: 'fetch'`, a `proxy` object, `HTTPS_PROXY` and an `httpsAgent` were each bypassed silently on all ten versions and both Node lines. The docs mark `proxy` as [Node.js only](https://axios.rest/pages/advanced/request-config), and in the lab only the default HTTP adapter read it, the proxy variables or the agents. **Fix:** remove `adapter: 'fetch'`, or let Node proxy its own `fetch`: with [`NODE_USE_ENV_PROXY=1`](https://nodejs.org/api/cli.html#node_use_env_proxy1) and `HTTPS_PROXY` set, the fetch adapter went through the proxy on Node 24.22.2 and 26.13.0. `proxy: false` did not switch that off. If the error is `fetch failed` instead, see [fix Node.js fetch failed behind a proxy](/guides/fix-node-fetch-failed-proxy) and [invalid onError method on Node.js 26](/guides/node-26-invalid-onerror-method). ### 4. The agent is in the wrong option An `HttpsProxyAgent` passed as `httpAgent` only, with an `https://` URL: bypassed silently on every version. Axios uses `httpAgent` for `http://` requests and `httpsAgent` for `https://` requests ([README](https://github.com/axios/axios/blob/v1.21.1/README.md#request-config)). **Fix:** set both options, as the SOCKS example below does. ## HTTPS through an HTTP proxy fails ### 5. Axios before 1.16.1 sends no CONNECT With a `proxy` object or `HTTPS_PROXY`, Axios 1.12.2, 1.13.6, 1.15.0 and 1.16.0 did not ask the proxy for a tunnel. The lab proxy received the whole URL in a plain request: ```text AxiosError: Request failed with status code 400 # exit code: 1 # proxy log: A GET https://target.test:/ip -> 400 # target log: (nothing) ``` Our proxy refuses such a request with `400`. A lab proxy that drops the connection produced `socket hang up` (`ECONNRESET`), the error reported in [#4531](https://github.com/axios/axios/issues/4531). That issue was opened in March 2022 and closed on 30 July 2025 in a cleanup that asked reporters to retest. [#3384](https://github.com/axios/axios/issues/3384), closed in June 2022, describes the same setup with a proxy-specific handshake error that we could not reproduce. [Axios 1.16.1](https://github.com/axios/axios/releases/tag/v1.16.1) changed this: [PR #10858](https://github.com/axios/axios/pull/10858) makes Axios use a CONNECT tunnel for HTTPS targets "instead of forwarding request URLs, headers, and bodies to the proxy in plaintext". From 1.16.1 on, every one of these cases tunnelled. **Fix:** upgrade to 1.16.1 or later. If you can't, use a proxy agent and switch Axios's own proxy handling off. This worked on all ten versions, 1.12.2 included: ```js import axios from 'axios'; import { HttpsProxyAgent } from 'https-proxy-agent'; const agent = new HttpsProxyAgent('http://proxy.example:8080'); const res = await axios.get('https://example.com/', { proxy: false, // Axios adds no proxy handling of its own httpsAgent: agent, // the agent opens the CONNECT tunnel signal: AbortSignal.timeout(15000), }); console.log(res.status); ``` ### 6. wrong version number: the proxy scheme is wrong or missing ```text write EPROTO :error:0A00010B:SSL routines:tls_validate_record_header:wrong version number:../deps/openssl/openssl/ssl/record/methods/tlsany_meth.c:78: ``` The client is speaking TLS to a proxy port that speaks plain HTTP. On every version the lab got this error from `protocol: 'https'` in the `proxy` object, from `HTTPS_PROXY=https://127.0.0.1:8080`, from `HTTPS_PROXY=127.0.0.1:8080` with no scheme at all, and from `new HttpsProxyAgent('https://…')`. Up to 1.16.0, a `proxy` object with no `protocol` failed the same way; from 1.16.1 it worked. `protocol` and the URL scheme describe the connection to the proxy, not to the site: use `https` only when the proxy itself serves TLS ([README](https://github.com/axios/axios/blob/v1.21.1/README.md#request-config)). [#6198](https://github.com/axios/axios/issues/6198) reports this error with an `HttpsProxyAgent`; it was closed in August 2025 for lack of a reproduction, and its configuration with an `http://` proxy URL worked in our lab. **Fix:** write `protocol: 'http'`, or `http://` in the URL, for an ordinary HTTP proxy. [SSL: wrong version number through a proxy](/guides/fix-ssl-wrong-version-number-proxy) covers the same error in other clients. ### 7. The proxy is a string, or the scheme is inside host - `proxy: 'http://proxy.example:8080'` (a string): `getaddrinfo ENOTFOUND undefined` from 1.16.1, `connect ECONNREFUSED ::1:443` before it. - `proxy: { host: 'http://proxy.example', port: 8080 }`: `Invalid URL` (`ERR_INVALID_URL`) from 1.16.1, `getaddrinfo ENOTFOUND http://127.0.0.1` before it. Neither reached the proxy. [#2072](https://github.com/axios/axios/issues/2072), closed in 2020, has the second form in browser code, where the `proxy` option does not apply at all ([docs](https://axios.rest/pages/advanced/request-config)); we did not test browsers. **Fix:** pass an object with a bare hostname in `host`, a numeric or string `port` and the scheme in `protocol`. ### 8. The request never returns From Axios 1.16.1, with a `proxy` object or `HTTPS_PROXY`, a proxy that closed the connection after `CONNECT`, or never answered it, left the request pending: no response and no error after 15 seconds, although `timeout: 5000` was set. Before 1.16.1 the same cases rejected with `socket hang up` or `timeout of 5000ms exceeded`. With `proxy: false` and an `HttpsProxyAgent`, a closed connection rejected with `Proxy connection ended before receiving CONNECT response`, and a silent proxy left the request pending on all ten versions. `http://` URLs rejected normally, with `timeout of 5000ms exceeded` or `socket hang up`. We found no Axios issue for this on 11 November 2026. **Fix:** give every proxied request a deadline of its own. `signal: AbortSignal.timeout(3000)` ended every pending case after 3 seconds with `canceled` (`ERR_CANCELED`). `maxRedirects: 0` also made `timeout` work for the built-in tunnel, a case the [1.16.0 notes](https://github.com/axios/axios/releases/tag/v1.16.0) mention. ## 407 and authentication errors A wrong password, or none, returned the same thing on every version, whether the credentials came from `proxy.auth`, from `HTTPS_PROXY` or from an `HttpsProxyAgent` URL: `Request failed with status code 407`, with `error.code` set to `ERR_BAD_REQUEST` and `error.response.status` to `407`. The proxy logged one request, answered with 407, and the target saw nothing. A SOCKS5 proxy has no status code: a wrong password there gave `Socks5 Authentication failed`. ### 9. The credentials are in the wrong place Putting the proxy's username and password in the top-level `auth` option returned 407, and the proxy log shows it received no credentials. Top-level `auth` is for the site; the proxy's credentials go in `proxy.auth` ([README](https://github.com/axios/axios/blob/v1.21.1/README.md#request-config)). With `proxy.auth`, from 1.16.1 the proxy authenticated the `CONNECT` and the target never saw a `Proxy-Authorization` header, on a redirect to a second host too. ### 10. Special characters encoded the wrong way The lab proxy expected the password `p@ss/w0rd#1`: | Where the password goes | Written | Result | | --- | --- | --- | | `proxy.auth.password` | as it is | through the proxy (1.16.1 and later) | | `proxy.auth.password` | percent-encoded | 407: the proxy received `p%40ss%2Fw0rd%231` | | `HTTPS_PROXY` URL | as it is | `getaddrinfo ENOTFOUND ss` | | `HTTPS_PROXY` URL | percent-encoded | 407: the proxy received `p%40ss%2Fw0rd%231` | | `HttpsProxyAgent` URL | percent-encoded | through the proxy (all versions) | Pasted as it is, the `@` ends the credentials early and `ss` becomes the host. Percent-encoded, the URL parses, but Axios copies the username and password out of it without decoding them ([http.js in 1.21.1](https://github.com/axios/axios/blob/v1.21.1/lib/adapters/http.js)). So on the tested versions a password with reserved characters could not go through `HTTPS_PROXY` at all. **Fix:** pass it in `proxy.auth` unencoded, or in an agent URL percent-encoded. Both requests below went through the proxy on 1.19.0 to 1.21.1: ```js import axios from 'axios'; import { HttpsProxyAgent } from 'https-proxy-agent'; const user = process.env.PROXY_USER; const pass = process.env.PROXY_PASS; // In the proxy object: the raw password, not percent-encoded. const a = await axios.get('https://example.com/', { proxy: { protocol: 'http', host: 'proxy.example', port: 8080, auth: { username: user, password: pass } }, }); // In a proxy URL for an agent: percent-encode both parts. const url = `http://${encodeURIComponent(user)}:${encodeURIComponent(pass)}@proxy.example:8080`; const b = await axios.get('https://example.com/', { proxy: false, httpsAgent: new HttpsProxyAgent(url) }); console.log(a.status, b.status); ``` For a 407 that survives correct credentials, such as an IP allowlist or a username format, see [fix proxy error 407](/guides/fix-proxy-error-407). ## Environment variables aren't picked up, or NO_PROXY matches wrongly What Axios read in the lab, on all ten versions: `HTTPS_PROXY` or `https_proxy` for `https://` URLs, `HTTP_PROXY` or `http_proxy` for `http://` URLs, and `ALL_PROXY` or `all_proxy` when the specific one is missing. With both spellings set, lowercase won. The variables are read at request time, so assigning `process.env.HTTPS_PROXY` in code before the request worked. A `proxy` object beat both the variables and `NO_PROXY`. Before 1.16.1 the variables were read the same way, but `https://` requests then failed as in cause 5. ### 11. The variable doesn't match the URL scheme With only `HTTP_PROXY` set, an `https://` request went direct with no error, on every version. With only `HTTPS_PROXY`, an `http://` request did. **Fix:** set both, usually to the same `http://` proxy URL. [Proxy environment variables](/guides/proxy-environment-variables) compares how other clients read them. ### 12. An environment proxy overrides your agent With `HTTPS_PROXY` set, an `HttpsProxyAgent` or `SocksProxyAgent` passed as `httpsAgent` without `proxy: false` was ignored: from 1.16.1 the request went through the proxy from the environment, not the agent's. A `proxy` object next to the agent won in the same way. A CI runner or a container that sets `HTTPS_PROXY` is enough to send your traffic through a different proxy than the one in your code. **Fix:** `proxy: false` on every request that uses a third-party proxy agent. With it, the agent's proxy carried the request on all ten versions, whatever the environment held. ### 13. NO_PROXY matches differently across versions With a proxy variable set and the URL host `target.test`: | `NO_PROXY` | Route | Versions | | --- | --- | --- | | `target.test`, `TARGET.TEST`, `.test`, `*.test`, `*`, `target.test:PORT` with the URL's port | direct | all | | `other.test target.test` or `other.test, target.test` | direct | all | | `.target.test`, `test`, `get.test`, `target.test:9999`, `https://target.test` | proxy | all | | `target.test`, when the URL says `target.test.` with a trailing dot | proxy on 1.12.2 and 1.13.6, direct from 1.15.0 | fixed in 1.15.0 | | `127.0.0.0/8`, URL host `127.0.0.1` | proxy up to 1.19.0, direct from 1.20.0 | fixed in 1.20.0 | | `localhost`, URL host `127.0.0.1` | proxy up to 1.15.0, direct from 1.16.0 | changed in 1.16.0 | The trailing-dot row is [GHSA-3p68-rc4w-qgx5](https://github.com/axios/axios/security/advisories/GHSA-3p68-rc4w-qgx5), fixed in 1.15.0. The CIDR row is [GHSA-44g4-m2mj-wpvx](https://github.com/axios/axios/security/advisories/GHSA-44g4-m2mj-wpvx) (CVE-2026-101899), fixed in 1.20.0; the advisory lists 1.15.0 and later as affected, and in the lab 1.12.2 and 1.13.6 ignored the CIDR entry as well. With `NO_PROXY` unset, requests to `localhost` and `127.0.0.1` went through the proxy on every version. [NO_PROXY matching, tested](/blog/no-proxy-matching-tested) has the same matrix for other clients. ## Redirects leave the proxy ### 14. A redirect changes scheme, or lands on a NO_PROXY host The lab target answers `302` to a second host. - **`http://` to `https://`, only `HTTP_PROXY` set:** the first hop went through the proxy and the second went direct, on every version. The same happened with `proxy: false` and only `httpAgent` set. With both agents, or from 1.16.1 with both variables, both hops were proxied. - **`https://` to `https://` on another host:** both hops went through the proxy with a `proxy` object, with `HTTPS_PROXY` and with an agent, from 1.16.1. With proxy authentication, both `CONNECT` requests carried the credentials. - **Redirect to a host listed in `NO_PROXY`:** on 1.21.0 and 1.21.1 the second hop went direct. On 1.16.1 to 1.20.0 it still went through the proxy. With an explicit `proxy` object both hops were proxied from 1.16.1 on. **Fix:** set both variables or both agents. If a redirect must never leave the proxy, use a `proxy` object or an agent pair with `proxy: false`, and keep that host out of `NO_PROXY`. ## SOCKS5 proxies ### 15. socks5:// in the proxy option or HTTPS_PROXY Axios has no SOCKS client. `proxy: { protocol: 'socks5', … }` and `HTTPS_PROXY=socks5://…` failed with `protocol mismatch` (`ERR_ASSERTION`) up to 1.16.0. From 1.16.1 Axios sent an HTTP `CONNECT` line to the SOCKS port, the lab's SOCKS server closed the connection, and the request never returned (cause 8). **Fix:** a SOCKS agent in both agent options, with `proxy: false` (cause 12). This went through the lab's SOCKS5 proxy on all ten versions: ```js import axios from 'axios'; import { SocksProxyAgent } from 'socks-proxy-agent'; // socks5h: the proxy resolves the hostname. socks5: this machine does. const agent = new SocksProxyAgent('socks5h://proxy.example:1080'); const res = await axios.get('https://example.com/', { proxy: false, httpAgent: agent, httpsAgent: agent, signal: AbortSignal.timeout(15000), }); console.log(res.status); ``` ### 16. socks5 instead of socks5h With `socks5://`, the lab's SOCKS server received an IP address: the client had resolved the name itself. With `socks5h://` it received the hostname ([socks-proxy-agent README](https://github.com/TooTallNate/proxy-agents/tree/main/packages/socks-proxy-agent)). For a name that only the proxy can resolve, `socks5://` failed with `getaddrinfo ENOTFOUND proxy-only.test` and `socks5h://` worked. [SOCKS5 vs SOCKS5h](/blog/socks5-vs-socks5h) explains what else the local lookup gives away. ## A known-good setup for each need All three went through the lab proxy on Axios 1.19.0, 1.20.0, 1.21.0 and 1.21.1, on both Node lines. On 1.12.2 only the third did. **A fixed proxy in code** (Axios 1.16.1 or later): ```js import axios from 'axios'; const client = axios.create({ proxy: { protocol: 'http', // how to reach the proxy, not the site host: 'proxy.example', port: 8080, auth: { username: process.env.PROXY_USER, password: process.env.PROXY_PASS }, }, }); const res = await client.get('https://example.com/', { signal: AbortSignal.timeout(15000) }); console.log(res.status); ``` **A company proxy from the environment** (Axios 1.16.1 or later). Set the variables outside the code: ```sh export HTTPS_PROXY=http://proxy.example:8080 export HTTP_PROXY=http://proxy.example:8080 export NO_PROXY=localhost,127.0.0.1 ``` ```js import axios from 'axios'; // Started with HTTPS_PROXY, HTTP_PROXY and NO_PROXY in the environment. // No proxy option, no agent, no httpVersion, default adapter. const res = await axios.get('https://example.com/', { signal: AbortSignal.timeout(15000) }); console.log(res.status); ``` **A different proxy per request** (every tested version): ```js import axios from 'axios'; import { HttpsProxyAgent } from 'https-proxy-agent'; const agents = new Map(); const agentFor = (proxyUrl) => { if (!agents.has(proxyUrl)) agents.set(proxyUrl, new HttpsProxyAgent(proxyUrl)); return agents.get(proxyUrl); }; const viaProxy = (url, proxyUrl) => axios.get(url, { proxy: false, httpsAgent: agentFor(proxyUrl), signal: AbortSignal.timeout(15000) }); const first = await viaProxy('https://example.com/', 'http://proxy-a.example:8080'); const second = await viaProxy('https://example.com/', 'http://proxy-b.example:8080'); console.log(first.status, second.status); ``` In the lab the two requests left through two different proxies. For `http://` URLs add an `HttpProxyAgent` from `http-proxy-agent` as `httpAgent`. ## A guard for your tests Most causes above return `200`, so a normal test suite stays green when an upgrade or a new option starts bypassing the proxy. This test starts a stand-in proxy that records what reaches it and refuses it, then sends one request through the client your application builds: ```js import assert from 'node:assert/strict'; import { once } from 'node:events'; import http from 'node:http'; import { test } from 'node:test'; import { createClient } from './client.mjs'; test('the HTTP client sends requests through the proxy', async () => { const seen = []; // A stand-in proxy: it records what arrives and refuses it, so nothing leaves the machine. const proxy = http.createServer((req, res) => { seen.push(`${req.method} ${req.url}`); res.writeHead(503).end(); }); proxy.on('connect', (req, socket) => { seen.push(`CONNECT ${req.url}`); socket.end('HTTP/1.1 503 Service Unavailable\r\n\r\n'); }); proxy.listen(0, '127.0.0.1'); await once(proxy, 'listening'); const client = createClient(`http://127.0.0.1:${proxy.address().port}`); // .invalid never resolves, so a request that skips the proxy cannot reach a real site. await client.get('https://guard.invalid/', { signal: AbortSignal.timeout(5000) }).catch(() => {}); proxy.close(); assert.deepEqual(seen, ['CONNECT guard.invalid:443']); }); ``` `createClient(proxyUrl)` is your own factory. With the per-request client above, `node --test` passed on all five main versions. After `adapter: 'fetch'` was added to the same client, it failed: ```text not ok 1 - the HTTP client sends requests through the proxy Expected values to be strictly deep-equal: + actual - expected + [] - [ - 'CONNECT guard.invalid:443' - ] # tests 1 # pass 0 # fail 1 # exit code: 1 ``` ## Versions to use or avoid - **Use 1.21.1**, the latest release on the test date, or at least 1.20.0. Check two things after the upgrade: `proxy: false` next to a `proxyEnv` agent (cause 1), and redirects to `NO_PROXY` hosts (cause 14). - **Before 1.16.1:** no CONNECT tunnel for `https://` URLs through an HTTP proxy (cause 5). Use the agent pattern or upgrade. - **1.13.0 up to 1.19.0 with `httpVersion: 2`:** inside the range of GHSA-3pq3-5fj3-cg6v. On 1.20.0 and later HTTP/2 still ignores `HTTPS_PROXY` (cause 2). - **Before 1.15.0 and before 1.20.0:** `NO_PROXY` misses trailing-dot hosts and CIDR ranges respectively (cause 13). - **Node.js:** 24.22.2 and 26.13.0 routed every case the same way. The one difference: through the fetch adapter, Node 26 negotiated HTTP/2 with the lab target and Node 24 used HTTP/1.1. ## FAQ ### Why does Axios ignore HTTPS_PROXY? In the lab it did so for six reasons: `proxy: false` on the request, `httpVersion: 2`, `adapter: 'fetch'`, a `proxy` object that takes precedence, a `NO_PROXY` match, or an `http://` URL, which reads `HTTP_PROXY` instead. ### Do I still need https-proxy-agent with Axios? Not for a single HTTP proxy on Axios 1.16.1 or later: the `proxy` object and `HTTPS_PROXY` tunnelled on their own. You need it on older versions, and it is the simplest way to use a different proxy per request. ### Does Axios support SOCKS5 proxies? Not through `proxy` or `HTTPS_PROXY`. Pass a `SocksProxyAgent` as `httpAgent` and `httpsAgent` with `proxy: false`. ### Why does my Axios request hang through a proxy when timeout is set? On the tested versions `timeout` did not cover a proxy that fails to answer `CONNECT` (cause 8). Add `signal: AbortSignal.timeout(ms)`. ### Does the Axios proxy option work in the browser? No. The docs mark `proxy` as Node.js only; a browser uses the proxy of the operating system or the browser itself. ## Related guides - [Axios proxy setup](/guides/axios-proxy-setup) is the setup page: one explicit proxy check and which layer owns routing. - [Proxy environment variables](/guides/proxy-environment-variables) compares how curl, Requests and Node read them. - [Fix proxy error 407](/guides/fix-proxy-error-407) covers a 407 that isn't about encoding. - [fetch failed: invalid onError method on Node.js 26](/guides/node-26-invalid-onerror-method) is the Node 26 failure of undici proxy agents. - [Fix Node.js TypeError: fetch failed behind a proxy](/guides/fix-node-fetch-failed-proxy) reads the error chain when you use `fetch`. - [NO_PROXY matching, tested](/blog/no-proxy-matching-tested) has the matching rules of other clients. **Test the fix through a real IP.** ipvolt sells [residential proxies](/residential-proxies) from $2.20 per GB and a dedicated [mobile proxy](/mobile-proxies) from $9 a day. Put the proxy in the setup above and run the quick check. [Check a proxy now](/tools/proxy-checker). ## Sources & further reading - [axios/axios#11402: axios@1.21.0 breaks custom https.Agent with proxyEnv enabled](https://github.com/axios/axios/issues/11402) - [axios/axios#11242: align request handling across runtimes (direct agents for proxy: false)](https://github.com/axios/axios/pull/11242) - [axios/axios commit 2498c23](https://github.com/axios/axios/commit/2498c233438eb72c9a9ee8540ded19c6ef4224fa) - [GHSA-3pq3-5fj3-cg6v (CVE-2026-101898): HTTP/2 adapter bypasses configured DNS lookup and proxy controls](https://github.com/axios/axios/security/advisories/GHSA-3pq3-5fj3-cg6v) - [GitLab advisory database: CVE-2026-101898](https://advisories.gitlab.com/npm/axios/CVE-2026-101898/) - [axios/axios#11141: HTTP/2 proxy handling and CIDR matching for NO_PROXY](https://github.com/axios/axios/pull/11141) - [GHSA-3p68-rc4w-qgx5: NO_PROXY hostname normalization bypass](https://github.com/axios/axios/security/advisories/GHSA-3p68-rc4w-qgx5) - [GHSA-44g4-m2mj-wpvx (CVE-2026-101899): CIDR-form NO_PROXY entries are ignored](https://github.com/axios/axios/security/advisories/GHSA-44g4-m2mj-wpvx) - [axios/axios#4531: Proxy support does not work properly with CONNECT on https requests](https://github.com/axios/axios/issues/4531) - [axios/axios#3384: HTTPS over HTTP Proxy Fails](https://github.com/axios/axios/issues/3384) - [axios/axios#2072: Axios proxy is not working](https://github.com/axios/axios/issues/2072) - [axios/axios#6198: https proxy agent not working as expected](https://github.com/axios/axios/issues/6198) - [axios/axios#10858: CONNECT tunnelling for HTTPS targets](https://github.com/axios/axios/pull/10858) - [Axios 1.16.0 release notes](https://github.com/axios/axios/releases/tag/v1.16.0) - [Axios 1.16.1 release notes](https://github.com/axios/axios/releases/tag/v1.16.1) - [Axios 1.20.0 release notes](https://github.com/axios/axios/releases/tag/v1.20.0) - [Axios 1.21.0 release notes](https://github.com/axios/axios/releases/tag/v1.21.0) - [Axios 1.21.1 release notes](https://github.com/axios/axios/releases/tag/v1.21.1) - [Axios docs: request config (proxy, httpAgent, httpsAgent, environment variables)](https://axios.rest/pages/advanced/request-config) - [Axios 1.21.1 README: request config](https://github.com/axios/axios/blob/v1.21.1/README.md#request-config) - [Axios 1.21.1: HTTP adapter source](https://github.com/axios/axios/blob/v1.21.1/lib/adapters/http.js) - [Node.js HTTP: built-in proxy support and the Agent proxyEnv option](https://nodejs.org/api/http.html#built-in-proxy-support) - [Node.js CLI: NODE_USE_ENV_PROXY=1](https://nodejs.org/api/cli.html#node_use_env_proxy1) - [Node.js CLI: --use-env-proxy](https://nodejs.org/api/cli.html#--use-env-proxy) - [socks-proxy-agent README](https://github.com/TooTallNate/proxy-agents/tree/main/packages/socks-proxy-agent) ## Related guides - [Axios proxy setup: routing, auth and NO_PROXY](https://ipvolt.com/guides/axios-proxy-setup.md) - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md) - [Fix proxy error 407 without guessing](https://ipvolt.com/guides/fix-proxy-error-407.md) - [fetch failed: invalid onError method on Node 26 (undici fix)](https://ipvolt.com/guides/node-26-invalid-onerror-method.md) - [Fix Node.js TypeError: fetch failed behind a proxy](https://ipvolt.com/guides/fix-node-fetch-failed-proxy.md) ## About ipvolt Examples use generic proxy settings, with links to the original technical documentation. Product-specific behavior must be checked with your provider. ipvolt sells mobile proxies and residential proxies from $2.20/GB. ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) --- Document 110 of 138: Proxy comparisons and practical analysis. URL: https://ipvolt.com/blog Markdown: https://ipvolt.com/blog.md # Proxy comparisons and practical analysis. Source: https://ipvolt.com/blog Markdown: https://ipvolt.com/blog.md Compare proxy types, understand common failures and evaluate performance. We explain the reasoning behind each recommendation. [Visit our developer guides for setup instructions.](https://ipvolt.com/guides.md) - [How to Check if a Proxy Is Really Mobile or Residential](https://ipvolt.com/blog/check-if-proxy-is-mobile-or-residential.md) (Analysis, Nov 8, 2026, 12 min read): No single check proves a proxy is mobile or residential. We tested ASN, RDAP, PeeringDB, reverse DNS and IP databases on a mobile line and a datacenter IP. - [Check a Proxy for IP, DNS and WebRTC Leaks with ToDetect](https://ipvolt.com/blog/proxy-leak-check-todetect.md) (Analysis, Oct 23, 2026, 9 min read): Check a browser proxy for IP, DNS, WebRTC and time zone leaks with ToDetect's free tools, using measured results from a 4G mobile line as the worked example. - [Python 3.15 for Web Scraping: What Installs, What Breaks](https://ipvolt.com/blog/python-3-15-web-scraping.md) (Analysis, Oct 16, 2026, 8 min read): pip install scrapy fails on Python 3.15 without a C compiler: brotli has no cp315 wheel. We tested 19 scraping packages with pip and uv to see what else breaks. - [Japanese price parsing: yen, width and tax labels](https://ipvolt.com/blog/japanese-price-parsing.md) (Analysis, Oct 6, 2026, 6 min read): Parse Japanese price fields without losing currency or tax basis. Run a tested Python fixture for fullwidth yen, mixed prices and deliberate review cases. - [How Many GB of Proxies Do You Need? Pages per GB, Measured](https://ipvolt.com/blog/how-many-gb-of-proxies-do-i-need.md) (Benchmark, Oct 5, 2026, 8 min read): We loaded 34 public pages three ways through a metering proxy. 1 GB fits about 44,000 HTML-only fetches, or about 900 full Playwright page loads. - [SOCKS5 vs SOCKS5h: where DNS is resolved, client by client](https://ipvolt.com/blog/socks5-vs-socks5h.md) (Comparison, Oct 4, 2026, 7 min read): In curl, socks5:// resolves DNS locally and socks5h:// sends the hostname to the proxy. HTTPX, aiohttp and Playwright differ. Tested results and config fixes. - [CONNECT tunnel failed, response 403: Why AI Agents Hit It](https://ipvolt.com/blog/connect-tunnel-failed-403.md) (Analysis, Oct 2, 2026, 8 min read): Your agent's curl fails with CONNECT tunnel failed, response 403 while other hosts work. The proxy refused the tunnel. How to tell who blocked it, and the fix. - [The Odds API vs scraping: update intervals, quota and cost](https://ipvolt.com/blog/betting-odds-api-vs-scraping.md) (Comparison, Sep 28, 2026, 7 min read): The Odds API updates featured markets every 60 s before matches and 40 s in play. Compare its quota with authorized scraping in an editable cost worksheet. - [Unlimited residential proxies: what they cost per GB](https://ipvolt.com/blog/unlimited-residential-proxies-cost-per-gb.md) (Comparison, Sep 27, 2026, 18 min read): Turn Mbps- and thread-based unlimited residential proxy plans into cost per GB, find the break-even with your per-GB rate, and check terms before you pay. - [NO_PROXY wildcard, CIDR and subdomains: 15 clients tested](https://ipvolt.com/blog/no-proxy-matching-tested.md) (Analysis, Sep 24, 2026, 19 min read): Does *.example.com, .example.com or a CIDR range work in NO_PROXY? Tested answers for curl, wget, Python, Node and Go, plus localhost, IPv6 and ports. - [Multiple Meta Ad Accounts: An Agency Setup Checklist](https://ipvolt.com/blog/manage-multiple-meta-ad-accounts.md) (Analysis, Sep 19, 2026, 6 min read): Manage multiple Meta ad accounts with a client access record, clear team responsibilities and a checklist for access errors, security incidents and routing. - [AI agent proxies and compute: choose by responsibility](https://ipvolt.com/blog/ai-agent-proxies-and-compute.md) (Analysis, Sep 17, 2026, 6 min read): Map an AI agent's retrieval, runtime and model requirements before choosing services, with a release-note monitoring example and editable worksheet. ## Topics - [Choosing proxies](https://ipvolt.com/blog/tag/choosing.md) (8 posts) - [Proxies](https://ipvolt.com/blog/tag/proxies.md) (24 posts) - [Troubleshooting](https://ipvolt.com/blog/tag/troubleshooting.md) (17 posts) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) RSS: https://ipvolt.com/blog/rss.xml [Developer guides](https://ipvolt.com/guides.md) --- Document 111 of 138: Older posts (page 2 of 2) URL: https://ipvolt.com/blog/page/2 Markdown: https://ipvolt.com/blog/page/2.md # Older posts (page 2 of 2) Source: https://ipvolt.com/blog/page/2 Markdown: https://ipvolt.com/blog/page/2.md Compare proxy types, understand common failures and evaluate performance. We explain the reasoning behind each recommendation. [Visit our developer guides for setup instructions.](https://ipvolt.com/guides.md) - [MostLogin proxy setup guide: add, test and share proxies](https://ipvolt.com/blog/mostlogin-proxy-setup.md) (Analysis, Sep 17, 2026, 8 min read): Add a proxy to MostLogin profiles step by step: protocol, host and port, credentials, the IP check, team access, batch import and the mistakes that break it. - [Amazon prices: your offer vs the Featured Offer](https://ipvolt.com/blog/amazon-offer-vs-featured-offer.md) (Analysis, Sep 16, 2026, 6 min read): Compare your Amazon offer with the Featured Offer using matched context, known shipping and a tested offline model that preserves missing data. - [Amazon listing updates: accepted is not live](https://ipvolt.com/blog/amazon-listing-update-reconciliation.md) (Analysis, Sep 14, 2026, 8 min read): Diagnose accepted Amazon listing updates by separating submitted attributes, live offers, inventory and buyability, with a practical reconciliation matrix. - [Bookmaker odds feeds: validate before comparing](https://ipvolt.com/blog/bookmaker-odds-feed-validation.md) (Analysis, Sep 14, 2026, 7 min read): Compare bookmaker odds only after checking market identity, settlement rules, timestamps and status. Use a local validator to expose false comparisons. - [Cloudflare AI Agent Blocks: What to Fix First](https://ipvolt.com/blog/cloudflare-ai-agent-proxy-setup.md) (Analysis, Sep 14, 2026, 8 min read): Diagnose Cloudflare failures in AI-agent jobs, configure a stable browser proxy, and reject challenges or invalid content before RAG ingestion. - [Proxy retries: one lost response, two created jobs](https://ipvolt.com/blog/proxy-retries-duplicate-jobs.md) (Analysis, Sep 13, 2026, 8 min read): A local proxy drops a response after a POST creates a job. See when retrying duplicates work, when an idempotency key helps, and when to reconcile. - [ETag monitoring: a no-cache header changed our results](https://ipvolt.com/blog/etag-monitoring-cache-control.md) (Analysis, Sep 11, 2026, 6 min read): A live proxy test found that one request header changed 304 responses into full downloads. Inspect the measured bytes, request policies and reproducible data. - [Price monitoring: a matching number hid a currency mismatch](https://ipvolt.com/blog/product-price-currency-validation.md) (Analysis, Sep 11, 2026, 7 min read): A live storefront check found USD and EUR prices labelled GBP in product JSON-LD. Inspect the recordings and validate currency before accepting a price signal. - [Proxy errors explained: 407, 429, 502 and 504](https://ipvolt.com/blog/proxy-status-codes-407-429-502.md) (Analysis, Sep 11, 2026, 7 min read): Identify which layer returned a proxy error, check authentication and rate limits, and decide when a bounded retry of a failed request is safe. - [Residential vs datacenter proxies: how to choose](https://ipvolt.com/blog/residential-vs-datacenter-proxies.md) (Comparison, Sep 11, 2026, 6 min read): Compare residential and datacenter proxies by network, content success, latency, session needs and billing, with five checks to guide your own tests. - [Amazon and Google: why HTTP 200 can still mean failure](https://ipvolt.com/blog/scraping-amazon-google-through-a-proxy.md) (Analysis, Sep 11, 2026, 7 min read): Why an HTTP 200 from Amazon or Google can still be a failed scrape: challenge pages, empty shells, robots rules and the official data options to check first. - [What to measure in a proxy benchmark](https://ipvolt.com/blog/what-a-proxy-benchmark-should-measure.md) (Analysis, Sep 11, 2026, 7 min read): Compare proxies using content success, response times and session behaviour, with a curl-based Python harness that records failures and calculates results. ## Topics - [Choosing proxies](https://ipvolt.com/blog/tag/choosing.md) (8 posts) - [Proxies](https://ipvolt.com/blog/tag/proxies.md) (24 posts) - [Troubleshooting](https://ipvolt.com/blog/tag/troubleshooting.md) (17 posts) RSS: https://ipvolt.com/blog/rss.xml [Developer guides](https://ipvolt.com/guides.md) --- Document 112 of 138: Choosing proxies URL: https://ipvolt.com/blog/tag/choosing Markdown: https://ipvolt.com/blog/tag/choosing.md # Choosing proxies Source: https://ipvolt.com/blog/tag/choosing Markdown: https://ipvolt.com/blog/tag/choosing.md Compare proxy types, evaluate providers and plan a test before committing to a service. - [How to Check if a Proxy Is Really Mobile or Residential](https://ipvolt.com/blog/check-if-proxy-is-mobile-or-residential.md) (Analysis, Nov 8, 2026, 12 min read): No single check proves a proxy is mobile or residential. We tested ASN, RDAP, PeeringDB, reverse DNS and IP databases on a mobile line and a datacenter IP. - [How Many GB of Proxies Do You Need? Pages per GB, Measured](https://ipvolt.com/blog/how-many-gb-of-proxies-do-i-need.md) (Benchmark, Oct 5, 2026, 8 min read): We loaded 34 public pages three ways through a metering proxy. 1 GB fits about 44,000 HTML-only fetches, or about 900 full Playwright page loads. - [Unlimited residential proxies: what they cost per GB](https://ipvolt.com/blog/unlimited-residential-proxies-cost-per-gb.md) (Comparison, Sep 27, 2026, 18 min read): Turn Mbps- and thread-based unlimited residential proxy plans into cost per GB, find the break-even with your per-GB rate, and check terms before you pay. - [Multiple Meta Ad Accounts: An Agency Setup Checklist](https://ipvolt.com/blog/manage-multiple-meta-ad-accounts.md) (Analysis, Sep 19, 2026, 6 min read): Manage multiple Meta ad accounts with a client access record, clear team responsibilities and a checklist for access errors, security incidents and routing. - [AI agent proxies and compute: choose by responsibility](https://ipvolt.com/blog/ai-agent-proxies-and-compute.md) (Analysis, Sep 17, 2026, 6 min read): Map an AI agent's retrieval, runtime and model requirements before choosing services, with a release-note monitoring example and editable worksheet. - [Residential vs datacenter proxies: how to choose](https://ipvolt.com/blog/residential-vs-datacenter-proxies.md) (Comparison, Sep 11, 2026, 6 min read): Compare residential and datacenter proxies by network, content success, latency, session needs and billing, with five checks to guide your own tests. - [Amazon and Google: why HTTP 200 can still mean failure](https://ipvolt.com/blog/scraping-amazon-google-through-a-proxy.md) (Analysis, Sep 11, 2026, 7 min read): Why an HTTP 200 from Amazon or Google can still be a failed scrape: challenge pages, empty shells, robots rules and the official data options to check first. - [What to measure in a proxy benchmark](https://ipvolt.com/blog/what-a-proxy-benchmark-should-measure.md) (Analysis, Sep 11, 2026, 7 min read): Compare proxies using content success, response times and session behaviour, with a curl-based Python harness that records failures and calculates results. [All posts](https://ipvolt.com/blog.md) --- Document 113 of 138: Proxy analysis and comparisons URL: https://ipvolt.com/blog/tag/proxies Markdown: https://ipvolt.com/blog/tag/proxies.md # Proxy analysis and comparisons Source: https://ipvolt.com/blog/tag/proxies Markdown: https://ipvolt.com/blog/tag/proxies.md Analysis of proxy types, performance and common connection failures. - [How to Check if a Proxy Is Really Mobile or Residential](https://ipvolt.com/blog/check-if-proxy-is-mobile-or-residential.md) (Analysis, Nov 8, 2026, 12 min read): No single check proves a proxy is mobile or residential. We tested ASN, RDAP, PeeringDB, reverse DNS and IP databases on a mobile line and a datacenter IP. - [Check a Proxy for IP, DNS and WebRTC Leaks with ToDetect](https://ipvolt.com/blog/proxy-leak-check-todetect.md) (Analysis, Oct 23, 2026, 9 min read): Check a browser proxy for IP, DNS, WebRTC and time zone leaks with ToDetect's free tools, using measured results from a 4G mobile line as the worked example. - [Python 3.15 for Web Scraping: What Installs, What Breaks](https://ipvolt.com/blog/python-3-15-web-scraping.md) (Analysis, Oct 16, 2026, 8 min read): pip install scrapy fails on Python 3.15 without a C compiler: brotli has no cp315 wheel. We tested 19 scraping packages with pip and uv to see what else breaks. - [Japanese price parsing: yen, width and tax labels](https://ipvolt.com/blog/japanese-price-parsing.md) (Analysis, Oct 6, 2026, 6 min read): Parse Japanese price fields without losing currency or tax basis. Run a tested Python fixture for fullwidth yen, mixed prices and deliberate review cases. - [How Many GB of Proxies Do You Need? Pages per GB, Measured](https://ipvolt.com/blog/how-many-gb-of-proxies-do-i-need.md) (Benchmark, Oct 5, 2026, 8 min read): We loaded 34 public pages three ways through a metering proxy. 1 GB fits about 44,000 HTML-only fetches, or about 900 full Playwright page loads. - [SOCKS5 vs SOCKS5h: where DNS is resolved, client by client](https://ipvolt.com/blog/socks5-vs-socks5h.md) (Comparison, Oct 4, 2026, 7 min read): In curl, socks5:// resolves DNS locally and socks5h:// sends the hostname to the proxy. HTTPX, aiohttp and Playwright differ. Tested results and config fixes. - [CONNECT tunnel failed, response 403: Why AI Agents Hit It](https://ipvolt.com/blog/connect-tunnel-failed-403.md) (Analysis, Oct 2, 2026, 8 min read): Your agent's curl fails with CONNECT tunnel failed, response 403 while other hosts work. The proxy refused the tunnel. How to tell who blocked it, and the fix. - [The Odds API vs scraping: update intervals, quota and cost](https://ipvolt.com/blog/betting-odds-api-vs-scraping.md) (Comparison, Sep 28, 2026, 7 min read): The Odds API updates featured markets every 60 s before matches and 40 s in play. Compare its quota with authorized scraping in an editable cost worksheet. - [Unlimited residential proxies: what they cost per GB](https://ipvolt.com/blog/unlimited-residential-proxies-cost-per-gb.md) (Comparison, Sep 27, 2026, 18 min read): Turn Mbps- and thread-based unlimited residential proxy plans into cost per GB, find the break-even with your per-GB rate, and check terms before you pay. - [NO_PROXY wildcard, CIDR and subdomains: 15 clients tested](https://ipvolt.com/blog/no-proxy-matching-tested.md) (Analysis, Sep 24, 2026, 19 min read): Does *.example.com, .example.com or a CIDR range work in NO_PROXY? Tested answers for curl, wget, Python, Node and Go, plus localhost, IPv6 and ports. - [Multiple Meta Ad Accounts: An Agency Setup Checklist](https://ipvolt.com/blog/manage-multiple-meta-ad-accounts.md) (Analysis, Sep 19, 2026, 6 min read): Manage multiple Meta ad accounts with a client access record, clear team responsibilities and a checklist for access errors, security incidents and routing. - [AI agent proxies and compute: choose by responsibility](https://ipvolt.com/blog/ai-agent-proxies-and-compute.md) (Analysis, Sep 17, 2026, 6 min read): Map an AI agent's retrieval, runtime and model requirements before choosing services, with a release-note monitoring example and editable worksheet. - [MostLogin proxy setup guide: add, test and share proxies](https://ipvolt.com/blog/mostlogin-proxy-setup.md) (Analysis, Sep 17, 2026, 8 min read): Add a proxy to MostLogin profiles step by step: protocol, host and port, credentials, the IP check, team access, batch import and the mistakes that break it. - [Amazon prices: your offer vs the Featured Offer](https://ipvolt.com/blog/amazon-offer-vs-featured-offer.md) (Analysis, Sep 16, 2026, 6 min read): Compare your Amazon offer with the Featured Offer using matched context, known shipping and a tested offline model that preserves missing data. - [Amazon listing updates: accepted is not live](https://ipvolt.com/blog/amazon-listing-update-reconciliation.md) (Analysis, Sep 14, 2026, 8 min read): Diagnose accepted Amazon listing updates by separating submitted attributes, live offers, inventory and buyability, with a practical reconciliation matrix. - [Bookmaker odds feeds: validate before comparing](https://ipvolt.com/blog/bookmaker-odds-feed-validation.md) (Analysis, Sep 14, 2026, 7 min read): Compare bookmaker odds only after checking market identity, settlement rules, timestamps and status. Use a local validator to expose false comparisons. - [Cloudflare AI Agent Blocks: What to Fix First](https://ipvolt.com/blog/cloudflare-ai-agent-proxy-setup.md) (Analysis, Sep 14, 2026, 8 min read): Diagnose Cloudflare failures in AI-agent jobs, configure a stable browser proxy, and reject challenges or invalid content before RAG ingestion. - [Proxy retries: one lost response, two created jobs](https://ipvolt.com/blog/proxy-retries-duplicate-jobs.md) (Analysis, Sep 13, 2026, 8 min read): A local proxy drops a response after a POST creates a job. See when retrying duplicates work, when an idempotency key helps, and when to reconcile. - [ETag monitoring: a no-cache header changed our results](https://ipvolt.com/blog/etag-monitoring-cache-control.md) (Analysis, Sep 11, 2026, 6 min read): A live proxy test found that one request header changed 304 responses into full downloads. Inspect the measured bytes, request policies and reproducible data. - [Price monitoring: a matching number hid a currency mismatch](https://ipvolt.com/blog/product-price-currency-validation.md) (Analysis, Sep 11, 2026, 7 min read): A live storefront check found USD and EUR prices labelled GBP in product JSON-LD. Inspect the recordings and validate currency before accepting a price signal. - [Proxy errors explained: 407, 429, 502 and 504](https://ipvolt.com/blog/proxy-status-codes-407-429-502.md) (Analysis, Sep 11, 2026, 7 min read): Identify which layer returned a proxy error, check authentication and rate limits, and decide when a bounded retry of a failed request is safe. - [Residential vs datacenter proxies: how to choose](https://ipvolt.com/blog/residential-vs-datacenter-proxies.md) (Comparison, Sep 11, 2026, 6 min read): Compare residential and datacenter proxies by network, content success, latency, session needs and billing, with five checks to guide your own tests. - [Amazon and Google: why HTTP 200 can still mean failure](https://ipvolt.com/blog/scraping-amazon-google-through-a-proxy.md) (Analysis, Sep 11, 2026, 7 min read): Why an HTTP 200 from Amazon or Google can still be a failed scrape: challenge pages, empty shells, robots rules and the official data options to check first. - [What to measure in a proxy benchmark](https://ipvolt.com/blog/what-a-proxy-benchmark-should-measure.md) (Analysis, Sep 11, 2026, 7 min read): Compare proxies using content success, response times and session behaviour, with a curl-based Python harness that records failures and calculates results. [All posts](https://ipvolt.com/blog.md) --- Document 114 of 138: Troubleshooting URL: https://ipvolt.com/blog/tag/troubleshooting Markdown: https://ipvolt.com/blog/tag/troubleshooting.md # Troubleshooting Source: https://ipvolt.com/blog/tag/troubleshooting Markdown: https://ipvolt.com/blog/tag/troubleshooting.md Technical articles from the ipvolt team, with sources and related setup guides. - [Check a Proxy for IP, DNS and WebRTC Leaks with ToDetect](https://ipvolt.com/blog/proxy-leak-check-todetect.md) (Analysis, Oct 23, 2026, 9 min read): Check a browser proxy for IP, DNS, WebRTC and time zone leaks with ToDetect's free tools, using measured results from a 4G mobile line as the worked example. - [Python 3.15 for Web Scraping: What Installs, What Breaks](https://ipvolt.com/blog/python-3-15-web-scraping.md) (Analysis, Oct 16, 2026, 8 min read): pip install scrapy fails on Python 3.15 without a C compiler: brotli has no cp315 wheel. We tested 19 scraping packages with pip and uv to see what else breaks. - [Japanese price parsing: yen, width and tax labels](https://ipvolt.com/blog/japanese-price-parsing.md) (Analysis, Oct 6, 2026, 6 min read): Parse Japanese price fields without losing currency or tax basis. Run a tested Python fixture for fullwidth yen, mixed prices and deliberate review cases. - [SOCKS5 vs SOCKS5h: where DNS is resolved, client by client](https://ipvolt.com/blog/socks5-vs-socks5h.md) (Comparison, Oct 4, 2026, 7 min read): In curl, socks5:// resolves DNS locally and socks5h:// sends the hostname to the proxy. HTTPX, aiohttp and Playwright differ. Tested results and config fixes. - [CONNECT tunnel failed, response 403: Why AI Agents Hit It](https://ipvolt.com/blog/connect-tunnel-failed-403.md) (Analysis, Oct 2, 2026, 8 min read): Your agent's curl fails with CONNECT tunnel failed, response 403 while other hosts work. The proxy refused the tunnel. How to tell who blocked it, and the fix. - [The Odds API vs scraping: update intervals, quota and cost](https://ipvolt.com/blog/betting-odds-api-vs-scraping.md) (Comparison, Sep 28, 2026, 7 min read): The Odds API updates featured markets every 60 s before matches and 40 s in play. Compare its quota with authorized scraping in an editable cost worksheet. - [NO_PROXY wildcard, CIDR and subdomains: 15 clients tested](https://ipvolt.com/blog/no-proxy-matching-tested.md) (Analysis, Sep 24, 2026, 19 min read): Does *.example.com, .example.com or a CIDR range work in NO_PROXY? Tested answers for curl, wget, Python, Node and Go, plus localhost, IPv6 and ports. - [MostLogin proxy setup guide: add, test and share proxies](https://ipvolt.com/blog/mostlogin-proxy-setup.md) (Analysis, Sep 17, 2026, 8 min read): Add a proxy to MostLogin profiles step by step: protocol, host and port, credentials, the IP check, team access, batch import and the mistakes that break it. - [Amazon prices: your offer vs the Featured Offer](https://ipvolt.com/blog/amazon-offer-vs-featured-offer.md) (Analysis, Sep 16, 2026, 6 min read): Compare your Amazon offer with the Featured Offer using matched context, known shipping and a tested offline model that preserves missing data. - [Amazon listing updates: accepted is not live](https://ipvolt.com/blog/amazon-listing-update-reconciliation.md) (Analysis, Sep 14, 2026, 8 min read): Diagnose accepted Amazon listing updates by separating submitted attributes, live offers, inventory and buyability, with a practical reconciliation matrix. - [Bookmaker odds feeds: validate before comparing](https://ipvolt.com/blog/bookmaker-odds-feed-validation.md) (Analysis, Sep 14, 2026, 7 min read): Compare bookmaker odds only after checking market identity, settlement rules, timestamps and status. Use a local validator to expose false comparisons. - [Cloudflare AI Agent Blocks: What to Fix First](https://ipvolt.com/blog/cloudflare-ai-agent-proxy-setup.md) (Analysis, Sep 14, 2026, 8 min read): Diagnose Cloudflare failures in AI-agent jobs, configure a stable browser proxy, and reject challenges or invalid content before RAG ingestion. - [Proxy retries: one lost response, two created jobs](https://ipvolt.com/blog/proxy-retries-duplicate-jobs.md) (Analysis, Sep 13, 2026, 8 min read): A local proxy drops a response after a POST creates a job. See when retrying duplicates work, when an idempotency key helps, and when to reconcile. - [ETag monitoring: a no-cache header changed our results](https://ipvolt.com/blog/etag-monitoring-cache-control.md) (Analysis, Sep 11, 2026, 6 min read): A live proxy test found that one request header changed 304 responses into full downloads. Inspect the measured bytes, request policies and reproducible data. - [Price monitoring: a matching number hid a currency mismatch](https://ipvolt.com/blog/product-price-currency-validation.md) (Analysis, Sep 11, 2026, 7 min read): A live storefront check found USD and EUR prices labelled GBP in product JSON-LD. Inspect the recordings and validate currency before accepting a price signal. - [Proxy errors explained: 407, 429, 502 and 504](https://ipvolt.com/blog/proxy-status-codes-407-429-502.md) (Analysis, Sep 11, 2026, 7 min read): Identify which layer returned a proxy error, check authentication and rate limits, and decide when a bounded retry of a failed request is safe. - [What to measure in a proxy benchmark](https://ipvolt.com/blog/what-a-proxy-benchmark-should-measure.md) (Analysis, Sep 11, 2026, 7 min read): Compare proxies using content success, response times and session behaviour, with a curl-based Python harness that records failures and calculates results. [All posts](https://ipvolt.com/blog.md) --- Document 115 of 138: How to check if a proxy is really mobile, residential or datacenter URL: https://ipvolt.com/blog/check-if-proxy-is-mobile-or-residential Markdown: https://ipvolt.com/blog/check-if-proxy-is-mobile-or-residential.md # How to check if a proxy is really mobile, residential or datacenter Source: https://ipvolt.com/blog/check-if-proxy-is-mobile-or-residential Markdown: https://ipvolt.com/blog/check-if-proxy-is-mobile-or-residential.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / How to Check if a Proxy Is Really Mobile or Residential Category: Analysis Published: 2026-11-08 Updated: 2026-11-08 Author: ipvolt Reading time: 12 minutes Tags: proxies, choosing No single check proves a proxy is mobile or residential. We tested ASN, RDAP, PeeringDB, reverse DNS and IP databases on a mobile line and a datacenter IP. ## Short answer No single check proves that a proxy is mobile or residential. The strongest signal is the network its exit IP belongs to: the autonomous system number (ASN), who registered it, and what type of network that is. Look those up in RDAP and PeeringDB, then compare at least two IP databases, because they disagree. In our test the datacenter IP gave itself away on every check, while a mobile line on Singtel showed up under two different networks depending on which site it connected to. What we tested, on 8 November 2026 between 12:06 and 13:18 UTC: - **From:** ipvolt's server in Helsinki, Finland, running Ubuntu with curl 8.18.0 and dig 9.20. - **Datacenter sample:** that server's own IPv4 address, which sits with a hosting company. - **Mobile sample:** ipvolt's Singapore test line on the Singtel network, used as an HTTP and a SOCKS5 proxy with a username and password, and rotated 10 times. - **Residential sample:** none. We had no home connection to test, so nothing below about residential IPs comes from our own measurements. - **Masking:** IPv4 addresses are cut to /24 (203.0.113.x) here and in the [results file](/downloads/check-if-proxy-is-mobile-or-residential/results.json), which lists every lookup with its time. The commands below use 203.0.113.7, an address reserved for documentation. Put your proxy's exit IP in its place. ## The fastest check: ipvolt's proxy checker Paste the proxy into the free [proxy checker](/tools/proxy-checker) as `host:port:user:pass`, or as a `socks5://` URL. It connects through the proxy to its own echo server and reports, for each proxy: - **Status:** whether HTTP, HTTPS and IPv6 work through it. [HTTP vs SOCKS5 proxies](/guides/http-vs-socks5-proxies) explains the protocol difference. - **Exit IP:** the address the echo server saw. - **ASN and network:** looked up in DB-IP Lite. - **Network type:** Hosting or data centre, Mobile carrier, Carrier (mobile and fixed lines), Internet provider, or Unknown. It is an estimate from the ASN, made from a list of known networks or from words in the network's name. It does not test the device. - **Location:** the city and country DB-IP Lite gives for the exit IP. - **Headers:** whether the proxy added headers that reveal your own IP. We ran both samples through the checker's own service, the one the page sends your list to: | | Datacenter (ipvolt's server) | Mobile line (Singtel test line) | | --- | --- | --- | | Status | Not checked: the checker refuses ipvolt's own servers, so we ran its lookup code on the address | Working over HTTP and SOCKS5; IPv6 not available | | Exit IP | 204.168.249.x | 165.173.26.x | | ASN and network | AS24940, Hetzner Online GmbH | AS56300, MYREPUBLIC LIMITED | | Network type | Hosting or data centre (estimate) | Internet provider (estimate) | | Location | Helsinki, Finland | Singapore (Toa Payoh New Town) | | Headers added | Not checked | None, and your IP was not passed on | The datacenter row is what you'd expect. The mobile row isn't. In all four runs, at 12:06 and three times between 12:58 and 12:59 UTC, the checker's endpoint saw the line leave from 165.173.26.x in AS56300, a block registered to MYREPUBLIC LIMITED, so it estimated Internet provider rather than Mobile carrier. In the same hour, four other sites saw only Singtel Mobile addresses through the same line, and the checker's lookup code labels those Mobile carrier. Section 5 has the details. Checking one destination isn't enough. ## The checks, one by one ### 1. ASN and RDAP: whose network is it? An autonomous system is "a connected group of one or more IP prefixes run by one or more network operators which has a SINGLE and CLEARLY DEFINED routing policy" ([RFC 1930](https://www.rfc-editor.org/rfc/rfc1930)). Start by finding which one announces the exit IP. RIPEstat's [network-info call](https://stat.ripe.net/docs/data-api/api-endpoints/network-info) returns the routed prefix and the announcing ASN from RIPE's routing data: ```bash curl -s "https://stat.ripe.net/data/network-info/data.json?resource=203.0.113.7" ``` Then ask the registry who holds the address and the ASN. RDAP is the registries' JSON interface for this data, an alternative to WHOIS ([APNIC](https://www.apnic.net/about-apnic/whois_search/about/rdap/)). IANA publishes [bootstrap files](https://data.iana.org/rdap/ipv4.json) that list which registry's RDAP server answers for each address block ([RFC 9224](https://www.rfc-editor.org/rfc/rfc9224)). The RIPE NCC's server also redirects queries for other regions to the right registry with an HTTP 301 ([RIPE Database docs](https://docs.db.ripe.net/How-to-Query-the-RIPE-Database/Registration-Data-Access-Protocol/)), so `-L` gets you there from one URL: ```bash curl -sL "https://rdap.db.ripe.net/ip/203.0.113.7" curl -sL "https://rdap.db.ripe.net/autnum/64496" ``` To check an offline copy as well, the [iptoasn.com dataset](https://iptoasn.com/) maps address ranges to ASNs in one file. We used the copy dated 1 November 2026. What came back: | | Datacenter | Mobile line | | --- | --- | --- | | Prefix and ASN (RIPEstat) | 204.168.128.0/17, AS24940 | 119.234.24.0/21, AS45143 | | AS holder (RIPEstat) | HETZNER-AS Hetzner Online GmbH | SINGTELMOBILE-AS-AP - SINGTEL MOBILE INTERNET SERVICE PROVIDER Singapore | | RDAP registry | RIPE NCC (IANA's file points to ARIN, which redirected with HTTP 303) | APNIC (RIPE's server redirected with HTTP 301) | | RDAP network name and block | CLOUD-HEL1, 204.168.240.0/20 | SINGTELMOBILE, 119.234.0.0/17 | | RDAP holder | Hetzner Online GmbH | Singapore Telecom Mobile Pte Ltd | | iptoasn.com | AS24940, country DE | AS45143, country SG | The mobile range is registered to Singapore Telecom Mobile and its ASN says "mobile" in the name. The datacenter range is registered to a hosting company. Names are only names, but this is the first thing to compare with what the proxy was sold as. One request showed why the network type matters in practice. rdap.org, a public service that forwards RDAP queries to the right registry, answered our datacenter server with a Cloudflare 403 page each time we tried (12:06, 12:56 and 13:15 UTC). Through the mobile line, over HTTP and over SOCKS5, the same request at 13:15 got a 302 redirect to the registry. ### 2. PeeringDB: what type of network? PeeringDB is where networks describe themselves to other networks. Each entry has a network type, such as Cable/DSL/ISP, Content or Enterprise. PeeringDB calls this data "self-declared and might be rarely updated" and says "We haven't commissioned research into the accuracy of the data" ([PeeringDB](https://docs.peeringdb.com/blog/network_type_what_why_how/)). The [API](https://docs.peeringdb.com/api_specs/) answers without an account: ```bash curl -s "https://www.peeringdb.com/api/net?asn=64496" ``` Read `info_types` in the answer. Our results: - **AS24940 (datacenter):** an entry named Hetzner Online, `info_types` Content, scope Europe. - **AS45143 (Singtel Mobile):** no entry; the API answered HTTP 404. - **AS56300 (MyRepublic, the network ipvolt's checker saw, see section 5):** an entry named MyRepublic Singapore, `info_types` Cable/DSL/ISP, Content and NSP. A hosting ASN that lists itself as Content fits a datacenter. Many access networks have no PeeringDB entry at all, so a missing entry tells you nothing either way. ### 3. Reverse DNS: what does the address call itself? A PTR record maps an address back to a name, under the in-addr.arpa domain ([RFC 1035, section 3.5](https://www.rfc-editor.org/rfc/rfc1035#section-3.5)). Whoever runs the reverse zone for the block decides whether there is one and what it says. ```bash dig -x 203.0.113.7 +short ``` - **Datacenter:** `static.x.249.168.204.clients.your-server.de`, which is the address written backwards inside the name (last octet masked here). The name resolves back to the same address, and the reverse zone's primary name server is `ns1.your-server.de`, run by the hosting company. - **Mobile line:** no PTR record (NXDOMAIN) for any of the 17 Singtel addresses the line used. For the 119.234 addresses the answer came from APNIC's own `119.in-addr.arpa` zone, so the carrier had no reverse zone for them. The one MyRepublic address had a PTR name, `165-173-26-x.myrepublic.com.sg`, which did not resolve back to an address. A name with "static", "server" or a hosting company's domain points to a server. No name at all is common on mobile networks, and also on many other networks, so on its own it proves nothing. ### 4. IP databases: what do the free tiers say? We asked three free sources about every address. None of them returned a connection or usage type: - **ipinfo, JSON API without a token:** the ASN and network name, a hostname when there is a PTR record, and a city. No type field. Its free Lite API returns ASN, AS name, AS domain, country and continent ([IPinfo docs](https://ipinfo.io/developers/lite-api)). - **IP2Location.io without a key:** ASN, network name, location and an `is_proxy` flag. Its `usage_type` field, with codes such as MOB (Mobile ISP), ISP (Fixed Line ISP) and DCH (Data Center/Web Hosting/Transit) ([IP2Location.io docs](https://www.ip2location.io/ip2location-documentation)), starts with the paid plans, and the free plan's proxy detection covers open public proxies only ([IP2Location.io pricing](https://www.ip2location.io/pricing)). - **DB-IP Lite**, the database inside ipvolt's checker (build of 1 November 2026): ASN, network name and city. Its IP to ASN file lists the first and last address of each range, the AS number and the AS organization ([DB-IP](https://db-ip.com/db/download/ip-to-asn-lite)). MaxMind sells connection type (Cable/DSL, Cellular, Corporate, Satellite) as a separate database ([MaxMind](https://dev.maxmind.com/geoip/docs/databases/connection-type/)); we did not buy it. Where the free sources disagreed: - **Where the datacenter is.** ipinfo and DB-IP Lite put 204.168.249.x in Helsinki, Finland, which is where the server is. IP2Location.io put it in Amsterdam, Netherlands. iptoasn.com lists DE for the range, the network's registered country rather than the server's location. - **Where the mobile line is.** ipinfo and IP2Location.io said Singapore for every Singtel address. DB-IP Lite named 11 different places for the 17 addresses, from Punggol to Tanjong Pagar. For the MyRepublic address, ipinfo said Yishun New Town and DB-IP Lite said Toa Payoh New Town. - **Whether it's a proxy.** IP2Location.io answered `is_proxy: false` for every address we asked about, including each exit of the proxy line. ### 5. Rotation and CGNAT (mobile only) Rotation asks the device to reconnect to the carrier, which hands it a new public IP; [IP rotation](/docs/rotation) covers how that works on ipvolt devices. Our test line accepted one rotation every 4 minutes and answered HTTP 429 to anything sooner, so we spaced the 10 rotations 250 seconds apart. All 10 rotation requests were accepted, and each time ipify saw a new address 6.3 to 7.7 seconds later (median 6.5 seconds). The 10 new addresses were all different and fell in 10 different /24 blocks. iptoasn.com put every one in AS45143, RDAP named every one SINGTELMOBILE (APNIC), and RIPEstat agreed for the 8 it returned data for. None had a PTR record, and ipinfo and IP2Location.io placed all of them in Singapore. The address also moved without a rotation: in 5 of the 10 rounds, the new address and three checks a few seconds later did not all match. Carriers can share one public IPv4 address between many subscribers with carrier-grade NAT (CGNAT). RFC 6598 reserves 100.64.0.0/10 as "Shared Address Space" so that carriers can number the links between their CGN devices and customer equipment ([RFC 6598](https://www.rfc-editor.org/rfc/rfc6598)). Behind the NAT, "A public IPv4 address in the CGN pool is shared by several subscribers at the same time" ([RFC 6269](https://www.rfc-editor.org/rfc/rfc6269)). This matters for two reasons: - **Blocking hurts everyone on the address.** RFC 6269 notes that limiting one shared address after failed logins "may block out other users who have not made any previous attempts". - **Location is coarse.** "A subscriber behind a CGN geo-locates to wherever the prefix of the CGN appears to be" (RFC 6269, section 7). You can't see the CGNAT from outside. Through the proxy we only ever saw public addresses, never a 100.64.0.0/10 one. What we could see is how the exits behaved: Right after the 10th rotation we sent 24 requests in about 90 seconds to four echo services (ipify, icanhazip, ifconfig.me and checkip.amazonaws.com), 16 over HTTP and 8 over SOCKS5, without rotating. They came from two public addresses, both Singtel Mobile (AS45143): 119.234.48.x for 16 requests and 119.234.44.x for 8. Every SOCKS5 request used 119.234.48.x; the HTTP requests switched between the two. Meanwhile ipvolt's checker saw 165.173.26.x, in MyRepublic's AS56300, in every run, over HTTP and SOCKS5. That address had a PTR name under myrepublic.com.sg. So the same line reached the internet through at least three public addresses on two networks, and which one a site saw depended on the site. Several Singtel addresses at once fits a carrier NAT that hands different connections different addresses from its pool, but we can't see the NAT, and from outside we can't tell why one destination saw a different network. ## Results side by side | Check | Datacenter (ipvolt's server, Helsinki) | Mobile line (Singtel test line, Singapore) | | --- | --- | --- | | ASN and holder | AS24940, Hetzner Online GmbH | AS45143, Singapore Telecom Mobile Pte Ltd (17 addresses); AS56300, MYREPUBLIC LIMITED (1 address, seen only by ipvolt's checker) | | RDAP network name | CLOUD-HEL1 (RIPE NCC) | SINGTELMOBILE (APNIC); MYREPUBLIC-SG for the checker's address | | PeeringDB type | Content | No entry for AS45143; AS56300: Cable/DSL/ISP, Content, NSP | | Reverse DNS | `static.x.249.168.204.clients.your-server.de`, resolves back | None for any Singtel address; `165-173-26-x.myrepublic.com.sg` for the checker's address | | ipvolt's checker | Hosting or data centre (lookup code only) | Internet provider in all 4 runs (AS56300 exit) | | ipinfo, no token | Helsinki; no type field | Singapore; no type field | | IP2Location.io, no key | Amsterdam; `is_proxy` false; no `usage_type` | Singapore; `is_proxy` false; no `usage_type` | | DB-IP Lite | Helsinki | 11 different places in Singapore | | rdap.org | HTTP 403 (Cloudflare) | HTTP 302 to the registry | | 10 rotations | Not applicable | 10 new addresses, all AS45143, median 6.5 s | | Addresses at once | One | Two Singtel addresses in 24 requests, plus the MyRepublic address for the checker | There is no residential column: we had no home connection to test. ## Signs a "mobile" or "residential" proxy isn't what it claims Each of these comes from our runs or from the sources above: 1. **The ASN belongs to a hosting company.** Our datacenter address sat in AS24940, Hetzner Online. RDAP named its block CLOUD-HEL1, and PeeringDB lists the network as Content. 2. **Reverse DNS names a server.** Ours was `static.x.249.168.204.clients.your-server.de`, a static name under the hosting company's domain. 3. **Sites that refuse datacenter ranges refuse it.** rdap.org returned a Cloudflare 403 to our server and a redirect to the mobile line. 4. **The exit network changes with the destination.** A line sold as mobile should reach every site from the carrier's network. Ours reached four echo services from Singtel Mobile and ipvolt's checker from MyRepublic's AS56300, whose PeeringDB types are Cable/DSL/ISP, Content and NSP. Check the exit IP on at least two services and look up every ASN you see. 5. **Rotated addresses leave the carrier.** On our line, all 10 stayed in AS45143. New addresses in a hosting ASN would mean the "mobile" IPs aren't on a carrier. Signs 1 to 3 apply to "residential" proxies too. We had no residential line to test them on. ## What these checks can't tell you - **The device.** An ASN describes a network, not the device on it. Many carriers serve phones and home lines from one ASN, and no outside lookup can tell which one a request came from. That is why the checker has a "Carrier (mobile and fixed lines)" type, and why [mobile vs residential proxies](/guides/mobile-vs-residential-proxies) treats the two as overlapping. - **Accuracy of self-description.** PeeringDB types are self-declared, RDAP names are whatever the holder registered, and many access networks have no PeeringDB entry. AS45143 had none. - **Agreement between databases.** Free databases disagree with each other: on the same day, two of them placed our datacenter address in two different countries. - **Connection type, for free.** None of the free tiers we used returns one. - **CGNAT.** It is invisible from outside. We saw how the exits behaved, not the carrier's NAT. - **Paths you didn't test.** A proxy can send different destinations over different routes. Each check only tells you about the connection it made. - **Our sample.** One mobile line on one carrier, one datacenter address, one day, no residential line. **Check a proxy now:** paste it into ipvolt's free [proxy checker](/tools/proxy-checker), then look up the ASN it reports with the commands above. Need a mobile IP in a specific country? [Dedicated mobile proxies from $9 a day.](/mobile-proxies) ## Sources - [RFC 1930: Guidelines for creation, selection, and registration of an Autonomous System (AS)](https://www.rfc-editor.org/rfc/rfc1930) - [RIPEstat Data API: network-info](https://stat.ripe.net/docs/data-api/api-endpoints/network-info) - [RFC 9224: Finding the Authoritative Registration Data Access Protocol (RDAP) Service](https://www.rfc-editor.org/rfc/rfc9224) - [IANA: RDAP bootstrap file for IPv4 address allocations](https://data.iana.org/rdap/ipv4.json) - [RIPE Database docs: Registration Data Access Protocol (RDAP)](https://docs.db.ripe.net/How-to-Query-the-RIPE-Database/Registration-Data-Access-Protocol/) - [APNIC: Registration Data Access Protocol](https://www.apnic.net/about-apnic/whois_search/about/rdap/) - [PeeringDB API specification](https://docs.peeringdb.com/api_specs/) - [PeeringDB: Network Type: What's it for? How to use it?](https://docs.peeringdb.com/blog/network_type_what_why_how/) - [RFC 1035: Domain names, implementation and specification (section 3.5, IN-ADDR.ARPA)](https://www.rfc-editor.org/rfc/rfc1035#section-3.5) - [iptoasn.com: IP to ASN dataset](https://iptoasn.com/) - [IPinfo Lite API documentation](https://ipinfo.io/developers/lite-api) - [IP2Location.io API documentation](https://www.ip2location.io/ip2location-documentation) - [IP2Location.io pricing and plans](https://www.ip2location.io/pricing) - [DB-IP: IP to ASN Lite](https://db-ip.com/db/download/ip-to-asn-lite) - [MaxMind: GeoIP Connection Type database](https://dev.maxmind.com/geoip/docs/databases/connection-type/) - [RFC 6598: IANA-Reserved IPv4 Prefix for Shared Address Space](https://www.rfc-editor.org/rfc/rfc6598) - [RFC 6269: Issues with IP Address Sharing](https://www.rfc-editor.org/rfc/rfc6269) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [How Many GB of Proxies Do You Need? Pages per GB, Measured](https://ipvolt.com/blog/how-many-gb-of-proxies-do-i-need.md) (Benchmark, Oct 5, 2026, 8 min read): We loaded 34 public pages three ways through a metering proxy. 1 GB fits about 44,000 HTML-only fetches, or about 900 full Playwright page loads. - [Unlimited residential proxies: what they cost per GB](https://ipvolt.com/blog/unlimited-residential-proxies-cost-per-gb.md) (Comparison, Sep 27, 2026, 18 min read): Turn Mbps- and thread-based unlimited residential proxy plans into cost per GB, find the break-even with your per-GB rate, and check terms before you pay. - [Multiple Meta Ad Accounts: An Agency Setup Checklist](https://ipvolt.com/blog/manage-multiple-meta-ad-accounts.md) (Analysis, Sep 19, 2026, 6 min read): Manage multiple Meta ad accounts with a client access record, clear team responsibilities and a checklist for access errors, security incidents and routing. ## Related guides - [Mobile vs residential proxies: build a useful evaluation](https://ipvolt.com/guides/mobile-vs-residential-proxies.md): Compare carrier and household exit networks for QA, keep browser emulation separate, and measure the capabilities your workflow actually needs. - [HTTP vs SOCKS5 proxies: choose by the connection](https://ipvolt.com/guides/http-vs-socks5-proxies.md): Compare HTTP CONNECT and SOCKS5, understand DNS placement and TLS boundaries, and select a protocol your actual client and provider support. - [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md): Choose rotation around the smallest complete workflow, distinguish exit affinity from cookies, and test what happens when a sticky session ends early. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 116 of 138: How to check a proxy for IP, DNS and WebRTC leaks with ToDetect URL: https://ipvolt.com/blog/proxy-leak-check-todetect Markdown: https://ipvolt.com/blog/proxy-leak-check-todetect.md # How to check a proxy for IP, DNS and WebRTC leaks with ToDetect Source: https://ipvolt.com/blog/proxy-leak-check-todetect Markdown: https://ipvolt.com/blog/proxy-leak-check-todetect.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / Check a Proxy for IP, DNS and WebRTC Leaks with ToDetect Category: Analysis Published: 2026-10-23 Updated: 2026-10-23 Author: ipvolt Reading time: 9 minutes Tags: proxies, troubleshooting Check a browser proxy for IP, DNS, WebRTC and time zone leaks with ToDetect's free tools, using measured results from a 4G mobile line as the worked example. A browser proxy changes where page requests come from. DNS lookups, WebRTC connections and the browser's time zone can still point to the machine's own network. This guide shows how to check each one with ToDetect's free tools, what a pass and a fail look like, and which fixes held up in our test. The worked example is a real test that ipvolt ran: - **When:** 23 October 2026, 16:45 to 16:57 UTC. - **Machine:** a Mac running macOS 15.7.4. - **Browsers:** Chromium 153 and Firefox, driven by Playwright 1.63.0, in headless mode and in normal windows. - **Proxy:** a 4G mobile proxy on Vodafone Germany that we used for pre-launch testing, set up as an HTTP proxy with a username and password. [Germany proxies](/guides/germany-proxies) covers the German mobile network context. - **The machine's own connection:** a commercial VPN exit in Tallinn, Estonia, which is a datacenter address. - **Masking:** IP addresses are masked in the screenshots and removed from the [results file](/downloads/proxy-leak-check-todetect/results.json), which lists the counts and scores from every run. ## 1. Get a baseline without the proxy Run each test once with the proxy off, so you know what your own connection looks like. Our baseline on [ToDetect's IP Quality Check](https://www.todetect.net/ip/) was: location Tallinn, IP type Datacenter, ASN organization labelled HOSTING, and an IP Quality Score of 68%. The [DNS Leak Test](https://www.todetect.net/dns-leak/) showed one resolver, the VPN's, in Estonia. ## 2. Check the IP the website sees Turn the proxy on and reload [the IP Quality Check](https://www.todetect.net/ip/). Check four fields against what you expect from the proxy: location, ISP and ASN, IP type, and time zone. Through the mobile proxy, the page showed Berlin, ISP D2VODAFONE, ASN 3209 (Vodafone GmbH), IP type Mobile, IP Abuse "No", time zone Europe/Berlin and language German. ![ToDetect IP Quality Check through the mobile proxy: Berlin, D2VODAFONE, IP type Mobile, IP Quality Score 94%](/media/blog/proxy-leak-check-todetect/leak-ip.png) *ToDetect IP Quality Check through the 4G test line, 23 October 2026. IP address and prefix masked.* The score is built from listed deductions, and you can open them to see why it changed: | Connection | IP type | Score | Deductions shown | | --- | --- | ---: | --- | | Machine's own (VPN, Estonia) | Datacenter | 68% | IP Usage Frequency -3%, VPS/IDC Provider -25%, Occasional ASN Organization Change -4% | | 4G mobile proxy (Vodafone Germany) | Mobile | 94% | IP Usage Frequency -3%, Regional ISP -3% | Most of the gap is the VPS/IDC Provider deduction. A pass means the location, ISP and IP type match the proxy you configured; step 5 compares the time zone with the browser. If you still see your own ISP or city, the browser is not using the proxy, and the other tests will not mean much until that is fixed. The score reflects ToDetect's own databases; treat it as one signal. ## 3. Check where DNS is resolved Run [the DNS Leak Test](https://www.todetect.net/dns-leak/) with the proxy on. It lists the DNS resolvers that answered lookups for your browser. A pass is a resolver list that belongs to the proxy's network or a resolver you chose on purpose. A fail is your own ISP's or your own network's resolver. Through the proxy, the resolvers were 139.7.74.9 and 139.7.74.10, both "Vodafone Germany, Germany". The Estonian resolver from the baseline was gone. ![ToDetect DNS Leak Test through the proxy: two Vodafone Germany resolvers](/media/blog/proxy-leak-check-todetect/leak-dns-leak.png) *Both resolvers belong to Vodafone Germany. The client IP at the top is masked.* This is expected for an HTTP proxy in Chromium, whose documentation says "name resolution is always deferred to the proxy": the hostname travels in the CONNECT request. DNS leaks can happen with SOCKS4, or with SOCKS5 clients that resolve names locally before connecting, such as curl with `socks5://` rather than `socks5h://`. [SOCKS5 vs SOCKS5h](/blog/socks5-vs-socks5h) covers that case. ## 4. Check WebRTC Open [the WebRTC Leak Test](https://www.todetect.net/webrtc/). It asks 17 STUN servers which public address your browser appears to come from. A pass is "Not detected" or the proxy's address for every server. A fail is the red "WebRTC IP Exposure Detected" banner and your own address in the Public IP fields. With default settings, both browsers failed: - **Chromium, default:** 13 of 17 STUN servers returned the machine's own address (11 or 12 as IPv4, 1 or 2 as IPv6, across three runs). The other 4 showed "Not detected". - **Firefox, default:** 10 of 17 returned the machine's own IPv4 address and 4 showed "Not detected". The other 3 showed 0.0.0.0, which revealed neither IP; we did not determine why. ![ToDetect WebRTC Leak Test with default Chromium settings: WebRTC IP Exposure Detected](/media/blog/proxy-leak-check-todetect/leak-webrtc.png) *The page places the connection in Berlin, from the proxy's IP, but STUN servers returned the machine's own address (masked): 13 of 17 in this run. The crop shows three.* The reason is the transport. WebRTC sends STUN requests over UDP. A standard HTTP proxy relays only TCP connections, so by default those requests go out over the machine's own connection, and the STUN server sees that public IP. RFC 8828 describes this case: if direct Internet access is permitted, "WebRTC's STUN checks will bypass the proxy and reveal the public IP address of the client." ### Fixes we tested | Browser and setting | STUN servers showing the machine's own address | Result | | --- | ---: | --- | | Chromium, default | 13 of 17 (three runs) | Leak | | Chromium headless, `--force-webrtc-ip-handling-policy=disable_non_proxied_udp` | 0 of 17 (one run) | Pass | | Chromium in a normal window, same flag | 13 of 17 (two runs) | Leak | | Chromium in a normal window, profile preference `webrtc.ip_handling_policy` = `disable_non_proxied_udp` | 0 of 17 (two runs) | Pass | | Firefox, default | 10 of 17 (one run) | Leak | | Firefox, `media.peerconnection.ice.proxy_only` = true | 0 of 17 (one run) | Pass | *Counts include both IPv4 and IPv6 addresses.* The command-line flag fixed headless Chromium but not a normal window. Chromium's source reads the switch in the headless shell, while normal Chrome reads the `webrtc.ip_handling_policy` profile preference. We found no documentation saying the flag is ignored in a normal window, so treat this as a measured result, not a documented rule. The Chromium fix we measured writes the preference into the profile's `Default/Preferences` file before launch. In Playwright, that needs a persistent context: ```js import { chromium } from 'playwright'; import { mkdtempSync, mkdirSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; const dir = mkdtempSync(join(tmpdir(), 'leak-check-')); mkdirSync(join(dir, 'Default')); writeFileSync( join(dir, 'Default', 'Preferences'), JSON.stringify({ webrtc: { ip_handling_policy: 'disable_non_proxied_udp' } }), ); const context = await chromium.launchPersistentContext(dir, { headless: false, proxy: { server: process.env.PROXY_SERVER, username: process.env.PROXY_USERNAME, password: process.env.PROXY_PASSWORD, }, }); ``` `PROXY_SERVER` holds the proxy URL, including the scheme and port. [Playwright proxy setup](/guides/playwright-proxy-setup) covers the rest of the client configuration. Two other ways to set the same preference in Chrome, which we did not test: - Set the [WebRtcIPHandling](https://chromeenterprise.google/policies/#WebRtcIPHandling) enterprise policy to `disable_non_proxied_udp`. Chrome then uses UDP only if the configured proxy supports it, and otherwise uses TCP through the proxy. The policy page gives the Windows registry location and the macOS and Linux preference name. - Install Google's [WebRTC Network Limiter](https://chromewebstore.google.com/detail/webrtc-network-limiter/npeicpdbkakmehahjeeohfdhnlpdklia) extension. Its store listing says disabling non-proxied UDP is off by default and is turned on from the Options page. According to Chromium's policy definition and the `chrome.privacy` documentation, both control the preference we set. Rerun the WebRTC test after applying either. In Firefox, open `about:config` and set `media.peerconnection.ice.proxy_only` to `true`, so WebRTC traffic goes only through the configured proxy. In Playwright, pass it as `firefoxUserPrefs: { 'media.peerconnection.ice.proxy_only': true }` to `firefox.launch()`. Setting `media.peerconnection.enabled` to `false` turns WebRTC off entirely. We tested only the first setting, without the time zone options from step 5. ![ToDetect WebRTC Leak Test after the fix: every STUN server shows Not detected](/media/blog/proxy-leak-check-todetect/fixed-webrtc.png) *Chromium in a normal window with the profile preference: no exposure banner, all 17 servers "Not detected" (three shown).* ## 5. Check the time zone Open [the Timezone Detection page](https://www.todetect.net/timezone/). It compares the time zone inferred from your IP with the browser's own time zone ID. If you are checking how a site behaves for visitors in the proxy's location, such as localised pages or ad placements, the two should match. With the proxy on and the browser left on the machine's settings, the IP-based zone was Europe/Berlin and the browser's IANA time zone ID was Europe/Vilnius. That is a mismatch in the time zone ID. The proxy changes the network path, not the browser's time zone setting. In our run ToDetect showed the same UTC offset for both; only the zone ID differed. ![ToDetect Timezone Detection: IP-based Europe/Berlin vs browser Europe/Vilnius](/media/blog/proxy-leak-check-todetect/leak-timezone.png) *The IP-based zone follows the proxy. The browser's zone ID stays on the machine's setting.* In Chromium, we then added `timezoneId: 'Europe/Berlin'` and `locale: 'de-DE'` to the `launchPersistentContext()` options from step 4. This combined setup is the one behind the "after" screenshots. Both zones then read Europe/Berlin. ![ToDetect Timezone Detection after the change: both zones Europe/Berlin, locale de-DE](/media/blog/proxy-leak-check-todetect/fixed-timezone.png) *After the change: the browser's IANA time zone ID is Europe/Berlin and the locale is de-DE.* In a normal browser without automation, the time zone comes from the operating system: change the system time zone and set the language in the browser's settings. We did not test this route, so recheck the page afterwards. ## 6. Read the fingerprint overview last [ToDetect's homepage](https://www.todetect.net/) combines the checks above into a "Browser Fingerprint Consistency" score, which ToDetect says "does not represent a definitive pass or fail result". In a normal Chromium window with a persistent profile, it showed 65% with default settings and 87% after the WebRTC and time zone changes, as displayed. The Timezone Anomaly and WebRTC Alert deductions were gone. The WebDriver and ClientRect deductions that remained come from the automated test browser; a Language Anomaly also remained, and we did not establish what triggered it. The [Bot Detection page](https://www.todetect.net/bot-detection/) flagged WebDriver and Dev Tool anomalies in every run, and a Headless Chrome anomaly in the headless runs, which is expected for automation. Private-style contexts and headless mode added fingerprint deductions of their own, so for QA, ad verification or geo checks, test in the browser profile you will use for the real work. ## What we did not test We did not test SOCKS5 in the browser (Chromium does not support username/password login to SOCKS5 proxies), Safari, Edge, mobile browsers or IP rotation during a session. These results describe one line, one machine and one day. ## Checklist 1. Record a baseline with the proxy off: IP, ISP, IP type and DNS resolvers. 2. With the proxy on, confirm the [IP check](https://www.todetect.net/ip/) shows the proxy's location, ISP and IP type, not yours. 3. Confirm the [DNS Leak Test](https://www.todetect.net/dns-leak/) lists only the proxy network's resolvers or ones you chose. 4. Run the [WebRTC Leak Test](https://www.todetect.net/webrtc/). If your own address appears, set Chrome's `webrtc.ip_handling_policy` preference to `disable_non_proxied_udp` or Firefox's `media.peerconnection.ice.proxy_only` to `true`, then rerun it. Do not rely on the command-line flag in a normal window. 5. If your test depends on the proxy's location, match the browser's time zone and locale to it (Playwright options, or the system time zone and browser language in a normal browser), then recheck [Timezone Detection](https://www.todetect.net/timezone/). 6. Read the fingerprint deductions, separating those caused by the proxy from those caused by your test setup. 7. Rerun every test after any change, in the browser setup you will actually use. ipvolt ran these checks for its own pre-launch testing. It now sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources - [Chromium: Proxy support in Chrome (net/docs/proxy.md)](https://chromium.googlesource.com/chromium/src/+/main/net/docs/proxy.md) - [RFC 8828: WebRTC IP Address Handling Requirements](https://www.rfc-editor.org/rfc/rfc8828) - [Chrome Enterprise policy: WebRtcIPHandling](https://chromeenterprise.google/policies/#WebRtcIPHandling) - [Chromium policy definition: WebRtcIPHandling.yaml](https://chromium.googlesource.com/chromium/src/+/main/components/policy/resources/templates/policy_definitions/WebRtc/WebRtcIPHandling.yaml) - [Chrome extensions API: chrome.privacy (webRTCIPHandlingPolicy)](https://developer.chrome.com/docs/extensions/reference/api/privacy) - [Chrome Web Store: WebRTC Network Limiter](https://chromewebstore.google.com/detail/webrtc-network-limiter/npeicpdbkakmehahjeeohfdhnlpdklia) - [Chromium source: content_switches.cc (force-webrtc-ip-handling-policy)](https://chromium.googlesource.com/chromium/src/+/main/content/public/common/content_switches.cc) - [Chromium source: headless_web_contents_impl.cc](https://chromium.googlesource.com/chromium/src/+/main/headless/lib/browser/headless_web_contents_impl.cc) - [Chromium source: renderer_preferences_util.cc](https://chromium.googlesource.com/chromium/src/+/main/chrome/browser/renderer_preferences_util.cc) - [Firefox source: modules/libpref/init/all.js (media.peerconnection prefs)](https://github.com/mozilla-firefox/firefox/blob/main/modules/libpref/init/all.js) - [Firefox source: StaticPrefList.yaml](https://github.com/mozilla-firefox/firefox/blob/main/modules/libpref/init/StaticPrefList.yaml) - [ToDetect IP Quality Check](https://www.todetect.net/ip/) - [ToDetect DNS Leak Test](https://www.todetect.net/dns-leak/) - [ToDetect WebRTC Leak Test](https://www.todetect.net/webrtc/) - [ToDetect Timezone Detection](https://www.todetect.net/timezone/) - [ToDetect Browser Fingerprint Checker](https://www.todetect.net/) - [ToDetect Bot Detection](https://www.todetect.net/bot-detection/) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [Python 3.15 for Web Scraping: What Installs, What Breaks](https://ipvolt.com/blog/python-3-15-web-scraping.md) (Analysis, Oct 16, 2026, 8 min read): pip install scrapy fails on Python 3.15 without a C compiler: brotli has no cp315 wheel. We tested 19 scraping packages with pip and uv to see what else breaks. - [Japanese price parsing: yen, width and tax labels](https://ipvolt.com/blog/japanese-price-parsing.md) (Analysis, Oct 6, 2026, 6 min read): Parse Japanese price fields without losing currency or tax basis. Run a tested Python fixture for fullwidth yen, mixed prices and deliberate review cases. - [SOCKS5 vs SOCKS5h: where DNS is resolved, client by client](https://ipvolt.com/blog/socks5-vs-socks5h.md) (Comparison, Oct 4, 2026, 7 min read): In curl, socks5:// resolves DNS locally and socks5h:// sends the hostname to the proxy. HTTPX, aiohttp and Playwright differ. Tested results and config fixes. ## Related guides - [Configure a proxy in Playwright](https://ipvolt.com/guides/playwright-proxy-setup.md): Set an authenticated HTTP proxy for a Playwright browser context, keep test state isolated, and diagnose navigation separately from subresources. - [How to test a Germany proxy: networks, cities and regions](https://ipvolt.com/guides/germany-proxies.md): Evaluate Germany proxies with current carrier and roaming context, city-location limits, browser-language controls and a practical acceptance checklist. - [HTTP vs SOCKS5 proxies: choose by the connection](https://ipvolt.com/guides/http-vs-socks5-proxies.md): Compare HTTP CONNECT and SOCKS5, understand DNS placement and TLS boundaries, and select a protocol your actual client and provider support. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 117 of 138: Python 3.15 for web scraping: what installs, what breaks URL: https://ipvolt.com/blog/python-3-15-web-scraping Markdown: https://ipvolt.com/blog/python-3-15-web-scraping.md # Python 3.15 for web scraping: what installs, what breaks Source: https://ipvolt.com/blog/python-3-15-web-scraping Markdown: https://ipvolt.com/blog/python-3-15-web-scraping.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / Python 3.15 for Web Scraping: What Installs, What Breaks Category: Analysis Published: 2026-10-16 Updated: 2026-10-16 Author: ipvolt Reading time: 8 minutes Tags: proxies, troubleshooting pip install scrapy fails on Python 3.15 without a C compiler: brotli has no cp315 wheel. We tested 19 scraping packages with pip and uv to see what else breaks. On Python 3.15.0, most of a scraping stack installs from ready-made wheels and passed a smoke test. Anything that needs brotli or zstandard fails on a machine without a C compiler, because neither has a wheel for 3.15, and that includes a plain `pip install scrapy`. The quick fix is to install `gcc` before `pip install` ([Fix 1](#fix-1-add-a-compiler-to-the-image)) or to stay on Python 3.14 until brotli publishes cp315 wheels ([Fix 2](#fix-2-stay-on-python-314-until-the-wheels-exist)). **Last checked: 16 October 2026, 10:09 UTC.** At that time PyPI still had no cp315 wheel for brotli 1.2.0 or zstandard 0.25.0. zope.interface 8.7, released on 15 October, added cp315 wheels. | Package | Version | cp315 wheel | With compiler | Without compiler | Notes | | --- | --- | --- | --- | --- | --- | | `scrapy` | 2.19.0 | pure Python; no (brotli 1.2.0) | installs | fails: brotli build | requires brotli on CPython since 2.18.0 | | `requests[socks]` | 2.34.2 + PySocks 1.7.1 | pure Python | installs | installs | | | `httpx[socks]` | 0.28.1 + socksio 1.0.0 | pure Python | installs | installs | | | `httpx[brotli]` | 0.28.1 | no (brotli 1.2.0) | installs | fails: brotli build | `httpx brotlicffi` installs without a compiler | | `httpx[zstd]` | 0.28.1 | no (zstandard 0.25.0) | installs | fails: zstandard build | slowest build | | `aiohttp` | 3.14.5 | yes | installs | installs | | | `aiohttp[speedups]` | 3.14.5 + aiodns 4.0.4 | no (Brotli 1.2.0) | installs | fails: Brotli build | `aiohttp aiodns brotlicffi` installs | | `aiohttp-socks` | 0.12.0 | pure Python | installs | installs | | | `urllib3[brotli]` | 2.8.0 | no (brotli 1.2.0) | installs | fails: brotli build | `urllib3 brotlicffi` installs | | `curl_cffi` | 0.16.3 | abi3 | installs | installs | | | `playwright` | 1.64.0 | not version-specific | installs | installs | browsers not tested | | `lxml` | 6.1.3 | yes | installs | installs | | | `beautifulsoup4` | 4.15.0 | pure Python | installs | installs | | | `parsel` | 1.12.1 | pure Python | installs | installs | | | `selectolax` | 1.0.0 | yes | installs | installs | 1.0: `selectolax.parser` raised ImportError, use `selectolax.lexbor` | | `pandas` | 3.0.6 + numpy 2.5.4 | yes | installs | installs | | | `pydantic` | 2.14.1 + pydantic-core 2.50.1 | pydantic-core: yes | installs | installs | | | `orjson` | 3.13.0 | yes | installs | installs | | | `tenacity` | 9.2.1 | pure Python | installs | installs | | "With compiler" and "without compiler" are the official `python:3.15-slim` image with and without `gcc`, and every package was installed with both pip and uv, which agreed in every case. A pure-Python package has no compiled code, so it needs no cp315 wheel. Each install passed its smoke test. ## pip install scrapy fails on Python 3.15: Failed building wheel for brotli In the slim image, pip 26.2.1 stops at brotli: ```text × Building wheel for brotli (pyproject.toml) did not run successfully. │ exit code: 1 error: [Errno 2] No such file or directory: 'gcc' ERROR: Failed building wheel for brotli error: failed-wheel-build-for-install × Failed to build installable wheels for some pyproject.toml based projects ╰─> brotli ``` uv 0.13.1 fails at the same package and names the chain: ```text error: Failed to build `brotli==1.2.0` cause: The build backend returned an error hint: `brotli` (v1.2.0) was included because `scrapy` (v2.19.0) depends on `brotli` ``` The chain is short. Scrapy 2.19.0 is pure Python, but it requires `brotli>=1.2.0; implementation_name != "pypy"`, so every CPython install pulls in brotli. That requirement arrived in Scrapy 2.18.0 (20 August 2026); 2.17.0 did not have it. brotli 1.2.0, released 5 November 2025, has wheels for CPython 2.7 and 3.6 to 3.14 and nothing newer. Without a matching wheel, pip and uv download the source archive and compile the `_brotli` extension, which needs `gcc`. The same thing happens with `httpx[brotli]`, `aiohttp[speedups]` and `urllib3[brotli]`, which also want the `brotli` package on CPython, and with `httpx[zstd]`, which wants zstandard 0.25.0. ### Fix 1: add a compiler to the image This one line, run in the slim image, was enough for every failing package: ```sh apt-get update && apt-get install -y --no-install-recommends gcc libc6-dev ``` It installed gcc 14.2.0. Afterwards `pip install scrapy` took 28 seconds instead of failing, uv took 19, and the spider crawled its test pages, including a brotli-compressed one. zstandard is the slow build: 63 seconds for `httpx[zstd]` with pip. In a Dockerfile, put the line before the `pip install`. Only this Debian line was tested. On Windows, the compiler these builds need comes with Microsoft's [C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/); we did not test Windows. ### Fix 2: stay on Python 3.14 until the wheels exist Python 3.14 has brotli and zstandard wheels, so the problem does not exist there. To see whether brotli has caught up, run this with Python 3.15: ```sh python3 -m pip download --only-binary :all: --no-deps -d /tmp/wheel-check brotli ``` On 16 October it still ended with `ERROR: No matching distribution found for brotli`. Once it downloads a `.whl` file, the cp315 wheels are out and `pip install scrapy` works without a compiler. Upstream, [google/brotli-wheels issue #25](https://github.com/google/brotli-wheels/issues/25), "Python 3.15 wheels missing", was opened on 9 October and had no replies on 16 October. [google/brotli pull request #1583](https://github.com/google/brotli/pull/1583) adds a CI job that builds cp315 wheels. On 16 October it was still open with no review, and the only comment was the CLA bot's. Its description notes that a maintainer would still need to publish the wheels to PyPI. ### Not Scrapy? brotlicffi has a wheel brotlicffi 1.2.0.2 ships an `abi3` wheel that pip installed on 3.15. HTTPX, urllib3 and aiohttp accept it in place of `brotli`, so without a compiler these worked and decoded a brotli response: ```sh pip install httpx brotlicffi pip install urllib3 brotlicffi pip install aiohttp aiodns brotlicffi ``` The last one is `aiohttp[speedups]` minus the `Brotli` requirement. Scrapy cannot use this route: on CPython it requires the `brotli` package itself. zstd is easier than it looks. On Python 3.14 and newer, urllib3 2.8.0 and aiohttp 3.14.5 decode zstd with the standard library's `compression.zstd`, so both offered `zstd` and decoded a zstd response with no extra package installed. Only `httpx[zstd]` needs zstandard. ## Don't use --only-binary blindly `--only-binary :all:` tells pip to never build from source. It looks like the obvious workaround, and it does not fail: ```sh pip install --only-binary :all: "httpx[brotli]" "aiohttp[speedups]" ``` pip printed `INFO: This is taking longer than usual` while it searched, then installed httpx 0.18.2 (June 2021) and aiohttp 0.13.1 (December 2014). The only other hint was one line: ```text WARNING: aiohttp 0.13.1 does not provide the extra 'speedups' ``` The resolver walked back through old releases until it found ones whose requirements could all be met with wheels. `uv pip install --no-build` picked the same two versions and printed ``warning: The package `aiohttp==0.13.1` does not have an extra named `speedups` ``. Narrowing the flag to one package does not make it safe. `pip install --only-binary brotli scrapy` also exits 0, and it installs Scrapy 2.17.0, the last release without the brotli requirement. uv did the same. That Scrapy crawled the test pages, but it offered servers only `gzip, deflate` where 2.19.0 with brotli offered `gzip, deflate, br, zstd`. If your spiders use `async def start()`, 2.17.0 still runs them. To spot a silent downgrade, read the installed versions after every install: ```sh pip list uv pip list ``` To make it fail loudly instead, pin the version you want next to the flag: ```sh pip install --only-binary brotli "scrapy==2.19.0" ``` ```text ERROR: Could not find a version that satisfies the requirement brotli>=1.2.0; implementation_name != "pypy" (from scrapy) (from versions: none) ERROR: No matching distribution found for brotli>=1.2.0; implementation_name != "pypy" ``` uv with the same pin stopped with `error: No solution found when resolving dependencies`. A `requirements.txt` with exact versions for your top-level packages gives you the same protection on every build. ## Fixed on 15 October: zope.interface without C speedups Twisted, and with it Scrapy, depends on zope.interface. zope.interface 8.6 has wheels up to CPython 3.14 only. On 14 October, without a compiler, pip and uv still installed it on 3.15: its build falls back to pure Python when the C extension cannot be compiled. No error and no warning appeared in the install output. The cost showed up in the basic interface check. In the lab, `IThing.providedBy(obj)` took 271 ns per call without the C extension and 101 ns with it. The lab did not measure what that means for a whole crawl. zope.interface 8.7, released on 15 October, ships cp315 wheels. On 16 October a fresh install without a compiler got the 8.7 binary wheel with pip and uv, the C extension imported, and the same check took 102 ns. A virtual environment created before 15 October keeps the pure-Python 8.6 until you upgrade zope.interface. To see which one you have: ```sh python -c "import zope.interface._zope_interface_coptimizations" ``` A `ModuleNotFoundError` means the pure-Python fallback. With the 8.7 wheel, or with gcc installed, the import succeeded. ## Other 3.15 changes that matter to scrapers The one most scrapers will notice is UTF-8 mode, now on by default ([PEP 686](https://peps.python.org/pep-0686/)). [What's New in Python 3.15](https://docs.python.org/3.15/whatsnew/3.15.html#whatsnew315-utf8-default) says I/O operations without an explicit encoding, such as `open('flying-circus.txt')`, now use UTF-8 whatever the system's environment. In the lab, with `LANG=C`, `open()` without `encoding` wrote UTF-8 on 3.15; with `-X utf8=0` it fell back to `ANSI_X3.4-1968`, which is ASCII. For scrapers this mostly shows up in exports. A CSV or JSON file written with `open(path, "w")` is now UTF-8 on every machine, including Windows systems where 3.14 used the locale's code page. That is usually what you want. If a downstream tool expects the old encoding, pass `encoding="locale"` or set `PYTHONUTF8=0`; better, pass the encoding explicitly in both writer and reader. ## If you're upgrading Scrapy at the same time A move to Python 3.15 often comes with a new Scrapy. Since 2.16, Scrapy no longer calls `start_requests()`: a spider that defines only that method opens, sends nothing and closes as finished, with no warning. [Scrapy crawls 0 pages after upgrading](/guides/scrapy-start-requests-not-called) has the one-line fix, `async def start()`, which the spider in this lab used. ## Method and limits Recorded on 14 October 2026 on an x86_64 Ubuntu host, in the file system of the official `python:3.15-slim` image (Debian 13 trixie, index digest `sha256:ea4f1f29…`, built 12 October 2026), run in a private Linux namespace rather than Docker. The interpreter reported `Python 3.15.0 (main, Oct 12 2026, 22:33:31) [GCC 14.2.0]`, with pip 26.2.1 as bundled and uv 0.13.1. The compiler copy added gcc 14.2.0 with the apt line above. The table comes from those runs. On 16 October the Scrapy, `--only-binary brotli` and zope.interface cases were run again without a compiler: everything matched 14 October except zope.interface, which now came from the 8.7 wheel. Every case got a new virtual environment and no package cache. The installed versions and whether each came from a binary wheel, a pure-Python wheel or a local build were read from the wheel tags. The smoke tests ran against a local `http.server` that compresses only with encodings the client offers. Playwright was installed but its browsers were not. No proxy was used. The lab says nothing about macOS, Windows, ARM, musl-based images or free-threaded builds. PyPI changes daily, so rerun the wheel check before acting on any row. The script, the smoke tests and the raw output are in the [download folder](/downloads/python-3-15-web-scraping/README.md): [lab315.py](/downloads/python-3-15-web-scraping/lab315.py), [results.csv](/downloads/python-3-15-web-scraping/results.csv), [results.json](/downloads/python-3-15-web-scraping/results.json) and the 16 October rerun, [results-2026-10-16.json](/downloads/python-3-15-web-scraping/results-2026-10-16.json). ## Related - [Scrapy proxies in 2.19](/guides/scrapy-proxy-setup), for auth, rotation and the proxy errors Scrapy logs. - [aiohttp proxies](/guides/aiohttp-proxy-setup) and [curl_cffi proxies](/guides/curl-cffi-proxy-setup), both of which installed from wheels on 3.15. - [Fix "Missing dependencies for SOCKS support"](/guides/fix-missing-dependencies-for-socks-support), the other install-time error in this stack. - [How many GB of proxies do I need?](/blog/how-many-gb-of-proxies-do-i-need), for sizing traffic once the stack runs. Compression matters there: a client that offers fewer encodings can download more bytes. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources - [Python.org: Python 3.15.0 release page](https://www.python.org/downloads/release/python-3150/) - [What's New in Python 3.15: UTF-8 is the default encoding](https://docs.python.org/3.15/whatsnew/3.15.html#whatsnew315-utf8-default) - [PEP 686: Make UTF-8 mode default](https://peps.python.org/pep-0686/) - [PyPI: brotli 1.2.0 files](https://pypi.org/project/brotli/1.2.0/#files) - [PyPI: zstandard 0.25.0 files](https://pypi.org/project/zstandard/0.25.0/#files) - [PyPI: zope.interface 8.6 files](https://pypi.org/project/zope.interface/8.6/#files) - [PyPI: zope.interface 8.7 files](https://pypi.org/project/zope.interface/8.7/#files) - [PyPI: Scrapy 2.19.0](https://pypi.org/project/Scrapy/2.19.0/) - [google/brotli-wheels issue #25: Python 3.15 wheels missing](https://github.com/google/brotli-wheels/issues/25) - [google/brotli pull request #1583: Build and test CPython 3.15 wheels in CI](https://github.com/google/brotli/pull/1583) - [Microsoft C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [Check a Proxy for IP, DNS and WebRTC Leaks with ToDetect](https://ipvolt.com/blog/proxy-leak-check-todetect.md) (Analysis, Oct 23, 2026, 9 min read): Check a browser proxy for IP, DNS, WebRTC and time zone leaks with ToDetect's free tools, using measured results from a 4G mobile line as the worked example. - [Japanese price parsing: yen, width and tax labels](https://ipvolt.com/blog/japanese-price-parsing.md) (Analysis, Oct 6, 2026, 6 min read): Parse Japanese price fields without losing currency or tax basis. Run a tested Python fixture for fullwidth yen, mixed prices and deliberate review cases. - [SOCKS5 vs SOCKS5h: where DNS is resolved, client by client](https://ipvolt.com/blog/socks5-vs-socks5h.md) (Comparison, Oct 4, 2026, 7 min read): In curl, socks5:// resolves DNS locally and socks5h:// sends the hostname to the proxy. HTTPX, aiohttp and Playwright differ. Tested results and config fixes. ## Related guides - [Scrapy proxies in 2.19: auth, rotation and the errors you'll hit](https://ipvolt.com/guides/scrapy-proxy-setup.md): Scrapy 2.19 proxy setup: credentials in meta["proxy"], per-request rotation, HTTP_PROXY, and fixes for TunnelError 407, ignored 407 responses and socks5. - [Scrapy crawls 0 pages after upgrading: start_requests() is no longer called](https://ipvolt.com/guides/scrapy-start-requests-not-called.md): Scrapy 2.16 removed Spider.start_requests(): the spider logs Crawled 0 pages and closes as finished with no warning. Fix: async def start(). Tested on 2.19. - [aiohttp proxies in 3.14: auth without BasicAuth, env vars and the errors you'll hit](https://ipvolt.com/guides/aiohttp-proxy-setup.md): Set up an HTTP or SOCKS proxy in aiohttp 3.14: replace the deprecated BasicAuth and proxy_auth, turn on trust_env, and read the 407 and Bad status line errors. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 118 of 138: Japanese price parsing: yen, width and tax labels URL: https://ipvolt.com/blog/japanese-price-parsing Markdown: https://ipvolt.com/blog/japanese-price-parsing.md # Japanese price parsing: yen, width and tax labels Source: https://ipvolt.com/blog/japanese-price-parsing Markdown: https://ipvolt.com/blog/japanese-price-parsing.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / Japanese price parsing: yen, width and tax labels Category: Analysis Published: 2026-10-06 Updated: 2026-10-06 Author: ipvolt Reading time: 6 minutes Tags: proxies, troubleshooting Parse Japanese price fields without losing currency or tax basis. Run a tested Python fixture for fullwidth yen, mixed prices and deliberate review cases. A Japanese price parser should return an amount together with currency evidence, original text and tax basis. Select one offer field first, guard Unicode normalization, and hold ambiguous inputs. A `parsed` field still needs checks before it becomes an accepted monitoring record. The downloadable Python example makes that boundary explicit. Its **36 synthetic offline cases produced 36 expected classifications: 11 parsed fields, 25 review outcomes and zero fixture failures**. No Japanese storefront or proxy was tested. The useful result is a reproducible set of decisions, including when the parser declines to choose a price. ## A display can contain two legitimate amounts Japan's National Tax Agency gives this example in its total-price display guidance: ```text 10,000円(税込価格11,000円) ``` The explicitly tax-inclusive amount is 11,000 yen, although 10,000 appears first. The NTA's examples permit displays containing both inclusive and exclusive figures. Taking the first number would lose that distinction. [NTA No. 6902, display examples](https://www.nta.go.jp/taxes/shiraberu/taxanswer/shohi/6902.htm). Removing every nondigit is worse: applied to this string, Python's `re.sub(r"\D", "", text)` produces `1000011000`. The supplied parser returns `review` with reason `unsupported_or_multiple_price_text`. It does not choose an amount from a multi-price container. Resolve that upstream: identify the intended amount and its label within the selected offer, preserving the source context. If your extractor cannot distinguish the amounts, keep the record under review. A general display obligation does not prove the tax basis of an arbitrary extracted field. ## Require currency context before parsing The `¥` character does not establish Japanese yen. Unicode specifies U+00A5 for both Japanese yen and Chinese yuan, independent of glyph styling. Obtain explicit currency context for the same offer before supplying `JPY`. [Unicode 17, “Yen and Yuan”](https://www.unicode.org/versions/Unicode17.0.0/core-spec/chapter-22/). The function accepts only three keys, with `text` limited to a string of 1–200 characters. Here is a **synthetic fixture input**, whose evidence reference is deliberately a fixture label: ```json { "text": "¥1,298(税込)", "currency": "JPY", "currency_evidence": "fixture.selected_offer.priceCurrency" } ``` For that input, the recorded result is: ```json { "original": "¥1,298(税込)", "status": "parsed", "normalized": "¥1,298(税込)", "amount_yen": 1298, "currency": "JPY", "currency_evidence": "fixture.selected_offer.priceCurrency", "tax_basis": "included", "tax_label": "税込" } ``` In an adapter, call `parse_price(record)` from the downloaded module with those three keys. Keep product identity, URL, timestamp and other monitoring context in an outer record; extra keys in this function's input return `invalid_record`. **The evidence reference is a caller assertion.** The function requires a nonempty string but neither retrieves nor authenticates it. An author probe using a deliberately fabricated reference still returned `parsed`. Supplying `JPY` because the page has a yen-shaped glyph would therefore defeat the intended contract even if the parser passes. Check the underlying currency evidence separately and preserve conflicts. ## Guard normalization before it changes the field Fullwidth digits can represent ordinary decimal digits, but compatibility normalization also changes other characters. Unicode's NFKC form can erase distinctions beyond width; Python exposes it through `unicodedata.normalize`. [Unicode compatibility digits](https://www.unicode.org/versions/Unicode17.0.0/core-spec/chapter-22/), [normalization guidance](https://unicode.org/faq/normalization.html), [Python unicodedata](https://docs.python.org/3/library/unicodedata.html). This parser checks each character before normalizing the whole field. It permits changes for fullwidth ASCII U+FF01–U+FF5E, ideographic space U+3000 and fullwidth yen U+FFE5. Other characters that change under NFKC go to review. The grammar is checked after normalization; an allowed width conversion does not itself make an input a price. That order matters for `¥①298(税込)` and `¥¹298(税込)`. Blind compatibility folding can turn the circled or superscript character into an ordinary digit. The fixture holds both as `unsupported_compatibility_character`. It also holds ASCII and fullwidth backslashes; a character's font appearance does not make it a yen sign. Preserve `original` alongside `normalized`, as the successful record does above. This guarded policy is specific to the downloaded parser. It is not a prescription to apply NFKC indiscriminately to product names, identifiers or arbitrary page text. ## Preserve tax basis without calculating tax The parser accepts one whole-yen expression: `¥1298`, `1298円` or `JPY 1298`, with optional correctly grouped commas. A supported trailing tax label can appear in parentheses or after whitespace. It maps `税込` and `税込価格` to `included`; `税抜`, `税抜き` and `税別` to `excluded`. No label produces `unspecified`. Selected outcomes from the executed fixture are below. Except where stated, the input has `currency: "JPY"` and the synthetic evidence reference shown above. | Input field | Result | Consequence for a later comparison | | --- | --- | --- | | `¥1,298(税込)` | `parsed`: 1298, `included` | Keep the inclusive basis with the amount. | | `1,180円(税抜)` | `parsed`: 1180, `excluded` | Do not silently compare it as the same basis as an inclusive amount. | | `1,298円` | `parsed`: 1298, `unspecified` | If the job requires known tax basis, that requirement remains unresolved. | | `10,000円(税込価格11,000円)` | `review` | Select and evidence the intended field before parsing. | | `12,98円(税込)` | `review` | The grouping does not meet this grammar. | | `¥①298(税込)` | `review` | An unsupported compatibility change is held before normalization. | | `¥1298(税込)`, currency missing or `CNY` | `review` | A familiar glyph cannot supply the required JPY context. | There is **no tax-rate calculation, currency conversion or cents multiplier**. `amount_yen` is an integer under this parser's whole-yen input contract; it does not define the units used by every API. Do not derive a missing gross or net value from the nearby number. The grammar also holds ranges, instalments, points, multiple prices, negatives, decimals, Kanji-number units, prefixed tax labels and leading zeros. Some may be valid store presentations outside this scope. A `review` outcome means the input is unresolved under this grammar, not that the merchant's display is invalid. ## Run the same offline fixture Download [parse_price.py](https://ipvolt.com/downloads/japanese-price-parsing/parse_price.py) and [fixtures.json](https://ipvolt.com/downloads/japanese-price-parsing/fixtures.json) into one directory. The script uses Python's standard library; the [README](https://ipvolt.com/downloads/japanese-price-parsing/README.md) gives the Python 3.10-or-newer input contract and limits. Run: ```sh python3 parse_price.py fixtures.json > replay.json ``` The command makes no network requests. Compare `replay.json` with the published [results.json](https://ipvolt.com/downloads/japanese-price-parsing/results.json). A matching run reports `cases: 36`, `passed: 36` and `failed: 0`. The 25 review outcomes are expected decisions, so they do not count as fixture failures. The fixture checks each declared expected field and retains complete actual outputs. Exit status 0 means the fixture expectations matched; status 1 means at least one did not; status 2 reports an invalid or unreadable fixture. None is a storefront acceptance signal. The original [environment record](https://ipvolt.com/downloads/japanese-price-parsing/environment.json) documents Python 3.14.7 with Unicode database 16.0.0. The author replay on Python 3.14.8, also using Unicode database 16.0.0, produced the same complete result JSON. Citing Unicode 17 documentation does not mean the executable used a Unicode 17 database. ## Decide whether a parsed field is usable Before accepting a monitoring record, bind the field to the exact product and variant, retain the source and observation time, validate currency evidence and resolve the price basis your comparison requires. Check quantity, membership, sale conditions and delivery context when the job depends on them. Those are decisions outside this parser. For example, the fixture's 1298-yen inclusive field and 1180-yen exclusive field both parse. That does not make their numeric difference a measured price change. An unlabelled field can also parse while remaining unsuitable for a comparison that requires inclusive prices. The separate [price and currency validation case](/blog/product-price-currency-validation) addresses conflicting offer and storefront signals. If your collection also requires a Japanese exit or named mobile access, use the [Japan proxy evaluation guide](/guides/japan-proxies) for that evidence. A local parsing result supplies no evidence about an exit's country, network or availability. *Method: agent-assisted source research and synthesis, with executed synthetic fixtures and the separately described limit probe on 6 October 2026. These cases demonstrate the stated parser behavior; they are not a sample of Japanese retailers or an accuracy benchmark. No storefront, proxy or tax calculation was tested.* ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources - [No.6902 「総額表示」の義務付け](https://www.nta.go.jp/taxes/shiraberu/taxanswer/shohi/6902.htm) - [Unicode 17.0.0, Chapter 22: Symbols](https://www.unicode.org/versions/Unicode17.0.0/core-spec/chapter-22/) - [FAQ: Normalization](https://unicode.org/faq/normalization.html) - [Python unicodedata](https://docs.python.org/3/library/unicodedata.html) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [Check a Proxy for IP, DNS and WebRTC Leaks with ToDetect](https://ipvolt.com/blog/proxy-leak-check-todetect.md) (Analysis, Oct 23, 2026, 9 min read): Check a browser proxy for IP, DNS, WebRTC and time zone leaks with ToDetect's free tools, using measured results from a 4G mobile line as the worked example. - [Python 3.15 for Web Scraping: What Installs, What Breaks](https://ipvolt.com/blog/python-3-15-web-scraping.md) (Analysis, Oct 16, 2026, 8 min read): pip install scrapy fails on Python 3.15 without a C compiler: brotli has no cp315 wheel. We tested 19 scraping packages with pip and uv to see what else breaks. - [SOCKS5 vs SOCKS5h: where DNS is resolved, client by client](https://ipvolt.com/blog/socks5-vs-socks5h.md) (Comparison, Oct 4, 2026, 7 min read): In curl, socks5:// resolves DNS locally and socks5h:// sends the hostname to the proxy. HTTPX, aiohttp and Playwright differ. Tested results and config fixes. ## Related guides - [Japan proxies: IP location and mobile network checks](https://ipvolt.com/guides/japan-proxies.md): Evaluate Japan proxies with separate IP-location, egress and mobile-access evidence. Work through au/UQ branding and Rakuten roaming before accepting a sample. - [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md): Configure a proxy in Python Requests: the proxies dictionary, Session defaults, credentials, SOCKS5 via requests[socks], environment variables and ProxyError. - [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md): Choose rotation around the smallest complete workflow, distinguish exit affinity from cookies, and test what happens when a sticky session ends early. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 119 of 138: How many GB of proxies do you need? We measured pages per GB URL: https://ipvolt.com/blog/how-many-gb-of-proxies-do-i-need Markdown: https://ipvolt.com/blog/how-many-gb-of-proxies-do-i-need.md # How many GB of proxies do you need? We measured pages per GB Source: https://ipvolt.com/blog/how-many-gb-of-proxies-do-i-need Markdown: https://ipvolt.com/blog/how-many-gb-of-proxies-do-i-need.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / How Many GB of Proxies Do You Need? Pages per GB, Measured Category: Benchmark Published: 2026-10-05 Updated: 2026-11-11 Author: ipvolt Reading time: 8 minutes Tags: proxies, choosing We loaded 34 public pages three ways through a metering proxy. 1 GB fits about 44,000 HTML-only fetches, or about 900 full Playwright page loads. 1 GB holds about 44,000 pages if you fetch only the HTML with an HTTP client, and about 900 if you load the same pages in a browser. How you fetch changed the answer about 49 times over; the kind of site changed it far less. We loaded 34 public pages on 5 October 2026, three times in each of three modes, through a local metering proxy. The bytes are counted on the wire in both directions, so they include TLS handshakes, HTTP headers, everything sent upstream and an estimate of the proxy's CONNECT exchange, not only page weight. | How the page is fetched | Median per page | 90th percentile | Pages per GB, median page | Pages per GB, 90th percentile page | | --- | --- | --- | --- | --- | | HTTP client, HTML only (Requests 2.34.2) | 22.7 KB | 59.2 KB | 44,083 | 16,880 | | Playwright 1.63.0, full load | 1.10 MB | 2.45 MB | 906 | 408 | | Playwright, images, media and fonts blocked | 454.6 KB | 2.28 MB | 2,199 | 437 | 1 GB is 10^9 bytes. Each page's value is the median of its three loads, and the 90th percentile is the fourth-heaviest of the 34 pages. If your targets are heavy, plan with that column: blocking images barely moved it (2.45 MB to 2.28 MB), because the heaviest pages were heavy with scripts. ## Estimate your own GB ```text GB per day = pages per day × bytes per page × attempts per page ÷ 1,000,000,000 ``` A worked example: 50,000 pages a day in a full browser at the 1.10 MB median, with 1.2 attempts per page, is 50,000 × 1,103,256 × 1.2 ÷ 10^9 = 66.2 GB a day. The same job with an HTTP client at the 22.7 KB median is 1.4 GB a day. The 1.2 is an assumption for the example (one retry for every five pages), not something measured here. Count attempts, not pages, because a retry downloads the page again; [Proxy retries: one lost response, two created jobs](/blog/proxy-retries-duplicate-jobs) covers when a retry is safe at all. And these medians describe our 34 pages, not yours. [Scrapescope](/guides/scraper-bandwidth-report), the free meter used for this post, measures your own pages without a proxy account. ## Pages per GB by page type Median bytes per page, with pages per GB in brackets: | Page type | HTML only | Full load | Images, media and fonts blocked | | --- | --- | --- | --- | | Docs and reference (7 pages) | 37.2 KB (26,912) | 589.6 KB (1,696) | 433.5 KB (2,306) | | News articles (5) | 51.7 KB (19,355) | 1.32 MB (758) | 2.24 MB (445) | | Blog posts (5) | 24.9 KB (40,202) | 601.1 KB (1,663) | 444.3 KB (2,250) | | Forum threads (3) | 20.8 KB (48,167) | 2.45 MB (408) | 2.26 MB (441) | | Shop category pages (5) | 20.0 KB (50,042) | 1.33 MB (751) | 388.6 KB (2,573) | | Shop product pages (5) | 21.3 KB (46,983) | 1.16 MB (858) | 347.9 KB (2,874) | | JavaScript apps (4) | 11.1 KB (90,009) | 1.39 MB (717) | 751.0 KB (1,331) | The groups are small, so read them as examples. The shop pages are scraping sandboxes and a demo store, because we left out retailers whose terms forbid automated access; real retail pages may be heavier. For the JavaScript apps, the 11 KB is the HTML document alone. An HTTP client fetches that one document and nothing a script would load, and we measured bytes, not whether the data you need is in that HTML. ## What changed the bytes most In order of effect in this data: 1. **Browser or HTTP client.** A full browser load moved a median of 31 times the bytes of the HTML fetch for the same page, from 2.1 times on a Python documentation page to 195 times on a JavaScript-rendered demo page. 2. **Scripts, more than images.** Scripts were 49% of all full-load bytes; images, media and fonts together were 35%. The three forum threads stayed between 2.2 MB and 2.6 MB in both browser modes. 3. **Other sites' hosts.** Half of the full-load bytes (49.9%) went to hosts outside the page's own site. The median page sent 38% there, and 7 pages sent nothing. The largest single host was `www.googletagmanager.com`: it appeared on 17 of the 34 pages at about 308 KB per load, 12% of all full-load bytes. One news article contacted 32 hosts. 4. **Blocking images, media and fonts.** The median saving was 28%. It was over 50% on 10 pages, up to 84%, and under 10% on 6. Three of those 6 moved more bytes with blocking on. One news article pulled 1.14 MB from `www.gstatic.com` in two of its three blocked loads, a host that was not among its three largest in any full load. On another, a YouTube embed moved 1.9 MB to 2.0 MB with blocking and 1.2 MB without. Blocking changes what a page does, so measure a second run before relying on it; [Playwright's network guide](https://playwright.dev/python/docs/network#abort-requests) documents the route call used here, and [Playwright proxy setup](/guides/playwright-proxy-setup) covers the proxy side. [Block images and fonts in Playwright](/guides/playwright-block-images-save-bandwidth) shows how to set the blocking up. Compression is not ranked because it was on in every run: all 34 HTML responses came back compressed (17 Brotli, 14 gzip, 3 Zstandard). The median HTML document was 83.5 KB after decoding, against 22.7 KB on the wire for the whole fetch. A client that does not ask for compression downloads closer to the decoded size; see [which clients skip compression](/guides/curl-compressed-accept-encoding). ## Upload share and tunnel overhead | Mode | Upstream share of all bytes | Median upstream bytes per page | | --- | --- | --- | | HTTP client, HTML only | 6.3% | 1.9 KB | | Playwright, full load | 2.7% | 28.9 KB | | Playwright, blocked | 2.9% | 17.3 KB | Upload is a small share overall and a large one on small pages: up to 21% of a single HTML fetch, because the TLS handshake and the request cost the same however small the reply is. Check whether your provider counts both directions. The estimated CONNECT exchange added a median of 109 bytes to an HTML fetch and 2.6 KB to a full browser page, one exchange per tunnel. The browser fetched nothing in the background by itself: scrapescope's background, idle-preconnect and unattributed buckets were 0 bytes in all 204 browser runs. That is Playwright's bundled Chromium with default launch settings; other browser builds were not tested. ## Cost per 1,000 pages Median page, with the 90th percentile page in brackets: | Price per GB | HTML only | Full load | Images, media and fonts blocked | | --- | --- | --- | --- | | $1.00 | $0.02 ($0.06) | $1.10 ($2.45) | $0.45 ($2.28) | | $2.20 | $0.05 ($0.13) | $2.43 ($5.39) | $1.00 ($5.02) | | $5.00 | $0.11 ($0.30) | $5.52 ($12.24) | $2.27 ($11.42) | | $10.00 | $0.23 ($0.59) | $11.03 ($24.48) | $4.55 ($22.83) | $2.20 is where ipvolt's residential proxies start: the [pricing section](https://ipvolt.com/#pricing) says "Residential proxies from $2.20/GB, in prepaid packs." The mobile proxies ipvolt sells now are rented for 1 day or 30 days, so this per-GB table does not price them. The other three are round reference points, not anyone's price list; for market prices see [what unlimited residential plans cost per GB](/blog/unlimited-residential-proxies-cost-per-gb). Each figure is bytes ÷ 10^9 × price. It estimates transfer and is not a bill. ## Compared with the 2025 Web Almanac The [Page Weight chapter](https://almanac.httparchive.org/en/2025/page-weight) of the 2025 Web Almanac says "The median home page in 2025 was 2.86 MB on desktop and 2.56 MB on mobile." Its inner-page chart ends at 1,963 KB on desktop and 1,769 KB on mobile in July 2025, and its median HTML response is 35 KB on desktop and 33 KB on mobile. The chapter defines page weight as "the total volume of bytes transferred to a user’s device" and notes that its JavaScript figures are "bytes for compressed JavaScript files", so these are transfer sizes, not uncompressed sizes. It does not repeat that statement next to the HTML figure. Our full-load median of 1.10 MB is below the Almanac's inner-page medians. The set leans on documentation and sandbox pages and is mostly inner pages. The HTML figures are close: 22.7 KB on the wire here, 33 KB to 35 KB there. The two count different things. The Almanac counts what a page's responses weigh; this test counts every byte through the tunnel in both directions. ## Method and limits - **When and where.** 5 October 2026, 08:37 to 09:04 UTC, from a server in Helsinki, Finland, on a direct connection. No paid proxy was used. - **Tools.** scrapescope 0.1.0 in direct sizing mode as the local metering proxy, Python 3.14.4, Requests 2.34.2 with urllib3 2.8.0, and Playwright 1.63.0 with its bundled Chromium headless shell 153.0.8010.12. - **Each load.** A new process, a new browser and an empty cache, with no cookies and no consent given. The browser used a 1280×900 viewport, waited for the load event and then up to 10 seconds for the network to go idle. It did not scroll or click, so content that loads on scroll is not counted. The HTTP client sent one GET and followed redirects. - **Pages.** 34 URLs that robots.txt allowed, with no logins and no paywalls. One forum candidate was dropped before measuring because its site terms forbid automated access. All 306 loads returned HTTP 200. - **Variation.** The median gap between a page's heaviest and lightest load was 0.05% for HTML, 0.2% for a full load and 0.3% with blocking. The largest was 54%, on the news article described above. - **Limits.** A direct connection reproduces the transport, not a proxy's exit location, blocks or retries; the scrapescope README calls sizing mode "a lower bound" for protected sites. The CONNECT bytes are estimated. Shares by resource type are allocated by the tool from host totals, not measured per request. One location, one day, and pages change. Downloads: the [URL list](https://ipvolt.com/downloads/how-many-gb-of-proxies-do-i-need/urls.csv), the [raw CSV](https://ipvolt.com/downloads/how-many-gb-of-proxies-do-i-need/results.csv) with all 306 runs, the [computed summary](https://ipvolt.com/downloads/how-many-gb-of-proxies-do-i-need/summary.json), and the [measurement scripts](https://ipvolt.com/downloads/how-many-gb-of-proxies-do-i-need/pages-per-gb-lab.zip) with a README. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources - [Web Almanac 2025: Page Weight (HTTP Archive)](https://almanac.httparchive.org/en/2025/page-weight) - [scrapescope README at the commit used: sizing mode, what is counted, limits](https://github.com/ipvolt/scrapescope/blob/e33e8fb90b28ea32fba92cd26e70aef474e2eccd/README.md) - [Playwright for Python: network, aborting requests with route()](https://playwright.dev/python/docs/network#abort-requests) - [Playwright for Python: Request.resource_type](https://playwright.dev/python/docs/api/class-request#request-resource-type) - [Requests: response content and automatic decoding of compressed bodies](https://requests.readthedocs.io/en/latest/user/quickstart/#response-content) ## Plug in your first proxy. Residential from $2.20 per GB. Mobile from $9 a day. [Buy residential](https://ipvolt.com/dashboard/residential) [Buy mobile](https://ipvolt.com/dashboard/mobile) ## Related posts - [How to Check if a Proxy Is Really Mobile or Residential](https://ipvolt.com/blog/check-if-proxy-is-mobile-or-residential.md) (Analysis, Nov 8, 2026, 12 min read): No single check proves a proxy is mobile or residential. We tested ASN, RDAP, PeeringDB, reverse DNS and IP databases on a mobile line and a datacenter IP. - [Unlimited residential proxies: what they cost per GB](https://ipvolt.com/blog/unlimited-residential-proxies-cost-per-gb.md) (Comparison, Sep 27, 2026, 18 min read): Turn Mbps- and thread-based unlimited residential proxy plans into cost per GB, find the break-even with your per-GB rate, and check terms before you pay. - [Multiple Meta Ad Accounts: An Agency Setup Checklist](https://ipvolt.com/blog/manage-multiple-meta-ad-accounts.md) (Analysis, Sep 19, 2026, 6 min read): Manage multiple Meta ad accounts with a client access record, clear team responsibilities and a checklist for access errors, security incidents and routing. ## Related guides - [Configure a proxy in Playwright](https://ipvolt.com/guides/playwright-proxy-setup.md): Set an authenticated HTTP proxy for a Playwright browser context, keep test state isolated, and diagnose navigation separately from subresources. - [curl --compressed: which clients skip compression](https://ipvolt.com/guides/curl-compressed-accept-encoding.md): curl, Wget 1.x, urllib, node:http, PHP curl, Guzzle and java.net.http.HttpClient send no Accept-Encoding (or identity) by default. Tested fixes and byte checks. - [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md): Configure a proxy in Python Requests: the proxies dictionary, Session defaults, credentials, SOCKS5 via requests[socks], environment variables and ProxyError. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 120 of 138: socks5 vs socks5h: what six clients actually send to the proxy URL: https://ipvolt.com/blog/socks5-vs-socks5h Markdown: https://ipvolt.com/blog/socks5-vs-socks5h.md # socks5 vs socks5h: what six clients actually send to the proxy Source: https://ipvolt.com/blog/socks5-vs-socks5h Markdown: https://ipvolt.com/blog/socks5-vs-socks5h.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / SOCKS5 vs SOCKS5h: where DNS is resolved, client by client Category: Comparison Published: 2026-10-04 Updated: 2026-10-10 Author: ipvolt Reading time: 7 minutes Tags: proxies, troubleshooting In curl, socks5:// resolves DNS locally and socks5h:// sends the hostname to the proxy. HTTPX, aiohttp and Playwright differ. Tested results and config fixes. In curl, `socks5://` resolves the destination hostname on your machine and `socks5h://` hands the hostname to the proxy. Other clients do not follow that rule: in this test three of six sent the hostname with plain `socks5://`, and two of those refused `socks5h://` before connecting. | Client (version tested) | `socks5://` sends the proxy | `socks5h://` | | --- | --- | --- | | curl 8.22.0 | an IPv4 address (resolved locally) | the hostname | | Requests 2.34.2 + PySocks 1.7.1 | an IPv4 address (resolved locally) | the hostname | | HTTPX 0.28.1 + socksio 1.0.0 | the hostname | the hostname | | aiohttp 3.14.3 + aiohttp-socks 0.12.0 | the hostname | `ValueError`, no connection | | Playwright 1.63.0 (Chromium 153.0.8010.12) | the hostname | `net::ERR_NO_SUPPORTED_PROXIES`, no connection | | Node.js 24.20.0 + socks-proxy-agent 10.1.0 | an IPv4 address (resolved locally) | the hostname | | curl_cffi 0.16.3 (libcurl 8.21.0) | an IPv4 address (resolved locally) | the hostname | Each cell is what a logging SOCKS5 server on `127.0.0.1` received when the client was asked for `http://dnsprobe.example/`, a name that exists only in the local hosts file as `127.0.0.2`. "An IPv4 address" means the proxy saw `127.0.0.2` and never learned the name. "The hostname" means it received `dnsprobe.example` and would have to resolve it. Every client gave the same result for an `https://` target. Updated 10 October 2026: the curl_cffi row was added from a separate loopback lab, in which curl_cffi 0.16.3 with libcurl 8.21.0 was asked for `http://dnsprobe.example:8080/`. It is not one of the six clients counted in this post. [curl_cffi proxies](/guides/curl-cffi-proxy-setup) has the setup and that lab. ## Why the address type matters A SOCKS5 request carries one destination address, and its `ATYP` byte says which kind: `X'01'` for IPv4, `X'03'` for a domain name, `X'04'` for IPv6. [RFC 1928, section 4](https://www.rfc-editor.org/rfc/rfc1928#section-4) A client that sends a domain name leaves DNS to the proxy. A client that sends an IP address has already done the lookup itself. That has three consequences: 1. **Your own resolver sees the lookup.** The DNS query for the destination goes to the resolver configured on your machine, outside the proxy connection. The Requests documentation says it directly: `socks5` "causes the DNS resolution to happen on the client, rather than on the proxy server". [Requests: SOCKS](https://requests.readthedocs.io/en/latest/user/advanced/#socks) 2. **The answer can be for the wrong place.** RFC 7871 notes that many authoritative nameservers "return different responses based on the perceived topological location of the user", judged from the address the query arrives from, which is normally your resolver. [RFC 7871, section 1](https://www.rfc-editor.org/rfc/rfc7871#section-1) A CDN hostname resolved locally can therefore point at a server chosen for your network, and the proxy connects to exactly that address. The exit IP is in the region you asked for, but the server it reached was picked for yours, so the content can be the wrong region's. This follows from how the request is built; the loopback test did not measure any CDN. 3. **Names only the proxy can resolve fail.** With a name that does not resolve locally, curl 8.22.0 stopped at `curl: (6) Could not resolve host: dnsprobe-missing.example`, Requests raised a `ConnectionError` containing `[Errno -2] Name or service not known`, and socks-proxy-agent failed with `getaddrinfo ENOTFOUND dnsprobe-missing.example`. None of them sent the proxy a request. With `socks5h://`, all three sent the name to the proxy. The [HTTP vs SOCKS5 guide](/guides/http-vs-socks5-proxies) covers where DNS placement fits when you choose a proxy protocol. The rest of this post is about getting the scheme right per client. ## What to put in your config | Client | Sends the hostname to the proxy | Avoid | | --- | --- | --- | | curl | `socks5h://` or `--socks5-hostname` | `socks5://` and `--socks5` resolve locally | | Requests + PySocks | `socks5h://` | `socks5://` resolves locally | | HTTPX + socksio | `socks5://` or `socks5h://` | `socks://` raises `ValueError` | | aiohttp + aiohttp-socks | `socks5://` | `socks5h://` raises `ValueError` | | Playwright Chromium | `socks5://` | `socks5h://` fails at navigation | | Node socks-proxy-agent | `socks5h://` or `socks://` | `socks5://` resolves locally | No single URL is right for all six. If one `PROXY_URL` setting feeds several tools, `socks5h://` breaks aiohttp-socks and Playwright, and `socks5://` makes curl, Requests and socks-proxy-agent resolve locally. Set the scheme per client. The two clients that reject `socks5h://` fail at different moments. aiohttp-socks raises from `ProxyConnector.from_url()`, before any socket is opened: ```text ValueError: Invalid scheme component: socks5h ``` Playwright accepts the proxy in `chromium.launch()` and fails on the first navigation, without contacting the proxy: ```text page.goto: net::ERR_NO_SUPPORTED_PROXIES at http://dnsprobe.example/ ``` Playwright's documentation gives `socks5://myproxy.com:3128` as the SOCKS form of the `server` option. [Playwright: proxy option](https://playwright.dev/docs/api/class-browsertype#browser-type-launch-option-proxy) The [Playwright proxy guide](/guides/playwright-proxy-setup) has the rest of the launch and context settings. The bare `socks://` scheme is just as inconsistent. Chromium and socks-proxy-agent treated it as SOCKS5 and sent the hostname. curl opened with a SOCKS4 greeting (first byte `0x04`), which a SOCKS5-only server cannot answer. Requests raised `ValueError: Unable to determine SOCKS version from socks://127.0.0.1:11080`, HTTPX raised `ValueError: Unknown scheme for proxy URL URL('socks://127.0.0.1:11080')` and aiohttp-socks raised `ValueError: Invalid scheme component: socks`. Two setup details from the Python side: Requests needs the `requests[socks]` extra and HTTPX needs `httpx[socks]`. Without them Requests raises `Missing dependencies for SOCKS support` and HTTPX raises an `ImportError` naming socksio; [the fix for both](/guides/fix-missing-dependencies-for-socks-support) also covers the case where the proxy URL comes from `ALL_PROXY`. The [Python Requests proxy guide](/guides/python-requests-proxy) and the [HTTPX async proxy guide](/guides/httpx-async-proxy) show complete client code. This test passed the proxy URL to each client explicitly. If yours comes from `ALL_PROXY` or `HTTPS_PROXY`, first confirm which variable the client reads; the [proxy environment variables guide](/guides/proxy-environment-variables) lists that per client, and [NO_PROXY matching, tested](/blog/no-proxy-matching-tested) shows that bypass rules differ between clients as well. ## How to check your own setup You do not need a proxy account to see what your client sends. Download [socks5_log.py](/downloads/socks5-vs-socks5h/socks5_log.py), a 42-line Python script with no dependencies. It completes the SOCKS5 greeting, prints the address type and address of each request, then answers "general SOCKS server failure", so nothing is forwarded. Give your machine a test name that only the hosts file knows. Do not use `localhost`: Chromium sends requests for localhost names directly instead of through the proxy. [Chromium: implicit bypass rules](https://chromium.googlesource.com/chromium/src/+/HEAD/net/docs/proxy.md#Implicit-bypass-rules) Add this line to `/etc/hosts`: ```text 127.0.0.2 dnsprobe.example ``` Start the server in one terminal and send one request per scheme from another: ```sh python3 socks5_log.py 1080 curl -x socks5://127.0.0.1:1080 http://dnsprobe.example/ curl -x socks5h://127.0.0.1:1080 http://dnsprobe.example/ ``` With curl 8.18.0 the server printed: ```text LISTENING 127.0.0.1:1080 CMD=1 IPv4 127.0.0.2 port=80 CMD=1 DOMAIN dnsprobe.example port=80 ``` The first request arrived as an IP address, so curl resolved the name locally. The second arrived as a name. Both curl commands end with `curl: (97) cannot complete SOCKS5 connection to dnsprobe.example. (1)`, which is the server's refusal and is expected. Replace curl with your own client and proxy setting, and read the same two fields. If no line appears at all, the client rejected the scheme or bypassed the proxy. ## Remote DNS options besides the scheme Some clients expose the same choice as an option, usually named `rdns`: - **curl**: `--socks5-hostname host:port` behaved like `socks5h://` and `--socks5 host:port` like `socks5://` in the test. [curl man page](https://curl.se/docs/manpage.html#-x) - **Requests**: there is no separate option. urllib3's SOCKS manager sets PySocks' `rdns` flag from the scheme: `False` for `socks5`, `True` for `socks5h`. [urllib3 source](https://github.com/urllib3/urllib3/blob/2.8.0/src/urllib3/contrib/socks.py) PySocks itself, used directly, takes `rdns` in `set_proxy()` and documents its default as `True`. [PySocks README](https://github.com/Anorov/PySocks) - **aiohttp-socks**: `ProxyConnector` takes `rdns`, and its README notes "default is True for socks5". [aiohttp-socks README](https://github.com/romis2012/aiohttp-socks/blob/v0.12.0/README.md) In the test, `ProxyConnector.from_url("socks5://127.0.0.1:11080", rdns=False)` sent `127.0.0.2` and `rdns=True` sent the hostname. - **HTTPX**: version 0.28.1 routes `socks5` and `socks5h` to the same SOCKS transport, so the scheme changes nothing. [HTTPX source](https://github.com/encode/httpx/blob/0.28.1/httpx/_transports/default.py) - **socks-proxy-agent**: the scheme alone sets its `lookup` flag: `socks5` and `socks4` resolve locally, `socks5h`, `socks4a` and `socks` do not. [socks-proxy-agent source](https://github.com/TooTallNate/proxy-agents/blob/main/packages/socks-proxy-agent/src/index.ts) - **Chromium**: no option. Its documentation says that for SOCKSv5 "name resolution is always done proxy side". [Chromium network docs](https://chromium.googlesource.com/chromium/src/+/HEAD/net/docs/proxy.md#SOCKSv5-proxy-scheme) ## Method and limits Recorded on 4 October 2026 on Ubuntu 26.04 (x86_64) with Python 3.14.4 and Node.js 24.20.0. The versions are the ones in the first table, plus urllib3 2.8.0, httpcore 1.0.9, python-socks 3.1.1 and the `socks` package 2.8.10. curl 8.18.0 was run next to 8.22.0 and sent the same addresses. A name that resolves only to IPv6 arrived as an `IPv6` address from curl, Requests and socks-proxy-agent, and as a hostname from the other three. The lab is one loopback server that refuses every request. It says nothing about any proxy service, about SOCKS5 with authentication or UDP, or about macOS, Windows, Firefox or WebKit. Library defaults change, so check the versions you run. The [lab archive](/downloads/socks5-vs-socks5h/socks5-vs-socks5h-lab.zip) contains the server, the six client scripts, the runner and a [README](/downloads/socks5-vs-socks5h/README.md); the raw output of all 62 cases is in [results.json](/downloads/socks5-vs-socks5h/results.json). ## Related - [HTTP vs SOCKS5 proxies](/guides/http-vs-socks5-proxies), for choosing the protocol and deciding where DNS runs. - [Proxy environment variables](/guides/proxy-environment-variables), for which variable each client reads. - [NO_PROXY matching, tested](/blog/no-proxy-matching-tested), the same kind of test for bypass rules. - [Playwright proxy setup](/guides/playwright-proxy-setup), [HTTPX async proxy](/guides/httpx-async-proxy) and [Python Requests proxy](/guides/python-requests-proxy), for full client configuration. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources - [curl man page: --proxy (socks5:// and socks5h://)](https://curl.se/docs/manpage.html#-x) - [RFC 1928: SOCKS Protocol Version 5, section 4 (address types)](https://www.rfc-editor.org/rfc/rfc1928#section-4) - [Requests: SOCKS proxies](https://requests.readthedocs.io/en/latest/user/advanced/#socks) - [urllib3 2.8.0 source: contrib/socks.py (scheme to rdns)](https://github.com/urllib3/urllib3/blob/2.8.0/src/urllib3/contrib/socks.py) - [PySocks README: set_proxy and rdns](https://github.com/Anorov/PySocks) - [HTTPX: SOCKS proxies](https://www.python-httpx.org/advanced/proxies/#socks) - [HTTPX 0.28.1 source: proxy schemes in _transports/default.py](https://github.com/encode/httpx/blob/0.28.1/httpx/_transports/default.py) - [aiohttp-socks 0.12.0 README: ProxyConnector and rdns](https://github.com/romis2012/aiohttp-socks/blob/v0.12.0/README.md) - [python-socks 3.1.1 source: parse_proxy_url schemes](https://github.com/romis2012/python-socks/blob/v3.1.1/python_socks/_helpers.py) - [socks-proxy-agent source: parseSocksURL](https://github.com/TooTallNate/proxy-agents/blob/main/packages/socks-proxy-agent/src/index.ts) - [Chromium network docs: SOCKSv5 proxy scheme and implicit bypass rules](https://chromium.googlesource.com/chromium/src/+/HEAD/net/docs/proxy.md#SOCKSv5-proxy-scheme) - [Playwright: browserType.launch proxy option](https://playwright.dev/docs/api/class-browsertype#browser-type-launch-option-proxy) - [RFC 7871: Client Subnet in DNS Queries, section 1](https://www.rfc-editor.org/rfc/rfc7871#section-1) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [Check a Proxy for IP, DNS and WebRTC Leaks with ToDetect](https://ipvolt.com/blog/proxy-leak-check-todetect.md) (Analysis, Oct 23, 2026, 9 min read): Check a browser proxy for IP, DNS, WebRTC and time zone leaks with ToDetect's free tools, using measured results from a 4G mobile line as the worked example. - [Python 3.15 for Web Scraping: What Installs, What Breaks](https://ipvolt.com/blog/python-3-15-web-scraping.md) (Analysis, Oct 16, 2026, 8 min read): pip install scrapy fails on Python 3.15 without a C compiler: brotli has no cp315 wheel. We tested 19 scraping packages with pip and uv to see what else breaks. - [Japanese price parsing: yen, width and tax labels](https://ipvolt.com/blog/japanese-price-parsing.md) (Analysis, Oct 6, 2026, 6 min read): Parse Japanese price fields without losing currency or tax basis. Run a tested Python fixture for fullwidth yen, mixed prices and deliberate review cases. ## Related guides - [HTTP vs SOCKS5 proxies: choose by the connection](https://ipvolt.com/guides/http-vs-socks5-proxies.md): Compare HTTP CONNECT and SOCKS5, understand DNS placement and TLS boundaries, and select a protocol your actual client and provider support. - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md): Diagnose HTTP_PROXY, HTTPS_PROXY, ALL_PROXY and NO_PROXY routing differences in curl, Python Requests and Node.js with an isolated local check. - [Configure a proxy in Playwright](https://ipvolt.com/guides/playwright-proxy-setup.md): Set an authenticated HTTP proxy for a Playwright browser context, keep test state isolated, and diagnose navigation separately from subresources. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 121 of 138: Why Your Coding Agent Gets "CONNECT tunnel failed, response 403" URL: https://ipvolt.com/blog/connect-tunnel-failed-403 Markdown: https://ipvolt.com/blog/connect-tunnel-failed-403.md # Why Your Coding Agent Gets "CONNECT tunnel failed, response 403" Source: https://ipvolt.com/blog/connect-tunnel-failed-403 Markdown: https://ipvolt.com/blog/connect-tunnel-failed-403.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / CONNECT tunnel failed, response 403: Why AI Agents Hit It Category: Analysis Published: 2026-10-02 Updated: 2026-10-02 Author: ipvolt Reading time: 8 minutes Tags: proxies, troubleshooting Your agent's curl fails with CONNECT tunnel failed, response 403 while other hosts work. The proxy refused the tunnel. How to tell who blocked it, and the fix. ```text curl: (56) CONNECT tunnel failed, response 403 ``` That is curl 8.15 to 8.17 asking a proxy to open a tunnel to an `https://` host and being refused. curl 8.18.0 and 8.22.0 print the same message with exit code 7 instead of 56. The same refusal, recorded through one local test proxy, looks like this in Python Requests 2.34.2, which raises `requests.exceptions.ProxyError` with this message: ```text HTTPSConnectionPool(host='example.org', port=443): Max retries exceeded with url: / (Caused by ProxyError('Unable to connect to proxy', OSError('Tunnel connection failed: 403 Forbidden'))) ``` And in Node.js 24.20.0's built-in `fetch` with `NODE_USE_ENV_PROXY=1`, printed one `err.cause` level per line: ```text depth 0: TypeError: fetch failed depth 1: DOMException: Request was cancelled. depth 2: RequestAbortedError [UND_ERR_ABORTED]: Proxy response (403) !== 200 when HTTP Tunneling ``` In all three, the proxy said no before your request left it. Through the same proxy, `https://example.com/` returned 200 in every client. Only the host changed. From Python, curl_cffi 0.16 and later raise `ConnectionError`, not `ProxyError`, when a proxy rejects `CONNECT`; [curl_cffi proxies](/guides/curl-cffi-proxy-setup) shows how to catch it. ## What the 403 means For an `https://` URL the client sends `CONNECT example.org:443` to the proxy and waits for permission to open a tunnel. RFC 9110 says any 2xx reply switches the connection to tunnel mode, and "any response other than a successful response indicates that the tunnel has not yet been formed." A 403 is the proxy refusing that tunnel. [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-connect) Two things follow: - **It is not a credentials problem.** A proxy that wants credentials answers 407 with a `Proxy-Authenticate` challenge; the [407 guide](/guides/fix-proxy-error-407) covers that case. A 403 means the proxy decided not to forward this request, so changing the password will not help. - **The target site was never reached.** No tunnel means no TLS handshake and no request to `example.org`. curl's write-out shows it: `connect=403` is the proxy's answer and `http=000` means the site never sent one. ## Why coding agents hit it Sandboxes and CI runners often send all outbound traffic through an egress proxy with an allowlist. The proxy address arrives in `HTTPS_PROXY`, so curl, pip, npm and `fetch` all go through it. Hosts on the list get a tunnel; everything else gets a 403. That is why one host works and the next one fails from the same shell. Two public reports show this pattern: - In [anthropics/claude-code#56959](https://github.com/anthropics/claude-code/issues/56959), Claude Code running with Bedrock had `HTTPS_PROXY` pointing at the sandbox's own proxy on localhost. That proxy allowed four hosts (`bedrock-runtime.us-east-1.amazonaws.com`, `api.anthropic.com` and two Sentry patterns) and, in the reporter's words, "any other host returns HTTP 403 from the local proxy". `curl https://github.com` failed with `curl: (56) CONNECT tunnel failed, response 403`. The reporter said `sandbox.network.allowedDomains` entries in user and managed settings were ignored in that mode. The issue was closed as a duplicate of #37970. - In [SocketDev/socket-sdk-js#659](https://github.com/SocketDev/socket-sdk-js/issues/659), an agent running a weekly dependency update in CI could not finish. The update tool, taze, looked up versions at `npm.antfu.dev`, which "the CI sandbox firewall blocks (403 CONNECT tunnel failed)". curl to that host returned HTTP 000 with curl error 56, while `curl https://registry.npmjs.org/semver` returned 200. The maintainers fixed it by keeping lookups on `registry.npmjs.org`, which was already allowlisted. ## How to tell who said no Run the failing URL once with `curl -v` through the same proxy. Lines starting with `>` are what curl sent; lines starting with `<` before `CONNECT tunnel failed` are the proxy's reply. This is curl 8.16.0 against the test proxy: ```text * Trying 127.0.0.1:41745... * CONNECT: no ALPN negotiated * allocate connect buffer * Establish HTTP proxy tunnel to example.org:443 > CONNECT example.org:443 HTTP/1.1 > Host: example.org:443 > User-Agent: curl/8.16.0 > Proxy-Connection: Keep-Alive > < HTTP/1.1 403 Forbidden < Content-Type: text/plain < Content-Length: 32 < Connection: close < * CONNECT tunnel failed, response 403 * closing connection #0 curl: (56) CONNECT tunnel failed, response 403 ``` The `Trying` line names the proxy, not the site. The 403 arrives in answer to `CONNECT`, and there are no TLS lines after it, so the site never took part. If a 403 instead appears after a successful `CONNECT` and a TLS handshake, it came from the website, and the proxy is not the problem. If `CONNECT` returns 200 and the connection then closes with no HTTP status, that is a different failure: [SSL EOF occurred in violation of protocol behind a proxy](/guides/fix-ssl-unexpected-eof-proxy). Then compare an allowed host and a blocked host through the same proxy, using the write-out to separate the two status codes: ```sh curl --disable -sS -o /dev/null -x http://127.0.0.1:41745 -w 'http=%{http_code} connect=%{http_connect} exit=%{exitcode}\n' https://example.com/ curl --disable -sS -o /dev/null -x http://127.0.0.1:41745 -w 'http=%{http_code} connect=%{http_connect} exit=%{exitcode}\n' https://example.org/ ``` With curl 8.18.0 the first printed `http=200 connect=200 exit=0`. The second printed `http=000 connect=403 exit=7` plus `curl: (7) CONNECT tunnel failed, response 403`. Same client, same proxy, different host: the proxy has a per-host rule. Repeat the comparison with your own allowed and blocked hosts. In an agent sandbox, use a host you know works, such as the package registry the agent already reached. Finally, check which proxy the process actually uses. Print `HTTPS_PROXY`, `HTTP_PROXY`, `NO_PROXY` and their lowercase forms in the same shell or job step that fails. A host listed in `NO_PROXY` skips the proxy and connects directly, which a sandbox may block in a different way. The [proxy environment variables guide](/guides/proxy-environment-variables) explains how clients choose between these variables, and [NO_PROXY matching, tested](/blog/no-proxy-matching-tested) shows that clients do not agree on what a `NO_PROXY` entry matches. Node's built-in `fetch` ignores these variables unless `NODE_USE_ENV_PROXY=1` or `--use-env-proxy` is set, so a Node script and a curl command in the same shell can take different routes. [Node.js CLI documentation](https://nodejs.org/api/cli.html#node_use_env_proxy1) ## Fix it without going around the proxy The 403 is a policy decision, so the fix is on the policy side or the source side: - **Allow the host.** Add the exact domain the tool needs to the sandbox or CI egress allowlist. Find the domain in the `CONNECT` line of `curl -v` or the tool's own error, not in its configuration: in the Socket report, taze looked up versions at `npm.antfu.dev`, not at the npm registry. - **Use a source that is already allowed.** A mirror, an internal registry or the official registry the policy already permits often removes the need for a policy change. That was the Socket fix. - **Check the port.** Some proxies only tunnel port 443. Squid's suggested configuration includes `http_access deny CONNECT !SSL_ports` with `SSL_ports` set to port 443. [Squid http_access](http://www.squid-cache.org/Doc/config/http_access/) In the test proxy, which allowed `example.com` on port 443 only, `https://example.com:8443/` got the same `CONNECT tunnel failed, response 403` as the blocked host. - **Check the provider's destination rules.** Commercial proxy providers can also refuse destinations. Bright Data's error catalog lists policy errors under HTTP 403, for example "You tried to target %HOST% which is blocked by Bright Data policy". [Bright Data error catalog](https://docs.brightdata.com/proxy-networks/errorCatalog) Decodo lists categories of targets, such as banking and government sites, that it restricts by default. [Decodo restricted targets](https://help.decodo.com/docs/residential-proxy-restricted-targets) Do not bypass a sandbox's egress rules. Unsetting `HTTPS_PROXY`, adding the host to `NO_PROXY` or routing through a different proxy to get around an allowlist defeats the control someone put there on purpose, and it may simply fail: the reporter of #56959 found that the sandbox blocked direct network access underneath the proxy as well. Ask whoever manages the sandbox or CI runner to allow the host, and give them the exact `CONNECT` line from `curl -v`. The agent in the Socket report did exactly that: it stopped, reported the blocked host and did not try to evade the firewall. ## Why curl reports http:// differently For an `http://` URL there is no `CONNECT`. curl sends the whole request to the proxy, and the proxy's 403 is the response to that request. The test proxy answered both forms with 403, but curl reported them differently: | Through the same proxy | curl 8.15.0 to 8.17.0 | curl 8.18.0 and 8.22.0 | | --- | --- | --- | | `https://example.org/` (blocked) | exit 56, `curl: (56) CONNECT tunnel failed, response 403` | exit 7, `curl: (7) CONNECT tunnel failed, response 403` | | `http://example.org/` (blocked) | exit 0, the proxy's 403 page printed as the body | exit 0, the proxy's 403 page printed as the body | | `http://example.org/` with `--fail` | exit 22, `curl: (22) The requested URL returned error: 403` | exit 22, `curl: (22) The requested URL returned error: 403` | | `https://example.com/` (allowed) | exit 0, `http=200 connect=200` | exit 0, `http=200 connect=200` | For the `http://` case, `curl -v` shows `> GET http://example.org/ HTTP/1.1` followed by `< HTTP/1.1 403 Forbidden`, and curl prints the body. curl maintainer Daniel Stenberg described the difference in [curl discussion #15718](https://github.com/curl/curl/discussions/15718), which is about a 407 but applies to any refusal: failing to set up the tunnel means the transfer is not performed, which is a failure, while a GET to a proxy that returns a response "is a *successful* transfer containing a 4xx code." So an `http://` URL in a script without `--fail` can look like success. The other clients split the same way, with one exception. Python Requests returned a normal `Response` with status 403 for `http://example.org/`. Node.js 24.20.0's `fetch` with `NODE_USE_ENV_PROXY=1` opened a `CONNECT example.org:80` tunnel even for the `http://` URL, so it failed with the same `Proxy response (403) !== 200 when HTTP Tunneling` cause. One more version detail: the curl 8.22.0 static build we used includes HTTP/3. When the host advertised HTTP/3, it first tried a `CONNECT-UDP` tunnel, so `-v` showed two 403 replies before the final `curl: (7) CONNECT tunnel failed, response 403`. ## Reproduce it Everything above was recorded on 2 October 2026 with the lab in the [download folder](/downloads/connect-tunnel-failed-403/README.md): a Node.js proxy on `127.0.0.1` that tunnels only to `example.com` on port 443 and answers 403 to every other `CONNECT` and plain-HTTP request, with curl 8.15.0, 8.16.0, 8.17.0, 8.18.0 and 8.22.0, Python 3.14.4 with Requests 2.34.2 and urllib3 2.8.0, and Node.js 24.20.0. The raw output is in [results.json](/downloads/connect-tunnel-failed-403/results.json). The test proxy's 403 body (`403 Forbidden: lab proxy policy`) is its own; a real sandbox or provider proxy will send different text. ## Related - [Fix proxy error 407](/guides/fix-proxy-error-407), when the proxy asks for credentials instead. - [Tunnel connection failed: 502](/guides/fix-proxy-tunnel-502-503), when the proxy answers CONNECT with 502, 503 or 504 instead. - [Fix ERR_TUNNEL_CONNECTION_FAILED](/guides/fix-err-tunnel-connection-failed), for the same refusal inside Chromium, Playwright and Puppeteer. - [Proxy environment variables](/guides/proxy-environment-variables), for which variable a client actually reads. - [NO_PROXY matching, tested](/blog/no-proxy-matching-tested), for why a bypass entry matches in one client and not another. - [AI agent proxies and compute](/blog/ai-agent-proxies-and-compute), for deciding which parts of an agent need a proxy at all. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources - [RFC 9110: CONNECT](https://www.rfc-editor.org/rfc/rfc9110.html#name-connect) - [anthropics/claude-code#56959: sandbox allowlist answering 403 to CONNECT](https://github.com/anthropics/claude-code/issues/56959) - [SocketDev/socket-sdk-js#659: CI sandbox firewall blocking one host](https://github.com/SocketDev/socket-sdk-js/issues/659) - [curl discussion #15718: proxy responses for http and https URLs](https://github.com/curl/curl/discussions/15718) - [Squid configuration: http_access suggested rules](http://www.squid-cache.org/Doc/config/http_access/) - [Bright Data: proxy error catalog](https://docs.brightdata.com/proxy-networks/errorCatalog) - [Decodo: residential proxy restricted targets](https://help.decodo.com/docs/residential-proxy-restricted-targets) - [Node.js CLI: NODE_USE_ENV_PROXY](https://nodejs.org/api/cli.html#node_use_env_proxy1) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [Check a Proxy for IP, DNS and WebRTC Leaks with ToDetect](https://ipvolt.com/blog/proxy-leak-check-todetect.md) (Analysis, Oct 23, 2026, 9 min read): Check a browser proxy for IP, DNS, WebRTC and time zone leaks with ToDetect's free tools, using measured results from a 4G mobile line as the worked example. - [Python 3.15 for Web Scraping: What Installs, What Breaks](https://ipvolt.com/blog/python-3-15-web-scraping.md) (Analysis, Oct 16, 2026, 8 min read): pip install scrapy fails on Python 3.15 without a C compiler: brotli has no cp315 wheel. We tested 19 scraping packages with pip and uv to see what else breaks. - [Japanese price parsing: yen, width and tax labels](https://ipvolt.com/blog/japanese-price-parsing.md) (Analysis, Oct 6, 2026, 6 min read): Parse Japanese price fields without losing currency or tax basis. Run a tested Python fixture for fullwidth yen, mixed prices and deliberate review cases. ## Related guides - [Fix proxy error 407 without guessing](https://ipvolt.com/guides/fix-proxy-error-407.md): Diagnose Proxy Authentication Required in a repeatable order: gateway, authentication method, credential encoding, account scope and client configuration. - [Fix ERR_TUNNEL_CONNECTION_FAILED in Playwright and Puppeteer](https://ipvolt.com/guides/fix-err-tunnel-connection-failed.md): ERR_TUNNEL_CONNECTION_FAILED and ERR_PROXY_CONNECTION_FAILED explained with a verified failure matrix, plus how to recover the CONNECT status Chromium hides. - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md): Diagnose HTTP_PROXY, HTTPS_PROXY, ALL_PROXY and NO_PROXY routing differences in curl, Python Requests and Node.js with an isolated local check. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 122 of 138: The Odds API vs scraping: update intervals, quota and cost URL: https://ipvolt.com/blog/betting-odds-api-vs-scraping Markdown: https://ipvolt.com/blog/betting-odds-api-vs-scraping.md # The Odds API vs scraping: update intervals, quota and cost Source: https://ipvolt.com/blog/betting-odds-api-vs-scraping Markdown: https://ipvolt.com/blog/betting-odds-api-vs-scraping.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / The Odds API vs scraping: update intervals, quota and cost Category: Comparison Published: 2026-09-28 Updated: 2026-09-28 Author: ipvolt Reading time: 7 minutes Tags: proxies, troubleshooting The Odds API updates featured markets every 60 s before matches and 40 s in play. Compare its quota with authorized scraping in an editable cost worksheet. Start by evaluating an odds API against your required bookmakers, markets, history and source-age budget. If it meets those requirements at an acceptable total cost, it is a reasonable first candidate for a source trial. Evaluate an authorized scraper when you can name the gap it would fill and account for its collection and maintenance work. The decision needs more than an API subscription price beside a proxy bandwidth price. This article provides an editable worksheet for developers building odds archives, displays or data-quality monitoring. It separates source suitability from workload and cost, so a cheap source with missing data cannot win merely by having a smaller bill. ## Reject unsuitable sources before comparing prices Write down one target dataset and use it for every candidate. “Football odds” is too broad: identify the competitions, bookmakers, market and line types, pre-match or in-play state, operating window and intended use. Two collection methods are only comparable if they cover that same requirement. The worksheet uses four source gates. Each accepts `yes`, `no` or `unknown`, alongside a note describing the requirement and supporting evidence. | Gate | Evidence to obtain before entering yes | | --- | --- | | Coverage | The required bookmaker, event and market combinations, including fields and known omissions | | Allowed use | Source-specific permission for the proposed collection, storage and display or other downstream use | | Freshness | Timestamp meaning and evidence that source age fits your decision deadline | | History | The required date range, snapshot resolution and fields, or an explicit decision that backfill is unnecessary | A `no` or `unknown` keeps the candidate on hold even if its modeled cost is known. Entering `yes` records your assessment; the calculator cannot verify a provider, permission or timestamp. Keep the document, sample or agreement supporting each note with your project. Historical coverage deserves an early check. The Odds API documents featured-market snapshots from June 6, 2020, initially ten minutes apart and five minutes apart from September 2022. It says a historical request selects the available snapshot at or before the requested time, and each sport, bookmaker and market has its own coverage start. An advertised earliest date therefore does not establish coverage for your exact dataset. These are the provider's published terms, checked September 27, 2026. [Historical data documentation](https://the-odds-api.com/historical-odds-data/) If you need past observations, establish that a source actually retains them. Beginning to poll current pages today cannot reconstruct every unobserved past price change. ## Keep polling frequency separate from freshness A ten-second polling schedule describes your collector. It does not establish that the underlying prices update every ten seconds. For example, The Odds API lists featured-market update intervals of 60 seconds before matches and 40 seconds in play; its exchange category has different intervals. Those are published update intervals, not our measurements or a guarantee of end-to-end freshness. Polling faster can retrieve unchanged source state. [Provider update intervals](https://the-odds-api.com/sports-odds-data/update-intervals.html) For the source trial, retain the source timestamp and its documented meaning, your receipt time, and missing or suspended observations. Define the oldest acceptable observation before examining the results. If the source exposes no timestamp with the meaning your requirement needs, leave freshness unknown rather than substituting your HTTP response time. This article chooses how to acquire data. After acquisition, use the separate [bookmaker odds-feed validation guide](https://ipvolt.com/blog/bookmaker-odds-feed-validation) to check whether two observations describe comparable markets and usable states. ## Model the workload in each source's billing units Save the [offline calculator](https://ipvolt.com/downloads/odds-acquisition/odds_acquisition.py) and [worked example](https://ipvolt.com/downloads/odds-acquisition/example.json) in one directory, then run: ```sh python3 odds_acquisition.py example.json ``` It needs Python 3.10 or newer, uses no external packages and makes no network requests. For your own assessment, use the [blank worksheet](https://ipvolt.com/downloads/odds-acquisition/blank.json) and [field guide](https://ipvolt.com/downloads/odds-acquisition/README.md): ```sh python3 odds_acquisition.py blank.json ``` Replace unknowns with evidence or quotes; do not change missing costs to zero. The output separates request attempts, API credits, billed bandwidth, cost components, quota status and the source-trial decision. A numeric total is a calculation under your inputs, not a purchase recommendation. For an API, obtain the endpoint-specific credit formula. The Odds API v4 documents current sport-odds quota as specified markets multiplied by regions, while event-odds quota uses unique returned markets multiplied by regions. Their historical counterparts apply a tenfold multiplier. Named bookmakers override regions and are counted in groups of ten; empty responses do not consume credits. These provider-specific rules show why counting HTTP calls alone is insufficient. Use the documented usage headers to check your actual endpoint's accounting during a trial. [V4 usage-quota documentation](https://the-odds-api.com/liveapi/guides/v4/) The calculator takes your derived `credits_per_attempt`; it does not implement that provider's endpoint rules. The worked example assigns a fictional three credits to every attempt, including retries. Replace that assumption when real responses have different charges. For a collector, enter requests per poll and billed bytes per attempt. Count browser subresources or extra endpoints if your implementation requires them. Keep observed wire bytes separate from the provider's billing measure. The worksheet prices decimal GB, with one GB equal to one billion bytes, and also reports GiB so the unit difference is visible. ## A worked monthly comparison Everything in this example is hypothetical: coverage, permissions, freshness, prices and maintenance time. It is not a vendor quote, benchmark or ipvolt service trial. The target is the same 20-event dataset with specified bookmakers and full-time totals, collected for eight hours on each of 30 days. Both candidates are assumed to meet a 120-second source-age budget, with no historical backfill needed. All four suitability gates are assumed yes solely to demonstrate the arithmetic. At a 60-second interval, that is 480 polls per active day and 14,400 polls in the modeled month. The fictional API batches the dataset into two requests per poll; the collector uses 20. Both add planned retries equal to 5% of scheduled requests. This is a workload allowance, not a measured failure rate. | Monthly input or result | Fictional API | Fictional collector | | --- | --- | --- | | Scheduled requests | 28,800 | 288,000 | | Attempts including planned retries | 30,240 | 302,400 | | Usage | 90,720 credits | 60.48 billed GB at 200,000 bytes per attempt | | Fixed charge | $100, including 100,000 credits | $40 for infrastructure and storage | | Additional usage charge | $0 within that quota | $120.96 at $2 per GB | | Maintenance | 2 hours at $50: $100 | 8 hours at $50: $400 | | Modeled total | **$200** | **$560.96** | The API is the cheaper trial candidate under these assumptions. That result depends on batching, quota, billed bytes and the time estimates. It does not establish that APIs are generally cheaper. One-time implementation, taxes and any costs absent from the inputs are outside these totals; add relevant recurring items to the fixed cost and assess initial engineering separately. The output label `eligible_for_source_trial` means the supplied gates, workload, cost fields and aggregate quota checks allow further evaluation. It does not mean the source has passed an actual trial. The worksheet also does not simulate request bursts, concurrency limits or stream recovery. ## Change the assumptions before trusting the result The supplied file runs two additional scenarios. They show where a seemingly affordable plan stops being a valid comparison. | Hypothetical scenario | API outcome | Collector outcome | | --- | --- | --- | | Poll every 10 seconds; keep 200,000 billed bytes per collector attempt | 544,320 credits exceed the 100,000-credit quote; hold, total unavailable | 362.88 GB; $1,165.76 | | Keep 60-second polling; increase collector billing to 1,000,000 bytes per attempt | Unchanged: 90,720 credits; $200 | 302.4 GB; $1,044.80 | In the faster scenario, the calculator returns `modeled_total: null` for the API. It does not invent an overage price or pretend the original subscription still covers the workload. Obtain a quote for that volume before choosing between candidates. The second scenario changes billed bytes, leaving the example's wire-byte input unchanged. This deliberately tests a different billing assumption; it is not a measurement of page size or compression. Replace both fields with the appropriate evidence for your collector. Changing the polling interval also leaves the example's fictional freshness gate unchanged. In a real assessment, revisit that gate: six times as many requests do not prove six times fresher data. The cost calculation cannot resolve whether a source meets the deadline. ## Use the worksheet to choose a bounded trial Start with the lowest-cost candidate whose requirements and quote are supported. If the API misses a required market, record that specific gap and assess another feed or an authorized collector against it. If permission, historical coverage or freshness remains unknown, resolve that dependency before treating the candidate as suitable. During the trial, record expected event-market observations, observations received, usable observations and reasons for exclusions. Retain actual quota consumption, billed transfer and maintenance time. Those records let you replace the fictional workload inputs without treating successful HTTP responses as proof of useful odds data. Re-run the worksheet when coverage, operating hours or the quote changes. An API-only choice may need no proxy. For an authorized collector that does need a proxy, include that transport cost in the model and investigate setup problems with the [proxy environment variables guide](https://ipvolt.com/guides/proxy-environment-variables) or [timeout troubleshooting](https://ipvolt.com/guides/proxy-timeout-troubleshooting). Changing the route cannot supply missing historical observations or establish source permissions. Method: this article is an AI-assisted synthesis of primary provider documentation and an executed synthetic worksheet. The [calculator tests](https://ipvolt.com/downloads/odds-acquisition/test_odds_acquisition.py) are available with the inputs and field guide. No live bookmaker collection, authenticated odds API trial or provider performance measurement was performed. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources - [The Odds API v4 documentation](https://the-odds-api.com/liveapi/guides/v4/) - [The Odds API update intervals](https://the-odds-api.com/sports-odds-data/update-intervals.html) - [The Odds API historical data](https://the-odds-api.com/historical-odds-data/) - [ipvolt homepage and prices](https://ipvolt.com/) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [Check a Proxy for IP, DNS and WebRTC Leaks with ToDetect](https://ipvolt.com/blog/proxy-leak-check-todetect.md) (Analysis, Oct 23, 2026, 9 min read): Check a browser proxy for IP, DNS, WebRTC and time zone leaks with ToDetect's free tools, using measured results from a 4G mobile line as the worked example. - [Python 3.15 for Web Scraping: What Installs, What Breaks](https://ipvolt.com/blog/python-3-15-web-scraping.md) (Analysis, Oct 16, 2026, 8 min read): pip install scrapy fails on Python 3.15 without a C compiler: brotli has no cp315 wheel. We tested 19 scraping packages with pip and uv to see what else breaks. - [Japanese price parsing: yen, width and tax labels](https://ipvolt.com/blog/japanese-price-parsing.md) (Analysis, Oct 6, 2026, 6 min read): Parse Japanese price fields without losing currency or tax basis. Run a tested Python fixture for fullwidth yen, mixed prices and deliberate review cases. ## Related guides - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md): Diagnose HTTP_PROXY, HTTPS_PROXY, ALL_PROXY and NO_PROXY routing differences in curl, Python Requests and Node.js with an isolated local check. - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md): Separate proxy DNS, TCP, CONNECT, TLS and response delays with curl timings, then set request deadlines and decide whether a retry is safe. - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md): How to use a proxy with curl: the -x flag, http_proxy and https_proxy variables, SOCKS5 with socks5h, proxy authentication, and reading CONNECT and 407 errors. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 123 of 138: Unlimited residential proxies: what they cost per GB URL: https://ipvolt.com/blog/unlimited-residential-proxies-cost-per-gb Markdown: https://ipvolt.com/blog/unlimited-residential-proxies-cost-per-gb.md # Unlimited residential proxies: what they cost per GB Source: https://ipvolt.com/blog/unlimited-residential-proxies-cost-per-gb Markdown: https://ipvolt.com/blog/unlimited-residential-proxies-cost-per-gb.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / Unlimited residential proxies: what they cost per GB Category: Comparison Published: 2026-09-27 Updated: 2026-09-27 Author: ipvolt Reading time: 18 minutes Tags: proxies, choosing Turn Mbps- and thread-based unlimited residential proxy plans into cost per GB, find the break-even with your per-GB rate, and check terms before you pay. An "unlimited" residential proxy plan does not sell unlimited gigabytes. It sells a speed channel in Mbps, a number of threads or a number of ports for a period, from an hour to a year, so the traffic you can move is capped by speed × time. One division tells you whether that beats a per-GB plan on bandwidth cost: `plan price ÷ your per-GB rate = break-even GB`. Move more than that within the plan's period and the flat plan costs less per GB. Move less and per-GB is cheaper. On 26 September 2026, 15 of the 22 vendors checked had a residential plan priced this way on a public page. At the 13 that sell 200 Mbps for 30 days or a month, that plan cost $700 to $2,525.53: $0.0108 to $0.0390 per GB with the line full all month and no overhead, or $0.120 to $0.433 at 10% use of its usable capacity. Both ends appear only after JavaScript runs, at vendors that assign locations at random by default; the 7 static-page prices run from $1,249 to $2,499. Against per-GB rates from $0.24 (a listed bundle) to $4.00 (illustrative), the plan breaks even at 175 GB to 10,523 GB a month, or 0.30% to 18.0% of the month's usable capacity. The $0.24 bundle's own page also says $0.28, which lowers the top to 9,020 GB (15.5%). An unlimited plan is the wrong purchase if: - **You move a few hundred GB a month or less**, unless your per-GB rate is high. The cheapest monthly plan in the dataset, ScaleProxy's 25 Mbps for $279, needs 698 GB a month to beat $0.40 per GB, 279 GB to beat $1.00 and 69.8 GB to beat $4.00. - **Your job needs targeting or rotation the plan lacks.** By their own descriptions, 3 of the 15 vendors assign locations at random by default and 4 target countries only. - **You cannot keep the channel busy.** Utilisation sets the real price: a $1,800 200 Mbps month costs $0.309 per GB at 10% use of its usable capacity and $3.09 at 1%. Price is the last check. Pool, targeting, rotation and refund terms come first, and ipvolt has not measured the quality, speed or success rate of any plan here. ## Small budgets: what applies instead No 30-day or monthly plan in the dataset costs less than $279 (ScaleProxy, 25 Mbps), then $300 (Proxyrack, 100 threads) and $350 (IPcook, 100 Mbps). Only 5 of the 15 vendors list a monthly tier below 200 Mbps: ScaleProxy (25, 50 and 100 Mbps for $279, $449 and $849), and IPcook, ProxyScrape, ProxyEmpire and Lightning Proxies at 100 Mbps ($350, $1,425, $1,500 and $1,570). Below that budget, look elsewhere: - **Short periods are tests, not budgets.** The lowest prices in the dataset are $5 for 5 ports for a day (711Proxy's trial), $10 for 10 days (ScaleProxy's trial, one per customer) and $12 for a 200 Mbps hour (LokiProxy). 711Proxy's ports otherwise come only in 3-day periods, from 20 ports for $48, so a month takes ten purchases. Thirty single 200 Mbps days cost 3.1 to 4.0 times a 30-day plan at the 8 vendors that list both. Use one to [test a pool](#test-before-you-commit). - **Small per-GB bundles.** 14 of the 15 vendors also sell per-GB residential traffic, some from 1 GB. Rainproxy lists 100 GB of its cheapest pool for $40. - **Static addresses priced per IP**, if your target accepts ISP or datacenter addresses. [Residential vs datacenter proxies](/blog/residential-vs-datacenter-proxies#what-each-one-costs-and-how-it-is-billed) explains how per-IP billing changes the calculation. Mobile plans priced per device are a different product, not covered here. If you run several accounts, no network plan changes each platform's rules. ## What "unlimited" means on each kind of plan Vendors use the word for five different products. Only the first three are residential plans with no per-GB meter; those are the plans in this article's tables. | What you buy | Metered per GB? | What limits you | |---|---|---| | A speed channel (Mbps) for a period: 14 of the 15 vendors | No | Speed × time, plus any concurrency or fair-use terms | | Threads (simultaneous connections): Proxyrack | No | Threads × a per-thread speed the vendor does not publish | | Ports with a stated speed: 711Proxy | No | A 5 Mbps base per port; the IP changes every 3 to 30 minutes | | Static ISP or datacenter IPs, priced per IP | No, up to a fair-use threshold | The threshold | | Per-GB residential plans called "unlimited" | Yes | The GB meter | Static thresholds on the check date: [Decodo](https://decodo.com/faq/getting-started/fair-usage-policy), "Up to 10 TB total traffic per subscription cycle"; [Bright Data ISP](https://brightdata.com/pricing/proxy-network/isp-proxies), "Each IP includes a 100 GB fair usage allowance per month."; [Webshare](https://www.webshare.io/fair-usage-policy), at least 10 TB per plan before throttling, more on larger plans. [Bright Data's "Unlimited Proxies"](https://brightdata.com/solutions/unlimited-proxies) and [Live Proxies](https://liveproxies.io/products/rotating-residential) still bill residential traffic per GB. ## Check the pool before the price ipvolt did not buy or test any of these plans; below is what the vendors say. - **Is the unlimited plan on the same pool?** [Geonode](https://geonode.com/products/unlimited-residential-proxies) says "Unlimited Residential uses a separate pool from Premium Residential." [ProxyEmpire](https://proxyempire.io/unlimited-bandwidth-residential-proxies/) lists "41+ countries, 500K+ daily IPs" for its unlimited plan and says its per-GB plans "offer a larger residential IP pool with more targeting options." [PrivateProxy.me](https://privateproxy.me/unlimited-rotating-proxies/) says of its two products: "Both use the same 200M+ residential pool." [ScaleProxy](https://scaleproxy.com/) says it "runs on ProxyRack's infrastructure" and shares its IP pool, so those two brands may not be two separate networks. - **Can you choose the location?** By ipvolt's grouping of what each vendor states for its unlimited plan: 5 of the 15 offer city-level or finer targeting, 4 country level, 1 continent (country on request) and 3 random assignment by default; 2 do not say. [LokiProxy's docs](https://docs.lokiproxy.com/configure-proxies/unlimited-residential-proxy): "country/region selection is currently unavailable for unlimited residential proxies"; [IPcook](https://www.ipcook.com/product/unlimited-proxy): "IP locations are assigned automatically and cannot be manually selected." - **Does it rotate the way your job needs?** [GloryCloud](https://www.glorycloud.com/proxy/unlimited-proxies/) offers "optional sticky sessions up to 60 minutes", PrivateProxy.me "sticky sessions from 1 minute to 24 hours", and 711Proxy's ports rotate every 3 to 30 minutes. [Rotating vs sticky proxies](/guides/rotating-vs-sticky-proxies) covers what to test. - **What caps speed and concurrency?** Geonode's product page says "Each tier has a concurrency limit" without giving it, while [its docs](https://docs.geonode.com/docs/proxies/guides/unlimited-residential-proxies/00_unlimited_residential_proxies) say "There are no thread or concurrency limits enforced by the plan." ScaleProxy calls the tier "your guaranteed sustained floor", while [its terms](https://scaleproxy.com/terms) define the maximum speed as "connections × 2 Mbps = total speed". The vendor pages checked do not say whether their Mbps counts downloads only or both directions. - **Does it work on your target?** Only your own test shows that. The fair-use and refund clauses are [quoted below](#fair-use-and-refund-terms-quoted). ## The arithmetic: from Mbps to GB to dollars Mbps means megabits per second, 10^6 bits. A byte is 8 bits and a GB here is 10^9 bytes ([SI prefixes](https://www.bipm.org/en/publications/si-brochure), [NIST](https://physics.nist.gov/cuu/Units/binary.html)). One Mbps kept busy for a day therefore moves at most 10.8 GB: ```text 10^6 bit/s ÷ 8 bit per byte × 86,400 s ÷ 10^9 byte per GB = 10.8 GB per Mbps-day = 0.45 GB per Mbps-hour = 324 GB per Mbps over 30 days = 10.058 GiB per Mbps-day ``` The rest follows: ```text capacity (GB) = Mbps × 10.8 × days usable GB = capacity × h effective $/GB = price ÷ (usable GB × u) break-even GB = price ÷ your per-GB rate utilisation needed = break-even GB ÷ usable GB average Mbps needed = GB per month ÷ 324 ÷ h ``` - **Capacity is a ceiling on line bits.** 200 Mbps for 30 days is 64,800 GB. - **h is the share of the line that arrives as response payload.** On standard 1500-byte Ethernet, TCP payload is at most 94.9% of the link rate, 1,460 of every 1,538 bytes after TCP/IP headers and Ethernet framing ([RFC 6349](https://www.rfc-editor.org/rfc/rfc6349)), before TLS, HTTP headers and retries. The tables use h = 0.90, an assumption you can change, not a measurement. 200 Mbps for 30 days is then 58,320 usable GB. - **u is the utilisation you sustain** over the whole period, nights and idle hours included. - If a vendor means megabytes per second, multiply by 8. ProxyEmpire writes "Mbit"; it is read here as megabits per second. Two vendors' own figures agree with the constant: PrivateProxy.me's "roughly 2.2 TB per day" at 200 Mbps, and [ScaleProxy's](https://scaleproxy.com/pricing) "$0.0193/GB at full speed" for its $1,249 month ($1,249 ÷ 64,800 GB). Check the utilisation behind any such equivalent: PrivateProxy.me's 200 Mbps card ("Equivalent at $1.1/GB", "$35,200/mo") implies 32,000 GB, about 49% of a full line. For thread plans, the speed comes from your workload: ```text Mbps per thread = bytes per response × 8 ÷ seconds per request ÷ 10^6 aggregate Mbps = threads × Mbps per thread ``` A hypothetical 150 kB page every 2 seconds is 0.6 Mbps per thread; a 2.56 MB browser page load every 6 seconds is 3.41 Mbps. ## Prices, capacity and $/GB across 15 vendors **Prices and terms last checked on 26 September 2026 (UTC).** They change often, so open the vendor's page before you buy. One row per vendor at 200 Mbps for 30 days or a month, or the nearest tier it sells. Prices are in USD as listed, after any on-page discount and without coupon codes: before tax at the 7 vendors that say so, while 8 of the 15 do not state a tax basis. The last column is $/GB at 10% use of the usable capacity (58,320 GB for 200 Mbps over 30 days). For utilisation u, multiply it by 0.1 ÷ u; for a full line with no overhead, by 0.09. | Vendor | Period | Price | $/GB at 10% use | |---|---|---|---| | [Geonode](https://geonode.com/products/unlimited-residential-proxies) | Month | $1,800 | $0.309 | | [ProxyEmpire](https://proxyempire.io/unlimited-bandwidth-residential-proxies/) | Month | $2,400 | $0.412 | | [711Proxy](https://www.711proxy.com/pricing/regular/unlimited-rotating-proxies) | 30 days | $1,920 | $0.329 | | [711Proxy ports](https://www.711proxy.com/pricing/regular/port-rotating-proxies) | 3 days | $95 † | $0.130 | | [LokiProxy](https://www.lokiproxy.com/product/unlimited-residential-proxy) | 30 days | $1,800 | $0.309 | | [PrivateProxy.me](https://privateproxy.me/unlimited-rotating-proxies/) | Month | $2,499 | $0.428 | | [Rainproxy](https://rainproxy.io/products/unlimited-residential-proxies) | 30 days | $1,925.63 | $0.330 | | [IPcook](https://www.ipcook.com/pricing/buy-unlimited-proxy) | 30 days | $700 † | $0.120 | | [ScaleProxy](https://scaleproxy.com/pricing) | Month | $1,249 | $0.214 | | [IPDeep](https://www.ipdeep.com/unlimited-residential-proxy) | 3 days | $165.30 | $0.283 | | [Rapidproxy](https://www.rapidproxy.io/unlimited-residential-proxies/pricing) | 30 days | $1,800 † | $0.309 | | [GloryCloud](https://www.glorycloud.com/proxy/unlimited-proxies/) | 30 days | $2,175 † | $0.373 | | [Lightning Proxies](https://lightningproxies.net/pricing/unlimited-residential-proxies) | 30 days | $2,300 † | $0.394 | | [ProxyScrape](https://proxyscrape.com/products/unlimited-residential-proxies) | 30 days | $2,367 † | $0.406 | | [Lumiproxy](https://www.lumiproxy.com/proxies/unlimited/) | 30 days | $2,525.53 † | $0.433 | † The price appears only after JavaScript runs or a public price toggle is clicked, so a plain page fetch cannot recheck it. What the rows do not show: - ScaleProxy's page defaults to annual billing ($1,145 a month, billed $13,739 a year); the row is its month-to-month price. - IPcook's 200 Mbps price appears after a click; its page opens on 100 Mbps at $350. - Lumiproxy's price also moves with an unlabelled selector: $2,525.53 at its default of 1000, $2,998.09 at 5000. - GloryCloud showed an "Original price" of $2,300 with a discount line; ProxyScrape showed $2,630 struck through beside an expiring-offer countdown. Both may be promotions. - IPDeep sells only 3-day periods, though its page also says "Billing is based on actual bandwidth usage". - 711Proxy's port row is 50 ports at a stated 5 Mbps base each; a port may exceed it, "reaching up to 50 Mbps". **Thread plans.** [Proxyrack](https://www.proxyrack.com/unmetered-residential-proxies/) sells 100 threads for $300 a month and says only that "The speed varies depending on the connection of the exit node". With every thread busy all month, 100 threads carry 3,240 GB at a hypothetical 0.1 Mbps per thread (a 50 kB response every 4 seconds), 19,440 GB at 0.6 Mbps and 110,592 GB at 3.41 Mbps: $0.0926, $0.0154 or $0.0027 per GB. Your workload sets the answer, capped by exit-node speeds that Proxyrack does not publish. ## Break-even against your per-GB rate Use the rate you would actually pay at your volume. Low "from" prices usually need a large purchase, so every table here applies one rule: a per-GB rate counts only if you would use up its minimum purchase within the bundle's validity or 12 months, whichever is shorter. Break-even GB within each plan's period for four plans, with the share of its usable capacity (h = 0.90) in brackets: | Rate | $700 month | $2,525.53 month | $200 day | $12 hour | |---|---|---|---|---| | $0.24 ‡ | 2,917 (5.0%) | 10,523 (18.0%) | 833 (42.9%) | 50.0 (61.7%) | | $0.28 ‡ | 2,500 (4.3%) | 9,020 (15.5%) | 714 (36.7%) | 42.9 (52.9%) | | $0.40 | 1,750 (3.0%) | 6,314 (10.8%) | 500 (25.7%) | 30.0 (37.0%) | | $0.48 | n/a | 5,262 (9.0%) | 417 (21.4%) | 25.0 (30.9%) | | $0.55 | 1,273 (2.2%) | 4,592 (7.9%) | 364 (18.7%) | 21.8 (26.9%) | | $1.00 | 700 (1.2%) | 2,526 (4.3%) | 200 (10.3%) | 12.0 (14.8%) | | $2.00 | 350 (0.60%) | 1,263 (2.2%) | 100 (5.1%) | 6.0 (7.4%) | | $4.00 | 175 (0.30%) | 631 (1.1%) | 50.0 (2.6%) | 3.0 (3.7%) | - **Plans:** IPcook's and Lumiproxy's 200 Mbps for 30 days (the ends of the price range, both rendered-only with random locations by default), Rapidproxy's 200 Mbps day and LokiProxy's 200 Mbps hour. For the day and the hour, the rule uses the monthly pace of rebuying the plan. - **Rates:** listed bundles that never expire. [Rainproxy](https://rainproxy.io/pricing) sells "Residential Smart", its cheapest pool and not its unlimited line, at $0.40 per GB for 100 GB and $0.28 for 500 GB. ‡ Its 1,000 GB card shows $0.24, but the same page says it "auto-discounts to $0.28/GB at 1 TB". [LokiProxy's](https://www.lokiproxy.com/pricing/rotating-residenial-proxy) $0.48 needs 50,000 GB, so it counts only from 4,167 GB a month. [Rapidproxy's](https://www.rapidproxy.io/residential-proxies/pricing) $0.55 needs 5,000 GB. - **$1.00, $2.00 and $4.00 are illustrative.** On the check date, [Bright Data](https://brightdata.com/solutions/unlimited-proxies) showed pay-as-you-go residential at $4.00 per GB with a three-month 50%-off code (list $8.00). The download has these figures for every Mbps and port plan. A month of per-GB traffic costs this, against $700 to $2,525.53 for a flat 200 Mbps month whatever you move: | GB a month | $0.24 | $0.40 | $0.55 | $1.00 | |---|---|---|---|---| | 100 | $24 § | $40 | n/a | $100 | | 300 | $72 § | $120 | n/a | $300 | | 1,000 | $240 | $400 | $550 § | $1,000 | | 3,000 | $720 | $1,200 | $1,650 § | $3,000 | | 10,000 | $2,400 | $4,000 | $5,500 | $10,000 | | 30,000 | $7,200 | $12,000 | $16,500 | $30,000 | § One bundle lasts months: Rainproxy's 1,000 GB ($240) lasts 10 months at 100 GB and 3.3 at 300 GB; Rapidproxy's 5,000 GB ($2,750) lasts 5 months at 1,000 GB and 1.7 at 3,000 GB. Below 417 GB a month it would outlast a year, so $0.55 does not count (n/a). At $4.00, multiply the $1.00 column by 4. - At 100 GB a month, even $4.00 per GB ($400) costs less than any flat 200 Mbps month. - At 3,000 GB, $0.40 to $0.55 per GB costs $1,200 to $1,650: a large discounted bundle lands within tens of percent of a flat month, and only the $700 and $1,249 months cost less than $1,650. At $1.00 or more, every flat month costs less. - At 10,000 GB, even the $0.24 rate costs $2,400, more than 10 of the 13 flat months (at $0.28, $2,800 is more than all 13); at 30,000 GB it costs more than all of them. So from around 10 TB a month, 17.1% of a 200 Mbps month's usable capacity, most flat plans are the cheaper way to buy bandwidth at these list prices, provided you sustain the utilisation and the pool passes the checks above. Below that, the break-even table and your own rate decide. ipvolt, which publishes this post, sells [mobile proxies](/mobile-proxies) and [residential proxies](/residential-proxies) from $2.20/GB. It does not sell Mbps- or thread-based unlimited residential plans. ### Worked example: 2 TB a month (hypothetical) A crawler that moves 2,000 GB a month averages 6.17 Mbps of payload, or 6.86 Mbps on the line at h = 0.90: 3.4% of a 200 Mbps month. - As per-GB traffic, that costs $480 at $0.24, $800 at $0.40, $1,100 at $0.55, $2,000 at $1.00 and $8,000 at $4.00. - The 13 flat 200 Mbps months work out at $0.35 to $1.26 per GB at this volume. Against $0.40 per GB, 12 of the 13 cost more; against $1.00, 7 of the 13 cost less; against $2.00 or more, all 13 do. - The smallest monthly plan that covers the volume is ScaleProxy's 25 Mbps at $279, about $0.14 per GB, provided 25 Mbps also covers your peak and you keep 27.4% of it busy. Against the 200 Mbps months, the answer flips inside the rate band, so your own rate decides. Three smaller Mbps months cost less than 2,000 GB at even $0.24 per GB ($480): ScaleProxy's 25 and 50 Mbps ($279 and $449) and IPcook's 100 Mbps ($350), if that speed covers your peak and the pool passes the checks above. Size the channel to your peak, not to the 200 Mbps default. ### Against the same vendor's per-GB plan If you already buy per GB from one of these vendors, compare on its own price list, under the same rule. The two products may use different pools. | Vendor | Flat month | Per-GB rate | Break-even | |---|---|---|---| | [Geonode](https://geonode.com/products/residential-proxies) | $1,800 | $0.441 | 4,082 GB (7.0%) | | [ProxyEmpire](https://proxyempire.io/rotating-residential-proxies/) | $2,400 | $3.00–$3.97 | 605–800 GB (1.0–1.4%) | | [711Proxy](https://www.711proxy.com/pricing/enterprise/residential-proxies-gb) | $1,920 | $0.571 | 3,360 GB (5.8%) | | [LokiProxy](https://www.lokiproxy.com/pricing/rotating-residenial-proxy) | $1,800 | $0.550 | 3,273 GB (5.6%) | | [PrivateProxy.me](https://privateproxy.me/residential-rotating-proxies/) | $2,499 | $1.00 | 2,499 GB (4.3%) | | [Rainproxy](https://rainproxy.io/pricing) | $1,925.63 | $0.240 | 8,023 GB (13.8%) | | [IPcook](https://www.ipcook.com/pricing/buy-residential-proxy) | $700 | $0.600 | 1,167 GB (2.0%) | | [Rapidproxy](https://www.rapidproxy.io/residential-proxies/pricing) | $1,800 | $0.550 | 3,273 GB (5.6%) | - **The rate** is the bundle in force at the break-even: Geonode's 3,000 GB and PrivateProxy.me's 1,000 GB monthly plans, used within the month; 711Proxy's 5,250 GB Enterprise, LokiProxy's 10,000 GB Premium, IPcook's and Rapidproxy's 5,000 GB and Rainproxy's 1,000 GB bundles, which never expire. [results.json](https://ipvolt.com/downloads/unlimited-proxy-cost/results.json) gives each bundle's page and retrieval time. - **ProxyEmpire** is at list price, without its 50%-off code, and a range because the price of its listed 500 GB card is not transcribed in the dataset. - **Rainproxy's** bundle is Residential Smart, not its unlimited pool; at the $0.28 its page also gives for 1 TB, the break-even is 6,877 GB (11.8%). - **Buying only a month's traffic at a time** lowers four break-evens: 700 GB at IPcook, 2,769 GB at LokiProxy, 3,000 GB at Rapidproxy and 3,102 GB at 711Proxy. ## Fair-use and refund terms, quoted Quotes are exact excerpts as of the check date; vendor names link to the refund terms, and the other pages are in the sources. **Fair use.** None of the 15 vendors publishes a GB threshold on the pages read, and ScaleProxy says "No fair use policy. No hidden throttling. No data caps." Geonode, GloryCloud, LokiProxy, 711Proxy and IPcook have general clauses, such as Geonode's "Unlimited plans remain subject to applicable throughput limits", 711Proxy's ban on "abusing bandwidth" and IPcook's warning of "throttling or account suspension in cases of excessive bandwidth consumption". PrivateProxy.me may refuse refunds for "excessive consumption of resources", and ProxyScrape's published limits cover datacenter plans only. The other 7 have none on the pages read. **Refunds and renewal.** By ipvolt's grouping of the refund text: 2 offer a money-back window, 2 refund only an unused or barely used plan, 4 only a service failure or error, 6 give no refund after purchase or use, and 1 publishes none. 8 of the 15 describe recurring billing: Geonode, ProxyEmpire, PrivateProxy.me, Rainproxy, ScaleProxy, Proxyrack and ProxyScrape sell subscriptions, and IPcook's terms have a general auto-renew clause. Cancel any plan you only meant to test. | Vendor | Shortest paid option | Refund | |---|---|---| | [Geonode](https://geonode.com/refund-policy) | 1-day trial, any tier, $100 | Only if Geonode "fails to deliver"; "Paid trials are non-refundable." | | [ProxyEmpire](https://proxyempire.io/terms-of-service/) | 1 day: 100 Mbit $200, 200 Mbit $275 | "All sales and charges are final" | | [711Proxy](https://www.711proxy.com/policy/RefundPolicy) | 5 ports for a day, $5; 200 Mbps hour, $15 | None "after the order is placed or the proxies are used" | | [LokiProxy](https://www.lokiproxy.com/RefundPolicy.html) | 200 Mbps hour, $12 | None "upon order completion or proxy utilization" | | [PrivateProxy.me](https://privateproxy.me/terms-of-service/) | Monthly only; trial by sales contact | Within 24 hours, if "the plan was not substantially used" | | [Rainproxy](https://rainproxy.io/refund-policy) | 200 Mbps hour, $15 | "Non-refundable, including unused days." | | [IPcook](https://www.ipcook.com/policy) | 100 Mbps for 7 days, $100 | Within 24 hours, if unused "(zero bandwidth consumption)" | | [ScaleProxy](https://scaleproxy.com/pricing) | $10 for 10 days, fee non-refundable | "10-day money-back guarantee on all plans." | | [Proxyrack](https://www.proxyrack.com/refund-policy/) | 100 threads for a month, $300 | Within 3 days, card or PayPal via Paddle only | | [IPDeep](https://www.ipdeep.com/protocol/userService) | 100 Mbps for 3 days, $85.50 | None published | | [Rapidproxy](https://www.rapidproxy.io/terms_of_service) | 200 Mbps for a day, $200 | "non-refundable", unless inactive or defective in the first 24 hours | | [GloryCloud](https://www.glorycloud.com/terms-of-service/) | 50 Mbps hour, $20 | "Under most circumstances, we do not support refunds", except a double order or the wrong plan | | [Lightning Proxies](https://lightningproxies.net/legal/terms-of-service) | 100 Mbps for a day, $155 | Non-refundable, except "technical issues for more than 48 hours" | | [ProxyScrape](https://proxyscrape.com/terms-and-conditions) | 100 Mbps for a day, $190 excl. VAT | Only purchases up to $100 with at most 1 GB used, so no unlimited plan | | [Lumiproxy](https://www.lumiproxy.com/policy/) | 30 days, the shortest listed | None "Once an order is placed and the product is dispatched" | ## Test before you commit 1. **Measure your bytes first.** [The scraper bandwidth report](/guides/scraper-bandwidth-report) shows bytes per page and where they go, so you can estimate GB a month. It measures a run on your machine; it is not a provider bill. For a starting figure before you measure, [we counted pages per GB on 34 public pages](/blog/how-many-gb-of-proxies-do-i-need): about 44,000 HTML-only fetches, or about 900 full browser loads. HTTP clients that send no `Accept-Encoding` header, such as curl without `--compressed`, can move several times the bytes; [check which clients skip compression](/guides/curl-compressed-accept-encoding) before you compare plans. In that guide's local lab, the uncompressed bodies of 23 CPython documentation pages were 6.67 times their gzip size, a ratio for that corpus only. 2. **Buy the shortest paid option** of a plan you are considering (table above), after reading its refund terms; several cannot be refunded. A short plan needs far higher utilisation to beat a per-GB rate (see the day and hour columns of the break-even table), so treat it as a test, not a purchase of traffic. 3. **Run your real target at your real concurrency** for the whole period. Log bytes moved, achieved Mbps over time, success on the content you need, and the locations and rotation you actually get. 4. **Work out effective $/GB and cost per successful GB** (next section) and compare them with your per-GB rate at your volume. [What a proxy benchmark should measure](/blog/what-a-proxy-benchmark-should-measure) covers how to define success and sample fairly across providers, but not throughput or bytes: log those from your own client or proxy. ## Cost per successful GB: the number only your test gives Failed, blocked and retried requests use a flat plan's channel and, depending on the provider, add to a per-GB bill. ipvolt has not measured success for any plan here; your test supplies s: ```text s = bytes of successful responses ÷ all bytes moved flat plan: cost per successful GB = price ÷ successful GB = effective $/GB ÷ s per-GB plan: cost per successful GB = rate × billed GB ÷ successful GB ``` Which failed or retried bytes count toward a per-GB bill varies by provider; the [bandwidth report's notes on reading a report](/guides/scraper-bandwidth-report#how-to-read) list what to check. A plan with a lower bandwidth price and a lower success rate can still cost more per useful GB. ## How the dataset was built - **Inclusion rule.** A vendor is in the tables when its own public page offers a residential plan billed by Mbps, threads or ports for a period, with no per-GB meter, and the price, period and unit can be read without a login, signup or form. Pages were read as static HTML or in a fresh headless browser that clicked only public price toggles. The same rule applies to every vendor. - **Coverage.** 15 of the 22 vendors checked on 26 September 2026 (17:52 to 18:23 UTC) met the rule, with 314 plan rows between them. Not included: [Thordata](https://www.thordata.com/pricing/unlimited-proxies) (price by quote only), [Storm Proxies](https://stormproxies.com/rotating_reverse_proxies.html) (HTTP 403 bot challenge), [Shifter](https://shifter.io/pricing/residential-proxies), Bright Data and Live Proxies (residential billed per GB), and Decodo and Webshare (static plans priced per IP). - **Normalisation.** Mbps is megabits per second, GB is 10^9 bytes and "monthly" is 30 days. Where a page defaulted to annual billing, the month-to-month price is used. Prices are in USD as listed. 7 of the 15 vendors say their listed prices exclude tax. PrivateProxy.me's terms let it charge "applicable taxes" without saying whether prices include them, and the other 7 do not mention tax on the pages read, so 8 of the 15 do not state a tax basis. None says its prices include tax. - **Not verified.** Pool size, IP quality, throughput, success rate, location accuracy, how fair-use clauses are enforced, whether coupons apply and the tax added at checkout. Nothing was bought, and no account, trial or form was used. **Download.** [unlimited-proxy-cost.zip](https://ipvolt.com/downloads/unlimited-proxy-cost/unlimited-proxy-cost.zip) holds the plans with every quote behind the groupings, the reference rates, every table (results.json), a README, checksums and compute.py, a calculator that needs only the Python 3 standard library and no network: ```sh # your plan, your per-GB rate, your GB a month and the success share from your test python3 compute.py --price 1800 --mbps 200 --days 30 --rate 0.8 --gb 2000 --success 0.85 # a thread plan: each thread fetches a 150 kB response every 2 s python3 compute.py --price 300 --threads 100 --bytes-per-response 150000 --seconds-per-request 2 --days 30 --rate 0.8 ``` ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources - [Geonode: Unlimited Residential Proxies (plans, pool, trial)](https://geonode.com/products/unlimited-residential-proxies) - [Geonode: Refund Policy](https://geonode.com/refund-policy) - [Geonode: Acceptable Use Policy, 6.5 Fair Use and Unlimited Plans](https://geonode.com/acceptable-use-policy) - [Geonode: Terms and Conditions, 5.3 (renewal)](https://geonode.com/terms-and-conditions) - [Geonode docs: Unlimited Residential Proxies overview (concurrency)](https://docs.geonode.com/docs/proxies/guides/unlimited-residential-proxies/00_unlimited_residential_proxies) - [Geonode: Residential proxies, per-GB pricing](https://geonode.com/products/residential-proxies) - [ProxyEmpire: Unlimited Bandwidth Residential Proxies](https://proxyempire.io/unlimited-bandwidth-residential-proxies/) - [ProxyEmpire: Terms of Service, 6.4, 7.3 and 8.1](https://proxyempire.io/terms-of-service/) - [ProxyEmpire: Rotating residential proxies, per-GB pricing](https://proxyempire.io/rotating-residential-proxies/) - [711Proxy: Unlimited Proxies, high bandwidth](https://www.711proxy.com/pricing/regular/unlimited-rotating-proxies) - [711Proxy: Unlimited Proxies, by port](https://www.711proxy.com/pricing/regular/port-rotating-proxies) - [711Proxy: Refund Policy](https://www.711proxy.com/policy/RefundPolicy) - [711Proxy: Terms of Service, 3(h)](https://www.711proxy.com/policy/TermsOfService) - [711Proxy: Residential proxies per GB, Enterprise](https://www.711proxy.com/pricing/enterprise/residential-proxies-gb) - [LokiProxy: Unlimited Residential Proxy](https://www.lokiproxy.com/product/unlimited-residential-proxy) - [LokiProxy docs: Unlimited residential proxy (location selection)](https://docs.lokiproxy.com/configure-proxies/unlimited-residential-proxy) - [LokiProxy: Refund Policy](https://www.lokiproxy.com/RefundPolicy.html) - [LokiProxy: Rotating residential proxy pricing (per GB)](https://www.lokiproxy.com/pricing/rotating-residenial-proxy) - [PrivateProxy.me: Unlimited Rotating Proxies](https://privateproxy.me/unlimited-rotating-proxies/) - [PrivateProxy.me: Terms of Service, 6.2 and 6.3](https://privateproxy.me/terms-of-service/) - [PrivateProxy.me: Residential rotating proxies, per-GB pricing](https://privateproxy.me/residential-rotating-proxies/) - [Rainproxy: Unlimited Residential Proxies](https://rainproxy.io/products/unlimited-residential-proxies) - [Rainproxy: Refund Policy](https://rainproxy.io/refund-policy) - [Rainproxy: Terms of Service, 3 (payments and taxes)](https://rainproxy.io/terms-of-service) - [Rainproxy: Pricing (Residential Smart per-GB bundles)](https://rainproxy.io/pricing) - [IPcook: Buy Unlimited Proxy (pricing)](https://www.ipcook.com/pricing/buy-unlimited-proxy) - [IPcook: Unlimited Proxy (product FAQ)](https://www.ipcook.com/product/unlimited-proxy) - [IPcook: Refund Policy](https://www.ipcook.com/policy) - [IPcook: Terms of Service, 2.2 and 4.2](https://www.ipcook.com/terms) - [IPcook: Residential proxy pricing (per GB)](https://www.ipcook.com/pricing/buy-residential-proxy) - [ScaleProxy: Pricing](https://scaleproxy.com/pricing) - [ScaleProxy: Home page (speed floor, Proxyrack infrastructure)](https://scaleproxy.com/) - [ScaleProxy: FAQ (fair use)](https://scaleproxy.com/faq) - [ScaleProxy: Terms of Service, 4, 6, 7 and 8](https://scaleproxy.com/terms) - [Proxyrack: Unmetered Residential Proxies](https://www.proxyrack.com/unmetered-residential-proxies/) - [Proxyrack: Refund Policy](https://www.proxyrack.com/refund-policy/) - [Proxyrack: Terms of Use (renewal)](https://www.proxyrack.com/terms-of-use/) - [IPDeep: Unlimited residential proxy](https://www.ipdeep.com/unlimited-residential-proxy) - [IPDeep: User Service Agreement](https://www.ipdeep.com/protocol/userService) - [Rapidproxy: Unlimited residential proxies pricing](https://www.rapidproxy.io/unlimited-residential-proxies/pricing) - [Rapidproxy: Terms of Service, 6.9 and 6.10](https://www.rapidproxy.io/terms_of_service) - [Rapidproxy: Residential proxies pricing (per GB)](https://www.rapidproxy.io/residential-proxies/pricing) - [GloryCloud: Unlimited proxies](https://www.glorycloud.com/proxy/unlimited-proxies/) - [GloryCloud: Unlimited proxies pricing (FAQ on taxes)](https://www.glorycloud.com/pricing/unlimited-proxies/) - [GloryCloud: Terms of Service, 6.3](https://www.glorycloud.com/terms-of-service/) - [GloryCloud: Acceptable Use Policy, 3 Fair Use Policy](https://www.glorycloud.com/acceptable-use-policy/) - [Lightning Proxies: Unlimited residential proxies pricing](https://lightningproxies.net/pricing/unlimited-residential-proxies) - [Lightning Proxies: Terms of Service, 20 Refund Policy](https://lightningproxies.net/legal/terms-of-service) - [ProxyScrape: Unlimited Residential Proxies](https://proxyscrape.com/products/unlimited-residential-proxies) - [ProxyScrape: Terms and Conditions, 05 Pricing, 8 and 17](https://proxyscrape.com/terms-and-conditions) - [Lumiproxy: Unlimited proxies](https://www.lumiproxy.com/proxies/unlimited/) - [Lumiproxy: Refund Policy](https://www.lumiproxy.com/policy/) - [Decodo: Unlimited proxies](https://decodo.com/proxies/unlimited-proxies) - [Decodo: Fair usage policy](https://decodo.com/faq/getting-started/fair-usage-policy) - [Webshare: Unlimited bandwidth proxies](https://www.webshare.io/features/unlimited-bandwidth-proxy) - [Webshare: Fair usage policy](https://www.webshare.io/fair-usage-policy) - [Bright Data: ISP proxies pricing (fair usage per IP)](https://brightdata.com/pricing/proxy-network/isp-proxies) - [Bright Data: Unlimited Proxies (per-GB residential)](https://brightdata.com/solutions/unlimited-proxies) - [Live Proxies: Rotating residential proxies](https://liveproxies.io/products/rotating-residential) - [Thordata: High-Bandwidth Proxies pricing (contact sales)](https://www.thordata.com/pricing/unlimited-proxies) - [Storm Proxies: Rotating reverse proxies (HTTP 403 on the check date)](https://stormproxies.com/rotating_reverse_proxies.html) - [Shifter: Residential proxies pricing](https://shifter.io/pricing/residential-proxies) - [BIPM: The International System of Units (SI Brochure), SI prefixes and the day](https://www.bipm.org/en/publications/si-brochure) - [NIST: Prefixes for binary multiples (byte, GB and GiB)](https://physics.nist.gov/cuu/Units/binary.html) - [RFC 6349: Framework for TCP Throughput Testing, section 4.1.1](https://www.rfc-editor.org/rfc/rfc6349) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [How to Check if a Proxy Is Really Mobile or Residential](https://ipvolt.com/blog/check-if-proxy-is-mobile-or-residential.md) (Analysis, Nov 8, 2026, 12 min read): No single check proves a proxy is mobile or residential. We tested ASN, RDAP, PeeringDB, reverse DNS and IP databases on a mobile line and a datacenter IP. - [How Many GB of Proxies Do You Need? Pages per GB, Measured](https://ipvolt.com/blog/how-many-gb-of-proxies-do-i-need.md) (Benchmark, Oct 5, 2026, 8 min read): We loaded 34 public pages three ways through a metering proxy. 1 GB fits about 44,000 HTML-only fetches, or about 900 full Playwright page loads. - [Multiple Meta Ad Accounts: An Agency Setup Checklist](https://ipvolt.com/blog/manage-multiple-meta-ad-accounts.md) (Analysis, Sep 19, 2026, 6 min read): Manage multiple Meta ad accounts with a client access record, clear team responsibilities and a checklist for access errors, security incidents and routing. ## Related guides - [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md): Choose rotation around the smallest complete workflow, distinguish exit affinity from cookies, and test what happens when a sticky session ends early. - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md): How to use a proxy with curl: the -x flag, http_proxy and https_proxy variables, SOCKS5 with socks5h, proxy authentication, and reading CONNECT and 407 errors. - [curl --compressed: which clients skip compression](https://ipvolt.com/guides/curl-compressed-accept-encoding.md): curl, Wget 1.x, urllib, node:http, PHP curl, Guzzle and java.net.http.HttpClient send no Accept-Encoding (or identity) by default. Tested fixes and byte checks. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 124 of 138: NO_PROXY wildcard, CIDR and subdomains: 15 clients tested URL: https://ipvolt.com/blog/no-proxy-matching-tested Markdown: https://ipvolt.com/blog/no-proxy-matching-tested.md # NO_PROXY wildcard, CIDR and subdomains: 15 clients tested Source: https://ipvolt.com/blog/no-proxy-matching-tested Markdown: https://ipvolt.com/blog/no-proxy-matching-tested.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / NO_PROXY wildcard, CIDR and subdomains: 15 clients tested Category: Analysis Published: 2026-09-24 Updated: 2026-09-24 Author: ipvolt Reading time: 19 minutes Tags: proxies, troubleshooting Does *.example.com, .example.com or a CIDR range work in NO_PROXY? Tested answers for curl, wget, Python, Node and Go, plus localhost, IPv6 and ports. NO_PROXY has no standard grammar, and the clients that read it disagree on most of it. In the main matrix of a loopback lab run on 23 September 2026, 15 clients received identical `no_proxy` and `NO_PROXY` values: two curl builds, wget, Go, five Python clients and six Node.js configurations. Of 49 value-and-request combinations in the main matrix, 21 routed the same way in every client and 28 did not. Every cell is in the published [results.csv](https://ipvolt.com/downloads/no-proxy-matching-tested/results.csv), one row per client and request. If one value has to serve all of them, use only the shapes that behaved identically everywhere, and give both variable names the same value: ```sh # example.com and 192.0.2.10 stand for your own domain and address export no_proxy="localhost,127.0.0.1,example.com,.example.com,192.0.2.10" export NO_PROXY="$no_proxy" ``` - The pair `example.com,.example.com` (tested as `example.test,.example.test`) was the only spelling that covered a domain and all of its subdomains in all 15 clients. It never matched `notexample.test`. - An exact IPv4 address matched only itself in every client. An IPv4 CIDR range worked in only 4 of the 15. - `localhost,127.0.0.1` bypassed the proxy for `127.0.0.1` and `localhost` in every client. Without loopback entries, only Go skipped the proxy for loopback. - wget reads only `no_proxy`. Go 1.27.1's `net/http` prefers `NO_PROXY` when both are set, and Go 1.28 is due to prefer `no_proxy` instead. Keep the two names identical. The published dataset tests these entries in separate cases. In a one-off run of the exact line above, with `example.test` in place of `example.com`, each of its nine test requests also routed the same way in all 15 clients. Two kinds of spelling cause trouble. Some break a client or turn a list off. A bracketed IPv6 entry makes httpx and httpx2 fail when the client is created, and so does an IPv6 CIDR entry in httpx 0.28.1. An empty lowercase `no_proxy` next to a set `NO_PROXY` switched the list off in 9 clients. Others are silently ignored by some clients: `*.example.com` by 8, `*` inside a list by 9, an IPv4 CIDR range by 11, a trailing dot by 11, a space-separated list by 9, and a `host:port` entry by 4 to 6, depending on its form. Even a bare `*` is ignored by wget. These results are synthetic. They come from one Mac, a proxy on 127.0.0.1, reserved `.test` names and documentation IP addresses, and they describe how the pinned client versions choose a route, not how any proxy service behaves. For how each client reads the proxy variables in the first place, see [how clients read HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables). If Node's `fetch()` ignores the proxy completely, start with [Fix Node.js TypeError: fetch failed behind a proxy](https://ipvolt.com/guides/fix-node-fetch-failed-proxy). ## The portable subset and the spellings to avoid The tables use the names the lab requested: `example.test`, `sub.example.test`, `a.b.example.test` and `notexample.test`. No client here resolves a host name before deciding: their source code compares names as text, and curl, Go and Requests parse an IP address in the URL for CIDR checks. None of the 662 proxied requests triggered a recorded sandbox denial for a DNS lookup or connection, although the kernel log drops some denial lines. Real domain names should therefore behave like these. The 15 clients, each reading the proxy variables from the environment with the settings shown, were: - curl 8.7.1 (macOS) and curl 8.22.0; - GNU Wget 1.25.0; - Go 1.27.1 `net/http` with `http.ProxyFromEnvironment`; - Python 3.14.7 `urllib`, requests 2.34.2, httpx 0.28.1, httpx2 2.13.1 and aiohttp 3.14.3 with `trust_env=True`; - Node.js 26.10.0 and 24.21.0 built-in `fetch()` and `http.get()`, each with `NODE_USE_ENV_PROXY=1` (called "Node 26 fetch", "Node 26 http" and so on below); - npm undici 7.29.1 and 8.11.0 `fetch()` with `dispatcher: new EnvHttpProxyAgent()`, both on Node 26.10.0. An undici 6 `EnvHttpProxyAgent` passed to Node 26's built-in `fetch()` fails before it reaches the proxy, with `invalid onError method`; [fetch failed: invalid onError method on Node.js 26](/guides/node-26-invalid-onerror-method) covers that error. These entries gave the same result in all 15 clients for the requests shown: | Entry | Result in every client | |---|---| | `example.test` | Bypassed `example.test`; `notexample.test` still used the proxy (subdomains differed in Node's `http` client) | | `.example.test` | Bypassed `sub.example.test` and `a.b.example.test` (the apex differed in 4 clients) | | `example.test,.example.test` | Bypassed the apex and both subdomains; `notexample.test` still used the proxy | | `192.0.2.10` | Bypassed that address; `192.0.2.11` still used the proxy | | `EXAMPLE.TEST`, or a request to `EXAMPLE.TEST` | Letter case made no difference | | `other.test , example.test` | A space after a comma made no difference | | `other.test,,example.test` or `other.test,,` | Empty items matched nothing | | `localhost,127.0.0.1,::1` | Bypassed `127.0.0.1` and `localhost` (`[::1]` differed; see the loopback section) | | `no_proxy` set, `NO_PROXY` unset | Every client read the lowercase variable | Each spelling to avoid from the answer above has its own section below, with the clients that diverged. ## NO_PROXY wildcard: does `*.example.com` match `example.com`? It depends on the client, and 8 of 15 did not treat it as a wildcard at all. With `NO_PROXY=*.example.test`: | Request | Bypassed the proxy | Used the proxy | |---|---|---| | `example.test` | Node 26 fetch, Node 24 fetch, undici 7.29.1 | The other 12 | | `sub.example.test`, `a.b.example.test` | Go, Node 26 and 24 fetch and http, undici 7.29.1 and 8.11.0 | curl (both), wget, urllib, requests, httpx, httpx2, aiohttp | | `notexample.test` | None | All 15 | curl, wget and all five Python clients matched nothing with this entry. Go, Node's `http` client and undici 8.11.0 read it as "subdomains only", and Node's built-in `fetch()` and undici 7.29.1 also bypassed the apex. The apex split between Node 26's built-in `fetch()` and npm undici 8.11.0 is new. [undici PR #5777](https://github.com/nodejs/undici/pull/5777), released in [undici 8.11.0](https://github.com/nodejs/undici/releases/tag/v8.11.0) on 22 September 2026, says a `*.domain` entry "must only match `sub.example.com` / `a.b.example.com`, not the apex". Node 26.10.0 still [bundles undici 8.10.2](https://github.com/nodejs/node/blob/v26.10.0/deps/undici/src/package.json). So on the same Node 26.10.0 runtime, built-in `fetch()` bypassed `example.test` and npm undici 8.11.0 sent it to the proxy. The same pull request made `*` work inside a list or with spaces around it, which accounts for the only other rows where those two clients differed. For subdomains in every client, write `.example.com`. Add `example.com` if the apex should bypass too. No tested spelling kept the apex on the proxy in all 15 clients while bypassing its subdomains. ## Leading dot vs bare domain: `.example.com`, `example.com` and subdomains | Entry and request | Bypassed the proxy | Used the proxy | |---|---|---| | `example.test`, request `sub.example.test` | 13 clients | Node 26 http, Node 24 http | | `.example.test`, request `example.test` | 11 clients | wget, Go, httpx, httpx2 | A bare domain matched its subdomains everywhere except in Node's built-in `http` client, which matched `example.test` exactly. The lab reproduced [node#65616](https://github.com/nodejs/node/issues/65616), first reported on Node 24.18.1, on 26.10.0 and 24.21.0. Node's own [NO_PROXY format list](https://nodejs.org/docs/v26.10.0/api/http.html#no_proxy-format) calls `example.com` an "Exact host name match", which describes `http.request()`, not `fetch()`. A fix, [node#65617](https://github.com/nodejs/node/pull/65617), was still open on 23 September 2026. A leading dot matched every subdomain in every client, but wget, Go, httpx and httpx2 did not apply it to the apex. Go documents this: a domain name with a leading dot "matches subdomains only" ([httpproxy](https://pkg.go.dev/golang.org/x/net/http/httpproxy#Config)). Neither entry matched `notexample.test` in any client. Requests has enforced that label boundary only since 2.34.0; its [release notes](https://github.com/psf/requests/releases/tag/v2.34.0) say it "no longer performs greedy matching on no_proxy domains". Older Requests versions were not tested. ## `NO_PROXY=*` and `*` inside a list | Value | Bypassed the proxy | Used the proxy | |---|---|---| | `*` | 14 clients | wget | | `other.test,*` or `" * "` | Go, httpx, httpx2, Node 26 http, Node 24 http, undici 8.11.0 | curl (both), wget, urllib, requests, aiohttp, Node 26 fetch, Node 24 fetch, undici 7.29.1 | `*` works as the entire value, with no spaces, in every client except wget. curl documents it that way: "The only wildcard available is a single `*` character" ([CURLOPT_NOPROXY](https://curl.se/libcurl/c/CURLOPT_NOPROXY.html)). wget 1.25.0 has no wildcard. To keep one wget command off the proxy, use its `--no-proxy` option ([wget manual](https://www.gnu.org/software/wget/manual/wget.html#Proxies)). ## CIDR, IP ranges and subnets in NO_PROXY With `NO_PROXY=192.0.2.0/24`, a request to `192.0.2.10` bypassed the proxy in curl 8.7.1, curl 8.22.0, Go and requests. The other 11 sent it to the proxy: wget, urllib, httpx, httpx2, aiohttp and all six Node clients. `198.51.100.10`, outside the range, used the proxy in every client. No client raised an error for the IPv4 range; the 11 without support ignored it. - curl added CIDR support in 7.86.0 ([changelog](https://curl.se/changes.html)). - Requests checks CIDR in [its own matcher](https://github.com/psf/requests/blob/v2.34.2/src/requests/utils.py) before falling back to urllib, which is why the two Python clients differ. - httpx and httpx2 accepted the entry without matching the range. [httpx2 PR #1165](https://github.com/pydantic/httpx2/pull/1165), which would add CIDR ranges, was open on 23 September. - Node's [NO_PROXY format list](https://nodejs.org/docs/v26.10.0/api/http.html#no_proxy-format) documents a dash range such as `192.168.1.1-192.168.1.100` instead of CIDR. The lab did not test dash ranges. A [node#57872 comment](https://github.com/nodejs/node/issues/57872#issuecomment-5495669370) reports that a dash range worked in `node:http` but not in `fetch()` on a v27 pre-release. To keep a subnet off the proxy in a mixed stack: - List the exact addresses your clients call. Exact IPv4 addresses were the only form that matched in all 15. - An IPv4 range can be added next to them for curl, Go and Requests. With `192.0.2.10,192.0.2.0/24`, a one-off run outside the published dataset bypassed `192.0.2.10` in all 15 clients and `192.0.2.11` only in those 4; no client raised an error. Leave IPv6 ranges out, because httpx 0.28.1 fails on them (see below). - A range applies only to an IP address written in the URL. curl, Go and Requests do not resolve a host name first, so `192.0.2.0/24` does not cover a name that resolves into it. This comes from their source code; the lab used IP addresses only. ## IPv6 in NO_PROXY: bare, bracketed and CIDR For a request to `http://[2001:db8::10]/`: | Entry | Bypassed the proxy | Did not bypass | |---|---|---| | `2001:db8::10` | 12 clients | urllib, Node 24 fetch, undici 7.29.1 used the proxy | | `[2001:db8::10]` | urllib, Node 26 fetch, Node 24 fetch, undici 7.29.1, undici 8.11.0 | 8 used the proxy; httpx and httpx2 raised an error | | `2001:db8::/48` | curl 8.22.0, Go | 12 used the proxy; httpx raised an error | | `[2001:db8::10]:8080`, request on port 8080 | Go, urllib, Node 26 fetch, Node 24 fetch, undici 7.29.1, undici 8.11.0 | 7 used the proxy; httpx and httpx2 raised an error | The bare form did best: it matched in 12 clients and broke none. curl asks for it: "Enter IPv6 numerical addresses in the list of hostnames without enclosing brackets" ([CURLOPT_NOPROXY](https://curl.se/libcurl/c/CURLOPT_NOPROXY.html)). undici added bare IPv6 matching in 8.10.0 ([PR #5623](https://github.com/nodejs/undici/pull/5623)); undici 7.29.1, which Node 24.21.0 bundles, does not have it. Of the two curl builds, only 8.22.0 matched the IPv6 range. Before 8.18.0 ([curl#19828](https://github.com/curl/curl/pull/19828)), curl's matcher treated a host as IPv6 only when it arrived in brackets, which it never does, so an IPv6 CIDR entry could not match. ### httpx `InvalidURL: Invalid port` from a bracketed IPv6 entry A bracketed entry is worse than ignored in httpx 0.28.1 and httpx2 2.13.1. Creating a client with default environment handling raised `InvalidURL: Invalid port: 'db8::10]'` before any request was sent. With `NO_PROXY=localhost,127.0.0.1,[::1]`, the error was `Invalid port: ':1]'`, and requests to `127.0.0.1` and `localhost` failed as well, because the client was never created. httpx 0.28.1 raised the same way for `2001:db8::/48` (`Invalid port: 'db8::'`). httpx2 2.5.0 stopped that crash ("Allow IPv6 CIDR notation in `no_proxy`", [changelog](https://github.com/pydantic/httpx2/blob/v2.13.1/src/httpx2/CHANGELOG.md)), but as the table shows, it still did not match the range. To fix it, write IPv6 entries without brackets, such as `::1` or `2001:db8::10`; both clients were created normally with those. Keep IPv6 ranges out of any value httpx 0.28.1 reads. If you cannot change the variable, create that client with `trust_env=False`, which was also created normally, and pass its proxy in code, as the [HTTPX proxy guide](https://ipvolt.com/guides/httpx-async-proxy) does. That client then ignores all the proxy variables. ## Ports in NO_PROXY: `host:port` For a request on the listed port 8080: | Entry | Bypassed the proxy | Used the proxy | |---|---|---| | `example.test:8080` | 11 clients | curl (both), wget, aiohttp | | `192.0.2.10:8080` | 10 clients | curl (both), wget, requests, aiohttp | | `.example.test:8080` | 9 clients | curl (both), wget, aiohttp, Node 26 http, Node 24 http | On port 80, all three entries used the proxy in every client, so no client applied a port entry to a different port. The failure was the opposite: some clients never matched the entry at all. curl's documentation describes no port syntax for entries, and wget compares the host name only. aiohttp passes the host without its port to urllib's matcher ([source](https://github.com/aio-libs/aiohttp/blob/v3.14.3/aiohttp/helpers.py)). Requests never matched an IPv4 entry that includes a port: with `192.0.2.10:8080`, it used the proxy on port 8080 as well as on port 80. Its IPv4 check compares only the host, according to [PR #7586](https://github.com/psf/requests/pull/7586), a fix that was still open on 23 September. Keep ports out of a shared value. If one port must bypass the proxy, configure that bypass in the client that needs it. ## Spaces, empty items, trailing dots and uppercase - **Space before a comma:** with `example.test ,other.test`, wget kept the trailing space as part of the entry and sent `example.test` to the proxy. The other 14 bypassed it. - **Spaces instead of commas:** with `other.test example.test`, curl 8.7.1, Node 26 fetch, Node 24 fetch, undici 7.29.1 and undici 8.11.0 bypassed both hosts. curl 8.22.0 bypassed only `other.test`. The other 9 bypassed neither. curl 8.9.0 made the change: "noproxy: patterns need to be comma separated" ([changelog](https://curl.se/changes.html)). - **Empty items:** `other.test,,` did not bypass `example.test` in any client, so no client treated an empty item as "match everything". - **Trailing dots:** an `example.test.` entry, or a request to `http://example.test./`, matched only in curl 8.7.1, curl 8.22.0, Node 26 fetch and undici 8.11.0. undici added this in 8.10.1 ([PR #5637](https://github.com/nodejs/undici/pull/5637)), so Node 24 fetch and undici 7.29.1 do not have it. - **Uppercase:** entries and hosts in capitals matched in all 15 clients. ## `NO_PROXY` vs `no_proxy`: which one wins, and the empty-variable trap For a request to `example.test`: | Environment | Bypassed the proxy | Used the proxy | |---|---|---| | `NO_PROXY=example.test` only | 14 clients | wget | | `no_proxy=example.test` only | All 15 | None | | `NO_PROXY=example.test`, `no_proxy=other.test` | Go 1.27.1 | The other 14 | | `NO_PROXY=example.test`, `no_proxy=""` | curl (both), Go, requests, Node 26 http, Node 24 http | wget, urllib, httpx, httpx2, aiohttp, Node 26 fetch, Node 24 fetch, undici 7.29.1, undici 8.11.0 | When the two names disagree, Go 1.27.1's `net/http` uses `NO_PROXY` and the other 14 use `no_proxy`. An empty lowercase variable splits the clients 6 to 9. curl, Go, requests and Node's `http` client treat it as unset and fall back to `NO_PROXY`. The other nine treat it as an empty list. [node#66202](https://github.com/nodejs/node/issues/66202), opened on 22 September 2026 against a pre-release build, describes this split between `fetch()` and `http.request()`. The lab reproduced it on released Node 26.10.0 and 24.21.0. Go's precedence is changing. golang.org/x/net [commit a02ddfa7ea](https://github.com/golang/net/commit/a02ddfa7eacb4cf63a5bea6b23761244a6df69f6), made for [golang/go#79656](https://github.com/golang/go/issues/79656) and released in x/net v0.58.0, makes the `httpproxy` package prefer the lowercase names, and the [Go 1.28 release-note draft](https://github.com/golang/go/blob/1c3a1bac8b14c866d70b330e0229e5555670f577/doc/next/6-stdlib/99-minor/net/http/79656.md) lists the same change for `ProxyFromEnvironment`. In a separate check, x/net v0.58.0 and v0.59.0 already followed `no_proxy` in the conflicting case. Go still skips empty values, so its empty-variable results do not change. The proxy variable has the same trap. With `http_proxy=""` and `HTTP_PROXY` set, only Go, Node 26 http and Node 24 http used the proxy; the other 12 went direct. curl reads `http_proxy` only in lowercase. Give both names the same value, and remove a variable with `unset` rather than exporting it empty. ## localhost, 127.0.0.1 and ::1: only Go skips the proxy on its own With no NO_PROXY at all, Go went direct for `127.0.0.1`, `localhost` and `[::1]`. Its [httpproxy package](https://pkg.go.dev/golang.org/x/net/http/httpproxy#Config.ProxyFunc) documents that localhost and loopback addresses never use a proxy. The other 14 clients sent all three to the proxy. With a remote proxy configured, those clients would therefore send a request for a local development server to that proxy unless loopback is listed. | Value | `127.0.0.1` and `localhost` | `[::1]` | |---|---|---| | `localhost,127.0.0.1,::1` | Bypassed in all 15 (Go: built-in loopback rule) | Bypassed in 12 (Go: built-in loopback rule); urllib, Node 24 fetch and undici 7.29.1 used the proxy | | `localhost,127.0.0.1,[::1]` | httpx and httpx2 raised an error; 13 bypassed (Go: built-in loopback rule) | Bypassed in urllib, Node 26 fetch, Node 24 fetch, undici 7.29.1 and 8.11.0, and in Go by its built-in loopback rule; httpx and httpx2 raised an error; 7 used the proxy | Go's bypasses in this table come from its built-in rule, not from the list, so they do not show that `[::1]` works as an entry in Go; in the main matrix Go used the proxy for the bracketed entry `[2001:db8::10]`. List `localhost,127.0.0.1`. Add a bare `::1` if you use IPv6 loopback, and never `[::1]`. ## Does HTTPS through CONNECT get the same bypass decision? Yes, in this run. For each of 8 HTTPS URLs, every client made the same choice as for the matching HTTP URL, 120 of 120 comparisons. Every proxied HTTPS request arrived at the proxy as `CONNECT`. ## Node.js: NO_PROXY not working with fetch or http.request Four separate things can make NO_PROXY look broken in Node. The explicit `ProxyAgent` case comes from undici's documentation and was not tested; the other three are lab results. **The opt-in.** Without `NODE_USE_ENV_PROXY=1` or `--use-env-proxy` ([docs](https://nodejs.org/docs/v26.10.0/api/cli.html#node_use_env_proxy1)), Node 26 and 24 `fetch()` and `http.get()` ignored the proxy variables and went direct in all 36 control cells. The [Node fetch guide](https://ipvolt.com/guides/fix-node-fetch-failed-proxy) covers that failure. **An explicit `ProxyAgent`.** undici's documentation describes a `ProxyAgent` as routing every request through its proxy and mentions no bypass list; reading `no_proxy` and `NO_PROXY` is what `EnvHttpProxyAgent` adds (undici 8.11.0 docs for [ProxyAgent](https://github.com/nodejs/undici/blob/v8.11.0/docs/docs/api/ProxyAgent.md) and [EnvHttpProxyAgent](https://github.com/nodejs/undici/blob/v8.11.0/docs/docs/api/EnvHttpProxyAgent.md)). Code that passes a `ProxyAgent` as the `dispatcher`, as the [Node.js fetch proxy setup guide](https://ipvolt.com/guides/nodejs-fetch-proxy) does, therefore ignores NO_PROXY. To keep a bypass list, use `new EnvHttpProxyAgent()`, which reads the variables or takes `httpProxy`, `httpsProxy` and `noProxy` options. **Two matchers in the same runtime.** `http.request()` uses Node's own matcher, and built-in `fetch()` uses undici's `EnvHttpProxyAgent`. They disagreed on 20 of 72 non-baseline rows on Node 26.10.0 and on 19 of 72 on Node 24.21.0. Node's matcher carries the comment `TODO(joyeecheung): share code with undici.` ([source](https://github.com/nodejs/node/blob/v26.10.0/lib/internal/http.js)), and sharing that code is still an open item in the tracking issue [node#57872](https://github.com/nodejs/node/issues/57872). **Bundled vs npm undici.** On Node 26.10.0, built-in `fetch()` (undici 8.10.2) and npm undici 8.11.0 differed on 4 rows, all wildcard cases. Node 24.21.0 `fetch()` and npm undici 7.29.1 did not differ at all. undici 7.29.1 and 8.11.0 differed on 11 rows. The table below shows one row for each kind of difference on Node 26.10.0, using the values from the sections above. The other 12 of the 20 differing rows repeat these kinds for other hosts and requests, plus the `http_proxy=""` case. | Difference | fetch | http | undici 8.11.0 | |---|---|---|---| | Bare domain, subdomain request | Bypassed | Proxy | Bypassed | | `*.example.test`, apex request | Bypassed | Proxy | Proxy | | `*` inside a list | Proxy | Bypassed | Bypassed | | Bracketed IPv6 address | Bypassed | Proxy | Bypassed | | Leading dot with a port | Bypassed | Proxy | Bypassed | | Trailing-dot entry | Bypassed | Proxy | Bypassed | | Spaces instead of commas | Bypassed | Proxy | Bypassed | | Empty `no_proxy`, `NO_PROXY` set | Proxy | Bypassed | Proxy | Node 24.21.0 showed the same pattern, with two exceptions. For the trailing dot, both of its clients used the proxy. For a bare IPv6 entry, only `http` bypassed it. A [2026-09-01 comment on node#57872](https://github.com/nodejs/node/issues/57872#issuecomment-5495669370) already compared `node:http` with `fetch()` on a v27.0.0 pre-release build. The lab's Node rows agree with all 8 rows of that table that it could compare. ## What GitLab found in 2021, and what changed GitLab's [2021 post by Stan Hu](https://about.gitlab.com/blog/we-need-to-talk-no-proxy/), with research by Nourdin el Bacha, compared curl, wget, Ruby, Python, Go and Java from their source code and documentation. It recommended a lowest common denominator and proposed a standard. Of the 32 cells in its no_proxy table that this lab could check (8 rows for curl, wget, Python via urllib and Go), 31 still match. The exception is curl and CIDR: the 2021 table says no, but both curl builds honored it here. Go's "Uppercase" precedence cell still matches Go 1.27.1 and is due to change in Go 1.28. The lab could not check the rows "Supports regexes?" and "Resolves IP addresses?"; the second marks Go "Yes", but the post's own text says only Ruby resolves host names, and Go 1.27.1's source does not. Ruby and Java were not tested. Its lowest-common-denominator advice holds up only in part. A lowercase-only `no_proxy`, commas and exact IPv4 addresses worked in all 15 clients, a leading dot still missed the apex in 4, as the post warned, and only 4 honored IPv4 CIDR, so avoiding CIDR is still sound. "Suffixes are always matched" failed in Node's `http` client, "comma-separated hostname:port values" matched in only 9 to 11 clients per entry (8 matched all three), and no IPv6 form agreed. Several of these behaviors are recent. Requests 2.34.0 (11 May 2026) added the label boundary. httpx2 2.5.0 (25 June 2026) stopped crashing on IPv6 CIDR entries without matching them. undici 8.10.0, 8.10.1 and 8.11.0 (August and September 2026) added bare IPv6, trailing dots and the new wildcard rules. ## How the test works, and how to rerun it A small HTTP proxy on 127.0.0.1 logged every absolute-form request and every `CONNECT`, answered it itself and forwarded nothing. Each request ran in its own process under macOS `sandbox-exec`, with a profile that denies all outbound traffic except loopback, so a direct attempt failed on the machine and reached no real host. A cell counts as proxied only when the proxy logged its request; whether the client got a response never decided anything. With no NO_PROXY set, all 15 clients proxied every URL shape. The published run, on 23 September 2026 from 19:13 to 19:15 UTC, has 1,266 cells. A clean rerun that followed the steps below from the published archive classified all 1,266 cells identically. To read the published matrix without running anything, extract the archive and run `python3 no_proxy_lab.py table results.json`. It needs no setup or network, and it printed the same output on Python 3.9.6 as on 3.14.7. A full rerun needs macOS, Python 3.14 and Go, about 700 MB of disk, and access to nodejs.org, pypi.org and registry.npmjs.org during `setup`, which installs nothing system-wide: ```sh curl -fLO https://ipvolt.com/downloads/no-proxy-matching-tested/no-proxy-matching-tested.zip unzip no-proxy-matching-tested.zip cd no-proxy-matching-tested python3.14 no_proxy_lab.py setup --work ./work python3.14 no_proxy_lab.py run --work ./work --out ./out python3.14 no_proxy_lab.py compare results.json out/results.json python3.14 no_proxy_lab.py table out/results.json --section main ``` `compare` exits 0 only when every cell has the same classification. The [README](https://ipvolt.com/downloads/no-proxy-matching-tested/README.md) explains its output with other client builds, how to test other versions or your own NO_PROXY value, the `--isolation none` mode for other systems, and every field of `results.json`. Downloads: - [no-proxy-matching-tested.zip](https://ipvolt.com/downloads/no-proxy-matching-tested/no-proxy-matching-tested.zip): every file below, with `clients/` in place (recreate it if you download files one at a time) - [README.md](https://ipvolt.com/downloads/no-proxy-matching-tested/README.md): method, requirements, commands and how to read the results - [results.json](https://ipvolt.com/downloads/no-proxy-matching-tested/results.json) and [results.csv](https://ipvolt.com/downloads/no-proxy-matching-tested/results.csv): every cell of the published run - [no_proxy_lab.py](https://ipvolt.com/downloads/no-proxy-matching-tested/no_proxy_lab.py), [clients/py_client.py](https://ipvolt.com/downloads/no-proxy-matching-tested/clients/py_client.py), [clients/node_client.cjs](https://ipvolt.com/downloads/no-proxy-matching-tested/clients/node_client.cjs), [clients/go_client.go](https://ipvolt.com/downloads/no-proxy-matching-tested/clients/go_client.go) and [nonet.sb](https://ipvolt.com/downloads/no-proxy-matching-tested/nonet.sb): the harness, the one-request clients and the loopback-only sandbox profile - [requirements.txt](https://ipvolt.com/downloads/no-proxy-matching-tested/requirements.txt), [package.json](https://ipvolt.com/downloads/no-proxy-matching-tested/package.json) and [package-lock.json](https://ipvolt.com/downloads/no-proxy-matching-tested/package-lock.json): exact Python and npm pins ## Limits - One macOS 15.7.4 arm64 machine, one date and the versions above. Any release can change a row: Node 26.10.0 does not yet bundle undici 8.11.0, and Go 1.28 is due to change the conflicting-variable row. - Linux was not tested. Each client matches NO_PROXY in its own code or its language's standard library, and with the proxy variables set, Python's urllib takes the [same environment path](https://github.com/python/cpython/blob/v3.14.7/Lib/urllib/request.py) on macOS as on Linux. On Linux the rows should therefore follow the client version rather than the operating system. That is an inference from the source code, not a Linux result; the README gives examples. - The matrix tested only environment-variable handling, with the settings listed above, and only HTTP forward proxying. It did not test explicit proxy options, other agents or dispatchers, system proxy settings, Windows, SOCKS, PAC files, redirects or proxy authentication. For a 407 response, see [how to fix proxy error 407](https://ipvolt.com/guides/fix-proxy-error-407). - Dash ranges, partial addresses such as `192.168.*`, entries that depend on DNS resolution, and Ruby, Java, .NET, Deno and Bun were not tested; the README lists the rest. - The two one-off checks above ran on 24 September 2026 with the same harness and clients. They are not in `results.json`; the README shows how to rerun them. ipvolt ran these checks locally on 23 and 24 September 2026 with the client versions listed above. No external provider, proxy service or network was tested, and nothing here describes ipvolt's own service. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources - [GitLab (2021): We need to talk: Can we standardize NO_PROXY?](https://about.gitlab.com/blog/we-need-to-talk-no-proxy/) - [nodejs/node#57872: node:http vs fetch() NO_PROXY table (comment, 2026-09-01)](https://github.com/nodejs/node/issues/57872#issuecomment-5495669370) - [nodejs/node#65616: NO_PROXY=example.com and http.request() subdomains](https://github.com/nodejs/node/issues/65616) - [nodejs/node#65617: http: match subdomains for plain NO_PROXY entries](https://github.com/nodejs/node/pull/65617) - [nodejs/node#66202: fetch() and http.request() with an empty lowercase variable](https://github.com/nodejs/node/issues/66202) - [Node.js 26.10.0 docs: NO_PROXY format](https://nodejs.org/docs/v26.10.0/api/http.html#no_proxy-format) - [Node.js 26.10.0 docs: NODE_USE_ENV_PROXY](https://nodejs.org/docs/v26.10.0/api/cli.html#node_use_env_proxy1) - [Node.js 26.10.0 source: lib/internal/http.js (http.request matcher)](https://github.com/nodejs/node/blob/v26.10.0/lib/internal/http.js) - [Node.js 26.10.0: bundled undici version](https://github.com/nodejs/node/blob/v26.10.0/deps/undici/src/package.json) - [undici PR #5777: NO_PROXY wildcard semantics](https://github.com/nodejs/undici/pull/5777) - [undici v8.11.0 release notes](https://github.com/nodejs/undici/releases/tag/v8.11.0) - [undici PR #5623: match bare IPv6 addresses in no_proxy](https://github.com/nodejs/undici/pull/5623) - [undici PR #5637: ignore trailing dots when matching no_proxy](https://github.com/nodejs/undici/pull/5637) - [undici v8.11.0 docs: ProxyAgent](https://github.com/nodejs/undici/blob/v8.11.0/docs/docs/api/ProxyAgent.md) - [undici v8.11.0 docs: EnvHttpProxyAgent](https://github.com/nodejs/undici/blob/v8.11.0/docs/docs/api/EnvHttpProxyAgent.md) - [libcurl: CURLOPT_NOPROXY](https://curl.se/libcurl/c/CURLOPT_NOPROXY.html) - [curl changelog](https://curl.se/changes.html) - [curl#19828: IPv6 CIDR notation in NO_PROXY (fixed in 8.18.0)](https://github.com/curl/curl/pull/19828) - [Go: golang.org/x/net/http/httpproxy Config](https://pkg.go.dev/golang.org/x/net/http/httpproxy#Config) - [Go: httpproxy Config.ProxyFunc (localhost and loopback)](https://pkg.go.dev/golang.org/x/net/http/httpproxy#Config.ProxyFunc) - [golang.org/x/net commit a02ddfa7ea: httpproxy prefers lowercase proxy variables (x/net v0.58.0)](https://github.com/golang/net/commit/a02ddfa7eacb4cf63a5bea6b23761244a6df69f6) - [golang/go#79656: inconsistent HTTP_PROXY precedence (milestone Go 1.28)](https://github.com/golang/go/issues/79656) - [Go 1.28 release-note draft: ProxyFromEnvironment prefers lowercase variables](https://github.com/golang/go/blob/1c3a1bac8b14c866d70b330e0229e5555670f577/doc/next/6-stdlib/99-minor/net/http/79656.md) - [GNU Wget manual: Proxies](https://www.gnu.org/software/wget/manual/wget.html#Proxies) - [Python 3.14 docs: urllib.request](https://docs.python.org/3.14/library/urllib.request.html) - [CPython 3.14.7 source: Lib/urllib/request.py (proxy_bypass by platform)](https://github.com/python/cpython/blob/v3.14.7/Lib/urllib/request.py) - [Requests v2.34.0 release notes](https://github.com/psf/requests/releases/tag/v2.34.0) - [Requests v2.34.2 source: utils.py (should_bypass_proxies)](https://github.com/psf/requests/blob/v2.34.2/src/requests/utils.py) - [Requests PR #7586: honor ports in IPv4 no_proxy entries](https://github.com/psf/requests/pull/7586) - [httpx2 changelog (v2.13.1)](https://github.com/pydantic/httpx2/blob/v2.13.1/src/httpx2/CHANGELOG.md) - [httpx2 PR #1165: support IP CIDR ranges in NO_PROXY](https://github.com/pydantic/httpx2/pull/1165) - [aiohttp docs: proxy support and trust_env](https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support) - [aiohttp v3.14.3 source: helpers.py](https://github.com/aio-libs/aiohttp/blob/v3.14.3/aiohttp/helpers.py) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [Check a Proxy for IP, DNS and WebRTC Leaks with ToDetect](https://ipvolt.com/blog/proxy-leak-check-todetect.md) (Analysis, Oct 23, 2026, 9 min read): Check a browser proxy for IP, DNS, WebRTC and time zone leaks with ToDetect's free tools, using measured results from a 4G mobile line as the worked example. - [Python 3.15 for Web Scraping: What Installs, What Breaks](https://ipvolt.com/blog/python-3-15-web-scraping.md) (Analysis, Oct 16, 2026, 8 min read): pip install scrapy fails on Python 3.15 without a C compiler: brotli has no cp315 wheel. We tested 19 scraping packages with pip and uv to see what else breaks. - [Japanese price parsing: yen, width and tax labels](https://ipvolt.com/blog/japanese-price-parsing.md) (Analysis, Oct 6, 2026, 6 min read): Parse Japanese price fields without losing currency or tax basis. Run a tested Python fixture for fullwidth yen, mixed prices and deliberate review cases. ## Related guides - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md): Diagnose HTTP_PROXY, HTTPS_PROXY, ALL_PROXY and NO_PROXY routing differences in curl, Python Requests and Node.js with an isolated local check. - [Fix Node.js TypeError: fetch failed behind a proxy](https://ipvolt.com/guides/fix-node-fetch-failed-proxy.md): TypeError: fetch failed hides the real error in err.cause. Find yours: ENOTFOUND, UND_ERR_CONNECT_TIMEOUT, invalid onError method or a proxy 403/407/502. - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md): How to use a proxy with curl: the -x flag, http_proxy and https_proxy variables, SOCKS5 with socks5h, proxy authentication, and reading CONNECT and 407 errors. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 125 of 138: Multiple Meta Ad Accounts: An Agency Setup Checklist URL: https://ipvolt.com/blog/manage-multiple-meta-ad-accounts Markdown: https://ipvolt.com/blog/manage-multiple-meta-ad-accounts.md # Multiple Meta Ad Accounts: An Agency Setup Checklist Source: https://ipvolt.com/blog/manage-multiple-meta-ad-accounts Markdown: https://ipvolt.com/blog/manage-multiple-meta-ad-accounts.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / Multiple Meta Ad Accounts: An Agency Setup Checklist Category: Analysis Published: 2026-09-19 Updated: 2026-09-19 Author: ipvolt Reading time: 6 minutes Tags: proxies, choosing Manage multiple Meta ad accounts with a client access record, clear team responsibilities and a checklist for access errors, security incidents and routing. To manage multiple Meta ad accounts, start with a record of each client's assets, authorized operators and decision-makers. Then organize the browser workspace and decide whether any separate network requirement exists. When something fails, identify whether it is an access problem, a wrong account selection, a security incident or a restriction before changing the setup. This checklist is for agencies managing clients' accounts with their authorization. It gives you a reusable private client record and a way to assign the next action when an operator cannot continue. ## Agree on client control before configuring tools For each engagement, agree who should control the assets, who approves spending and who handles recovery. Our recommendation is to preserve the client's intended control and give agency operators the access needed for their work. Settle this before creating assets: a plan to “sort out ownership later” leaves an important decision unresolved. Meta's business-portfolio training covers accounts, users and permissions, and its Marketing API documentation describes ad accounts managed by multiple people with different access levels. Those are useful starting points for organizing the relationship. The checklist below is our recommended operating record, rather than an official Meta form. [Meta Blueprint portfolio course](https://www.facebookblueprint.com/student/collection/606095/path/607467), [Meta Marketing API documentation](https://www.postman.com/meta/facebook-marketing-api/documentation/0zr4mes/facebook-marketing-api-mapi). Copy this record into your private project system for each client: - **Client and business owner:** - **Business portfolio ID and ad account ID:** - **Supporting assets needed for this job:** Page, Instagram account, dataset or catalog IDs, as applicable. - **Client access and recovery owner, plus backup contact:** - **Agency business ID:** - **Named operators and approved tasks:** - **Billing decision-maker:** - **Reporting app owner, approved permissions and removal procedure:** - **Device or workspace label; network owner if relevant:** - **Access checked on:** date and person who checked it. - **Offboarding owner and target date:** Keep passwords, API tokens, recovery codes and payment-card numbers out of this record. Asset IDs and business contact details still belong in a system with appropriate internal access controls. Before campaign work begins, have the assigned operator compare the intended ad account ID with the account actually selected and confirm that the required action is available. If the client has no existing setup, agree the record's ownership and billing fields first, then inspect the creation options available in Meta. This checklist assumes no universal account limit. ## Make the working context easy to recognize Use a consistent client label in the work ticket and browser workspace. Before changing a campaign or budget, compare the selected account with the ticket. A recognizable name helps; the account ID gives you a specific value to check when names are similar. Chrome profiles can separate bookmarks, history, passwords and settings. They are useful organizational tools, but Google warns that someone with access to the device can switch into another profile. Treat a browser profile as a workspace, not a replacement for device access controls. [Google's Chrome profile guidance](https://support.google.com/chrome/answer/2364824?hl=en). Secure the identities and devices used to administer the accounts. Meta recommends two-factor authentication, login alerts and reviewing sessions. Its business-malware report also describes attacks on personal accounts connected to advertising assets, including malware that can evade 2FA. Keep device security in the plan alongside authentication. [Meta's business malware guidance](https://about.fb.com/news/2023/05/how-meta-protects-businesses-from-malware/). For reporting automation, keep a separate app-access entry in the client record. Meta's Marketing API has its own app, access-token and permission requirements; an existing browser login does not establish that authorization. Identify who owns the app, what it needs to do and who removes access when the engagement ends. [Meta Marketing API documentation](https://www.postman.com/meta/facebook-marketing-api/documentation/0zr4mes/facebook-marketing-api-mapi). ## Decide whether a network change has a purpose [VoidMob's guide to running multiple Meta ad accounts in 2026](https://voidmob.com/blog/run-multiple-meta-ad-accounts-2026) presents a vendor perspective on account organization and technical isolation, including separate browser and mobile-network setups. It is useful context when comparing those workflows. For an agency implementation, first write down the specific problem a network change is supposed to solve. A missing account assignment, for example, belongs with the person who grants access. A documented, authorized network-testing requirement belongs with the technical owner. An IP check can help describe a route; it does not demonstrate that the operator has permission to manage a client's assets. Also distinguish a separate device from an exclusive public address. Carrier-grade NAT can share public IPv4 addresses among subscribers, so dedicated hardware alone is insufficient evidence of exclusive public IPv4 use. This says nothing about how Meta will assess a particular account. [IETF RFC 6888](https://www.rfc-editor.org/rfc/rfc6888.txt). If a route requirement exists, define the intended destination, continuity requirement and failure evidence before selecting infrastructure. Our [rotating versus sticky proxy guide](https://ipvolt.com/guides/rotating-vs-sticky-proxies) explains the session-continuity distinction. For a chosen browser implementation, the [MostLogin proxy setup guide](https://ipvolt.com/blog/mostlogin-proxy-setup) covers configuration. Neither is a prerequisite for completing the client access record. ## Route problems to the person who can act Use this table as a proposed first-response workflow. It helps collect evidence and assign responsibility; it does not diagnose every cause, and several faults can coexist. | Situation | First evidence to record | Owner and next action | Stop condition | | --- | --- | --- | --- | | Agreed client ad account is missing | Intended asset ID, signed-in identity, assigned tasks and exact error | Client access owner and agency lead compare the requested asset with the actual grant | Ownership or authorization remains unclear | | Browser shows another client | Selected account ID compared with the work ticket | Operator selects and rechecks the intended account; labels the workspace | Identity or account still does not match | | Unknown administrator or unexpected spend | Time, affected asset, unrecognized change and device/session evidence | Client security owner secures the identity/device, checks reachable assets and uses official recovery | Device may remain compromised; pause routine administration | | Restriction notice appears | Exact notice, affected asset, time and any review option shown | Client owner or authorized reviewer follows the notice and records the review | Cause remains unresolved; no replacement-account workaround | | Network error without a restriction notice | Error text, time, configured route and service reachability | IT/network owner diagnoses transport separately from asset permissions | No evidence connects the route to the failure; avoid claiming it does | The security row applies Meta's guidance above. The remaining routing choices are our operational recommendations. Follow the actual notice and available controls rather than assuming every restriction has the same review path or outcome. ## Worked example: one analyst, two clients Imagine fictional clients Cedar Bikes and Harbor Home. One agency analyst serves both. Cedar's ad account is visible; Harbor's is absent from the account selector. The next step is to compare Harbor's recorded account ID and approved tasks with the analyst's actual assignment. The authorized client access owner can then correct an incomplete grant. Until that check is complete, pause Harbor's campaign work. This observation alone gives no reason to buy a proxy or create another account. Now change the premise: Harbor is visible, but an administrator nobody recognizes has appeared. That belongs in the security row. Escalate to Harbor's recovery owner and secure the affected identity and device. Renaming the browser workspace would leave the incident unresolved. At offboarding, use the same record to remove the departing operator's or agency's approved access and any app credentials under your control, then verify that the client's designated owner retains access. Clear local working data according to the engagement's retention agreement. Record who completed the handoff and when. *Method: ipvolt prepared this checklist from Meta and vendor documentation and a fictional worked example. No Meta account, proxy, browser profile or device was tested, and nothing here describes how Meta assesses a particular account.* If future authorized work requires residential proxies, ipvolt sells them from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources - [Meta Blueprint: business portfolio, users and permissions](https://www.facebookblueprint.com/student/collection/606095/path/607467) - [Meta Marketing API documentation](https://www.postman.com/meta/facebook-marketing-api/documentation/0zr4mes/facebook-marketing-api-mapi) - [Google Chrome Help: share Chrome with others using profiles](https://support.google.com/chrome/answer/2364824?hl=en) - [Meta Newsroom: how Meta protects businesses from malware (2023)](https://about.fb.com/news/2023/05/how-meta-protects-businesses-from-malware/) - [IETF RFC 6888: common requirements for carrier-grade NATs](https://www.rfc-editor.org/rfc/rfc6888.txt) - [VoidMob: running multiple Meta ad accounts in 2026 (vendor perspective)](https://voidmob.com/blog/run-multiple-meta-ad-accounts-2026) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [How to Check if a Proxy Is Really Mobile or Residential](https://ipvolt.com/blog/check-if-proxy-is-mobile-or-residential.md) (Analysis, Nov 8, 2026, 12 min read): No single check proves a proxy is mobile or residential. We tested ASN, RDAP, PeeringDB, reverse DNS and IP databases on a mobile line and a datacenter IP. - [How Many GB of Proxies Do You Need? Pages per GB, Measured](https://ipvolt.com/blog/how-many-gb-of-proxies-do-i-need.md) (Benchmark, Oct 5, 2026, 8 min read): We loaded 34 public pages three ways through a metering proxy. 1 GB fits about 44,000 HTML-only fetches, or about 900 full Playwright page loads. - [Unlimited residential proxies: what they cost per GB](https://ipvolt.com/blog/unlimited-residential-proxies-cost-per-gb.md) (Comparison, Sep 27, 2026, 18 min read): Turn Mbps- and thread-based unlimited residential proxy plans into cost per GB, find the break-even with your per-GB rate, and check terms before you pay. ## Related guides - [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md): Choose rotation around the smallest complete workflow, distinguish exit affinity from cookies, and test what happens when a sticky session ends early. - [Configure a proxy in Playwright](https://ipvolt.com/guides/playwright-proxy-setup.md): Set an authenticated HTTP proxy for a Playwright browser context, keep test state isolated, and diagnose navigation separately from subresources. - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md): How to use a proxy with curl: the -x flag, http_proxy and https_proxy variables, SOCKS5 with socks5h, proxy authentication, and reading CONNECT and 407 errors. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 126 of 138: AI agent proxies and compute: choose by responsibility URL: https://ipvolt.com/blog/ai-agent-proxies-and-compute Markdown: https://ipvolt.com/blog/ai-agent-proxies-and-compute.md # AI agent proxies and compute: choose by responsibility Source: https://ipvolt.com/blog/ai-agent-proxies-and-compute Markdown: https://ipvolt.com/blog/ai-agent-proxies-and-compute.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / AI agent proxies and compute: choose by responsibility Category: Analysis Published: 2026-09-17 Updated: 2026-09-19 Author: ipvolt Reading time: 6 minutes Tags: proxies, choosing Map an AI agent's retrieval, runtime and model requirements before choosing services, with a release-note monitoring example and editable worksheet. Choose services from the job your agent must finish. For a release-note monitoring assistant, a proxy route helps with retrieval, while a model endpoint supplies inference. Scheduling the checks, running tools and saving reports still need an application runtime with an owner. Here, **proxy means an HTTP forward proxy for web requests**; an LLM API gateway that routes model calls is a different interface. HTTP defines the forward proxy as an intermediary selected by the client to forward requests. [HTTP intermediary semantics](https://www.rfc-editor.org/rfc/rfc9110.html#section-3.7) The example below is a hypothetical design for an internal assistant that reads permitted release-note pages and saves a source-linked change report. Use it to identify the missing capability before evaluating a proxy service or managed compute rental. For a filled example, assume a team checks six allowlisted public release-note pages daily. These are fictional requirements, not observations from a deployed monitor: - **Already working:** a team-managed runtime, scheduler, HTTP retriever and report store. Direct retrieval returns the intended text, and the application detects changed pages. - **Missing:** a model to summarize the changed text. The application will check the summary against its sources before saving it. - **Required model interface:** text messages in, text response out. The application does not require native tool calls, images, embeddings or a `response_format` field. - **Failure policy:** preserve an unsuccessful run for follow-up. The team still needs to evaluate model quality, context limits, data handling and availability against its operating requirements. This record gives us a specific choice to make: evaluate the missing summarization endpoint while retaining the working application components. ## Give every requirement an owner Start with the result: an accepted report must describe a source change, identify its source and be saved where the team can retrieve it. Then assign the work needed to reach that result. | Requirement | Component responsible | Evidence of completion | | --- | --- | --- | | Start each scheduled check | Application scheduler and runtime | Run ID, start time, deadline and final status | | Retrieve the intended source | HTTP client or browser; proxy where the route requires one | Intended URL, retrieval time and accepted page content | | Execute a browser or script | Your process, container or a purchased hosted runtime | The required tool actually runs through the supported interface | | Summarize accepted text | Inference adapter and model endpoint | Complete response whose claims match the source | | Support native tool calls if your framework needs them | Compatible model endpoint plus a tool executor | Required tool-call and result flow completes | | Produce machine-readable output if required | Supported output constraints or an explicit validation path | Valid output accepted; malformed output rejected | | Save the report | Application storage and output validator | Report ID, source references and validation outcome | A component may cover several rows. The table's purpose is to expose requirements that no selected service covers. A working model response completes only part of this job. ## Follow one monitoring run through its failure points For this assistant, first choose an allowlist of release-note URLs and the intended check interval. Use a suitable source API or feed where available; otherwise choose an HTTP client or browser for the pages you are permitted to retrieve. A proxy belongs in this design when a specific network-route requirement calls for it. Next, retain the source URL, retrieval time and accepted text. A challenge page, login screen or error message should create a retrieval failure. Sending that content to a capable model does not establish what the release notes said. When the challenge comes from Cloudflare, [Cloudflare AI agent blocks: what to fix first](/blog/cloudflare-ai-agent-proxy-setup) explains which layer to fix before changing the proxy. Compare the accepted text with the previous accepted snapshot. If it is unchanged, record a completed check with no update. If it changed, pass the relevant text to the summarization stage, then check the returned claims and source links before saving the report. That leaves three useful outcomes: **source unchanged, report saved, or run failed at a named stage**. A model error belongs to the inference stage. A valid summary that could not be saved belongs to the storage stage. Keep those outcomes separate so a failed report does not automatically become a reason to buy another proxy or switch models. For browser configuration details, see the [Playwright proxy setup guide](https://ipvolt.com/guides/playwright-proxy-setup). The [HTTP versus SOCKS5 guide](https://ipvolt.com/guides/http-vs-socks5-proxies) addresses the transport choice. ## Apply the requirements to Proxies.sx Proxies.sx provides a concrete example of why the interface matters. Its public documentation, checked on 17 September 2026, points to distinct starting points for proxy access, inference and compute operation. The [Proxies.sx proxy client portal](https://client.proxies.sx/) is the starting point for its proxy service. For our monitor, that is relevant to the retrieval row after you have identified a routing requirement. The [Proxies.sx compute overview](https://www.proxies.sx/compute) describes managed text inference on a dedicated Apple Silicon Mac for a 30-day rental. The customer receives a model API; shell access and a remote desktop are outside the documented rental. In this design, evaluate it for the summarization row, while assigning browser execution and scheduling elsewhere. The [compute technical reference](https://agents.proxies.sx/compute/) covers renters and Mac suppliers, including the supplier runtime and operating runbook. It explicitly separates compute nodes from proxy traffic and excludes renter access to arbitrary containers. Use it to check the service boundary, and keep proxy and inference configuration separate even when account access is shared. Framework compatibility is a separate decision. The [compute API guide](https://www.proxies.sx/compute/api) says requests using `tools` or `response_format` are rejected. If your framework depends on those fields, the documented endpoint is not a drop-in fit. Removing required fields does not preserve the workflow. A deliberately separate text-summarization stage, with tool execution and output validation in your application, is a different design to evaluate. Likewise, an MCP connection is not evidence that a model accepts native tool-calling fields. MCP defines how a host exchanges context with servers; the application still determines how to use that context and its models. Check both interfaces when they are part of your workflow. [MCP architecture](https://modelcontextprotocol.io/docs/learn/architecture) ## Choose the next component from the missing row For our filled example, keep the existing runtime, scheduler, retriever and report store. There is no unmet proxy-routing requirement. Evaluate a text-inference endpoint for the missing summarization stage. Proxies.sx's documented text interface is a candidate for that evaluation; this is a feature-fit conclusion, not a tested integration or purchasing recommendation. Change one premise and the decision changes: if the framework requires native `tools` or `response_format`, its documented rejection of those fields excludes it as a drop-in endpoint. Either choose a compatible endpoint or deliberately redesign the text-only stage and evaluate that different workflow. For another team whose inference already works but retrieval is the gap, investigate the source, client and route first. A compute rental does not follow from that requirement. If the missing row is a scheduled browser, arbitrary code execution or durable report storage, evaluate a runtime that explicitly exposes it. Name who will operate each remaining component before comparing service offers. [Download the editable infrastructure worksheet](https://ipvolt.com/downloads/ai-agent-proxies-and-compute/ai-agent-infrastructure-worksheet.md) and fill in your required interfaces, existing components, data handling and acceptance conditions. Before committing to a service, check its current availability and quote, then evaluate the complete workflow. Record retrieval, inference and output failures separately and keep failed runs in the total. A quick model response alone cannot tell you how often the assistant produces an accepted report by its deadline. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources - [HTTP intermediary semantics](https://www.rfc-editor.org/rfc/rfc9110.html#section-3.7) - [MCP architecture](https://modelcontextprotocol.io/docs/learn/architecture) - [Proxies.sx proxy portal](https://client.proxies.sx/) - [Proxies.sx compute overview](https://www.proxies.sx/compute) - [Proxies.sx compute technical reference](https://agents.proxies.sx/compute/) - [Proxies.sx compute API guide](https://www.proxies.sx/compute/api) - [ipvolt product status and consent](https://ipvolt.com/index.md) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [How to Check if a Proxy Is Really Mobile or Residential](https://ipvolt.com/blog/check-if-proxy-is-mobile-or-residential.md) (Analysis, Nov 8, 2026, 12 min read): No single check proves a proxy is mobile or residential. We tested ASN, RDAP, PeeringDB, reverse DNS and IP databases on a mobile line and a datacenter IP. - [How Many GB of Proxies Do You Need? Pages per GB, Measured](https://ipvolt.com/blog/how-many-gb-of-proxies-do-i-need.md) (Benchmark, Oct 5, 2026, 8 min read): We loaded 34 public pages three ways through a metering proxy. 1 GB fits about 44,000 HTML-only fetches, or about 900 full Playwright page loads. - [Unlimited residential proxies: what they cost per GB](https://ipvolt.com/blog/unlimited-residential-proxies-cost-per-gb.md) (Comparison, Sep 27, 2026, 18 min read): Turn Mbps- and thread-based unlimited residential proxy plans into cost per GB, find the break-even with your per-GB rate, and check terms before you pay. ## Related guides - [Configure a proxy in Playwright](https://ipvolt.com/guides/playwright-proxy-setup.md): Set an authenticated HTTP proxy for a Playwright browser context, keep test state isolated, and diagnose navigation separately from subresources. - [HTTP vs SOCKS5 proxies: choose by the connection](https://ipvolt.com/guides/http-vs-socks5-proxies.md): Compare HTTP CONNECT and SOCKS5, understand DNS placement and TLS boundaries, and select a protocol your actual client and provider support. - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md): How to use a proxy with curl: the -x flag, http_proxy and https_proxy variables, SOCKS5 with socks5h, proxy authentication, and reading CONNECT and 407 errors. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 127 of 138: MostLogin proxy setup guide: add, test and share proxies URL: https://ipvolt.com/blog/mostlogin-proxy-setup Markdown: https://ipvolt.com/blog/mostlogin-proxy-setup.md # MostLogin proxy setup guide: add, test and share proxies Source: https://ipvolt.com/blog/mostlogin-proxy-setup Markdown: https://ipvolt.com/blog/mostlogin-proxy-setup.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / MostLogin proxy setup guide: add, test and share proxies Category: Analysis Published: 2026-09-17 Updated: 2026-09-17 Author: ipvolt Reading time: 8 minutes Tags: proxies, troubleshooting Add a proxy to MostLogin profiles step by step: protocol, host and port, credentials, the IP check, team access, batch import and the mistakes that break it. MostLogin keeps proxies in one central list and assigns them to browser profiles from there, so a proxy is configured once and reused across as many profiles and team members as you allow. That is convenient, and it is also where most setup mistakes hide: a protocol picked by default, credentials that never reached the proxy, or a proxy that was tested on one machine and shared with a team on another. This walkthrough follows MostLogin's own help center and the current client (version 2.1.9 at the time of writing) from the first proxy to a shared, tested list. ![MostLogin Anti-detect Browser + Cloud Phone logo](/media/partners/mostlogin.svg) [MostLogin Anti-detect Browser + Cloud Phone](https://www.mostlogin.com/?invite-code=teoads1) is an antidetect browser for multi-account work, with isolated browser profiles that carry their own fingerprint, team sharing with role-based access, batch operations, an API, and a cloud phone product that runs Android in the cloud. Proxies are a first-class object in the client rather than a per-profile text field, which is why this guide exists. MostLogin lists proxy providers it works with on its [partners page](https://www.mostlogin.com/partners); nothing below depends on an ipvolt account. ## Where proxies live in MostLogin Open the client and click **Proxies** in the left sidebar (the location-pin icon). The page has four tabs at the top: ![MostLogin Proxies page in version 2.1.9: the Proxies, Dynamic IP proxy, Proxy provider hub and Free proxy giveaway tabs with the Add proxy button](/media/partners/mostlogin-proxies-page.png) - **Proxies**: your saved proxy list. Everything you add by hand or by import lands here and can be attached to profiles. - **Dynamic IP proxy**: proxies generated from a connected provider with a target location, for providers MostLogin integrates directly. - **Proxy provider hub**: the providers that can be connected for the dynamic tab. - **Free proxy giveaway**: partner traffic packages for paying MostLogin users, claimed through a one-click authorisation that creates an account on the partner's side. The list itself has one row per proxy with the protocol, `Host:Port`, the proxy server IP once it has been checked, who can use it (**Access**), tags and the edit and delete actions. Above the list sit **Add proxy**, **Batch ops** for actions on several selected rows, **Proxy server IP check** and a **Tags** filter. ## Add a proxy in MostLogin: the Basic form Click **Add proxy** and stay on the **Basic** tab. The form asks for the same five things every proxy provider gives you, plus MostLogin's own organisation fields: 1. **Proxy protocol.** The dropdown defaults to `socks5`; HTTP and HTTPS are the other options. Pick the one your provider's dashboard states for that gateway, not the default. An HTTP gateway addressed as SOCKS5 fails at the first connection. 2. **Host:Port.** The gateway hostname or IP in the first box, the port in the second. Both IPv4 and IPv6 are accepted. 3. **Account** and **Password.** Your proxy username and password, only if the gateway authenticates by credentials. Leave them empty for gateways that authorise your machine's IP instead. The eye icon shows the password so you can check for a stray space. 4. **Rotate URL.** Optional. If your provider gives you a link that rotates the exit IP when visited, paste it here; the **Rotate** button next to it triggers one rotation immediately so you can confirm it works. 5. **Check proxy server IP.** Press it before saving. MostLogin connects through the proxy and shows the detected IP and location, or an error. Then the organisation fields: **Access** is required and defaults to **Me**; **Tag** helps filtering later (a platform or client name works well); **Remark** takes up to 500 characters of notes. **Confirm** saves the proxy to the list. A note on pasting: in the **Global dynamic proxies** screen MostLogin auto-parses a full `host:port:user:password` string pasted into the Host field and fills the other boxes. In the basic form, enter the fields separately and keep an eye on the order your provider uses, because some dashboards print `user:password@host:port` and some print `host:port:user:password`. ## Pick the protocol and session type on purpose Two decisions you make in that form decide how the profile will behave for weeks. The protocol decides how the browser talks to the proxy. HTTP proxies tunnel HTTPS traffic with a `CONNECT` request; SOCKS5 forwards TCP without looking at it and can resolve hostnames remotely. Most providers expose both on different ports. If you are unsure which to choose, the [HTTP vs SOCKS5 guide](/guides/http-vs-socks5-proxies) explains what changes for DNS, authentication and error messages. The session type decides whether the exit IP stays the same. A profile that logs into an account and stays logged in usually wants a sticky session, where the provider keeps one exit for a defined time; a profile that only fetches public pages can rotate on every request. Providers encode this in the gateway port or in the username, so the same MostLogin form entry can represent either. The [rotating vs sticky guide](/guides/rotating-vs-sticky-proxies) covers how to plan the session around the smallest complete workflow, which for an antidetect profile means the whole login session. ## Test the MostLogin proxy before you assign it Use **Check proxy server IP** on every new proxy, and use it again after changing credentials. What the result tells you: - **An IP and location appear.** The gateway, port, protocol and credentials all work from this machine. Compare the location with what you bought. - **The check fails immediately.** Re-check the protocol dropdown first, then the port. A wrong protocol fails before authentication even happens. - **The check fails and your provider authenticates by IP.** The machine running MostLogin must be on the provider's allow-list. Team members on other networks will need their own entries or a switch to username and password. - **The check fails only with credentials filled in.** The proxy is answering `407 Proxy Authentication Required`. The [407 guide](/guides/fix-proxy-error-407) walks through the order to check: gateway, method, credential scope, encoding, then the client. A proxy that passes the check but shows the wrong country is not broken. It is the wrong product for the profile; fix the purchase, not the form. ## Assign proxies to profiles and share them with the team Once saved, the proxy is selectable when you create or edit a browser profile. Who can select it is governed by the **Access** column: - **Me**: only your account can view, select and edit the proxy. This is the default. - **Team view**: every team member can view and select it, but only you can edit the settings. - **Team edit**: every team member can view, select and edit it. MostLogin shows a confirmation dialog for this one because it hands full control to the whole team. Change access per row with the pencil icon in the Access column, or select several rows and use **Batch ops → Edit access** to switch many proxies at once. A practical pattern for teams: keep proxies at **Team view** so nobody edits shared credentials by accident, and reserve **Team edit** for a small operations group. ## Import many proxies into MostLogin at once Three routes exist for lists rather than single entries: - **Batch import.** Click the arrow next to **Add proxy** and choose **Batch import**, download MostLogin's template, fill one row per proxy in Excel or a CSV editor, upload it and confirm. The template fixes the column order, so the `host:port` versus `user:password` ordering problem from the basic form does not apply. - **API extraction.** The second tab of the **Add proxy** dialog takes an extraction link from providers that hand out proxies through an API, plus an extraction method that decides when a fresh IP is fetched. The **Extract** button tests the link before you save. - **Dynamic IP proxy.** For providers MostLogin integrates directly, the dynamic tab generates location-targeted proxies from your provider account without copying strings at all. MostLogin's own article names SX.ORG and Infatica as examples. Whichever route you use, the result lands in the same list with the same **Access**, **Tag** and **Remark** fields, so the sharing rules above still apply. ## Common MostLogin proxy errors and how to fix them - **Default protocol.** The form defaults to `socks5`. Providers that only publish HTTP gateways are common; the symptom is an instant failure on the IP check. - **Credentials in the wrong field.** The proxy password belongs in the proxy form, never in a website's login. Special characters in a password are fine here because the fields are separate; they only need percent-encoding when a tool wants a single URL. - **IP allow-listing on a shared list.** A proxy that authorises by source IP works on the machine that added it and fails for everyone else on the team. Shared proxies should use username and password. - **Sticky sessions that expired.** A profile that suddenly logs out after working for a while is often sitting on a sticky session that the provider ended. Check the provider's session length before changing anything in MostLogin. - **Proxy bypass rules.** MostLogin's settings include proxy bypass options. A bypassed domain leaves the profile through your real connection, which is rarely what an antidetect profile wants; review the list if one site sees a different IP than the check reported. - **Testing on one machine, running on another.** The IP check runs where the client runs. A cloud phone or a teammate's laptop is a different source network. ## Using ipvolt proxies in MostLogin ipvolt sells mobile proxies, which work over HTTP and SOCKS5, and residential proxies from $2.20/GB. A mobile proxy's endpoint and credentials appear in your ipvolt dashboard; enter them through the same **Basic** form described above. This post has no tested walkthrough of ipvolt proxies in MostLogin, so rely on **Check proxy server IP** to confirm yours connects. Everything on this page also works with whichever provider you already use, and the [guides library](/guides) covers the protocol, session and authentication questions that come up before a proxy ever reaches a browser profile. ## Sources - [MostLogin help center: How to add a new proxy?](https://help.mostlogin.com/articles/11659684-how-to-add-a-new-proxy) - [MostLogin help center: How to give proxy's access to team members?](https://help.mostlogin.com/articles/11659774-how-to-give-proxys-access-to-team-members) - [MostLogin help center: How to batch import proxies?](https://help.mostlogin.com/articles/11828307-how-to-batch-import-proxies) - [MostLogin help center: What is dynamic proxy and how to use it in MostLogin](https://help.mostlogin.com/articles/12973665-what-is-dynamic-proxy-and-how-to-use-it-in) - [MostLogin help center: Reward Center, free proxy traffic from partners](https://help.mostlogin.com/articles/14440621-reward-center-how-to-claim-free-proxy-traffic-from-partners) - [MostLogin: Anti-detect Browser & Cloud Phone (partner link)](https://www.mostlogin.com/?invite-code=teoads1) - [MostLogin partners page](https://www.mostlogin.com/partners) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [Check a Proxy for IP, DNS and WebRTC Leaks with ToDetect](https://ipvolt.com/blog/proxy-leak-check-todetect.md) (Analysis, Oct 23, 2026, 9 min read): Check a browser proxy for IP, DNS, WebRTC and time zone leaks with ToDetect's free tools, using measured results from a 4G mobile line as the worked example. - [Python 3.15 for Web Scraping: What Installs, What Breaks](https://ipvolt.com/blog/python-3-15-web-scraping.md) (Analysis, Oct 16, 2026, 8 min read): pip install scrapy fails on Python 3.15 without a C compiler: brotli has no cp315 wheel. We tested 19 scraping packages with pip and uv to see what else breaks. - [Japanese price parsing: yen, width and tax labels](https://ipvolt.com/blog/japanese-price-parsing.md) (Analysis, Oct 6, 2026, 6 min read): Parse Japanese price fields without losing currency or tax basis. Run a tested Python fixture for fullwidth yen, mixed prices and deliberate review cases. ## Related guides - [HTTP vs SOCKS5 proxies: choose by the connection](https://ipvolt.com/guides/http-vs-socks5-proxies.md): Compare HTTP CONNECT and SOCKS5, understand DNS placement and TLS boundaries, and select a protocol your actual client and provider support. - [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md): Choose rotation around the smallest complete workflow, distinguish exit affinity from cookies, and test what happens when a sticky session ends early. - [Fix proxy error 407 without guessing](https://ipvolt.com/guides/fix-proxy-error-407.md): Diagnose Proxy Authentication Required in a repeatable order: gateway, authentication method, credential encoding, account scope and client configuration. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 128 of 138: Amazon prices: your offer vs the Featured Offer URL: https://ipvolt.com/blog/amazon-offer-vs-featured-offer Markdown: https://ipvolt.com/blog/amazon-offer-vs-featured-offer.md # Amazon prices: your offer vs the Featured Offer Source: https://ipvolt.com/blog/amazon-offer-vs-featured-offer Markdown: https://ipvolt.com/blog/amazon-offer-vs-featured-offer.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / Amazon prices: your offer vs the Featured Offer Category: Analysis Published: 2026-09-16 Updated: 2026-09-19 Author: ipvolt Reading time: 6 minutes Tags: proxies, troubleshooting Compare your Amazon offer with the Featured Offer using matched context, known shipping and a tested offline model that preserves missing data. Before calculating a gap between your Amazon offer price and a Featured Offer price, establish that both observations describe the same product, marketplace and selected customer context. Keep the seller identity and price components attached to each observation. If shipping or the required offer is unknown, hold the comparison. This is a diagnostic for developers of authorized seller tools. The downloadable model makes that decision explicit before calculating a **pre-promotion item-plus-known-shipping subtotal**. All example records are synthetic. The fixed scope is US/USD, Consumer, New, one unit; there is no quantity field, so single-unit input is an assumption your adapter must enforce. ## A lower item price can produce a higher subtotal In the first synthetic case, your seller is `seller-A`. Both records use the same ASIN, `NON_PRIME` membership, representative location and shipping-service labels, with observation times 30 seconds apart: | Observation | Item | Known shipping | Subtotal | Seller | | --- | ---: | ---: | ---: | --- | | Your offer | $19.00 | $4.00 | $23.00 | `seller-A` | | Selected Featured Offer | $21.00 | $0.00 | $21.00 | `seller-B` | The model calculates `(19 + 4) - (21 + 0) = +2.00 USD`. Your item price is lower, but your defined subtotal is $2 higher. Positive output means your subtotal is higher; negative means lower. Known zero shipping is evidence; missing shipping cannot be replaced with zero. Currency is the same kind of evidence: [a matching number hid a currency mismatch](/blog/product-price-currency-validation) shows two amounts that agreed while their currencies did not. A second case gives both sellers a $20 item price and known $0 shipping. The gap is `0.00`, while `featured_is_own_seller` is `false`: the selected Featured Offer still belongs to `seller-B`. A third case changes that seller to `seller-A` and returns `true`. Price equality and seller identity answer separate questions. These results explain the supplied records. They do not explain why Amazon selected an offer or establish a price that will win. ## Select the response that answers your question The field name “price” is insufficient provenance. Choose the record by the question it answers: | Question | Appropriate evidence | Comparison role | | --- | --- | --- | | What offer does my seller/SKU report? | Requested `offers` from [getListingsItem](https://developer-docs.amazon/sp-api/reference/getlistingsitem), scoped to marketplace and offer type | Own-offer observation | | Which offer is featured for the selected segment? | `featuredBuyingOptions` from [getCompetitiveSummary](https://developer-docs.amazon/sp-api/reference/getcompetitivesummary), scoped to ASIN/marketplace | Featured-offer observation | | What are the lowest-priced offers? | Separate `lowestPricedOffers` data in the [retrieval guide](https://developer-docs.amazon/sp-api/docs/retrieve-featured-offers-batch-asins) | Different question; cannot substitute for featured data | | What external price reference is reported? | `CompetitivePrice` outside Japan; `CompetitivePriceThreshold` in Japan | External-retailer reference; see the [migration announcement](https://developer-docs.amazon/sp-api/changelog/update-product-pricing-api-v2022-05-01-returns-new-competitive-price-and-deprecates-competitivepricethreshold) | | What price might make my offer featured? | [Featured Offer Expected Price](https://developer-docs.amazon/sp-api/reference/getfeaturedofferexpectedpricebatch), or FOEP | Computed guidance, separate from an observed offer | FOEP describes a computed listing price before promotions. Amazon explicitly withholds a Featured Offer guarantee because competing offers and customer-specific fulfillment capabilities can affect selection. For the own side, request `offers` explicitly: `getListingsItem` defaults to `summaries`. Validate the seller/SKU request context and map the selected marketplace's SKU to the intended ASIN before joining competitive data. Select the applicable `B2C` offer and audience. The [Listings Items model](https://raw.githubusercontent.com/amzn/selling-partner-api-models/3659f96867bfc669aca7a524c2f95744ff0e4478/models/listings-items-api-model/listingsItems_2021-08-01.json) keeps these offer fields separate from the summary. That response alone does not supply all the shipping, membership and location context required by this model. Your adapter needs separately evidenced inputs for those fields. Until they are known, retain the own price but leave this subtotal comparison unresolved. ## Make comparability an explicit contract The model accepts normalized records, not raw Amazon responses. Its [complete cases file](https://ipvolt.com/downloads/amazon-offer-vs-featured-offer/cases.json) shows the exact shape. Each pair declares an `expected_own_seller_id` independently of both observations, then supplies source type, seller, ASIN, marketplace, currency, condition, customer type, membership, location, shipping service, timestamp and price components. Apply these checks before passing real observations into that shape: 1. **Validate the individual response.** A successful batch envelope does not establish every member's success. Check each member's status, body, ASIN, marketplace and requested dataset. Preserve failed, absent and incomplete observations. The [Pricing model](https://raw.githubusercontent.com/amzn/selling-partner-api-models/3659f96867bfc669aca7a524c2f95744ff0e4478/models/product-pricing-api-model/productPricing_2022-05-01.json) defines per-member status and optional datasets. 2. **Select the intended context.** Featured offers are segmented by membership and regional context. Optional `sampleLocation` represents a location within the segment, not an exact delivery quote for every shopper. Retain what the source actually establishes. 3. **Preserve unknown components.** Pricing `listingPrice` excludes shipping, Points and promotions; shipping options are optional estimates. The same model therefore cannot justify silently treating missing shipping as free. 4. **Keep the calculation narrow.** Amazon warns that returned promotions may omit active promotions. This subtotal excludes taxes, Amazon Points, coupon eligibility, complete promotion coverage and fulfillment quality. It is not a checkout total. [Promotion coverage](https://developer-docs.amazon/sp-api/docs/retrieve-featured-offers-batch-asins). The executable checks exact equality of normalized membership, location and service strings. Those are **trusted labels**, not proof of equivalent Amazon contexts. It also trusts the adapter's source, seller and product labels. Use `null` when context is unknown; two invented `unknown` strings would create false confidence. `US` and `STANDARD` are lab labels, not a raw marketplace ID or a claimed Amazon shipping-option value. ## Run the model and inspect the holds Extract the [complete comparison ZIP](https://ipvolt.com/downloads/amazon-offer-vs-featured-offer/amazon-offer-vs-featured-offer.zip), open a terminal in the directory containing `compare.py`, and run: ```sh python3 -B compare.py python3 -B compare.py --csv python3 -B -m unittest -v test_compare.py ``` No packages or account credentials are needed. The [README](https://ipvolt.com/downloads/amazon-offer-vs-featured-offer/README.md) documents the contract; [compare.py](https://ipvolt.com/downloads/amazon-offer-vs-featured-offer/compare.py) and the [test suite](https://ipvolt.com/downloads/amazon-offer-vs-featured-offer/test_compare.py) are individually inspectable. Compare stdout with the [recorded JSON](https://ipvolt.com/downloads/amazon-offer-vs-featured-offer/example-output.json) and [CSV matrix](https://ipvolt.com/downloads/amazon-offer-vs-featured-offer/example-matrix.csv). The 14 synthetic cases produce three comparisons and 11 holds under the default policy: | Cases | Result | Interpretation | | --- | --- | --- | | Lower item price, higher subtotal | Compare; `+2.00` | Defined own subtotal is higher | | Equal subtotals, different seller | Compare; `0.00`, seller flag `false` | Matching amount does not identify your seller | | Equal subtotals, same seller | Compare; `0.00`, seller flag `true` | Selected record identifies your seller | | Missing shipping; membership/location/currency mismatch; wrong own seller | Five holds | Resolve the missing evidence or incorrect join | | Failed or missing Featured Offer | Two holds | Preserve unavailable observations | | External reference, FOEP or lowest-price substitution | Three holds | Select featured-offer evidence | | Observations 360 seconds apart | One hold | Exceeds the default time-skew policy | A hold has no calculated subtotals or gap: JSON uses `null`, CSV uses empty cells. Invalid input instead stops the command with a nonzero exit. To experiment, edit a copy of `cases.json` and pass `--cases your-cases.json`; CSV is output, not an input format. The default maximum skew is **300 seconds, inclusive**, configurable with `--max-skew-seconds`. It checks the distance between observation times. It checks neither absolute age nor Amazon freshness: two equally old records can compare. Choose an evidence-age policy separately before using the result operationally. **Method:** ipvolt prepared this analysis with AI assistance, checked the primary sources and ran the offline model plus 14 passing tests on 16 September 2026 using CPython 3.14.7. Python 3.11+ is the source target; 3.11 was not exercised in that recorded run. No seller account, API response mapping or retail price collection was tested. For a mismatch between a submitted price and your own observed listing, use [Amazon listing updates: accepted is not live](https://ipvolt.com/blog/amazon-listing-update-reconciliation). To schedule durable refreshes after listing events, use the companion [SP-API notification guide](https://ipvolt.com/guides/amazon-listing-notifications). Keep this comparison's result attached to its two observations and stated subtotal basis before making a pricing decision. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources - [getListingsItem](https://developer-docs.amazon/sp-api/reference/getlistingsitem) - [Listings Items API 2021-08-01 model, pinned revision](https://raw.githubusercontent.com/amzn/selling-partner-api-models/3659f96867bfc669aca7a524c2f95744ff0e4478/models/listings-items-api-model/listingsItems_2021-08-01.json) - [getCompetitiveSummary](https://developer-docs.amazon/sp-api/reference/getcompetitivesummary) - [Retrieve featured offers for a batch of ASINs](https://developer-docs.amazon/sp-api/docs/retrieve-featured-offers-batch-asins) - [Product Pricing API 2022-05-01 model, pinned revision](https://raw.githubusercontent.com/amzn/selling-partner-api-models/3659f96867bfc669aca7a524c2f95744ff0e4478/models/product-pricing-api-model/productPricing_2022-05-01.json) - [Competitive-price migration and Japan exception](https://developer-docs.amazon/sp-api/changelog/update-product-pricing-api-v2022-05-01-returns-new-competitive-price-and-deprecates-competitivepricethreshold) - [getFeaturedOfferExpectedPriceBatch](https://developer-docs.amazon/sp-api/reference/getfeaturedofferexpectedpricebatch) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [Check a Proxy for IP, DNS and WebRTC Leaks with ToDetect](https://ipvolt.com/blog/proxy-leak-check-todetect.md) (Analysis, Oct 23, 2026, 9 min read): Check a browser proxy for IP, DNS, WebRTC and time zone leaks with ToDetect's free tools, using measured results from a 4G mobile line as the worked example. - [Python 3.15 for Web Scraping: What Installs, What Breaks](https://ipvolt.com/blog/python-3-15-web-scraping.md) (Analysis, Oct 16, 2026, 8 min read): pip install scrapy fails on Python 3.15 without a C compiler: brotli has no cp315 wheel. We tested 19 scraping packages with pip and uv to see what else breaks. - [Japanese price parsing: yen, width and tax labels](https://ipvolt.com/blog/japanese-price-parsing.md) (Analysis, Oct 6, 2026, 6 min read): Parse Japanese price fields without losing currency or tax basis. Run a tested Python fixture for fullwidth yen, mixed prices and deliberate review cases. ## Related guides - [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md): Configure a proxy in Python Requests: the proxies dictionary, Session defaults, credentials, SOCKS5 via requests[socks], environment variables and ProxyError. - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md): Separate proxy DNS, TCP, CONNECT, TLS and response delays with curl timings, then set request deadlines and decide whether a retry is safe. - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md): How to use a proxy with curl: the -x flag, http_proxy and https_proxy variables, SOCKS5 with socks5h, proxy authentication, and reading CONNECT and 407 errors. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 129 of 138: Amazon listing updates: accepted is not live URL: https://ipvolt.com/blog/amazon-listing-update-reconciliation Markdown: https://ipvolt.com/blog/amazon-listing-update-reconciliation.md # Amazon listing updates: accepted is not live Source: https://ipvolt.com/blog/amazon-listing-update-reconciliation Markdown: https://ipvolt.com/blog/amazon-listing-update-reconciliation.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / Amazon listing updates: accepted is not live Category: Analysis Published: 2026-09-14 Updated: 2026-09-19 Author: ipvolt Reading time: 8 minutes Tags: proxies, troubleshooting Diagnose accepted Amazon listing updates by separating submitted attributes, live offers, inventory and buyability, with a practical reconciliation matrix. Your integration submits a price or inventory update, receives `ACCEPTED`, and marks the job complete. A seller then reports that the listing still cannot be bought. The missing step is to reconcile the submission with a subsequent observation of the listing. Amazon distinguishes acceptance for processing from later processing issues. Its write response cannot report issues that arise afterward; a subsequent `getListingsItem` read can expose them. Keep the receipt, but do not use it as proof that the intended live state has been reached. [Amazon's Listings Items overview](https://developer-docs.amazon/sp-api/docs/listings-items-api) explains this boundary. This runbook is for an authorized integration checking its own seller's standalone or sellable child SKU in one Amazon marketplace. The inventory example uses merchant fulfillment and the `DEFAULT` channel. It does not reconcile FBA stock, competitors' offers or the Featured Offer. A variation parent is deliberately non-buyable, so exclude it from an alert that expects a purchasable item. [Amazon's workflow guide](https://developer-docs.amazon/sp-api/docs/building-listings-management-workflows-guide) documents that exception. ## Keep four records instead of one success flag Use this proposed record structure to make each conclusion inspectable: | Record | What to retain | What it can establish | | --- | --- | --- | | Intended business state | Seller, SKU, marketplace, internal revision, intended price/currency, inventory intent and sale status | What your business meant to change | | Submission receipt | Request time, operation, response status, submission identifier and returned issues | Whether Amazon initially accepted that submission | | Seller contribution | Requested `attributes` data from a subsequent read, with its collection time | The latest contributed attributes returned by Amazon | | Observed listing state | Scoped summary, offers, fulfillment availability and issues from that read | What those returned datasets report about the listing | These are separate records, not an atomic transaction. Store the response and collection time so that a later reviewer can distinguish a field comparison from an assumption about processing order. Amazon says `attributes` represents the latest seller-provided data, while sections such as `fulfillmentAvailability` represent live listing data. Those quantities can legitimately differ after a sale. Comparing submitted inventory with live inventory as if they must always be equal creates a false repair signal. [Listings Items considerations](https://developer-docs.amazon/sp-api/docs/listings-items-api) gives that specific example. ## Ask for the datasets you intend to verify `getListingsItem` defaults to `summaries`. A successful request that omitted `offers` has not checked the live offer price. Explicitly select the datasets needed for this investigation. [The operation reference](https://developer-docs.amazon/sp-api/reference/getlistingsitem) lists the parameters and defaults. This is a request shape for an existing authorized SP-API client, not a complete authenticated command: ```text GET /listings/2021-08-01/items/{sellerId}/{sku} marketplaceIds={marketplaceId} includedData=summaries,attributes,issues,offers,fulfillmentAvailability ``` Use the regional endpoint and authorized seller context already configured in your client, encode the SKU as a path component, and send the last two lines as query parameters. We deliberately inspect one marketplace per investigation to simplify attribution. Match the returned SKU and the target marketplace's summary. For the price check, select an offer for that marketplace, the intended `B2C` or `B2B` offer type, the applicable audience if present, and the expected currency. If the intended offer cannot be selected unambiguously, leave the price check unresolved. Compare monetary amounts as decimals rather than floating-point approximations. For this merchant-fulfilled example, inspect the `DEFAULT` fulfillment channel, which Amazon defines as standard merchant fulfillment in its [fulfillment guide](https://developer-docs.amazon/sp-api/docs/manage-amazon-haul-advanced-multiple-offer-multiple-fulfillment-use-cases). Do not substitute another channel or treat an absent quantity as zero. The [official response model](https://github.com/amzn/selling-partner-api-models/blob/main/models/listings-items-api-model/listingsItems_2021-08-01.json) makes several datasets optional and does not require a fulfillment quantity. Missing data is a distinct result in this runbook. ## Turn each observation into a specific next action The following matrix is an operational policy derived from those response semantics. It is not an Amazon completion guarantee. | Observation | Conclusion allowed | Next action | | --- | --- | --- | | Submission is `ACCEPTED`; no subsequent read | Accepted, live result unverified | Queue a scoped read; retain the receipt | | Read fails with an authorization, throttling or service error | Current listing state is unknown | Resolve the read failure; keep it separate from listing status | | Successful response lacks a required dataset or matching offer | That check is unknown | Confirm requested datasets and scope; do not fill missing values with zero or false | | Valid target summary lacks `BUYABLE`, for a SKU expected to be sold | Returned status is non-buyable | Inspect requested issues and fulfillment availability; check intentional closure and inventory intent | | Issues dataset is empty | No issues are reported in that dataset | Check buyability independently; do not infer it from an empty list | | Issues are reported for the target listing | Those reported issues need diagnosis | Inspect code, severity, relevant attributes and marketplace/enforcement details where provided; investigate each applicable issue while checking buyability independently | | Returned offer matches the intended price and currency | This observed offer matches | Record the match; evaluate inventory and buyability separately | | Unambiguously selected offer has the expected currency but a different price | Observed price mismatch; needs attention | Retain expected/observed values, verify the latest business revision and other writes, then continue bounded reconciliation or escalate; do not blindly resubmit | | Contributed inventory differs from live inventory | Two different kinds of quantity were returned | Consult the current inventory authority and intervening changes before any write | `BUYABLE` and `DISCOVERABLE` describe different states. A valid status array without `BUYABLE` is different from a missing summary or a failed read. Amazon also says the absence of defined issues can coexist with other listing problems. [Status and issues notification definitions](https://developer-docs.amazon/sp-api/docs/notification-type-values) describe these distinctions; the [retrieval guide](https://developer-docs.amazon/sp-api/docs/retrieve-details-about-a-listing) connects non-buyable diagnosis to issues and inventory. Handle HTTP failures in the request layer. The reference distinguishes `403` authorization failures, `429` throttling and `500`/`503` service errors. A `404` needs listing and request-scope investigation; it does not mean a verified inventory quantity of zero. Use bounded read retries where appropriate, under the current API usage plan, without turning every failed read into a new listing write. [getListingsItem responses](https://developer-docs.amazon/sp-api/reference/getlistingsitem) supplies the error categories. ## Work through a quantity mismatch before repairing it Consider an entirely illustrative trace, not a live seller test. The intended update is a `B2C` price of USD 24.90 and five merchant-fulfilled units for one sellable SKU. The submission is accepted. A later, correctly scoped read reports: | Field | Illustrative observation | Interpretation | | --- | --- | --- | | Submitted inventory in `attributes` | 5 | Latest contribution returned | | `DEFAULT` live quantity | 4 | Four units reported available in that channel | | Selected offer | USD 24.90 | Observed price matches the intended amount and currency | | Summary status | `BUYABLE`, `DISCOVERABLE` | Both states are reported for this listing | | Requested issues | Empty array | No issue reported there | The inventory difference alone does not prove that the update failed. A sale is one possible explanation, but this response does not establish the cause. Reconcile against the inventory system and intervening orders or writes before deciding whether a correction is needed. Blindly restoring five units could undo a legitimate inventory change. The opposite shortcut also fails: the matching price does not prove that this particular submission caused the observed value. Another writer might have supplied the same amount. Record an observed match, retain the internal revision and receipt, and leave causation unclaimed. If this read had requested only `summaries`, buyability might be observable while the price and quantity checks remained unknown. Keep that partial result instead of promoting the entire job to success. ## Bound the investigation and keep late notifications useful Maintain a reconciliation record per seller, SKU, marketplace and internal revision. Give each required check its own state: pending, observed match, needs attention or unknown. A newer business revision should supersede an older target rather than be overwritten by that older job's retry. Choose a retry schedule, maximum attempts and an investigation deadline appropriate to your inventory risk and API allocation. These are your operating choices; this runbook supplies no universal delay after which an accepted update must be live. At the deadline, escalate unresolved checks with the retained receipt, scope, collection times and relevant response fields. Use applicable status or issues notifications to schedule another scoped read, and use a bounded reconciliation sweep for jobs still pending. Preserve the notification's identity and timing for diagnosis. A late notification should prompt investigation without replacing a newer observation just because it arrived last. Amazon's [Listings APIs FAQ](https://developer-docs.amazon/sp-api/docs/listings-apis-faq) acknowledges that notifications can lag direct reads. The [Amazon listing notifications guide](/guides/amazon-listing-notifications) covers consuming that feed reliably, and [ETag monitoring: a no-cache header changed our results](/blog/etag-monitoring-cache-control) shows how conditional requests keep the direct reads cheap. The summary's `lastUpdatedDate` is a listing update timestamp. The [model](https://github.com/amzn/selling-partner-api-models/blob/main/models/listings-items-api-model/listingsItems_2021-08-01.json) does not define it as a separate as-of timestamp for each price or inventory field. Do not treat it as proof that all returned sections describe one atomic state or that your submission has been fully applied. ## Keep transport troubleshooting separate from listing decisions Changing a proxy cannot resolve a catalog issue merely because the request now completes. If a request fails before a useful response arrives, diagnose the connection with the [proxy timeout guide](https://ipvolt.com/guides/proxy-timeout-troubleshooting). Once a valid listing response arrives, use its scoped fields and your business intent to decide the next action. For a separate public-page collection workflow, [checking whether an Amazon HTTP 200 contains the intended page](https://ipvolt.com/blog/scraping-amazon-google-through-a-proxy) addresses a different question. This seller reconciliation workflow uses authorized SP-API data and does not infer listing state from a scraped storefront. This article and its decision matrix were prepared with AI assistance from Amazon's primary documentation accessed on September 12, 2026, then independently reviewed. The example is illustrative; no seller account was queried and no listing was changed. The matrix is a proposed operational method, not a measured recovery result. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources - [Listings Items API](https://developer-docs.amazon/sp-api/docs/listings-items-api) - [getListingsItem](https://developer-docs.amazon/sp-api/reference/getlistingsitem) - [Retrieve details about a listing](https://developer-docs.amazon/sp-api/docs/retrieve-details-about-a-listing) - [Building Listings Management Workflows Guide](https://developer-docs.amazon/sp-api/docs/building-listings-management-workflows-guide) - [Notification Type Values](https://developer-docs.amazon/sp-api/docs/notification-type-values) - [Listings APIs FAQ](https://developer-docs.amazon/sp-api/docs/listings-apis-faq) - [Listings Items API 2021-08-01 model](https://github.com/amzn/selling-partner-api-models/blob/main/models/listings-items-api-model/listingsItems_2021-08-01.json) - [Multiple offer and fulfillment use cases](https://developer-docs.amazon/sp-api/docs/manage-amazon-haul-advanced-multiple-offer-multiple-fulfillment-use-cases) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [Check a Proxy for IP, DNS and WebRTC Leaks with ToDetect](https://ipvolt.com/blog/proxy-leak-check-todetect.md) (Analysis, Oct 23, 2026, 9 min read): Check a browser proxy for IP, DNS, WebRTC and time zone leaks with ToDetect's free tools, using measured results from a 4G mobile line as the worked example. - [Python 3.15 for Web Scraping: What Installs, What Breaks](https://ipvolt.com/blog/python-3-15-web-scraping.md) (Analysis, Oct 16, 2026, 8 min read): pip install scrapy fails on Python 3.15 without a C compiler: brotli has no cp315 wheel. We tested 19 scraping packages with pip and uv to see what else breaks. - [Japanese price parsing: yen, width and tax labels](https://ipvolt.com/blog/japanese-price-parsing.md) (Analysis, Oct 6, 2026, 6 min read): Parse Japanese price fields without losing currency or tax basis. Run a tested Python fixture for fullwidth yen, mixed prices and deliberate review cases. ## Related guides - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md): Diagnose HTTP_PROXY, HTTPS_PROXY, ALL_PROXY and NO_PROXY routing differences in curl, Python Requests and Node.js with an isolated local check. - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md): Separate proxy DNS, TCP, CONNECT, TLS and response delays with curl timings, then set request deadlines and decide whether a retry is safe. - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md): How to use a proxy with curl: the -x flag, http_proxy and https_proxy variables, SOCKS5 with socks5h, proxy authentication, and reading CONNECT and 407 errors. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 130 of 138: Bookmaker odds feeds: validate before comparing URL: https://ipvolt.com/blog/bookmaker-odds-feed-validation Markdown: https://ipvolt.com/blog/bookmaker-odds-feed-validation.md # Bookmaker odds feeds: validate before comparing Source: https://ipvolt.com/blog/bookmaker-odds-feed-validation Markdown: https://ipvolt.com/blog/bookmaker-odds-feed-validation.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / Bookmaker odds feeds: validate before comparing Category: Analysis Published: 2026-09-14 Updated: 2026-09-19 Author: ipvolt Reading time: 7 minutes Tags: proxies, troubleshooting Compare bookmaker odds only after checking market identity, settlement rules, timestamps and status. Use a local validator to expose false comparisons. Before comparing two bookmakers' prices, establish that both observations describe the same market and an acceptable state of that market. A larger decimal number is a poor signal when it belongs to a different line, includes extra time, or was retained after suspension. The same discipline applies to retail prices: [a matching number hid a currency mismatch](/blog/product-price-currency-validation) shows an amount that agreed while its currency did not. This article is for developers building odds archives, comparison displays and data-quality alerts from feeds they are authorized to use. The practical output is a comparison contract: a normalized record, explicit rejection reasons and a small offline checker. It validates your supplied evidence; it does not establish that an offer is currently executable. ## Define the market before comparing the number Consider two fictional records: Over 2.5 goals at 1.91 and Over 3.5 goals at 2.05. Treating the latter as an improvement compares two different outcomes. The numbers can both be valid while the comparison is invalid. Use an explicit identity key. The following is a proposed internal model, not a claim that every provider returns these field names: | Field | What to establish | Example mistake it prevents | | --- | --- | --- | | Event namespace and ID | The same event in one provider namespace, or a reviewed cross-provider mapping | Joining two fixtures just because their team names match | | Period | First half, regulation time or another defined period | Mixing a half-time market with a full-match market | | Market and line | Exact proposition and threshold, with a consistent unit | Mixing totals 2.5 and 3.5 | | Selection set | The same complete set of outcome identifiers | Treating a missing outcome as a price disappearance | | Settlement rules | A reviewed equivalence group for the rules that affect the result | Mixing regulation-only and extra-time-inclusive outcomes | | Event phase | A known pre-match or in-play state | Comparing a retained pre-match snapshot with an in-play observation | A matching in-play flag does not establish equal score, match clock or game state. This example does not validate those fields; a workflow that requires synchronized game state needs additional evidence and gates. Preserve the provider and bookmaker identifiers alongside that key. Identical raw IDs from different namespaces are not a cross-provider mapping. A `settlement_rules` label is only as reliable as the rule comparison behind it; copying the same label into both rows cannot establish equivalence. These distinctions map to real feed structures. The Odds API v4 documents bookmaker and market objects, outcome prices, and `point` values for spread and totals outcomes. Its event-odds response also carries market-level update timestamps. Normalize the endpoint you actually use rather than copying a sample from a different operation. [The Odds API v4](https://the-odds-api.com/liveapi/guides/v4/) ## Rebuild state before judging completeness A stream update is not necessarily a complete snapshot. Sportradar's Unified Odds Feed documentation says an `odds_change` can cover only some markets; markets omitted from that message remain unchanged. Clearing your entire market cache on each message would manufacture disappearing prices. [Sportradar odds-change semantics](https://docs.sportradar.com/uof/data-and-features/messages/event/odds-change) Separate two jobs: 1. A provider adapter applies the documented snapshot, delta, recovery and status rules to a cache. 2. A comparison gate evaluates the resulting normalized state. The checker linked below performs the second job. It must receive a complete normalized observation. Setting `complete_snapshot: true` on a raw delta bypasses the very question the adapter must answer. For a totals example, require both `OVER` and `UNDER` in the normalized selection set. A different market needs its own completeness definition. Preserve explicit suspension, closure and unknown state; do not fill a missing status with `OPEN` unless the source contract actually establishes that state. Some protocols define defaults, but a default from one protocol is not a rule for another. When a connection is lost, retain the last observation for your archive and mark it ineligible for current comparison until the adapter establishes usable state again. Historical visibility and current eligibility are separate properties. ## Keep collection time separate from price time Record when your collector received the observation and what the source timestamp means. A fresh HTTP response may contain an old price, while an unchanged price may remain valid for a long time. An age threshold is an admission policy, not proof that a price is wrong. Do not rewrite a price timestamp when the connection emits a heartbeat. Betfair distinguishes heartbeat messages from market changes; its stream `pt` is a message publish time. Connection activity alone does not establish that every cached selection was refreshed. [Betfair Exchange Stream API](https://betfair-developer-docs.atlassian.net/wiki/spaces/1smk3cen4v3lu3yomq5qye0ni/pages/2687396/Exchange%2BStream%2BAPI) For a monitoring job, define and record these limits before admitting a pair: - Maximum source age at the declared evaluation time. - Maximum difference between the two collection timestamps. - How missing, ambiguous, future or timezone-free timestamps are handled. - Which source field supports the normalized price-update time. Our fictional fixture policy uses a 30-second age limit and a two-second collection skew. Those values make the example reproducible; they are not bookmaker requirements or suitable defaults for every live feed. A production policy must fit the feed's documented timestamp semantics and the reader's decision deadline. A market-level update timestamp must remain identified as market-level evidence; it does not establish each outcome's last price change. Evaluate stored records against the intended historical evaluation time when replaying an archive. Comparing yesterday's fixtures with your current wall clock answers a different question. ## Use rejection reasons to locate the problem These are illustrative diagnostic branches, not measured bookmaker failure rates: | Observation | Comparison decision | Investigate next | | --- | --- | --- | | Same contract, complete open state, valid prices and acceptable timestamps | Eligible for this comparison | Compare the observations while preserving their timestamps | | Same label, different line or settlement rules | Reject this pairing | Correct the market mapping | | One side suspended or closed | Hold current comparison | Process the status transition; preserve history | | Outcome missing from a supposedly complete snapshot | Hold | Check adapter completeness and recovery | | Old price time with a recent collection time | Hold if outside your declared age policy | Inspect upstream update semantics and cache state | | Healthy heartbeat but no established usable market state | Hold | Diagnose stream state and recovery | | Decimal price missing, non-finite or at most one | Reject the normalized input | Check parsing and odds-format conversion | The last branch matters when ingesting multiple odds formats. Convert using a defined adapter and validate the resulting decimal representation; do not silently treat an American-odds integer as decimal odds. The Odds API exposes an explicit odds-format choice. [Odds API format options](https://the-odds-api.com/liveapi/guides/v4/) ## Run the offline comparison gate Save the [Python checker](https://ipvolt.com/downloads/odds-comparison/odds_compare.py) and [fictional input cases](https://ipvolt.com/downloads/odds-comparison/fixtures.json) in the same directory, then run: ```sh python3 odds_compare.py fixtures.json ``` The supplied checker deliberately accepts only its fixture contract: regulation-time total goals at 2.5 with the documented fictional rule ID. Other markets require a reviewed extension of the contract and tests, not just replacement prices. Keep bookmaker/source provenance in your surrounding observation log. In the executed local fixture, one of 14 pairs was eligible and 13 were held; 21 test methods passed. These are synthetic validator results, not bookmaker success or failure rates. The input file declares a fixed evaluation time under `now` and the illustrative age/skew policy, so replay does not depend on when you run it. Each case contains two candidate normalized records, including deliberately incomplete or invalid records that should be held. The example contract is regulation-time total goals at 2.5, with `OVER` and `UNDER` selections and a fictional settlement-rule ID. The checker returns `eligible_for_comparison` plus reasons for held pairs. Eligibility permits a data comparison under the supplied contract; it says nothing about staking, returns, liquidity or execution. Equal prices are not required. The [method and schema](https://ipvolt.com/downloads/odds-comparison/README.md) explain how to supply your own normalized records. The [tests](https://ipvolt.com/downloads/odds-comparison/test_odds_compare.py) exercise valid comparisons and malformed or ambiguous evidence. The checker makes no network requests and includes no API adapter. Its timestamp field, `price_updated_at`, is supplied by your adapter; the checker cannot prove that the upstream field has the meaning you assigned to it. ## Turn the contract into an operational check An HTTP success counter belongs in transport monitoring. Keep a separate denominator for comparisons admitted by the data gate. Record attempted pairs, admitted pairs and rejection reasons, including observations you could not normalize. Otherwise, an apparently clean chart can simply be hiding the difficult inputs. Store the mapping version, source identifiers, collection time, source timestamps, status and reasons with each decision. When an alert looks wrong, that record lets you distinguish a market-mapping defect from a stale cache or a transport failure. Do not replace unknown state with zero odds or erase the previous valid observation. A proxy can change the transport route used by an authorized collector. It cannot establish market equivalence, fill in missing selections or prove a price is current. If the evidence is incomplete, fix the data contract before increasing request volume. For network-layer diagnosis, see [proxy environment variables](https://ipvolt.com/guides/proxy-environment-variables) and [timeout troubleshooting](https://ipvolt.com/guides/proxy-timeout-troubleshooting). Method: this is an AI-assisted synthesis of the linked provider documentation and an explicitly synthetic local validation exercise. It reports no live bookmaker collection, provider performance, betting outcome or ipvolt service trial. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources - [Odds API Documentation V4](https://the-odds-api.com/liveapi/guides/v4/) - [List of API Betting Markets](https://the-odds-api.com/sports-odds-data/betting-markets.html) - [Exchange Stream API](https://betfair-developer-docs.atlassian.net/wiki/spaces/1smk3cen4v3lu3yomq5qye0ni/pages/2687396/Exchange%2BStream%2BAPI) - [Betting Enums](https://betfair-developer-docs.atlassian.net/wiki/spaces/1smk3cen4v3lu3yomq5qye0ni/pages/2687455/Betting%2BEnums) - [Odds Change](https://docs.sportradar.com/uof/data-and-features/messages/event/odds-change) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [Check a Proxy for IP, DNS and WebRTC Leaks with ToDetect](https://ipvolt.com/blog/proxy-leak-check-todetect.md) (Analysis, Oct 23, 2026, 9 min read): Check a browser proxy for IP, DNS, WebRTC and time zone leaks with ToDetect's free tools, using measured results from a 4G mobile line as the worked example. - [Python 3.15 for Web Scraping: What Installs, What Breaks](https://ipvolt.com/blog/python-3-15-web-scraping.md) (Analysis, Oct 16, 2026, 8 min read): pip install scrapy fails on Python 3.15 without a C compiler: brotli has no cp315 wheel. We tested 19 scraping packages with pip and uv to see what else breaks. - [Japanese price parsing: yen, width and tax labels](https://ipvolt.com/blog/japanese-price-parsing.md) (Analysis, Oct 6, 2026, 6 min read): Parse Japanese price fields without losing currency or tax basis. Run a tested Python fixture for fullwidth yen, mixed prices and deliberate review cases. ## Related guides - [Proxy environment variables: HTTP_PROXY and NO_PROXY](https://ipvolt.com/guides/proxy-environment-variables.md): Diagnose HTTP_PROXY, HTTPS_PROXY, ALL_PROXY and NO_PROXY routing differences in curl, Python Requests and Node.js with an isolated local check. - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md): Separate proxy DNS, TCP, CONNECT, TLS and response delays with curl timings, then set request deadlines and decide whether a retry is safe. - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md): How to use a proxy with curl: the -x flag, http_proxy and https_proxy variables, SOCKS5 with socks5h, proxy authentication, and reading CONNECT and 407 errors. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 131 of 138: Cloudflare AI Agent Blocks: What to Fix First URL: https://ipvolt.com/blog/cloudflare-ai-agent-proxy-setup Markdown: https://ipvolt.com/blog/cloudflare-ai-agent-proxy-setup.md # Cloudflare AI Agent Blocks: What to Fix First Source: https://ipvolt.com/blog/cloudflare-ai-agent-proxy-setup Markdown: https://ipvolt.com/blog/cloudflare-ai-agent-proxy-setup.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / Cloudflare AI Agent Blocks: What to Fix First Category: Analysis Published: 2026-09-14 Updated: 2026-09-14 Author: ipvolt Reading time: 8 minutes Tags: proxies, troubleshooting Diagnose Cloudflare failures in AI-agent jobs, configure a stable browser proxy, and reject challenges or invalid content before RAG ingestion. For a permitted browser-agent job, start with **one provider-supported stable exit, one browser context, and a response gate before extraction**. Then change the component the failure actually identifies. Proxy authentication needs a configuration fix. A destination refusal needs an access decision. A challenge page needs to stay out of your RAG corpus, even when it returns HTTP 200. That is the useful setup for a scraper, retrieval worker or browser agent facing Cloudflare failures. There is no evidence here that switching to residential or mobile proxies resolves every block. **Date check: September 14, 2026.** Cloudflare’s announced change is scheduled for September 15. This article describes that announcement and a diagnostic workflow; it does not report an observed rollout or establish the cause of your current error. ## What changes on September 15 Cloudflare’s July announcement separates **Search, Agent and Training** activity. Newly onboarding domains will default to blocking Training and Agent activity on pages displaying ads, while Search remains allowed. Separately, a crawler combining Search with Training follows the most restrictive applicable rule, including an existing Training block. The ad-page default and the mixed-purpose classification are distinct changes. [Cloudflare’s original announcement](https://blog.cloudflare.com/content-independence-day-ai-options/) The company’s press release says the ad-page defaults cover new customers, new sites from existing customers, and existing Free customers **if they have not changed their dashboard settings by September 15**. “All free-plan sites” loses that qualification. Customers can change their settings. [Cloudflare’s announcement of the affected customer groups](https://www.cloudflare.com/press/press-releases/2026/cloudflare-allows-the-agentic-internet-to-flourish-with-a-simple-philosophy-your-content-your-rules/) Owners can choose a whole-site block, an ad-page block or Allow for each category. The categories describe activity; the name of your browser library or RAG pipeline does not establish its classification. Cloudflare detects ad pages itself, so disabling ad downloads in your browser is not a policy override. [AI bot policy reference](https://developers.cloudflare.com/bots/additional-configurations/block-ai-bots/) ## Identify the failed hop before changing the proxy Keep the proxy exchange, destination navigation and any managed scraping API response separate in your retrieval record. An HTTP 402 from `api.firecrawl.dev` and an HTTP 402 from a publisher require different actions. A 403 alone does not identify the September 15 policy. Cloudflare documents multiple possible sources, including origin permissions and other security rules. `cf-ray` helps correlate a request with the site operator’s events; it does not name the rule that refused it. Record a UTC timestamp, the relevant path and the Ray ID when available. Keep sensitive URL parameters private. [403 causes](https://developers.cloudflare.com/support/troubleshooting/http-status-codes/4xx-client-error/error-403/), [Ray ID diagnostics](https://developers.cloudflare.com/fundamentals/reference/cloudflare-ray-id/) | Observation | Next action | RAG handling | | --- | --- | --- | | Proxy 407, or browser authentication/connection error | Verify the configured gateway, credentials and provider account. Chromium can expose a proxy failure as a navigation exception. | Mark retrieval unavailable; preserve the reason. | | Destination `cf-mitigated: challenge` | Investigate the site’s allowed access path and browser requirements. Stop automatic challenge retries. | Quarantine the response, including a nominal 200. | | Destination 403 without that challenge signal | Ask the site operator to correlate the request with access/security rules; use an agreed API, feed or allow path where available. | Unavailable; the specific policy remains unknown. | | 429 from a known hop | Respect `Retry-After` when supplied; reduce work at the affected scope and cap the total retry budget. | Defer retrieval; retain its freshness status. | | Destination 402 | Inspect the publisher’s payment/access context and documented integration. | Unavailable until a later accepted fetch. | | Firecrawl API HTTP 402 | Check Firecrawl credits and billing configuration. | Target status remains unknown unless separately reported. | | HTTP 200 with missing, empty or incorrect content | Check rendering, required subresources and the extraction contract. | Preserve any previous valid document; mark the failed refresh. | The challenge header is Cloudflare’s documented response signal. A missing header does not establish usable content. HTTP 407 identifies proxy authentication; 429 leaves the counting scope to the responding service, so changing an exit does not prove the allowance reset. [Challenge detection](https://developers.cloudflare.com/cloudflare-challenges/challenge-types/challenge-pages/detect-response/), [407 semantics](https://www.rfc-editor.org/rfc/rfc9110.html#section-15.5.8), [429 semantics](https://www.rfc-editor.org/rfc/rfc6585#section-4) For hosted Firecrawl, examine the outer API error alongside returned target metadata and job errors. Its API error catalog describes 402 as insufficient credits or missing billing configuration. Its scrape response can separately carry `data.metadata.statusCode`. These fields must remain separate in your logs. [Firecrawl errors](https://docs.firecrawl.dev/api-reference/errors), [scrape response contract](https://docs.firecrawl.dev/api-reference/endpoint/scrape) ## A proxy configuration for a complete browser job For a stateful workflow, request a stable exit for the duration of the job and retain one browser context through its steps. The provider controls exit affinity; the context holds cookies and browser storage. Confirm the provider’s session duration, reconnect behavior and early-exit replacement policy. A fixed gateway address alone proves none of those properties. The [session continuity guide](/guides/rotating-vs-sticky-proxies) explains what to verify. An approved fixed address is a useful starting point when the site owner allows that address. A required region can justify regional egress. For another workload, compare candidate routes under the same URL set, account, session, region and concurrency. Count fresh, valid documents per attempted document and cost per accepted document, including retries and rendering traffic. A residential/mobile label is insufficient evidence to choose a winner; the [proxy comparison](/blog/residential-vs-datacenter-proxies) covers that evaluation. Put proxy settings where the page request is made: | Stack | Configuration boundary | Detail that changes the diagnosis | | --- | --- | --- | | Playwright | Pass a `proxy` object with `server`, `username` and `password` to `browser.newContext`, or configure browser launch. | `httpCredentials` is destination authentication. A separate Node/Python HTTP client needs its own configuration. [Network docs](https://playwright.dev/docs/network#http-proxy) | | Puppeteer | Set context `proxyServer`; use `page.authenticate` for proxy username/password before navigation. | `proxyServer` is an endpoint string. Configure newly created pages too. [Context options](https://pptr.dev/api/puppeteer.browsercontextoptions), [authentication](https://pptr.dev/api/puppeteer.page.authenticate) | | Browser Use | The open-source browser accepts `Browser(proxy=ProxySettings(...))`. | With CDP or a managed browser, verify the remote browser’s egress contract. Local settings do not establish control over an already-running remote browser. [Parameters](https://docs.browser-use.com/open-source/customize/browser/all-parameters), [remote browsers](https://docs.browser-use.com/open-source/customize/browser/remote) | | Hosted Firecrawl | The v2 scrape `proxy` field selects `basic`, `enhanced` or `auto`; `auto` is the default. | This is a managed strategy selector, not a custom proxy URL. Setting a local `HTTP_PROXY` does not configure the remote target fetch. [Scrape API](https://docs.firecrawl.dev/api-reference/endpoint/scrape) | Keep retries under one job budget. A hosted service’s internal attempts plus the SDK’s retries plus the agent’s “try again” loop can multiply work. After a refusal, preserve the reason and choose the next action from the table before scheduling another attempt. ## Run the response gate before extraction The downloadable Playwright probe performs one navigation, classifies its main response and checks for nonempty text in an expected CSS selector. It emits a small JSON diagnostic, without the target URL, body, credentials or raw exception. It does not extract or ingest content. Download [probe.mjs](https://ipvolt.com/downloads/cloudflare-ai-agent/probe.mjs), [package.json](https://ipvolt.com/downloads/cloudflare-ai-agent/package.json), [package-lock.json](https://ipvolt.com/downloads/cloudflare-ai-agent/package-lock.json), [test-fixture.mjs](https://ipvolt.com/downloads/cloudflare-ai-agent/test-fixture.mjs) and the [README](https://ipvolt.com/downloads/cloudflare-ai-agent/README.md) into one directory. Use Node.js 22 or later, run `npm ci`, then `npx playwright install chromium`. The package pins Playwright 1.63.0. Inject these settings through your existing configuration/secrets mechanism, then run `node probe.mjs`: - `PROXY_SERVER`: a credential-free `http://` gateway URL, without a path or query. - `PROXY_USERNAME` and `PROXY_PASSWORD`: your provider’s credentials, with any documented session setting. - `TARGET_URL`: the page you are checking. - `EXPECTED_SELECTOR`: a specific CSS selector such as `main article[data-document-id]`, whose matched element must contain text. The probe allows 15 seconds for navigation and another 5 seconds for the content check. It creates and closes a fresh context per invocation. For a multi-step production job, retain the job’s context and apply the same checks to its relevant responses. The [Playwright setup guide](/guides/playwright-proxy-setup) covers credentials and context configuration. This classification section runs before the selector check: ```javascript if (result.cf_mitigated) return 'challenge'; if (result.status === 402) return 'payment_or_access_review'; if (result.status === 403) return 'access_review'; if (result.status === 407) return 'proxy_auth_error'; if (result.status === 429) return 'rate_limited'; if (result.status >= 500 && result.status < 600) return 'upstream_error'; if (result.status !== 200) return 'unexpected_status'; if (!/^text\/html(?:\s*;|$)/i.test(headers['content-type'] ?? '')) return 'invalid_content'; return null; ``` The full function sets `cf_mitigated` only when the response header equals `challenge`. A `null` here means proceed to the content check. The eventual `accepted_content` outcome requires HTTP 200, HTML and nonempty expected content; it exits 0. Other outcomes exit 2. In our **18 synthetic checks**, all expected outcomes matched: four responses passed the minimal gate and fourteen were withheld. A fixture response with status 200 and `cf-mitigated: challenge` produced `outcome: challenge` and exit 2. Missing or empty expected content also failed. Wrong proxy credentials exposed a 407 and `proxy_auth_error` after two authentication challenges; no request was forwarded. One accepted case deliberately included a failing 403 subresource, demonstrating the main-document check’s limit. [Exact fixture results](https://ipvolt.com/downloads/cloudflare-ai-agent/example-output.json) Run `node test-fixture.mjs` to reproduce the local suite. It used Node 26.8.1, Playwright 1.63.0 and Chromium 153.0.8010.12, with a local origin and authenticating HTTP proxy. The installation commands and fixture were also run from identical files downloaded from a local HTTP server. These checks establish this probe’s behavior on synthetic responses; they do not establish live Cloudflare access, provider exit stability or HTTPS CONNECT behavior. Treat acceptance as permission to run deeper validation. A broad selector can match a login screen, and a required JSON subrequest can fail while the main HTML passes. Validate document identity, required fields, locale and freshness on the exact content your worker will ingest. A successful probe cannot approve a later fetch that returns something different. Preserve the last valid document when a refresh fails, with its old retrieval time visible to the consumer. ## When the resolution belongs to the site’s access rules If you operate the target site, inspect the matched security rule alongside its AI crawler policy. An AI Crawl Control setting of Allow can still be overridden by WAF rules that run earlier. A missing request in the AI crawler view is therefore a reason to check the security events too. If another team owns the site, share the request identifiers and agree on the intended access route. [Cloudflare’s rule precedence](https://developers.cloudflare.com/ai-crawl-control/configuration/ai-crawl-control-with-waf/) Pay Per Crawl is a separate access arrangement. Its documentation currently labels it closed beta; an unpaid chargeable request can receive HTTP 402 with `crawler-price`. Paid requests require the documented enrollment and signed payment-intent flow. Adding an unsigned payment header is insufficient, and WAF/Bot Management blocks can still prevent access. Resolve participation and budget deliberately rather than letting an agent interpret any 402 as authority to spend. [Pay Per Crawl scope](https://developers.cloudflare.com/ai-crawl-control/features/pay-per-crawl/what-is-pay-per-crawl/), [request protocol](https://developers.cloudflare.com/ai-crawl-control/features/pay-per-crawl/use-pay-per-crawl-as-ai-owner/crawl-pages/) Your pipeline should be able to return “source unavailable” with a reason and timestamp. That gives the caller a usable decision when an authentication fix, owner-approved rule change or supported content interface is still required. *Method: AI-assisted writing by ipvolt, checked against the linked primary documentation on September 14, 2026. The downloadable test uses local synthetic responses. It does not measure live Cloudflare blocking, proxy-provider performance, HTTPS CONNECT behavior or the September 15 rollout.* ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources - [Cloudflare: Your site, your rules — new AI traffic options](https://blog.cloudflare.com/content-independence-day-ai-options/) - [Cloudflare: September 15 announcement and existing Free customer scope](https://www.cloudflare.com/press/press-releases/2026/cloudflare-allows-the-agentic-internet-to-flourish-with-a-simple-philosophy-your-content-your-rules/) - [Cloudflare: Block AI Bots](https://developers.cloudflare.com/bots/additional-configurations/block-ai-bots/) - [Cloudflare: Detect a Challenge Page response](https://developers.cloudflare.com/cloudflare-challenges/challenge-types/challenge-pages/detect-response/) - [Cloudflare: AI Crawl Control with WAF](https://developers.cloudflare.com/ai-crawl-control/configuration/ai-crawl-control-with-waf/) - [Cloudflare: Error 403](https://developers.cloudflare.com/support/troubleshooting/http-status-codes/4xx-client-error/error-403/) - [Cloudflare: Ray ID](https://developers.cloudflare.com/fundamentals/reference/cloudflare-ray-id/) - [Cloudflare: What is Pay Per Crawl?](https://developers.cloudflare.com/ai-crawl-control/features/pay-per-crawl/what-is-pay-per-crawl/) - [Cloudflare: Pay Per Crawl request protocol](https://developers.cloudflare.com/ai-crawl-control/features/pay-per-crawl/use-pay-per-crawl-as-ai-owner/crawl-pages/) - [Playwright: HTTP proxy configuration](https://playwright.dev/docs/network#http-proxy) - [Puppeteer: BrowserContextOptions](https://pptr.dev/api/puppeteer.browsercontextoptions) - [Puppeteer: Page.authenticate](https://pptr.dev/api/puppeteer.page.authenticate) - [Browser Use: Browser parameters](https://docs.browser-use.com/open-source/customize/browser/all-parameters) - [Browser Use: Remote browser configuration](https://docs.browser-use.com/open-source/customize/browser/remote) - [Firecrawl: Hosted v2 scrape API](https://docs.firecrawl.dev/api-reference/endpoint/scrape) - [Firecrawl: API errors](https://docs.firecrawl.dev/api-reference/errors) - [RFC 6585: HTTP 429](https://www.rfc-editor.org/rfc/rfc6585#section-4) - [RFC 9110: Proxy authentication required](https://www.rfc-editor.org/rfc/rfc9110.html#section-15.5.8) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [Check a Proxy for IP, DNS and WebRTC Leaks with ToDetect](https://ipvolt.com/blog/proxy-leak-check-todetect.md) (Analysis, Oct 23, 2026, 9 min read): Check a browser proxy for IP, DNS, WebRTC and time zone leaks with ToDetect's free tools, using measured results from a 4G mobile line as the worked example. - [Python 3.15 for Web Scraping: What Installs, What Breaks](https://ipvolt.com/blog/python-3-15-web-scraping.md) (Analysis, Oct 16, 2026, 8 min read): pip install scrapy fails on Python 3.15 without a C compiler: brotli has no cp315 wheel. We tested 19 scraping packages with pip and uv to see what else breaks. - [Japanese price parsing: yen, width and tax labels](https://ipvolt.com/blog/japanese-price-parsing.md) (Analysis, Oct 6, 2026, 6 min read): Parse Japanese price fields without losing currency or tax basis. Run a tested Python fixture for fullwidth yen, mixed prices and deliberate review cases. ## Related guides - [Configure a proxy in Playwright](https://ipvolt.com/guides/playwright-proxy-setup.md): Set an authenticated HTTP proxy for a Playwright browser context, keep test state isolated, and diagnose navigation separately from subresources. - [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md): Choose rotation around the smallest complete workflow, distinguish exit affinity from cookies, and test what happens when a sticky session ends early. - [Fix proxy error 407 without guessing](https://ipvolt.com/guides/fix-proxy-error-407.md): Diagnose Proxy Authentication Required in a repeatable order: gateway, authentication method, credential encoding, account scope and client configuration. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 132 of 138: Proxy retries: one lost response, two created jobs URL: https://ipvolt.com/blog/proxy-retries-duplicate-jobs Markdown: https://ipvolt.com/blog/proxy-retries-duplicate-jobs.md # Proxy retries: one lost response, two created jobs Source: https://ipvolt.com/blog/proxy-retries-duplicate-jobs Markdown: https://ipvolt.com/blog/proxy-retries-duplicate-jobs.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / Proxy retries: one lost response, two created jobs Category: Analysis Published: 2026-09-13 Updated: 2026-09-13 Author: ipvolt Reading time: 8 minutes Tags: proxies, troubleshooting A local proxy drops a response after a POST creates a job. See when retrying duplicates work, when an idempotency key helps, and when to reconcile. Before retrying a POST after a proxy failure, establish what the destination may already have done. Losing the response leaves the operation's outcome uncertain. A second request can create another job even though the first one already exists. In our local demonstration, the client received an error after the origin created a job. Repeating the POST created a second job. Repeating it with the same key also created a second job when the receiving endpoint ignored the key. Only the endpoint's implemented deduplication contract made a same-key replay return the original job. These are synthetic job records in memory, not completed production tasks. The useful result is the difference between requests attempted and application effects observed. You can reproduce both in the download. ## Lose the response after creating the job Download and extract the [proxy retry demonstration](https://ipvolt.com/downloads/proxy-retry-jobs/proxy-retry-jobs.zip). From the extracted directory, run: ```sh python3 -m venv .venv . .venv/bin/activate python -m pip install -r requirements.txt python retry_jobs_demo.py > result.json python retry_jobs_demo.py --csv result.json ``` The example requires Python 3.11 or later and pins HTTPX 0.28.1 with HTTPcore 1.0.9. It uses [`asyncio.timeout`, added in Python 3.11](https://docs.python.org/3/library/asyncio-task.html#asyncio.timeout). Installing dependencies uses the package index. The demonstration itself starts a temporary HTTP origin and forward proxy on loopback; no provider account or external destination is involved. In each of six separate cases, the origin applies the first POST and sends its response. The proxy reads that complete response, then deliberately closes the downstream connection without sending response headers. The client records `RemoteProtocolError` in this pinned run. Any repeat request or lookup is a subsequent, explicit client action. The captured ordering is: ```text origin: job applied origin: response sent proxy: complete origin response received proxy: response dropped before client headers client: request failed ``` The origin's own records produced this matrix. POST counts include the original attempt; a lookup is a separate GET. | Action after the lost response | POSTs received | GETs received | Jobs created | Next client result | |---|---:|---:|---:|---| | Repeat the POST without a replay contract | 2 | 0 | 2 | 201, second job | | Reuse a key that the endpoint ignores | 2 | 0 | 2 | 201, second job | | Reuse the supported key and unchanged input | 2 | 0 | 1 | 201, original saved result | | Generate a new key for the retry | 2 | 0 | 2 | 201, second job | | Reuse the supported key with changed input | 2 | 0 | 1 | 409, input conflict | | Look up the confirmed operation; send no second POST | 1 | 1 | 1 | 200, existing job found | A 201 on the second attempt therefore meant two different things in this fixture: a newly created second job or the saved result for the first job. We checked job identities and origin effect counts to distinguish them. Idempotency concerns the intended effect of repeating an operation; the status code alone cannot demonstrate it. [HTTP idempotency semantics](https://www.rfc-editor.org/rfc/rfc9110.html#section-9.2.2). The important boundary is between applying the operation and delivering its response. This is different from a connection attempt that failed before the application request was sent. For an HTTPS destination, a failure while establishing the CONNECT tunnel also happens at a different stage from losing the response to a POST sent through an established tunnel. The [timeout guide](https://ipvolt.com/guides/proxy-timeout-troubleshooting) explains those stages. The proxy in this demonstration does not retry requests. A second POST is an explicit action by the client. That distinction matters: HTTP semantics prohibit a proxy from automatically retrying a non-idempotent request. A client also needs a basis for treating a non-idempotent operation as repeatable, or evidence that the original was not applied. [RFC 9110, section 9.2.2](https://www.rfc-editor.org/rfc/rfc9110.html#section-9.2.2). ## Choose the next action from the operation's state An exception class describes a client observation. It is not an application receipt. Use evidence about the logical operation, meaning the job the caller intended to create, to decide what happens next. | Evidence available | What you know | Next action | |---|---|---| | An authoritative result identifies the created job | The creation took effect | Use or reconcile that result; do not create the job again | | Outcome is unknown, but the endpoint supports replay with your retained operation key and unchanged input | Its documented contract may let you repeat the attempt without repeating the effect | Reuse that identity within the endpoint's scope and retention rules | | Reliable evidence establishes that no attempt applied or can still apply | The logical operation has not taken effect | A new attempt can be considered within the normal request budget | | Outcome is unknown and no applicable replay contract exists | Repeating the POST could create a second effect | Use the service's status/reconciliation process or escalate the unresolved operation | For the lookup case, the caller retained `X-Operation-Ref: operation-1`; the fixture's `GET /operations/operation-1` returns the associated job. That reference was known before the POST, so the lookup does not need a job ID from the lost response. Treat an empty or failed lookup carefully. “Not found” at one instant does not establish that an earlier request cannot arrive or complete later. The positive lookup in the demonstration works because it returns the job already created. It does not test negative lookup safety. This distinction follows from the late-arrival problem discussed in the [AWS Builders Library](https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/). A backoff delay changes when you try again. It does not establish whether the first operation happened. A 502, 504, timeout or disconnected response still needs its request phase and application context. Use the [proxy status-code article](https://ipvolt.com/blog/proxy-status-codes-407-429-502) to identify the responding layer; avoid turning its error categories into a universal list of safe POST retries. ## A header needs a receiving application that understands it The supported-key fixture records the job and its response under an in-process lock. Within its single-caller scope, the key is bound to the POST endpoint and compared against the operation reference and parsed payload. A matching repeat receives the saved job result. A changed input receives the fixture's explicit 409 response without creating another job. The ignored-key case changes the receiving application's behavior, not the spelling of the header. The new-key case changes the operation identity presented to the application. Both created two jobs. Reuse the identity of the intended operation when its contract permits a replay; generating a new key on every attempt defeats that connection. This fixture retains records only in memory for its lifetime. Its lock demonstrates coordination inside one process. It does not make job creation durable, cover a restart, expire keys safely, or coordinate external effects such as sending a message. Those properties need an application design beyond this example. Real APIs define their own contracts. For example, Stripe documents storing a request's result for reuse with the same key, checking subsequent parameters, and treating a reused key as a new request after its stored record is removed. Those are Stripe's rules; sending a similarly named header to another endpoint does not import them. [Stripe idempotent requests](https://docs.stripe.com/api/idempotent_requests). Before relying on a key in production, verify four things with the receiving service: - **Identity and scope:** which caller, account, endpoint and operation does the key identify? - **Input and concurrency:** how are changed inputs and overlapping attempts handled? - **Retention and recovery:** how long does protection last, and what survives a restart or partial failure? - **Result semantics:** what is returned for an existing, pending, failed or completed operation? AWS's design discussion connects request identity with atomic recording of the mutation and describes why late arrivals and changed intent need explicit handling. It is useful background for these questions, not evidence that every API implements the same guarantees. [Making retries safe with idempotent APIs](https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/). ## Keep client retries and business outcomes separate Do not use the client's successful-response count as the job count. Record the logical operation identity separately from each transport attempt. When the response is lost, preserve an unresolved outcome until the service's contract or authoritative state supports a stronger conclusion. That makes a recovered response, a replayed result and a newly created job distinguishable in your investigation. Be precise about library settings too. HTTPX documents its built-in transport retries for connection errors and connection timeouts, not arbitrary read/write failures or status codes. In the pinned HTTPX 0.28.1 implementation, the HTTP-proxy branch does not pass the transport's `retries` setting into its proxy pool. This experiment uses explicit client actions and zero default retries; it does not depend on that option replaying a proxied POST. [HTTPX transport documentation](https://www.python-httpx.org/advanced/transports/#http-transport), [tagged transport source](https://raw.githubusercontent.com/encode/httpx/0.28.1/httpx/_transports/default.py). urllib3 is different: behind an HTTP proxy, a mounted `Retry` or `max_retries` can re-send a POST by itself after delivery, as [the SSL EOF guide](/guides/fix-ssl-unexpected-eof-proxy) shows on a loopback fixture. For monitoring, count attempts, observed response failures, confirmed jobs and unresolved logical operations separately. The [benchmark methodology article](https://ipvolt.com/blog/what-a-proxy-benchmark-should-measure) explains why an attempt denominator matters. For a state-changing integration, add the application outcome before calling recovery successful. ## Downloads and test boundaries The [archive](https://ipvolt.com/downloads/proxy-retry-jobs/proxy-retry-jobs.zip) contains the complete demonstration, tests, pins, README, recorded JSON and its derived CSV. You can also inspect the [code](https://ipvolt.com/downloads/proxy-retry-jobs/retry_jobs_demo.py), [tests](https://ipvolt.com/downloads/proxy-retry-jobs/test_retry_jobs.py), [requirements](https://ipvolt.com/downloads/proxy-retry-jobs/requirements.txt), [README](https://ipvolt.com/downloads/proxy-retry-jobs/README.md), [event output](https://ipvolt.com/downloads/proxy-retry-jobs/example-output.json) and [result matrix](https://ipvolt.com/downloads/proxy-retry-jobs/example-matrix.csv) separately. ipvolt ran the local checks on 13 September 2026 with CPython 3.14.7 on macOS arm64 and the pinned packages above. The checks cover the six-case matrix, overlapping same-key requests, changed-input conflicts, distinct identities, refusal to forward to an external destination and fixture cleanup. Recorded cases finished with the client closed and no remaining fixture handlers or writers. The test uses HTTP/1.1 forwarding. It does not test CONNECT, TLS, authentication, SOCKS, external providers, durable storage, key expiry or a remote service's late-arrival behavior. It makes no provider reliability or exactly-once processing claim. ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). This demonstration does not describe an ipvolt API or an ipvolt idempotency feature. ## Sources - [RFC 9110: idempotency and retry semantics](https://www.rfc-editor.org/rfc/rfc9110.html#section-9.2.2) - [AWS Builders Library: making retries safe with idempotent APIs](https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/) - [Stripe: idempotent requests](https://docs.stripe.com/api/idempotent_requests) - [HTTPX: transport retries](https://www.python-httpx.org/advanced/transports/#http-transport) - [HTTPX 0.28.1: transport implementation](https://raw.githubusercontent.com/encode/httpx/0.28.1/httpx/_transports/default.py) - [Python: asyncio.timeout](https://docs.python.org/3/library/asyncio-task.html#asyncio.timeout) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [Check a Proxy for IP, DNS and WebRTC Leaks with ToDetect](https://ipvolt.com/blog/proxy-leak-check-todetect.md) (Analysis, Oct 23, 2026, 9 min read): Check a browser proxy for IP, DNS, WebRTC and time zone leaks with ToDetect's free tools, using measured results from a 4G mobile line as the worked example. - [Python 3.15 for Web Scraping: What Installs, What Breaks](https://ipvolt.com/blog/python-3-15-web-scraping.md) (Analysis, Oct 16, 2026, 8 min read): pip install scrapy fails on Python 3.15 without a C compiler: brotli has no cp315 wheel. We tested 19 scraping packages with pip and uv to see what else breaks. - [Japanese price parsing: yen, width and tax labels](https://ipvolt.com/blog/japanese-price-parsing.md) (Analysis, Oct 6, 2026, 6 min read): Parse Japanese price fields without losing currency or tax basis. Run a tested Python fixture for fullwidth yen, mixed prices and deliberate review cases. ## Related guides - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md): Separate proxy DNS, TCP, CONNECT, TLS and response delays with curl timings, then set request deadlines and decide whether a retry is safe. - [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md): Configure a proxy in Python Requests: the proxies dictionary, Session defaults, credentials, SOCKS5 via requests[socks], environment variables and ProxyError. - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md): How to use a proxy with curl: the -x flag, http_proxy and https_proxy variables, SOCKS5 with socks5h, proxy authentication, and reading CONNECT and 407 errors. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 133 of 138: ETag monitoring: a no-cache header changed our results URL: https://ipvolt.com/blog/etag-monitoring-cache-control Markdown: https://ipvolt.com/blog/etag-monitoring-cache-control.md # ETag monitoring: a no-cache header changed our results Source: https://ipvolt.com/blog/etag-monitoring-cache-control Markdown: https://ipvolt.com/blog/etag-monitoring-cache-control.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / ETag monitoring: a no-cache header changed our results Category: Analysis Published: 2026-09-11 Updated: 2026-09-11 Author: ipvolt Reading time: 6 minutes Tags: proxies, troubleshooting A live proxy test found that one request header changed 304 responses into full downloads. Inspect the measured bytes, request policies and reproducible data. Before buying more proxy traffic for a content monitor, inspect the headers your client actually sends. On our live website, adding `Cache-Control: no-cache` changed unchanged-page checks from body-free `304` responses to full `200` downloads, even though the requests carried the matching ETag. In a controlled comparison, **12 conditional requests without that override transferred zero response-body bytes; 12 with it transferred 271,968 bytes of unchanged HTML.** The six initial downloads needed to obtain the ETags cost another 135,984 bytes and are included in the published records. That is a finding about one deployed Next.js 16.3.4 site and a particular request policy. It is not advice to remove freshness requirements from a monitor. The useful decision is whether to change the client policy, choose a smaller representation, or investigate the server's revalidation behavior. ## The task: monitor known content without downloading it unnecessarily We tested two existing ipvolt articles: the [proxy benchmark guide](https://ipvolt.com/blog/what-a-proxy-benchmark-should-measure) and [proxy error explanation](https://ipvolt.com/blog/proxy-status-codes-407-429-502), each as HTML and Markdown. Our monitor watched the article title and two specified section headings. It also checked media types and, for HTML, the page title and canonical URL. Those checks establish that the watched information is present. They do not make Markdown a substitute for layout, JavaScript behavior or a working signup journey. The exact assertions are in the [study configuration](https://ipvolt.com/downloads/content-monitoring/main-study.json). Collection used authenticated third-party proxy connections targeting the US, UK and Netherlands. The initial experiment also included a direct control. Country-check responses reported the requested countries at the checkpoints; an exit address changed during the initial US run, so these are route observations rather than fixed-IP or country-wide reliability results. The connection provider is omitted; this was not a test of ipvolt's proxies. All three HTTP experiments ran on 11 September 2026. They made **234 requests and transferred 2,975,066 response-body bytes**, including initial downloads, verification downloads and unsuccessful hypotheses. Every attempted request completed without a curl transport error. Additional geographic probes and browser QA are recorded separately in the [method note](https://ipvolt.com/downloads/content-monitoring/method.json); they are outside that HTTP-experiment total. ## The smaller first download did not answer the caching question The initial experiment requested gzip consistently and measured received body bytes. Across twelve initial observations per representation, the sizes were: | Article representation | Received body bytes per initial request | | --- | ---: | | Benchmark HTML | 26,521 | | Benchmark Markdown | 7,056–7,061 | | Error guide HTML | 18,807 | | Error guide Markdown | 5,081 | Both HTML endpoints supplied ETags. Neither Markdown endpoint supplied an ETag or Last-Modified validator in this experiment. HTML conditional checks without a Cache-Control override returned `304`; the runner reused the matching, previously accepted body instead of interpreting the empty response as a new document. The exploratory run made 144 requests: 120 full `200` responses and 24 accepted `304` responses. It skipped 36 conditional slots because the Markdown had no validator or the homepage was marked `no-store`. Skipped requests are not counted as successes or zero-byte network observations. We then ran five successive checks per representation through each of the three proxy routes. Each check explicitly sent `Cache-Control: no-cache`, and the client retained eligible validators between checks. All 60 requests returned `200`, including the 24 HTML rechecks carrying a matching ETag. The expectation that repeated HTML validation would avoid downloading the body did not hold under this policy. ## Isolating the header that changed the response To investigate, we held the URL, route configuration, Accept, language, gzip preference and exact seed ETag constant. For each of the six route/article combinations, we made one seed request and four conditional requests. The order was A/B/B/A or B/A/A/B, where A omitted a Cache-Control override and B sent `no-cache`. | Conditional request policy | Attempts | Responses | Received body bytes | | --- | ---: | --- | ---: | | Matching If-None-Match; no Cache-Control override | 12 | 12 × 304 | 0 | | Same If-None-Match; Cache-Control: no-cache | 12 | 12 × 200 | 271,968 | All 24 conditional observations matched the seed's watched values and decoded content. Including the six seeds, this controlled experiment transferred 407,952 body bytes across 30 requests. It used balanced ordering, not random sampling, and establishes the observed behavior of these endpoints during this short window. The implementation explains a plausible mechanism. We checked the actual deployed dependency files against the local Next.js 16.3.4 installation: the relevant source hashes matched. Its ETag response helper calls `fresh` before returning `304`; the bundled freshness check returns false when the request contains `no-cache`, before evaluating the matching ETag. A separate local function test reproduced the same branch. [Next.js response helper](https://github.com/vercel/next.js/blob/v16.3.4/packages/next/src/server/send-payload.ts), [fresh implementation](https://github.com/jshttp/fresh/blob/v0.5.2/index.js). This is stack-specific behavior consistent with the live results. HTTP does not define `no-cache` as a universal instruction to download a complete body. Nor does receiving `304` prove that the request reached the origin rather than a responding cache. [HTTP caching](https://www.rfc-editor.org/rfc/rfc9111.html). ## The useful optimization depends on the freshness you need For the five-check experiment that explicitly used `no-cache`, the actual totals were: | Representation | Requests, including initial downloads | Received body bytes | | --- | ---: | ---: | | HTML | 30 | 679,920 | | Markdown | 30 | 182,070 | | Difference | Same request count | 497,850 | **Markdown transferred 73.2% fewer response-body bytes for the watched content under that policy.** It did not reduce the request count. These are measured payload differences, not a measured invoice saving or a forecast of monthly traffic. curl's download-size metric excludes headers and other network overhead. [curl payload accounting](https://curl.se/libcurl/c/CURLINFO_SIZE_DOWNLOAD_T.html). There is another option when freshness requirements allow it: the Markdown responses advertised `public, max-age=300, must-revalidate`. A cache may reuse a still-fresh stored representation without making a request. Missing validators do not make it uncacheable. Our runners deliberately checked over the network; they did not implement that freshness-based scheduling policy. [Freshness and reuse](https://www.rfc-editor.org/rfc/rfc9111.html#section-4). Use the result to choose the next action: | Your monitoring requirement | Action supported by this case | | --- | --- | | Reuse within the server's freshness window is acceptable | Evaluate a local freshness-aware cache before scheduling another download. | | Ask the responding server or cache to validate every check | Test the final request headers against the actual endpoint; do not assume an ETag guarantees a body-free response. | | Need the watched text, and each check returns a full body | Compare compressed HTML with a text or Markdown representation that contains those same facts. | | Need rendered layout or an interactive journey | Keep browser checks; the smaller text representation does not cover that job. | Do not strip `no-cache` solely to reproduce the zero-byte row. The two header policies can have different freshness consequences. Establish what your monitor must detect, then measure the permitted implementation. ## Reproduce the result and adapt the check Download [the offline analysis script](https://ipvolt.com/downloads/content-monitoring/reproduce.py) and [the sanitized recordings](https://ipvolt.com/downloads/content-monitoring/recordings.zip) into the same directory. Python 3.10 or newer is sufficient; this command makes no network requests: ```sh python3 reproduce.py recordings.zip ``` It recomputes the attempt counts, body totals, header comparison and Markdown percentage. Compare its output with [the recorded result](https://ipvolt.com/downloads/content-monitoring/results.json). The dataset includes timestamps, request policies, selected response headers, content checks and hashes. Credentials, exit IPs, unfiltered headers and raw body captures remain private; replay verifies the published arithmetic rather than independently authenticating historical responses. The [download instructions](https://ipvolt.com/downloads/content-monitoring/README.md) link the exact collection programs, configurations and 27 passing offline tests. The live programs require curl 8.4 or newer, preserve TLS verification, bound requests and body transfer, and pass proxy authentication privately through curl's input. Their allowlist is restricted to this case's public site; adapt both the allowlist and content assertions for a property you operate. We did not observe a real content update or measure detection delay. Decoded content stayed stable for every tested endpoint; a few gzip byte streams differed despite identical decoded text. That is a reason to compare the content your monitor cares about, not evidence that this study eliminated operational false alerts. This is one site, two articles and a short observation window—not a provider ranking or a universal caching benchmark. *Method: agent-assisted collection and analysis, with separate evidence, editorial and search reviews. All reported network observations were actually executed; the offline tests exercise controlled fixtures and are labeled separately.* ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources - [RFC 9110: If-None-Match and conditional requests](https://www.rfc-editor.org/rfc/rfc9110.html#section-13.1.2) - [RFC 9111: request and response cache directives](https://www.rfc-editor.org/rfc/rfc9111.html) - [curl: downloaded response-body size](https://curl.se/libcurl/c/CURLINFO_SIZE_DOWNLOAD_T.html) - [Next.js 16.3.4: ETag response handling](https://github.com/vercel/next.js/blob/v16.3.4/packages/next/src/server/send-payload.ts) - [fresh 0.5.2: request freshness evaluation](https://github.com/jshttp/fresh/blob/v0.5.2/index.js) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [Check a Proxy for IP, DNS and WebRTC Leaks with ToDetect](https://ipvolt.com/blog/proxy-leak-check-todetect.md) (Analysis, Oct 23, 2026, 9 min read): Check a browser proxy for IP, DNS, WebRTC and time zone leaks with ToDetect's free tools, using measured results from a 4G mobile line as the worked example. - [Python 3.15 for Web Scraping: What Installs, What Breaks](https://ipvolt.com/blog/python-3-15-web-scraping.md) (Analysis, Oct 16, 2026, 8 min read): pip install scrapy fails on Python 3.15 without a C compiler: brotli has no cp315 wheel. We tested 19 scraping packages with pip and uv to see what else breaks. - [Japanese price parsing: yen, width and tax labels](https://ipvolt.com/blog/japanese-price-parsing.md) (Analysis, Oct 6, 2026, 6 min read): Parse Japanese price fields without losing currency or tax basis. Run a tested Python fixture for fullwidth yen, mixed prices and deliberate review cases. ## Related guides - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md): How to use a proxy with curl: the -x flag, http_proxy and https_proxy variables, SOCKS5 with socks5h, proxy authentication, and reading CONNECT and 407 errors. - [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md): Configure a proxy in Python Requests: the proxies dictionary, Session defaults, credentials, SOCKS5 via requests[socks], environment variables and ProxyError. - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md): Separate proxy DNS, TCP, CONNECT, TLS and response delays with curl timings, then set request deadlines and decide whether a retry is safe. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 134 of 138: Price monitoring: a matching number hid a currency mismatch URL: https://ipvolt.com/blog/product-price-currency-validation Markdown: https://ipvolt.com/blog/product-price-currency-validation.md # Price monitoring: a matching number hid a currency mismatch Source: https://ipvolt.com/blog/product-price-currency-validation Markdown: https://ipvolt.com/blog/product-price-currency-validation.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / Price monitoring: a matching number hid a currency mismatch Category: Analysis Published: 2026-09-11 Updated: 2026-09-11 Author: ipvolt Reading time: 7 minutes Tags: proxies, troubleshooting A live storefront check found USD and EUR prices labelled GBP in product JSON-LD. Inspect the recordings and validate currency before accepting a price signal. A price monitor can extract the right digits and still record the wrong money. In our live checks of one Finisterre product, the HTML served for a US storefront view showed **$50.00**, while the matching product offer in JSON-LD described **50.0 GBP**. Our EUR storefront views showed **€55,00** beside an embedded offer of **55.0 GBP**. The UK control showed £40 and 40.0 GBP, which agreed. The practical rule is to hold a price record when its currency conflicts with the selected product's page context. A successful response, parseable JSON and matching amount do not resolve that conflict. We built a small checker and preserved the observations so readers can reproduce the classification before adapting the check to their own monitoring jobs. ## What we actually checked The subject was Finisterre's [Barents Beanie in Olive](https://finisterre.com/products/wool-finisterre-barents-beanie-olive), One Size: SKU `212955`, variant `58572724830592`. We matched the selected variant input, the product-specific structured offer and the corresponding Ajax variant record. We did not take a category's minimum price, another size, a recommendation or a crossed-out price. The selected Offer parsed successfully; the collector separately recorded an empty JSON-LD block in each page. Our main experiment compared four storefront contexts, including US, UK and Netherlands views. For each context, we requested the unqualified product URL and the `/en-us/` entry twice, with balanced ordering. All observations were collected on 11 September 2026. The main collection completed **16 product-page observations across 48 GET requests: 40 responses were HTTP 200 and eight were redirects.** Every final HTML and product-JSON response was readable. Twelve page observations had a currency disagreement; the four UK observations agreed. The method records 1,344,100 received response-body bytes, including the redirects, with no transport failures or missing byte measurements. The initial country and browser probes are separate from that total. These observations describe the collection window, not country-wide reliability. ## The same variant carried conflicting currency labels We compared the product's own price block with two explicit currency signals in the same HTML document: the Open Graph price currency and the active storefront currency. Those signals agreed with each other. We then inspected the exact variant's JSON-LD Offer. | Observed storefront context | Product price block | Matching JSON-LD offer | Observations | | --- | --- | --- | ---: | | EUR storefront views | €55,00 | 55.0 GBP | 8 | | US / USD | $50.00 | 50.0 GBP | 4 | | GB / GBP | £40 | 40.0 GBP | 4 | The number in each embedded offer matched the displayed number; its currency label did not always match. That distinction matters to a price database: `50.0 GBP` and `50.00 USD` are different records even before any exchange-rate calculation. We did not convert currencies or treat these market views as a price change over time. Four fresh, restricted browser contexts displayed the same prices and currency disagreements. That first run blocked localization resources. We then repeated the US and Netherlands views while allowing the observed commerce scripts, including the cross-border application, and waited ten seconds after the document loaded. Both disagreements remained. A product-country metadata POST and other resources were still blocked; the four-context run recorded 12 page errors and the expanded run recorded eight. These checks do not prove what a fully loaded shopping session displays. The central finding is the currency conflict within the **served HTML**. The [method](https://ipvolt.com/downloads/price-currency/method.json) retains the restrictions, errors and earlier incomplete calibration. We have not identified which template, app or configuration produced the currency label. The finding concerns the captured product responses; it is not evidence of a platform-wide Shopify defect. ## A market-looking URL did not settle the context The second pitfall appeared when joining HTML and Ajax data. Shopify documents product monetary fields in the customer's presentment currency and advises using locale-aware URLs. Its example derives the request from `window.Shopify.routes.root`. A bare product JSON amount does not independently establish its currency. [Shopify Product API](https://shopify.dev/docs/api/ajax/reference/product), [Ajax routing](https://shopify.dev/docs/api/ajax). In eight of the 16 observations, the HTML redirected to a different storefront prefix while the originally requested product JSON kept its own path. All eight original-path JSON amounts differed from the JSON fetched under the effective page prefix. For example, on the US route the unqualified HTML redirected to `/en-us/` and showed $50.00. The unqualified product JSON returned `4000`, while the effective `/en-us/` JSON returned `5000`. Neither JSON response included a currency field. Labelling that first value as $40 by borrowing the redirected page's currency would join different contexts. This is why the checker records the requested URL, every redirect, the effective product-page URL and the emitted storefront route root. It treats a JSON request under another prefix as a separate diagnostic. It does not borrow the redirected page's currency to label that other amount. The HTTP arm sent no cookies and executed no JavaScript. The browser arm started with fresh state but could receive cookies. We report them separately rather than assuming they represent identical sessions. Neither arm selected a shipping address, submitted a localization form or added anything to a cart. ## Hold contradictory records before making a pricing decision The useful output is a reason to accept or investigate a record, not a claim that one source is always authoritative. | Check | What to do when it fails | | --- | --- | | Exact product, selected variant and SKU agree | Hold the record; do not substitute a similar title or the first offer. | | The page's explicit currency signals agree | Mark the context unverified until the conflict is resolved. | | The selected offer's amount and currency agree with that context | Flag the conflicting fields instead of silently changing the currency label. | | The API amount belongs to the effective page context | Keep a different-prefix response separate; obtain context evidence for it. | | Market, variant, currency and price basis match the comparison record | Treat a different context as a separate series, not a price movement. | Replaying this dataset holds **12 of 16 page records for a currency conflict**. The other four pass the implemented within-record checks; that means internal agreement for this observed variant and context, not a verified checkout price or permission to compare it with another market. The eight original-path API responses are retained as separate diagnostics rather than silently joined to redirected HTML. Here is a condensed view of actual record `r1-us-en-us`; the original fields remain in the download: ```json { "variant_id": "58572724830592", "source_price_text": "$50.00", "storefront_currency": "USD", "naive_jsonld_record": {"price": "50.0", "currency": "GBP"}, "accepted_for_price_comparison": false, "quarantine_reasons": ["jsonld_storefront_currency_disagreement"] } ``` That is a measured data-quality result. We did not observe a production repricing system act on these records, measure money saved or establish payable checkout totals. The economic purpose of the check is to keep contradictory price data out of a decision that could affect purchasing or margins. For storefront owners, the same comparison is useful when testing product markup across markets. Google's merchant-listing documentation defines the currency accompanying a price, and its general structured-data guidelines require markup to represent the visible content. Those requirements explain why consistency matters; we did not inspect this retailer's Merchant Center feed, Googlebot view or Search Console results. [Price and currency](https://developers.google.com/search/docs/appearance/structured-data/merchant-listing), [visible-content guidelines](https://developers.google.com/search/docs/appearance/structured-data/sd-policies). ## Reproduce the classification Download [replay.py](https://ipvolt.com/downloads/price-currency/replay.py) and [selected-records.zip](https://ipvolt.com/downloads/price-currency/selected-records.zip) into the same directory. With Python 3.10 or newer, run: ```sh python3 replay.py selected-records.zip ``` The command makes no network requests. It recomputes decisions from the recorded fields and checks the cell plan, request references and completion totals. Compare the output with [results.json](https://ipvolt.com/downloads/price-currency/results.json). A completed replay can contain legitimate quarantines; malformed or inconsistent recordings are errors. The [download instructions](https://ipvolt.com/downloads/price-currency/README.md) include the actual collector, configuration, tests and exact command requirements. The published records retain selected identifiers, original price strings, explicit currency fields, requested/effective URLs, timestamps, status codes and body hashes. Raw page captures, cookies, exit addresses and proxy credentials remain private. Offline replay checks the published classifications and arithmetic; it cannot independently authenticate historical network responses. The adapter is intentionally specific to this product's markup and GBP/USD/EUR formats. For a property you operate, change the allowlist, variant identity and selectors, then verify the amount scale and currency evidence against a real page before collecting more samples. Missing or ambiguous fields should remain unverified. The [ETag monitoring case](https://ipvolt.com/blog/etag-monitoring-cache-control) covers a separate decision: reducing body transfer once the content being monitored is useful. *Method: actual public GET observations with agent-assisted collection and analysis, followed by separate evidence, editorial and search reviews. Local fixture tests exercise the checker and are not additional retailer observations.* ipvolt sells mobile proxies, and residential proxies from $2.20/GB: [see the prices](https://ipvolt.com/pricing). ## Sources - [Shopify Ajax Product API: presentment currency and locale-aware URLs](https://shopify.dev/docs/api/ajax/reference/product) - [Shopify Ajax API: use the storefront route root](https://shopify.dev/docs/api/ajax) - [Google merchant listing structured data: price and currency](https://developers.google.com/search/docs/appearance/structured-data/merchant-listing) - [Google structured-data guidelines: represent the visible content](https://developers.google.com/search/docs/appearance/structured-data/sd-policies) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [Check a Proxy for IP, DNS and WebRTC Leaks with ToDetect](https://ipvolt.com/blog/proxy-leak-check-todetect.md) (Analysis, Oct 23, 2026, 9 min read): Check a browser proxy for IP, DNS, WebRTC and time zone leaks with ToDetect's free tools, using measured results from a 4G mobile line as the worked example. - [Python 3.15 for Web Scraping: What Installs, What Breaks](https://ipvolt.com/blog/python-3-15-web-scraping.md) (Analysis, Oct 16, 2026, 8 min read): pip install scrapy fails on Python 3.15 without a C compiler: brotli has no cp315 wheel. We tested 19 scraping packages with pip and uv to see what else breaks. - [Japanese price parsing: yen, width and tax labels](https://ipvolt.com/blog/japanese-price-parsing.md) (Analysis, Oct 6, 2026, 6 min read): Parse Japanese price fields without losing currency or tax basis. Run a tested Python fixture for fullwidth yen, mixed prices and deliberate review cases. ## Related guides - [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md): Configure a proxy in Python Requests: the proxies dictionary, Session defaults, credentials, SOCKS5 via requests[socks], environment variables and ProxyError. - [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md): Choose rotation around the smallest complete workflow, distinguish exit affinity from cookies, and test what happens when a sticky session ends early. - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md): How to use a proxy with curl: the -x flag, http_proxy and https_proxy variables, SOCKS5 with socks5h, proxy authentication, and reading CONNECT and 407 errors. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 135 of 138: Proxy errors explained: 407, 429, 502 and 504 URL: https://ipvolt.com/blog/proxy-status-codes-407-429-502 Markdown: https://ipvolt.com/blog/proxy-status-codes-407-429-502.md # Proxy errors explained: 407, 429, 502 and 504 Source: https://ipvolt.com/blog/proxy-status-codes-407-429-502 Markdown: https://ipvolt.com/blog/proxy-status-codes-407-429-502.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / Proxy errors explained: 407, 429, 502 and 504 Category: Analysis Published: 2026-09-11 Updated: 2026-09-19 Author: ipvolt Reading time: 7 minutes Tags: proxies, troubleshooting Identify which layer returned a proxy error, check authentication and rate limits, and decide when a bounded retry of a failed request is safe. A 407 indicates that proxy authentication is required. A 429 indicates rate limiting, but the response alone does not tell you which requests share that limit. A 502 or 504 indicates an upstream response or timeout problem. First identify where the response originated, then check authentication, limits or connectivity as appropriate. ## First, identify the responding layer An HTTPS request through an HTTP proxy normally has two exchanges: the proxy answers a CONNECT request, then the client communicates with the destination through the tunnel. An HTTPS proxy adds a TLS connection to the proxy before CONNECT. In an ordinary tunnel without TLS interception, a response received after destination TLS comes from the destination's infrastructure, which may include a CDN or reverse proxy. The following example prints the CONNECT status separately from the HTTP response status. It requires curl 8.3 or later and uses Basic proxy authentication. Set `PROXY_URL` to your provider's credential-free HTTP(S) gateway, and have your secret manager populate `PROXY_USERNAME` and `PROXY_PASSWORD` in the environment. Use the authentication method your provider documents. Save this as `proxy-status.sh` and run `sh proxy-status.sh` without shell tracing. It makes one GET request, discards the body and preserves curl's exit status. curl imports the credentials itself, so the shell does not expand them into command arguments. ```sh : "${PROXY_URL:?Set a credential-free HTTP(S) proxy URL}" case "$PROXY_URL" in http://*|https://*) ;; *) printf '%s\n' 'PROXY_URL must use http:// or https://' >&2; exit 2 ;; esac case "$PROXY_URL" in *'@'*|*'?'*|*'#'*) printf '%s\n' 'Keep credentials, queries and fragments out of PROXY_URL' >&2 exit 2 ;; esac curl --disable --silent --fail --http1.1 \ --noproxy '' --proxy "$PROXY_URL" --proxy-basic \ --variable %PROXY_USERNAME --variable %PROXY_PASSWORD \ --expand-proxy-user '{{PROXY_USERNAME}}:{{PROXY_PASSWORD}}' \ --connect-timeout 5 --max-time 15 --retry 0 \ --output /dev/null \ --write-out 'exit=%{exitcode} http=%{http_code} connect=%{http_connect} seconds=%{time_total}\n' \ 'https://example.com/' ``` `--disable` stays first to ignore curlrc settings, and `--noproxy ''` prevents an inherited exclusion from bypassing the selected gateway. The five-second connection budget and fifteen-second total budget are starting points for this small diagnostic. The command neither follows redirects nor retries, and prints numeric results without a verbose trace. See the [curl manual](https://curl.se/docs/manpage.html) for these options. The [curl proxy guide](/guides/curl-proxy-setup) covers the plain `-x` form, the `http_proxy` and `https_proxy` variables and SOCKS5 with `socks5h`, which decide where a request goes before any of these status codes appear. Read the fields together. `connect=407` means the proxy challenged authentication during CONNECT. `connect=200 http=429` means the tunnel was accepted and an HTTP 429 arrived afterwards. `http=000` means no HTTP response status was recorded for the transfer; inspect the CONNECT status and curl exit code. A successful CONNECT does not establish that TLS setup or the body transfer completed. If that comes with `error:0A000126`, or Python prints `SSLEOFError`, [check whether the request was sent](/guides/fix-ssl-unexpected-eof-proxy) before retrying. For a plain HTTP destination, there is normally no tunnel. The proxy forwards the request, so the returned status may come from the proxy or the destination. Provider headers and branded error pages can offer clues, but appearance alone does not establish the sender. Use the provider's documented errors or request diagnostics when attribution remains uncertain. In Node.js fetch, a CONNECT refused with 403, 407, 429 or 502 is not on the error you catch: the status sits two levels down, under `Request was cancelled.` ([read the Node.js fetch cause chain](/guides/fix-node-fetch-failed-proxy)). ## 407 Proxy Authentication Required A 407 must include a `Proxy-Authenticate` challenge. The client may retry with `Proxy-Authorization`; the destination's `Authorization` header does not provide proxy authentication. These requirements come from [RFC 9110, section 15.5.8](https://www.rfc-editor.org/rfc/rfc9110.html#section-15.5.8). Start with these checks: - Confirm the gateway, username and password match the active provider configuration. - Check that credentials are in the proxy-authentication setting, rather than the destination-authentication setting. - If the provider encodes country or session targeting in the username, check its documented format. How a malformed target is reported depends on the provider. - If the library requires a proxy URL containing credentials, encode the username and password separately so reserved characters cannot change the URL structure. The [407 fix guide](/guides/fix-proxy-error-407) covers authentication diagnosis and shows the exact exception each client raises, with a working sample for each. The [Python Requests guide](/guides/python-requests-proxy) demonstrates explicit proxy configuration and credential encoding. Follow the library's documented format before adding retries. Before adding them at all, read [one lost response, two created jobs](/blog/proxy-retries-duplicate-jobs): a retry after a lost response can repeat a write that already happened. ## 429 Too Many Requests A 429 reports rate limiting. [RFC 6585, section 4](https://www.rfc-editor.org/rfc/rfc6585#section-4) deliberately leaves user identification and request counting to the responding service. The limit might apply to an account, credential, session, address, resource or wider service. The sender tells you whose policy to investigate. A proxy may be enforcing a plan or concurrency limit; the destination may be enforcing its own request limit. Neither case establishes the scope from the status alone. Read the response details and documented limit, and honour `Retry-After` when supplied. Reduce traffic at the affected scope. For a shared account limit, that can mean coordinating all workers using that account. For a limit tied to one resource, it can mean slowing requests to that resource. If the scope is unknown, reduce concurrency while investigating. Changing an exit does not establish that a limit has reset. Backoff also needs a bound: if the required wait exceeds the remaining job deadline, stop or schedule the work for later. Repeatedly retrying during the same limit window adds load without resolving the limit. ## 502 and 504: an upstream failure or delay A 502 Bad Gateway indicates an invalid upstream response. A 504 Gateway Timeout indicates that a gateway did not receive a timely upstream response. Their [HTTP definitions](https://www.rfc-editor.org/rfc/rfc9110.html#section-15.6.3) do not identify the failed component. In a proxy pool, investigate the exit, intervening gateways and the destination. Use provider diagnostics and a small, authorised control request to narrow the fault. Keep the destination and client settings consistent when comparing gateways, and change one variable at a time. Three client decisions matter: - **Whether repetition is safe.** For an approved request safe to repeat, allow a small number of attempts with backoff inside an overall deadline. A failed response to a write does not prove the write was never applied. Check the operation's state or documented idempotency mechanism before resubmitting it. See [HTTP retry semantics](https://www.rfc-editor.org/rfc/rfc9110.html#section-9.2.2). - **How long the job can wait.** Set deadlines from the job's latency budget. A shorter client deadline limits waiting but does not repair an upstream failure. The [timeout guide](/guides/proxy-timeout-troubleshooting) explains connection, transfer and overall job budgets. - **Which failures are increasing.** Track 502 and 504 separately by gateway, destination and region alongside application success rate. A change confined to one route is a reason to investigate that route, not proof that the entire pool is unhealthy. Use a fresh connection or a different exit only when that change fits the diagnosis and session requirements. A new exit can also change the user's session context, so it is not a universal retry strategy. ## 403 and HTTP 200 responses with unusable content A 403 indicates refusal. It can reflect a forward proxy's access policy or a refusal from the destination's infrastructure. Check the responding layer and its documented reason before changing credentials, headers or addresses. A harder case to detect is an HTTP 200 response containing a challenge page, login screen or incomplete application shell. The status records an HTTP outcome; your application must also validate the content it needs. For example, a product-data task should check the expected product identifier and required fields, not just a word that might also appear in an error page. The diagnostic command above discards the body. The Python guide likewise demonstrates configuration and status checking, so a production client needs its own destination-specific body validation. The [Amazon and Google observations](/blog/scraping-amazon-google-through-a-proxy) show why that additional check matters. ## Choose the next check Use this table after identifying the responding layer. These are starting checks, not proof of a root cause. | Observed result | What to investigate | First action | | --- | --- | --- | | CONNECT 407 | Proxy authentication | Check the challenge, credential configuration and provider account. | | CONNECT 429 or destination 429 | The responding service's limit | Honour `Retry-After` and reduce traffic at the documented scope. | | 502 or 504 | Upstream response or timing failure | Compare diagnostics; retry only work safe to repeat within its budget. | | CONNECT 403 or destination 403 | Access policy or authorisation | Check which layer refused the request and why. | | HTTP 200 with an incomplete or unexpected body | Application success criteria | Validate required content before counting success. | | No HTTP status | Connection, tunnel or TLS progress | Read curl's exit code and follow the timeout guide's stage checks. | For repeated measurements, the [benchmark method](/blog/what-a-proxy-benchmark-should-measure) explains transport logs, timing distributions and their limits. Keep the content result and any provider diagnosis alongside those logs so a status count does not become an unsupported explanation. ## Sources - [RFC 9110: HTTP authentication, gateway responses and retry semantics](https://www.rfc-editor.org/rfc/rfc9110.html) - [RFC 6585: section 4, 429 Too Many Requests](https://www.rfc-editor.org/rfc/rfc6585#section-4) - [curl manual: variables, CONNECT status and timeout options](https://curl.se/docs/manpage.html) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [Check a Proxy for IP, DNS and WebRTC Leaks with ToDetect](https://ipvolt.com/blog/proxy-leak-check-todetect.md) (Analysis, Oct 23, 2026, 9 min read): Check a browser proxy for IP, DNS, WebRTC and time zone leaks with ToDetect's free tools, using measured results from a 4G mobile line as the worked example. - [Python 3.15 for Web Scraping: What Installs, What Breaks](https://ipvolt.com/blog/python-3-15-web-scraping.md) (Analysis, Oct 16, 2026, 8 min read): pip install scrapy fails on Python 3.15 without a C compiler: brotli has no cp315 wheel. We tested 19 scraping packages with pip and uv to see what else breaks. - [Japanese price parsing: yen, width and tax labels](https://ipvolt.com/blog/japanese-price-parsing.md) (Analysis, Oct 6, 2026, 6 min read): Parse Japanese price fields without losing currency or tax basis. Run a tested Python fixture for fullwidth yen, mixed prices and deliberate review cases. ## Related guides - [Fix proxy error 407 without guessing](https://ipvolt.com/guides/fix-proxy-error-407.md): Diagnose Proxy Authentication Required in a repeatable order: gateway, authentication method, credential encoding, account scope and client configuration. - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md): How to use a proxy with curl: the -x flag, http_proxy and https_proxy variables, SOCKS5 with socks5h, proxy authentication, and reading CONNECT and 407 errors. - [Python Requests proxy: proxies dict, auth, SOCKS5](https://ipvolt.com/guides/python-requests-proxy.md): Configure a proxy in Python Requests: the proxies dictionary, Session defaults, credentials, SOCKS5 via requests[socks], environment variables and ProxyError. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 136 of 138: Residential vs datacenter proxies: how to choose URL: https://ipvolt.com/blog/residential-vs-datacenter-proxies Markdown: https://ipvolt.com/blog/residential-vs-datacenter-proxies.md # Residential vs datacenter proxies: how to choose Source: https://ipvolt.com/blog/residential-vs-datacenter-proxies Markdown: https://ipvolt.com/blog/residential-vs-datacenter-proxies.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / Residential vs datacenter proxies: how to choose Category: Comparison Published: 2026-09-11 Updated: 2026-09-11 Author: ipvolt Reading time: 6 minutes Tags: proxies, choosing Compare residential and datacenter proxies by network, content success, latency, session needs and billing, with five checks to guide your own tests. Start by comparing the proxy types against your destination, session requirements and budget. Datacenter proxies are worth evaluating for throughput and predictable infrastructure. Residential proxies are worth testing when the destination's treatment of hosting-network addresses affects your authorised workload. Neither label guarantees a successful response, a particular speed or a lower bill. ## What actually differs between the two The main distinction is the network associated with the exit IP: the public address the destination sees. Routing, device quality and pool operation also affect performance. A datacenter proxy uses an exit on hosting or cloud infrastructure. Address-registration records can help identify the associated network, but they do not tell you the address's request history or how a particular destination classifies it. A residential proxy uses an exit associated with a consumer ISP. In a device-based residential pool, traffic passes through a device on a subscriber's connection. Check the provider's description: an ISP-associated address does not by itself prove that a request passed through a home device. Some connections use carrier-grade NAT, so several subscribers share a public IPv4 address. [RFC 6598](https://www.rfc-editor.org/rfc/rfc6598) reserves address space for use within these provider networks; it does not define the whole NAT mechanism. A shared public address also means that its traffic history may include other users. ## Which one gets blocked less, and why There is no destination-independent winner. A destination may use hosting-network classification as one risk signal, alongside individual address reputation, geography, request rate, cookies and client behaviour. When that classification matters, a residential pool may perform differently. We have not published a controlled comparison establishing how often it helps. Two things this does not mean: - A residential exit can still be blocked. Previous users of a shared address may have affected its reputation, and changing IP type does not resolve every request or account restriction. - A datacenter exit can work well. Being a public API, registry or business website does not establish a destination's IP policy, so check its documented access route and test the actual workload. Use the destination's documented access options first, then compare permitted requests under similar conditions. The checks below help separate evidence from an initial guess. ## Which one is faster Datacenter proxies are a useful starting point for latency-sensitive work because the exit runs on hosting infrastructure. A device-based residential exit also depends on the subscriber's access connection and forwarding device. However, gateway location, routing, congestion, connection reuse and destination response time can change the result in either direction. Comparable residential and datacenter measurements are not yet available from us. Measure the actual pools and routes before assuming a speed advantage. Record application success as well as time to first byte: a fast challenge page does not complete your task. Use the [benchmark method](/blog/what-a-proxy-benchmark-should-measure) to plan a comparison. The [proxy timeout troubleshooting guide](/guides/proxy-timeout-troubleshooting) covers deadlines so a stalled request does not hold up your queue, whichever proxy type you choose. ## What each one costs and how it is billed Compare the actual offer rather than assuming one billing model for each type. A provider may charge for an address allocation, transferred traffic, requests or a combination. Check the included bandwidth, concurrency limits, allocation period, session duration and address-replacement policy. That billing difference changes how you should think about a job: - With per-IP pricing, high request volume can spread the allocation cost across more completed work, subject to bandwidth and rate limits. Blocked addresses can reduce the value of that allocation; check whether replacements are included. - With per-GB pricing, retries and unused page assets add to billed traffic. Avoid downloading assets the task does not require, and check which traffic directions and failed requests count towards the bill. This article does not include a current price survey. For residential plans sold by Mbps or threads rather than per GB, see [what unlimited residential proxies cost per GB](/blog/unlimited-residential-proxies-cost-per-gb), which converts dated list prices into cost per GB and a break-even against your per-GB rate. For your comparison, date each quote and estimate the total cost of completing the same workload, including retries, minimum commitments and overage charges. A fixed or sticky address is a product feature to verify, not something the billing unit guarantees. ## Five checks before choosing Use the first two checks to choose a starting option, then apply the session, latency and network requirements. Complete all five before committing. 1. **What access route does the destination document?** Start with the supported API or integration, its authentication requirements and applicable limits. If a proxy is needed, datacenter is one candidate to evaluate; permission to send requests does not establish its acceptance rate. 2. **Do comparable requests return the expected content?** An HTTP 200 response can contain a CAPTCHA challenge. Keep the client, request, cookies and timing consistent, then compare several addresses from each category where testing is permitted. Different responses from a home connection and a cloud VM justify further testing; they do not prove that IP type caused the difference. Geography, individual reputation and changing destination behaviour remain possible explanations. 3. **Does the flow need one address?** For steps such as logging in, adding items to a basket and checking out, evaluate a sticky session: a configuration intended to retain an exit for a stated period. Check that the provider supports the required duration and explains what happens if an exit disconnects. Preserve the application's cookies and session state too. 4. **What latency and throughput does the job require?** Measure successful-response latency, failure counts and sustainable request volume for each candidate. Include tail latency and deadlines when monitoring has tight alert windows. Neither proxy type guarantees a particular response time. 5. **Does the task require an ISP-associated static address or a cellular-network exit?** Evaluate the relevant product specifically. A mobile app backend alone does not imply that a mobile proxy is necessary. The [curl proxy setup guide](/guides/curl-proxy-setup) provides a bounded connection check with status and elapsed time. Use it to confirm the gateway works, then add a destination-specific content check before counting a request as successful. ## When the answer is neither Products sold as ISP proxies commonly describe hosted exits with ISP-associated addresses. Verify the actual hosting arrangement, address stability, classification at your destination and performance. The product label does not guarantee residential treatment or a particular price. Mobile proxies exit through cellular carrier networks. Evaluate them when carrier-network access is relevant to the task, and compare acceptance, latency and cost for the actual pool. Carrier address sharing does not guarantee that a destination will accept the request. The [mobile vs residential comparison guide](/guides/mobile-vs-residential-proxies) covers the network and session tradeoffs to examine. ipvolt, which publishes this post, sells mobile proxies and residential proxies from $2.20/GB. Test these recommendations against your own destinations and workload. Before buying, record each candidate's content success rate, latency distribution, session behaviour and estimated cost per completed job. ## Sources - [RFC 6598: IANA-Reserved IPv4 Prefix for Shared Address Space (carrier-grade NAT)](https://www.rfc-editor.org/rfc/rfc6598) - [RFC 9110: HTTP Semantics, section 9.3.6 CONNECT](https://www.rfc-editor.org/rfc/rfc9110#name-connect) - [curl manual: --proxy and --write-out](https://curl.se/docs/manpage.html) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [How to Check if a Proxy Is Really Mobile or Residential](https://ipvolt.com/blog/check-if-proxy-is-mobile-or-residential.md) (Analysis, Nov 8, 2026, 12 min read): No single check proves a proxy is mobile or residential. We tested ASN, RDAP, PeeringDB, reverse DNS and IP databases on a mobile line and a datacenter IP. - [How Many GB of Proxies Do You Need? Pages per GB, Measured](https://ipvolt.com/blog/how-many-gb-of-proxies-do-i-need.md) (Benchmark, Oct 5, 2026, 8 min read): We loaded 34 public pages three ways through a metering proxy. 1 GB fits about 44,000 HTML-only fetches, or about 900 full Playwright page loads. - [Unlimited residential proxies: what they cost per GB](https://ipvolt.com/blog/unlimited-residential-proxies-cost-per-gb.md) (Comparison, Sep 27, 2026, 18 min read): Turn Mbps- and thread-based unlimited residential proxy plans into cost per GB, find the break-even with your per-GB rate, and check terms before you pay. ## Related guides - [Mobile vs residential proxies: build a useful evaluation](https://ipvolt.com/guides/mobile-vs-residential-proxies.md): Compare carrier and household exit networks for QA, keep browser emulation separate, and measure the capabilities your workflow actually needs. - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md): How to use a proxy with curl: the -x flag, http_proxy and https_proxy variables, SOCKS5 with socks5h, proxy authentication, and reading CONNECT and 407 errors. - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md): Separate proxy DNS, TCP, CONNECT, TLS and response delays with curl timings, then set request deadlines and decide whether a retry is safe. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 137 of 138: Amazon and Google: why HTTP 200 can still mean failure URL: https://ipvolt.com/blog/scraping-amazon-google-through-a-proxy Markdown: https://ipvolt.com/blog/scraping-amazon-google-through-a-proxy.md # Amazon and Google: why HTTP 200 can still mean failure Source: https://ipvolt.com/blog/scraping-amazon-google-through-a-proxy Markdown: https://ipvolt.com/blog/scraping-amazon-google-through-a-proxy.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / Amazon and Google: why HTTP 200 can still mean failure Category: Analysis Published: 2026-09-11 Updated: 2026-09-19 Author: ipvolt Reading time: 7 minutes Tags: proxies, choosing Why an HTTP 200 from Amazon or Google can still be a failed scrape: challenge pages, empty shells, robots rules and the official data options to check first. An HTTP 200 from Amazon or Google is not evidence that a scrape worked. Both sites can answer a bot-like request with a challenge page, a search shell that needs JavaScript to fill in, or a full page of markup that still lacks the records a parser needs, and all three arrive with a 200 status. This article describes those response patterns, why status alone is a poor success check, and the rules and official interfaces to review before collecting anything. It does not report measurements of either site and does not establish how residential or mobile proxies would perform. For Amazon listing state specifically, the [Amazon listing notifications guide](/guides/amazon-listing-notifications) covers the official notification interface for listing changes, which is the first place to look before collecting pages. ## What these responses look like in practice Three response classes account for most of the confusion, and none of them is distinguishable by status code. **A challenge page.** The status is 200, the body is small, the title is blank or generic, and the HTML consists mainly of JavaScript that triggers an interstitial or bot-management check. Amazon's challenge markup, for example, carries a challenge function and a verification marker rather than store content. A status-only success counter accepts this response even though the parser finds nothing. [Cloudflare AI agent blocks: what to fix first](/blog/cloudflare-ai-agent-proxy-setup) works through the same failure on a Cloudflare-protected site, where the challenge page rather than the content is what the client receives. **Search markup.** The status is 200, the body is large, the title echoes the query, and result-item containers repeat through the page. This looks like success, but a count of a container class name is not a validated record set. Counting a string is not the same as parsing each product card and confirming that its identifier, price and title are present. **A page shell.** The status is 200, the body has a moderate size, the title is the generic site name, and the HTML contains a script that asks the browser to enable JavaScript alongside a `noscript` block. No result headings exist for a parser to match. This is consistent with markup that expects further browser processing, but it does not tell you whether a browser would succeed, or whether a different exit address would receive the same shell. The same address can receive different classes of response on consecutive requests to different paths. An IP address alone therefore does not predict the response: path, timing, headers, cookies and server-side decisions all contribute, and none of them is controlled by changing the exit. The useful conclusion is narrow: the status line does not tell a parser whether it has the data it needs. Treat 200 as "a response arrived", not "the scrape succeeded". ## Check the body, not the status A content check needs at least four questions answered per response. - Does the title match what the page should be, rather than a blank, a generic site name or a verification page? - Does the body contain a challenge or bot-management script marker? If so, classify the response as a challenge regardless of status. - How many records parsed, and does each one carry the fields the application needs? Record the parsed count, not the count of a marker string. - Is the HTML a shell that expects JavaScript to populate it? A `noscript` block or an enable-JavaScript script is a strong signal. Log the answers next to the HTTP status, curl's exit code and the transfer timing. Curl's `--write-out` fields such as `size_download` and `time_starttransfer` are documented in the [curl manual](https://curl.se/docs/manpage.html); they describe the transfer, not the application result, and the two must be recorded side by side. ## Robots.txt and service rules The Robots Exclusion Protocol describes crawler instructions. [RFC 9309](https://www.rfc-editor.org/rfc/rfc9309.html) explicitly distinguishes those instructions from access authorisation. An absent disallow rule is not, by itself, permission to collect or reuse content. At the 11 September 2026 review, [Google's robots.txt](https://www.google.com/robots.txt) disallowed `/search` in its general user-agent group, with specific exceptions including `/search/about` and `/search/howsearchworks`. Evaluate the actual path and applicable group; a rule count or line number is not a useful permission check. For Amazon, check the applicable marketplace's [robots.txt](https://www.amazon.com/robots.txt) and [Conditions of Use](https://www.amazon.com/gp/help/customer/display.html?nodeId=508088), along with any programme-specific agreement. This article does not establish that any search or product path is authorised for a particular collection or reuse. [Google's terms effective 30 July 2026](https://policies.google.com/terms) restrict automated access that violates its machine-readable instructions. Its [Search policy on machine-generated traffic](https://developers.google.com/search/docs/essentials/spam-policies#machine-generated-traffic) separately covers automated Search access without express permission, including scraping results for rank checking. Review the current documents for your service and region; changing an exit address does not change those requirements. ## Official data-access options Choose an interface by the data and permitted use your application needs. Availability below was reviewed on 11 September 2026. - **Amazon Creators API** provides product-catalog access for publishers and affiliate partners under its programme requirements. It is the supported successor to Product Advertising API 5. Amazon's [deprecation notice](https://affiliate-program.amazon.com/creatorsapi/docs/en-us/paapiv5-deprecation) says continued calls to PA-API 5 receive a 403 response with `AccessDeniedException`. Start with the [Creators API documentation](https://affiliate-program.amazon.com/creatorsapi/docs/en-us/introduction). - **Amazon Selling Partner API** supports authorised applications working with selling-partner data, such as listings and orders. Its [overview](https://developer-docs.amazon/sp-api/docs/what-is-the-selling-partner-api) explains the scope; access depends on the application, permissions and selling partner. - **Google Custom Search JSON API** is closed to new customers. Existing customers must transition to an alternative by **1 January 2027**. Google's [overview](https://developers.google.com/custom-search/v1/overview) points to Vertex AI Search for up to 50 domains and an inquiry route for full-web search needs. These options require a separate fit and availability check; the legacy API is not an available starting point for a new customer. - **Google Search Console** reports your own site's search performance, including clicks, impressions and average position. Those [metrics](https://support.google.com/webmasters/answer/7042828?hl=en) can answer questions about your verified properties, but do not provide a complete competitor ranking feed. Official interfaces have eligibility requirements, permissions, quotas and usage terms. Compare their coverage with the actual fields, freshness and markets your application requires. A documented interface still needs error handling and does not guarantee unrestricted data access. ## When a location-specific connection may help An authorised location check might investigate how your listing appears in another market, whether a regional campaign is visible, or why a customer sees different content. These are reasons to evaluate a connection from the relevant region, subject to the service's rules. An exit IP is only one input to such a test. Keep the browser, language, account state and session settings consistent, and record what you changed. A single request or low volume does not itself establish permission, and a regional exit does not reproduce every customer's personalised view. The [rotating versus sticky guide](/guides/rotating-vs-sticky-proxies) explains session choices. The [residential versus datacenter comparison](/blog/residential-vs-datacenter-proxies) describes how to evaluate candidate pools. This article does not measure either type; choose between them with an authorised comparison of your own workload. ## What to record in an authorised comparison Define application success before making requests. For product data, that can mean a matching product identifier and all required fields; for search data, a parsed result structure and the expected query context. A title or marker count can be a useful diagnostic, but should not stand in for validating the records you will use. Record the exact public test URL and query, UTC timestamp, client version, request settings, redirect policy, gateway or direct route, and content-check method. Keep HTTP and CONNECT statuses, curl's exit code and timing with the application result. Retain enough sanitised response evidence to explain a challenge, missing fields or a changed parser result. A response header can change the result as much as the body: [ETag monitoring: a no-cache header changed our results](/blog/etag-monitoring-cache-control) records one such case. For a fair comparison, hold the client and request settings constant, sample multiple addresses from each candidate network type, and interleave the requests over the same observation window. Different outcomes justify investigation; they do not alone prove that network type caused the difference. Any sustained test also needs a permitted request rate and a defined stopping condition. The [benchmark method](/blog/what-a-proxy-benchmark-should-measure) provides a starting point for transport measurements and explains where application-specific checks are needed. If CONNECT returns 407, investigate proxy authentication with the [407 guide](/guides/fix-proxy-error-407). The [curl setup guide](/guides/curl-proxy-setup) shows how to record CONNECT and HTTP status separately. ## What this article does not establish This article does not compare responses across residential or mobile exits, test browser rendering, validate complete product records, or measure sustained challenge rates. No request count from a single address can estimate a provider's success rate or predict how a different request volume would behave. Use the patterns above to design a content check; base a proxy choice on a separate, authorised comparison of the workload you need to run. ## Sources - [Amazon robots.txt](https://www.amazon.com/robots.txt) - [Amazon Conditions of Use](https://www.amazon.com/gp/help/customer/display.html?nodeId=508088) - [Amazon Creators API introduction](https://affiliate-program.amazon.com/creatorsapi/docs/en-us/introduction) - [Amazon Product Advertising API 5 deprecation notice](https://affiliate-program.amazon.com/creatorsapi/docs/en-us/paapiv5-deprecation) - [Amazon Selling Partner API overview](https://developer-docs.amazon/sp-api/docs/what-is-the-selling-partner-api) - [Google robots.txt](https://www.google.com/robots.txt) - [Google Terms of Service, effective 30 July 2026](https://policies.google.com/terms) - [Google Search spam policies: machine-generated traffic](https://developers.google.com/search/docs/essentials/spam-policies#machine-generated-traffic) - [Google Custom Search JSON API availability](https://developers.google.com/custom-search/v1/overview) - [Google Search Console performance metrics](https://support.google.com/webmasters/answer/7042828?hl=en) - [RFC 9309: Robots Exclusion Protocol](https://www.rfc-editor.org/rfc/rfc9309.html) - [curl manual: transfer size and time to first byte](https://curl.se/docs/manpage.html) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [How to Check if a Proxy Is Really Mobile or Residential](https://ipvolt.com/blog/check-if-proxy-is-mobile-or-residential.md) (Analysis, Nov 8, 2026, 12 min read): No single check proves a proxy is mobile or residential. We tested ASN, RDAP, PeeringDB, reverse DNS and IP databases on a mobile line and a datacenter IP. - [How Many GB of Proxies Do You Need? Pages per GB, Measured](https://ipvolt.com/blog/how-many-gb-of-proxies-do-i-need.md) (Benchmark, Oct 5, 2026, 8 min read): We loaded 34 public pages three ways through a metering proxy. 1 GB fits about 44,000 HTML-only fetches, or about 900 full Playwright page loads. - [Unlimited residential proxies: what they cost per GB](https://ipvolt.com/blog/unlimited-residential-proxies-cost-per-gb.md) (Comparison, Sep 27, 2026, 18 min read): Turn Mbps- and thread-based unlimited residential proxy plans into cost per GB, find the break-even with your per-GB rate, and check terms before you pay. ## Related guides - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md): How to use a proxy with curl: the -x flag, http_proxy and https_proxy variables, SOCKS5 with socks5h, proxy authentication, and reading CONNECT and 407 errors. - [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md): Choose rotation around the smallest complete workflow, distinguish exit affinity from cookies, and test what happens when a sticky session ends early. - [Fix proxy error 407 without guessing](https://ipvolt.com/guides/fix-proxy-error-407.md): Diagnose Proxy Authentication Required in a repeatable order: gateway, authentication method, credential encoding, account scope and client configuration. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB. --- Document 138 of 138: What to measure in a proxy benchmark URL: https://ipvolt.com/blog/what-a-proxy-benchmark-should-measure Markdown: https://ipvolt.com/blog/what-a-proxy-benchmark-should-measure.md # What to measure in a proxy benchmark Source: https://ipvolt.com/blog/what-a-proxy-benchmark-should-measure Markdown: https://ipvolt.com/blog/what-a-proxy-benchmark-should-measure.md [Home](https://ipvolt.com/index.md) / [Blog](https://ipvolt.com/blog.md) / What to measure in a proxy benchmark Category: Analysis Published: 2026-09-11 Updated: 2026-09-11 Author: ipvolt Reading time: 7 minutes Tags: proxies, choosing, troubleshooting Compare proxies using content success, response times and session behaviour, with a curl-based Python harness that records failures and calculates results. Compare proxies using application success rate, response-time distributions, connection setup and session behaviour. Define success for each destination before collecting results. The examples below include an observed direct baseline and a small harness that checks a response marker and calculates success rate and latency. Comparable residential and datacenter results have not yet been published by us. ## Define success before measuring speed Low response times can hide a high cost per successful request when failures trigger retries. Count completed work as well as elapsed time, and include any retry traffic in your cost estimate. Success needs a definition per destination: the expected status, the required content and an acceptable redirect outcome. An HTTP 200 response containing a CAPTCHA challenge can fail that definition. A missing field or an incomplete download can fail it too. A simple text marker is useful for a starter check; a production workload may need parsed records, schema validation or a complete multi-step flow. Record successful responses and each failure category separately, then investigate the cause. A timeout can occur on several parts of the path. A 403 alone does not identify which intermediary or origin enforced a restriction. Neither response time nor status is enough to assign blame. ## Record time to first byte and total time curl reports timing milestones measured from the start of the transfer. Time to first byte (TTFB) tells you when the response began; total time includes receiving its body. Record both, because a prompt first byte can still precede a slow or incomplete download. On 11 September 2026, three consecutive direct requests to `https://example.com/` from a VPS in Helsinki using curl 8.18 produced the following values. No proxy was used. The labels below make the cumulative meaning explicit: ```text http=200 tcp_complete=0.009780s tls_complete=0.023224s ttfb=0.044821s total=0.044983s http=200 tcp_complete=0.008289s tls_complete=0.023851s ttfb=0.039902s total=0.039966s http=200 tcp_complete=0.008149s tls_complete=0.031935s ttfb=0.061614s total=0.061688s ``` That is an observed baseline of approximately 40–62 ms to first byte, not a lower bound on future requests. Three observations do not establish a stable distribution. Collect a fresh baseline on the same machine and destination close to the proxy comparison, and retain the run date, client version and configuration. This bounded command collects the same fields for a new direct request: ```sh curl --disable --silent --show-error --noproxy '*' \ --connect-timeout 5 --max-time 20 --retry 0 \ --output /dev/null \ --write-out 'http=%{http_code} tcp_complete=%{time_connect}s tls_complete=%{time_appconnect}s ttfb=%{time_starttransfer}s total=%{time_total}s exit=%{exitcode}\n' \ 'https://example.com/' ``` For the same request through an HTTP(S) proxy, use curl 8.3 or later. Set `PROXY_URL` to the provider's credential-free gateway, including its supported scheme and port. Have your secret manager supply `PROXY_USERNAME` and `PROXY_PASSWORD` in the environment. This example follows the [curl setup guide](/guides/curl-proxy-setup): curl imports credentials itself so the expanded password is not a shell argument. Do not enable shell tracing. ```sh : "${PROXY_URL:?Set a credential-free HTTP(S) gateway URL}" curl --disable --silent --show-error --noproxy '' \ --proxy "$PROXY_URL" --proxy-basic \ --variable %PROXY_USERNAME --variable %PROXY_PASSWORD \ --expand-proxy-user '{{PROXY_USERNAME}}:{{PROXY_PASSWORD}}' \ --connect-timeout 5 --max-time 20 --retry 0 \ --output /dev/null \ --write-out 'http=%{http_code} tunnel=%{http_connect} tcp_complete=%{time_connect}s tls_complete=%{time_appconnect}s ttfb=%{time_starttransfer}s total=%{time_total}s exit=%{exitcode}\n' \ 'https://example.com/' ``` `--disable` stays first to ignore personal curl configuration. The direct command's `--noproxy '*'` bypasses inherited proxies; the proxied command's empty bypass list prevents `NO_PROXY` from excluding the destination. These commands use one fresh connection per curl process, do not follow redirects and do not retry. An HTTP error can still have curl exit code zero because the commands deliberately omit `--fail`; inspect the HTTP status separately. See the [curl manual](https://curl.se/docs/manpage.html#--noproxy) for route selection and the [timeout guide](/guides/proxy-timeout-troubleshooting) for deadlines. ## Understand what connection timings include For an HTTPS destination through an HTTP proxy, curl establishes a connection to the proxy, requests a CONNECT tunnel, then negotiates TLS to the destination through that tunnel. [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110#name-connect) defines CONNECT. The interval between `time_connect` and `time_appconnect` includes tunnel setup and TLS establishment. Subtracting the corresponding direct interval does not isolate CONNECT overhead: routing and handshake conditions change too. An HTTPS proxy adds another TLS handshake. A static CDN object does not remove those differences. Use the milestones to locate where delay appears, then investigate with controlled endpoints or suitably instrumented client and proxy logs. Only subtract milestones that completed in the same simple transfer. Failed requests, reused connections and redirects need separate interpretation; a zero value may mean a phase was not reached. `%{http_connect}` reports the HTTP CONNECT response code separately from the transfer's HTTP status. `--proxy-header` sends a header to the proxy; it does not report tunnel status. Prefer selected status and timing fields over verbose traces that may contain authentication data. These interpretations follow curl's [documented timing fields](https://curl.se/docs/manpage.html#-w). ## Check rotation against the promised policy The exit IP is the public address observed by the destination. Query a provider-supported diagnostic endpoint or an endpoint you control that reports the caller's address. [ipify](https://www.ipify.org/) is one public option; check its current usage guidance before automating requests. Keep a timestamped sequence of results before reducing them to unique-address counts. For each attempt, record the selected region, session setting, transport result and a validated IPv4 or IPv6 address. Exclude failed requests and invalid bodies from address counts, while reporting those failures separately. In Python, `ipaddress.ip_address(value.strip())` can validate a plain-text address response. Compare that sequence with the provider's rotation policy. Rotation may occur per request, connection or time interval, and the pool may reuse an address. Ten requests do not require ten distinct exits unless the product explicitly promises that. A sticky session is intended to retain an exit for its documented duration; check its expiry and disconnection behaviour before treating a reassignment as a fault. Use the country or region and session settings your workload needs. Repeat the test across the relevant session window. The [rotating vs sticky guide](/guides/rotating-vs-sticky-proxies) explains which behaviours to evaluate. The content benchmark below does not measure rotation. ## Choose a sample and observation window Ten requests can uncover basic failures, but they offer little evidence about a latency distribution. Slow requests can hold up a queue; a mean alone can hide slow outliers. Our proposed starting point is 200 requests per destination per configuration, spread over at least an hour. This is a test-design choice, not a universal reliability threshold. The 95th percentile of a small sample depends on very few observations. Report sample size, failure counts and the observation window, then repeat across times and conditions relevant to the workload. When comparing providers, interleave their requests during the same window. This reduces differences caused by changing destination load without guaranteeing identical conditions. Keep request content, client settings and success criteria consistent. Test connection reuse and production concurrency separately from the sequential, fresh-process example below. ## A small content benchmark with a summary Save this as `proxy-bench.py` and run `python3 proxy-bench.py`. It requires Python 3 and curl 8.3+. It uses the same private proxy environment variables as above. Set `BENCH_MODE=direct` for a direct run or leave it at `proxy`. Each run creates a new result directory and prints its path. The default destination is a small illustrative page. For an actual comparison, set `BENCH_URL` to a permitted HTTPS endpoint and replace `BENCH_MARKER` with a meaningful expected string. Do not use URLs containing credentials or sensitive parameters. Adapt the content check for your real response format before quoting application success. ```python import collections import datetime import json import math import os from pathlib import Path import statistics import subprocess import tempfile import time url = os.environ.get("BENCH_URL", "https://example.com/") marker = os.environ.get("BENCH_MARKER", "

Example Domain

").encode() mode = os.environ.get("BENCH_MODE", "proxy") if not url.startswith("https://") or not marker or mode not in {"direct", "proxy"}: raise SystemExit("Use an HTTPS URL, a nonempty marker and direct or proxy mode") route = ["--noproxy", "*"] if mode == "proxy": route = ["--noproxy", "", "--proxy", os.environ["PROXY_URL"], "--proxy-basic", "--variable", "%PROXY_USERNAME", "--variable", "%PROXY_PASSWORD", "--expand-proxy-user", "{{PROXY_USERNAME}}:{{PROXY_PASSWORD}}"] fields = ["http", "tunnel", "tcp_complete", "tls_complete", "ttfb", "total"] write_out = "%{http_code} %{http_connect} %{time_connect} %{time_appconnect} %{time_starttransfer} %{time_total}" count, window = 200, 3600.0 directory = Path(tempfile.mkdtemp(prefix="proxy-bench-", dir=".")) rows = [] started = time.monotonic() with (directory / "results.jsonl").open("x") as log: for i in range(count): due = started + i * window / (count - 1) time.sleep(max(0, due - time.monotonic())) timestamp = datetime.datetime.now(datetime.timezone.utc).isoformat() with tempfile.TemporaryDirectory() as scratch: body = Path(scratch) / "body" result = subprocess.run( ["curl", "--disable", "--silent", "--connect-timeout", "5", "--max-time", "20", "--retry", "0", *route, "--output", str(body), "--write-out", write_out, "--url", url], capture_output=True, text=True) values = result.stdout.split() timings = dict(zip(fields, values)) if len(values) == len(fields) else {} if result.returncode: outcome = f"curl_{result.returncode}" elif not timings: outcome = "missing_measurements" elif timings["http"] != "200": outcome = "http_" + timings["http"] elif not body.exists() or marker not in body.read_bytes(): outcome = "content_mismatch" else: outcome = "success" row = dict(attempt=i + 1, timestamp=timestamp, mode=mode, exit_code=result.returncode, outcome=outcome, **timings) rows.append(row) log.write(json.dumps(row) + "\n") log.flush() successful = [row for row in rows if row["outcome"] == "success"] summary = {"attempts": len(rows), "successes": len(successful), "success_rate": len(successful) / len(rows), "outcomes": dict(collections.Counter(row["outcome"] for row in rows))} for metric in ("ttfb", "total"): samples = sorted(float(row[metric]) for row in successful) summary[metric] = ({"median_seconds": statistics.median(samples), "p95_seconds": samples[math.ceil(0.95 * len(samples)) - 1]} if samples else None) (directory / "summary.json").write_text(json.dumps(summary, indent=2) + "\n") print(directory) print(json.dumps(summary, indent=2)) ``` The first request starts immediately; the 200th is scheduled 3,600 seconds after the first. Requests remain sequential. If a request takes longer than the spacing, later starts slip and the run takes longer. Actual start timestamps are retained in the log. There are no automatic retries or followed redirects, so a 3xx response is an HTTP failure in this example. If your workload requires redirects, define which destinations and final content are acceptable before extending the harness. Each log row contains the attempt number, UTC start timestamp, route mode, curl exit code, outcome, HTTP and CONNECT status, and four cumulative timing milestones in seconds. The harness retains neither response bodies nor credentials in its result files. Keep a separate private run note for the provider, pool, target, client version and session configuration. The success-rate denominator is **all attempted requests**, including timeouts and content failures. curl exit codes such as 28 (timeout), 7 (connection failure) and 56 (receive failure) describe broad failure categories, not a confirmed faulty component. Use the [official exit-code reference](https://everything.curl.dev/cmdline/exitcode.html) when investigating. Latency statistics use only successful responses, and the summary keeps the failure counts beside them. The median is the middle value, averaging the middle pair when necessary. The 95th percentile uses the nearest-rank method: sort the successful samples and select rank `ceil(0.95 × sample_count)`, counting from one. With no successes, both latency summaries are `null`. For example, four successes from five attempts give an 80% success rate. If their TTFB values are 0.10, 0.12, 0.20 and 0.40 seconds, the median is 0.16 seconds and the nearest-rank p95 is 0.40 seconds. These are invented values to explain the calculation, not measured proxy results. Start with a short controlled check of the harness and your content rule, then run the agreed observation window. Publish the configuration, sample size, failures and success definition alongside any latency comparison. The direct baseline above is illustrative; it does not establish a proxy ranking. ## Sources - [curl manual: --write-out variables and proxy configuration](https://curl.se/docs/manpage.html#-w) - [everything curl: exit codes](https://everything.curl.dev/cmdline/exitcode.html) - [RFC 9110: HTTP Semantics, section 9.3.6 CONNECT](https://www.rfc-editor.org/rfc/rfc9110#name-connect) - [ipify: a simple public IP address API](https://www.ipify.org/) ## Plug in your first proxy. Mobile from $9 a day. Residential from $2.20 per GB. [Buy mobile](https://ipvolt.com/dashboard/mobile) [Buy residential](https://ipvolt.com/dashboard/residential) ## Related posts - [How to Check if a Proxy Is Really Mobile or Residential](https://ipvolt.com/blog/check-if-proxy-is-mobile-or-residential.md) (Analysis, Nov 8, 2026, 12 min read): No single check proves a proxy is mobile or residential. We tested ASN, RDAP, PeeringDB, reverse DNS and IP databases on a mobile line and a datacenter IP. - [Check a Proxy for IP, DNS and WebRTC Leaks with ToDetect](https://ipvolt.com/blog/proxy-leak-check-todetect.md) (Analysis, Oct 23, 2026, 9 min read): Check a browser proxy for IP, DNS, WebRTC and time zone leaks with ToDetect's free tools, using measured results from a 4G mobile line as the worked example. - [Python 3.15 for Web Scraping: What Installs, What Breaks](https://ipvolt.com/blog/python-3-15-web-scraping.md) (Analysis, Oct 16, 2026, 8 min read): pip install scrapy fails on Python 3.15 without a C compiler: brotli has no cp315 wheel. We tested 19 scraping packages with pip and uv to see what else breaks. ## Related guides - [Use a proxy with curl: -x, env vars, SOCKS5, auth](https://ipvolt.com/guides/curl-proxy-setup.md): How to use a proxy with curl: the -x flag, http_proxy and https_proxy variables, SOCKS5 with socks5h, proxy authentication, and reading CONNECT and 407 errors. - [Troubleshoot proxy timeouts one stage at a time](https://ipvolt.com/guides/proxy-timeout-troubleshooting.md): Separate proxy DNS, TCP, CONNECT, TLS and response delays with curl timings, then set request deadlines and decide whether a retry is safe. - [Rotating vs sticky proxies: plan for session continuity](https://ipvolt.com/guides/rotating-vs-sticky-proxies.md): Choose rotation around the smallest complete workflow, distinguish exit affinity from cookies, and test what happens when a sticky session ends early. ## About ipvolt Technical analysis from ipvolt. Mobile from $9 a day. Residential from $2.20 per GB.