<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mathew</title>
    <description>The latest articles on DEV Community by Mathew (@mathewtech).</description>
    <link>https://dev.to/mathewtech</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3931121%2F42e20eb3-45cc-436b-9204-8109e3f1f6d2.jpg</url>
      <title>DEV Community: Mathew</title>
      <link>https://dev.to/mathewtech</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mathewtech"/>
    <language>en</language>
    <item>
      <title>Forward Proxy vs Reverse Proxy: A Developer's Guide to the Difference</title>
      <dc:creator>Mathew</dc:creator>
      <pubDate>Mon, 28 Sep 2026 06:04:12 +0000</pubDate>
      <link>https://dev.to/mathewtech/forward-proxy-vs-reverse-proxy-a-developers-guide-to-the-difference-55j4</link>
      <guid>https://dev.to/mathewtech/forward-proxy-vs-reverse-proxy-a-developers-guide-to-the-difference-55j4</guid>
      <description>&lt;p&gt;"Proxy" is one of those terms that means different things depending on who's using it and in what context. An infrastructure engineer reaching for Nginx to handle load balancing is talking about a reverse proxy. A developer configuring a scraper to route traffic through residential IPs is talking about a forward proxy. Both are proxies in the general sense - an intermediary that sits between two parties in a network connection - but they solve opposite problems and sit on opposite sides of the client-server relationship.&lt;br&gt;
The confusion compounds because tools like Nginx and HAProxy can operate as either, depending on configuration, and some systems use both simultaneously. This guide draws a clear line between the two, explains the architectural role each plays, and covers the concrete use cases where each type is the right tool.&lt;br&gt;
&lt;strong&gt;The Core Distinction: Who the Proxy Serves&lt;/strong&gt;&lt;br&gt;
The simplest way to understand the difference is to ask who the proxy is working for.&lt;br&gt;
A forward proxy works on behalf of the client. It sits between a client (your browser, your scraper, your application) and the internet. When the client wants to reach a server, the request goes to the forward proxy first, which forwards it to the destination. The destination server sees the proxy's IP address, not the client's. The client is the party being served - their identity is hidden, their traffic is routed, their requests are filtered or modified on the way out.&lt;br&gt;
A reverse proxy works on behalf of the server. It sits between the internet and one or more origin servers. When a client makes a request, it hits the reverse proxy first, which decides how to handle it - which backend server to forward it to, whether to serve a cached response, whether to terminate TLS, whether to apply rate limiting. The client has no visibility into the origin server. The server infrastructure is the party being served - its identity is hidden, its load is distributed, its traffic is managed on the way in.&lt;br&gt;
Same intermediary pattern, opposite orientation. Forward proxy = client-side. Reverse proxy = server-side.&lt;br&gt;
&lt;strong&gt;Forward Proxy: Architecture and Use Cases&lt;/strong&gt;&lt;br&gt;
A forward proxy is explicitly configured by the client (or the network the client is on). The client knows it's using a proxy - it sends its requests to the proxy address rather than directly to the destination.&lt;br&gt;
How it works:&lt;br&gt;
Client → Forward Proxy → Internet → Destination Server&lt;/p&gt;

&lt;p&gt;The client sends a request to the proxy. The proxy forwards it to the destination on the client's behalf. The destination returns the response to the proxy, which passes it back to the client. From the destination's perspective, the request originated from the proxy IP.&lt;br&gt;
For HTTP/HTTPS traffic, forward proxies typically use one of two mechanisms. For HTTP, the proxy reads the full request and forwards it. For HTTPS, the proxy uses the CONNECT method to establish a tunnel - the client tells the proxy "connect me to host:port" and the proxy opens a TCP tunnel, after which the client and destination communicate directly through the tunnel (with the proxy passing bytes without inspecting them).&lt;br&gt;
Common use cases:&lt;br&gt;
Corporate network filtering is one of the oldest forward proxy use cases. Traffic from employees' machines routes through a proxy that enforces content policies, logs traffic for compliance, and blocks access to unauthorized sites. The proxy is transparent to users on the corporate network but explicitly configured in the browser or OS network settings.&lt;br&gt;
Privacy and IP masking are what most developers think of when they hear "proxy." Routing requests through a proxy hides the client's real IP from the destination. The destination sees the proxy's IP, not the requester's. This is the pattern used by residential and mobile proxy services for scraping, ad verification, account management, and geo-restricted content access - a full overview of how this applies in practice is covered in the &lt;a href="https://nodemaven.com/blog/what-is-a-proxy-server/" rel="noopener noreferrer"&gt;NodeMaven proxy guide&lt;/a&gt;.&lt;br&gt;
Caching is another forward proxy use case - a shared proxy can cache responses from frequently requested destinations, reducing bandwidth consumption for networks with many clients hitting the same external resources. This was a significant use case in the early web when bandwidth was expensive; it's less common now but still relevant in high-latency or bandwidth-constrained environments.&lt;br&gt;
Access control and geo-restriction bypass both use the same mechanism. A forward proxy in a specific geographic location allows clients anywhere to make requests that appear to originate from that location.&lt;br&gt;
Forward proxy in code:&lt;br&gt;
import requests&lt;/p&gt;

&lt;p&gt;Configure a forward proxy for a single request&lt;br&gt;
proxies = {&lt;br&gt;
    "http": "&lt;a href="http://user:pass@proxy-host:8080" rel="noopener noreferrer"&gt;http://user:pass@proxy-host:8080&lt;/a&gt;",&lt;br&gt;
    "https": "&lt;a href="http://user:pass@proxy-host:8080" rel="noopener noreferrer"&gt;http://user:pass@proxy-host:8080&lt;/a&gt;"&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;response = requests.get("&lt;a href="https://example.com" rel="noopener noreferrer"&gt;https://example.com&lt;/a&gt;", proxies=proxies)&lt;/p&gt;

&lt;p&gt;curl with a forward proxy&lt;br&gt;
curl --proxy &lt;a href="http://user:pass@proxy-host:8080" rel="noopener noreferrer"&gt;http://user:pass@proxy-host:8080&lt;/a&gt; &lt;a href="https://example.com" rel="noopener noreferrer"&gt;https://example.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Environment variable (applies to many tools automatically)&lt;br&gt;
export HTTPS_PROXY="&lt;a href="http://user:pass@proxy-host:8080" rel="noopener noreferrer"&gt;http://user:pass@proxy-host:8080&lt;/a&gt;"&lt;br&gt;
curl &lt;a href="https://example.com" rel="noopener noreferrer"&gt;https://example.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reverse Proxy: Architecture and Use Cases&lt;/strong&gt;&lt;br&gt;
A reverse proxy is configured on the server side and is invisible to the client. The client believes it's communicating directly with the application server - it has no awareness that its request is being handled by an intermediary.&lt;br&gt;
How it works:&lt;br&gt;
Client → Reverse Proxy → Origin Server(s)&lt;/p&gt;

&lt;p&gt;The client sends a request to what it believes is the application server (say, api.example.com). That DNS name resolves to the reverse proxy's IP. The proxy receives the request, applies its configured logic (routing, caching, rate limiting, TLS termination), and forwards the request to the appropriate backend. The response returns through the same path.&lt;br&gt;
Common use cases:&lt;br&gt;
Load balancing is the most common reverse proxy use case in production systems. A single reverse proxy distributes incoming requests across multiple backend instances, ensuring no single server is overwhelmed and providing redundancy when servers fail. Nginx, HAProxy, and cloud load balancers (AWS ALB, GCP Load Balancing) all operate in this mode.&lt;br&gt;
 Nginx reverse proxy with load balancing&lt;br&gt;
upstream backend {&lt;br&gt;
    server app1.internal:8000 weight=3;&lt;br&gt;
    server app2.internal:8000 weight=3;&lt;br&gt;
    server app3.internal:8000 weight=1;   less powerful instance&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;server {&lt;br&gt;
    listen 80;&lt;br&gt;
    server_name api.example.com;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;location / {
    proxy_pass http://backend;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;TLS termination is handled at the reverse proxy layer in most production architectures. The proxy accepts HTTPS connections from clients (handling the TLS handshake and certificate management), then forwards requests to backend servers over plain HTTP on the internal network. This centralizes certificate management and offloads TLS processing from application servers.&lt;br&gt;
server {&lt;br&gt;
    listen 443 ssl;&lt;br&gt;
    server_name api.example.com;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssl_certificate /etc/ssl/certs/example.com.pem;
ssl_certificate_key /etc/ssl/private/example.com.key;

location / {
    proxy_pass http://backend;   plain HTTP to backend
    proxy_set_header X-Forwarded-Proto https;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;Caching at the reverse proxy layer serves static assets and cacheable API responses without hitting the origin server. CDNs (Cloudflare, Fastly, AWS CloudFront) are distributed reverse proxies with global caching infrastructure - a request for a static asset gets served from the CDN edge node nearest the client rather than traveling to the origin.&lt;br&gt;
Security and DDoS protection are handled at the reverse proxy layer in most internet-facing architectures. The origin server's IP is hidden - clients only know the reverse proxy's address. Rate limiting, bot detection, WAF (Web Application Firewall) rules, and request validation all run at the proxy layer before traffic reaches the application.&lt;br&gt;
 Rate limiting at the reverse proxy&lt;br&gt;
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;&lt;/p&gt;

&lt;p&gt;server {&lt;br&gt;
    location /api/ {&lt;br&gt;
        limit_req zone=api burst=20 nodelay;&lt;br&gt;
        proxy_pass &lt;a href="http://backend" rel="noopener noreferrer"&gt;http://backend&lt;/a&gt;;&lt;br&gt;
    }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;API gateway functionality - routing different URL paths to different backend services, transforming requests and responses, handling authentication - is commonly implemented as a reverse proxy configuration. Tools like Kong, Traefik, and AWS API Gateway are specialized reverse proxies built for this purpose.&lt;br&gt;
&lt;strong&gt;Where They Overlap: The Transparent Proxy&lt;/strong&gt;&lt;br&gt;
There's a third category that blurs the forward/reverse distinction: the transparent proxy. A transparent proxy intercepts network traffic without explicit client configuration - the client doesn't know it exists. From the client's perspective, it's communicating directly with the destination. From the network's perspective, all traffic passes through the proxy.&lt;br&gt;
ISPs sometimes use transparent proxies for caching and traffic management. Corporate networks use them for content filtering when they don't want users to be able to bypass the proxy by removing browser settings. Router-level DNS redirect rules (intercepting port 53 traffic as described in router-level DNS configuration guides) are a form of transparent proxying for DNS specifically.&lt;br&gt;
The key difference from a forward proxy: the client doesn't configure or acknowledge the transparent proxy. The key difference from a reverse proxy: the transparent proxy is serving the network operator's interests, not the destination server's.&lt;br&gt;
&lt;strong&gt;Choosing Between Them in System Design&lt;/strong&gt;&lt;br&gt;
In practice, the choice isn't usually forward or reverse - most non-trivial architectures use both simultaneously.&lt;br&gt;
A user's browser might be configured to use a forward proxy (corporate network, VPN, residential proxy service) when it sends a request. That request hits the internet and reaches a reverse proxy (Nginx, CDN edge, API gateway) in front of the application. Both proxies are active in the same request path, serving different parties.&lt;br&gt;
The design question is which layer to add a proxy at and for what purpose. Forward proxy when you need to control outbound traffic from clients - masking origin, routing through specific geographic IPs, applying corporate policies, caching shared external resources. Reverse proxy when you need to control inbound traffic to servers - distributing load, terminating TLS, caching responses, protecting origin servers, routing requests to microservices.&lt;br&gt;
The confusion between the two usually comes from the word "proxy" appearing in both contexts without qualification. Adding "forward" or "reverse" to the conversation immediately clarifies which pattern is being discussed - and in most system design conversations, the qualifier is what tells you which problem is actually being solved.&lt;br&gt;
&lt;strong&gt;A Quick Reference&lt;/strong&gt;&lt;br&gt;
Forward proxy: client-side, client-configured, hides client identity, routes outbound requests. Reverse proxy: server-side, server-configured, hides server identity, manages inbound requests. Transparent proxy: neither client nor server-configured, intercepts traffic at the network level.&lt;br&gt;
Same underlying mechanism - an intermediary that forwards requests between two parties - oriented in different directions for different purposes.&lt;/p&gt;

</description>
      <category>proxy</category>
      <category>server</category>
    </item>
    <item>
      <title>US Free Proxy List for Ad Verification: What Actually Works in 2026</title>
      <dc:creator>Mathew</dc:creator>
      <pubDate>Mon, 28 Sep 2026 05:57:17 +0000</pubDate>
      <link>https://dev.to/mathewtech/us-free-proxy-list-for-ad-verification-what-actually-works-in-2026-2fdp</link>
      <guid>https://dev.to/mathewtech/us-free-proxy-list-for-ad-verification-what-actually-works-in-2026-2fdp</guid>
      <description>&lt;p&gt;Ad verification has specific proxy requirements that most general-purpose proxy guides don't address. You're not trying to scrape a million product pages or automate account creation - you're trying to answer a precise question: is this ad actually serving the right creative, to the right audience, through the right placement, in the right geographic market?&lt;br&gt;
That question requires a proxy that looks like a real US consumer in a specific city, with the connection history of someone who actually lives there. It's a harder requirement than "US IP that's not blocked," and it's why free proxy lists - which are genuinely useful for some scraping tasks - consistently fail for ad verification specifically.&lt;br&gt;
This post covers the failure modes in detail, documents 7-day test data across uptime, geo-accuracy, and ad-render success, and explains what the upgrade path looks like.&lt;br&gt;
&lt;strong&gt;What Ad Verification Actually Requires From a&amp;nbsp;Proxy&lt;/strong&gt;&lt;br&gt;
Before getting into the test data, it's worth being precise about why ad verification has stricter proxy requirements than most other workflows.&lt;br&gt;
Ad networks - Google Display Network, Meta Audience Network, programmatic exchanges - classify incoming traffic in real time. They know whether a request comes from a residential IP, a datacenter, or a known proxy range. They use this classification to decide what inventory to serve. A verification tool connecting from a datacenter IP or a flagged proxy IP gets served different inventory than a real consumer on residential broadband. In some cases it gets clean, brand-safe placements while the real consumer audience sees the fraudulent creative. In other cases it gets no ad at all.&lt;br&gt;
The three variables that determine whether a verification proxy produces accurate results are geo-accuracy (does the IP actually geolocate to the claimed city?), connection type classification (does the IP pass as residential consumer traffic?), and IP history (does the IP carry behavioral flags from prior users that trigger different ad serving?).&lt;br&gt;
Free US proxies from public lists typically fail on all three. They're datacenter or hosting-classified, they're in flagged IP ranges, and they carry the behavioral history of whatever automated activity previously ran through them. The ad network sees a request that looks nothing like a real US consumer.&lt;br&gt;
&lt;strong&gt;7-Day Test Data: Free US Proxies for Ad Verification&lt;/strong&gt;&lt;br&gt;
I ran a 7-day test on 60 free US proxies pulled from the three most commonly recommended sources - free-proxy-list.net, ProxyScrape, and Spys.one, 20 from each. Each proxy was tested daily across three metrics: uptime (did it respond at all?), geo-accuracy (did it geolocate to a US city within 50 miles of the claimed location?), and ad-render success (did it receive a real ad creative from Google Display Network's test endpoint, as opposed to a fallback, empty slot, or error?).&lt;br&gt;
Uptime over 7 days&lt;br&gt;
Day 1: 23 of 60 proxies alive (38%). By day 3: 14 alive (23%). By day 7: 8 alive (13%). The population decay is steep - most free proxies that are alive when you pull them from a list are dead within 72 hours. By the end of the week, only 8 proxies from the original 60 were still responding, and their average TTFB had increased to 5.2 seconds from 3.8 seconds on day 1 as the surviving IPs became more congested.&lt;br&gt;
Geo-accuracy on alive proxies&lt;br&gt;
Of the proxies alive at any point during the 7 days, 31 claimed a specific US city in the list metadata. Of those 31, 18 geolocated within 50 miles of the claimed city on lookup - a 58% geo-accuracy rate. The remaining 13 either geolocated to a different US city entirely or showed a geographic inconsistency between the list's claimed location and what IP geolocation databases returned.&lt;br&gt;
For ad verification, geo-accuracy matters because ad campaigns target at the DMA (Designated Market Area) level in the US. A proxy claiming to be in New York but actually geolocating to New Jersey or Connecticut lands in a different DMA, which means it sees different ad inventory than the campaign's actual New York target audience.&lt;br&gt;
Ad-render success&lt;br&gt;
This is the metric that matters most for ad verification workflows. Of all proxies tested over the 7 days, 4 returned a genuine ad creative from the test endpoint - not a fallback, not an empty slot, not an error response. That's 6.7% of the original 60 proxies, and those 4 successes weren't consistent - each one rendered an ad on some days but not others. No free proxy in the test maintained consistent ad rendering across all 7 days.&lt;br&gt;
The pattern was clear: proxies that were classified as datacenter or hosting by IP reputation databases never rendered real ads. Proxies that managed to pass as residential-classified rendered ads intermittently, depending on whether they'd accumulated enough behavioral flags from prior users to trigger ad network filtering on that specific day.&lt;br&gt;
What the numbers mean operationally&lt;br&gt;
An ad verification workflow that relies on free US proxies starts each week with roughly 38% of its proxies alive, loses most of them within 3 days, has 58% geo-accuracy on the proxies that are alive, and achieves ad rendering on roughly 7% of the original pool. By day 7, you have 8 alive proxies, and fewer than 1 in 10 is rendering actual ads.&lt;br&gt;
For a workflow that needs to verify US ad placements across 50 publisher sites in 10 DMAs, this translates to: constantly refreshing the proxy list, manually testing each new batch, handling the majority of requests as failures, and accepting that much of the "verification" being done is actually checking whether the proxy gets served the same clean inventory that ad networks show to recognized auditors.&lt;br&gt;
&lt;strong&gt;Why Free US Proxies Fail Ad Verification Specifically&lt;/strong&gt;&lt;br&gt;
The failure modes are worth understanding individually because they point to the correct fix.&lt;br&gt;
Datacenter classification. The majority of IPs on free proxy lists come from hosting providers and datacenter ranges - AWS, DigitalOcean, OVH, Hetzner. Ad networks maintain blocklists of these ranges and don't serve premium inventory to them. An IP from a free proxy list that resolves to an AWS range in us-east-1 will never see the same ads as a real New York consumer, regardless of which city it claims to be in.&lt;br&gt;
Shared behavioral history. A free proxy IP has been used by an unknown number of prior users for unknown purposes. If any of those users triggered bot detection, ran automated requests at inhuman rates, or got flagged for click fraud, the IP carries that history into your verification session. Ad networks score incoming traffic in real time based on IP behavioral history, and a flagged history changes what inventory gets served.&lt;br&gt;
No session persistence. Ad serving behavior - particularly for retargeted ads and frequency-capped creatives - depends on session continuity. A real consumer sees ad A on visit 1 and ad B on visit 2 because the ad network has built a frequency-cap profile. A proxy that changes IPs every session looks like a new unidentified user every time, which means it's always served the "new visitor" inventory rather than the inventory your campaign's actual audience sees.&lt;br&gt;
Geographic instability. Even the free proxies that geolocate correctly on day 1 often shift geolocation over time as IP reputation databases update and assign the IP to different ranges. A proxy that passes a geo-accuracy check on Monday may fail the same check on Thursday, which means your verification data is inconsistent even from the same proxy.&lt;br&gt;
&lt;strong&gt;What Works: US Residential Proxies With City-Level Targeting&lt;/strong&gt;&lt;br&gt;
The fix for all four failure modes above is a residential proxy pool with city-level targeting and pre-filtered IPs. Each failure mode maps to a specific capability:&lt;br&gt;
Datacenter classification → residential ISP-assigned IPs that pass consumer traffic checks. City-level geo-accuracy → targeting that maps to specific US DMAs rather than country-level routing. Shared behavioral history → pre-filtered pool where flagged IPs are removed before assignment. Session persistence → sticky sessions that hold the same IP for the duration of a verification workflow.&lt;br&gt;
The &lt;a href="https://nodemaven.com/free-proxy-list/united-states/" rel="noopener noreferrer"&gt;NodeMaven US free proxy list&lt;/a&gt; is available if you want a free starting point for basic US geo-checks - same caveats as any free proxy list apply, and the 7-day data above describes what to expect. For ad verification specifically, the $3.50 trial gives you 750MB of residential proxy traffic with a 95%+ clean IP rate, sticky sessions up to 24 hours, and city-level targeting across major US DMAs - New York, Los Angeles, Chicago, Houston, and others. That's enough bandwidth to run a meaningful verification sweep across 50–100 publisher placements and see directly whether the results differ from what your free proxy workflow was producing.&lt;br&gt;
The data point that makes the comparison concrete: the 7-day test showed 6.7% ad-render success on free US proxies. Residential proxies with pre-filtered IPs and city-level targeting consistently deliver 90%+ ad-render success on the same test endpoint. That's not a marginal improvement - it's the difference between a verification tool that catches fraud and one that produces false-clean reports.&lt;br&gt;
&lt;strong&gt;Building a US Ad Verification Workflow&lt;/strong&gt;&lt;br&gt;
For teams setting up an ad verification workflow with US residential proxies, the configuration that covers the requirements above looks like this.&lt;br&gt;
Assign one proxy per DMA being verified. A campaign targeting New York, Los Angeles, and Chicago needs a proxy session in each market - not three proxies in "US" that might all route through the same city. City-level targeting in your proxy configuration ensures each session maps to the right DMA.&lt;br&gt;
Use sticky sessions for the full verification sweep. A single publisher audit - loading the page, waiting for ad slots to fill, checking the creative, following the click-through chain - should run from the same IP. Rotating mid-session breaks the behavioral continuity that allows retargeted and frequency-capped ads to display correctly.&lt;br&gt;
Verify the full redirect chain, not just the impression. Ad fraud in 2026 often operates at the redirect layer - the impression looks clean but the click-through path runs through an affiliate domain before reaching the advertiser. Your verification tool needs to follow the full chain from ad slot to final landing page from the same residential IP.&lt;br&gt;
Run verifications on a schedule, not just on-demand. A fraudulent publisher that detects your verification tool will serve clean content during your audit window and revert to fraudulent behavior after. Running sweeps at randomized intervals from consistent residential IPs - rather than from obviously different proxy addresses each time - makes your verification traffic harder to distinguish from real consumer traffic.&lt;br&gt;
The proxy infrastructure is one layer of an ad verification workflow, not the whole thing. But it's the layer that determines whether the data your verification tool collects reflects the actual ad ecosystem your campaign's audience is experiencing - which is the only thing that makes verification meaningful.&lt;/p&gt;

</description>
      <category>proxy</category>
    </item>
    <item>
      <title>WebRTC Leak Test on Mobile: iOS Safari and Chrome Android Guide 2026</title>
      <dc:creator>Mathew</dc:creator>
      <pubDate>Fri, 25 Sep 2026 05:33:58 +0000</pubDate>
      <link>https://dev.to/mathewtech/webrtc-leak-test-on-mobile-ios-safari-and-chrome-android-guide-2026-1h5i</link>
      <guid>https://dev.to/mathewtech/webrtc-leak-test-on-mobile-ios-safari-and-chrome-android-guide-2026-1h5i</guid>
      <description>&lt;p&gt;Most WebRTC leak guides focus on desktop browsers - Firefox about:config, Chrome extensions, Puppeteer flags. Mobile gets a footnote at the end, if it's covered at all. But mobile proxy usage has grown significantly, and the WebRTC leak situation on iOS and Android is meaningfully different from desktop - different controls, different defaults, different failure modes.&lt;br&gt;
This guide covers mobile specifically: how to test for WebRTC leaks on iOS Safari and Chrome for Android, what the results mean, and the exact steps to fix them. No desktop content recycled here.&lt;br&gt;
&lt;strong&gt;Why Mobile WebRTC Leaks Differently Than&amp;nbsp;Desktop&lt;/strong&gt;&lt;br&gt;
The core mechanism is the same as desktop - WebRTC's ICE candidate gathering queries STUN servers and collects IP addresses from all available network interfaces, potentially exposing your real IP even when proxy traffic is routing correctly. But the mobile-specific layer adds complications.&lt;br&gt;
iOS Safari has no about:config. The fine-grained control that Firefox gives you on desktop simply doesn't exist on iOS. Safari's WebRTC behavior is controlled by Apple, and the settings available to users are limited to what Apple exposes in the browser UI or system settings.&lt;br&gt;
Chrome on Android can't be configured via extensions. The Chrome extension ecosystem that desktop users rely on for WebRTC control doesn't apply to Chrome on Android. Mobile Chrome has a flags menu (chrome://flags), but the options there have changed between versions and aren't guaranteed to persist across updates.&lt;br&gt;
Mobile apps bypass browser WebRTC settings entirely. If you're using a proxy through a native mobile app rather than a mobile browser, browser-level WebRTC settings are irrelevant - the app controls its own WebRTC behavior. This is a separate problem from browser-based WebRTC leaks.&lt;br&gt;
IPv6 exposure is more common on mobile. Mobile carrier networks are further along in IPv6 deployment than most residential broadband. An iOS device on a 5G carrier connection likely has an IPv6 address, and if your proxy only tunnels IPv4, that IPv6 address will appear in WebRTC ICE candidates as a direct leak vector.&lt;br&gt;
&lt;strong&gt;Step 1: Run the Test on Your Mobile&amp;nbsp;Device&lt;/strong&gt;&lt;br&gt;
Before configuring anything, establish a baseline - what does your current mobile browser configuration actually expose?&lt;br&gt;
Open your mobile browser and navigate to the NodeMaven WebRTC Leak Test - no account or setup needed. The test runs automatically on page load: it triggers WebRTC's ICE candidate gathering in your browser and displays every IP address collected, labeled by type.&lt;br&gt;
Here's what to look at in the results. Each candidate is shown with its type - host candidates are local network addresses (your LAN IP or an mDNS hostname like a3f2c1d0.local), while srflx (server-reflexive) candidates show your public IP as seen by a STUN server. The srflx candidates are the ones that matter. If your real carrier IP appears there while your proxy is active, WebRTC is leaking around the proxy tunnel.&lt;br&gt;
Run the test twice: first with no proxy active to record your real IP as a baseline, then with your proxy on. In the second test, srflx candidates should show your proxy's exit IP - or be absent entirely. If your real IP still appears in the second test, the proxy isn't routing WebRTC traffic and the fix steps below apply. The tool also flags IPv6 candidates separately, which is important on mobile since carrier networks are further along on IPv6 than most home broadband.&lt;br&gt;
What you're looking at in the results:&lt;br&gt;
The test displays ICE candidates gathered by your browser - the IP addresses WebRTC collected from your network interfaces. Each candidate is labeled with its type:&lt;br&gt;
host candidates - local network addresses (your LAN IP like 192.168.x.x, or an mDNS hostname like a3f2c1d0.local on modern browsers)&lt;br&gt;
srflx (server-reflexive) candidates - your public IP as seen by the STUN server. This is the critical one. If your real ISP-assigned public IP appears here while you're using a proxy, you have a leak.&lt;br&gt;
relay candidates - TURN server relay addresses, generally not a privacy concern&lt;/p&gt;

&lt;p&gt;Run the test twice: once without any proxy active (to establish your baseline real IP), and once with your proxy active. In the second test, the srflx candidates should show your proxy's exit IP, not your real IP. If they still show your real IP, WebRTC is leaking through the proxy configuration.&lt;br&gt;
&lt;strong&gt;iOS Safari: What the Test Shows and How to Fix&amp;nbsp;It&lt;/strong&gt;&lt;br&gt;
iOS Safari's WebRTC behavior has specific characteristics that differ from desktop Safari and from Android Chrome.&lt;br&gt;
What iOS Safari typically exposes:&lt;br&gt;
&lt;cite&gt;iOS Safari does not expose local IP addresses through WebRTC ICE candidates in the same way Chrome does - Apple implemented restrictions on local IP candidate generation in Safari 14 and later versions.&lt;/cite&gt; However, public IP exposure through srflx candidates is still possible when using a proxy, because Safari can still contact STUN servers directly via the device's real network connection rather than through the proxy tunnel.&lt;br&gt;
The result: on iOS Safari with a proxy configured, you may see your proxy IP in HTTP requests while WebRTC srflx candidates still show your real carrier IP.&lt;br&gt;
Step-by-step fix for iOS Safari:&lt;br&gt;
iOS Safari's WebRTC controls are accessed through the Advanced settings, not through the browser itself:&lt;br&gt;
Open Settings on your iPhone or iPad&lt;br&gt;
Scroll down to Safari&lt;br&gt;
Tap Advanced&lt;br&gt;
Tap Feature Flags (iOS 16+) or Experimental Features (older iOS)&lt;br&gt;
Find WebRTC mDNS ICE Candidates and toggle it on if it isn't already - this replaces local IPs with mDNS hostnames&lt;br&gt;
Look for ICE Candidate Restrictions - keeping this enabled limits which candidates Safari generates&lt;/p&gt;

&lt;p&gt;For iOS 15 and earlier, the path is slightly different:&lt;br&gt;
Settings → Safari → Advanced → Experimental Features&lt;br&gt;
Toggle ICE Candidate Restrictions to on&lt;/p&gt;

&lt;p&gt;&lt;cite&gt;For iOS Safari users, the fix is going into the phone's Advanced Settings and toggling off WebRTC mDNS ICE candidates - this controls how Safari handles local IP exposure through WebRTC peer connections.&lt;/cite&gt;&lt;br&gt;
Important limitation on iOS Safari:&lt;br&gt;
Even with these settings configured, &lt;cite&gt;Safari's protection is partial - it limits local IP exposure but may still leak your public IP in some configurations.&lt;/cite&gt; The fundamental issue is that Safari can still send STUN requests outside the proxy tunnel. The most reliable fix for public IP leaks on iOS Safari is using a VPN-based proxy client (like Shadowrocket) that routes UDP traffic - including WebRTC STUN requests - through the tunnel at the network level, rather than relying on browser-level settings alone.&lt;br&gt;
Re-test after configuration:&lt;br&gt;
After changing the iOS Safari settings, close all Safari tabs, reopen, navigate back to the WebRTC leak test, and check whether srflx candidates now show your proxy IP or are absent entirely. If your real IP still appears in srflx candidates, the browser-level fix is insufficient and a network-level solution (VPN-based proxy app) is needed.&lt;br&gt;
&lt;strong&gt;Chrome for Android: Flags, Limitations, and&amp;nbsp;Fixes&lt;/strong&gt;&lt;br&gt;
Chrome on Android shares the same underlying WebRTC implementation as desktop Chrome, but the configuration options available on mobile differ.&lt;br&gt;
Step 1: Check Chrome flags&lt;br&gt;
In Chrome for Android, navigate to chrome://flags in the address bar. Search for "WebRTC":&lt;br&gt;
enable-webrtc-hide-local-ips-with-mdns - when enabled, replaces local IP candidates with mDNS hostnames. This is enabled by default in recent Chrome versions.&lt;br&gt;
disable-webrtc-encryption - keep this at default (encryption enabled).&lt;/p&gt;

&lt;p&gt;Search for "IP handling":&lt;br&gt;
Look for WebRTC IP Handling Policy if it appears in your Chrome version. &lt;cite&gt;Setting this to "Disable non-proxied UDP" provides maximum protection by preventing WebRTC from making any UDP connections that don't go through the configured proxy.&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;Not all of these flags are present in every version of Chrome for Android - Google has added and removed flags across versions. If the flag isn't present, proceed to Step 2.&lt;br&gt;
Step 2: Use Brave for Android instead of Chrome&lt;br&gt;
If you need reliable WebRTC leak protection on Android and Chrome's mobile flags don't provide it, Brave for Android is the most practical alternative. &lt;cite&gt;Brave blocks known fingerprinting scripts by default and has built-in WebRTC leak protection in its privacy settings.&lt;/cite&gt;&lt;br&gt;
In Brave for Android:&lt;br&gt;
Tap the three-dot menu → Settings&lt;br&gt;
Go to Privacy and Security&lt;br&gt;
Find WebRTC IP Handling Policy&lt;br&gt;
Set to Disable Non-Proxied UDP&lt;/p&gt;

&lt;p&gt;This is the same setting available in desktop Brave, now accessible directly in the mobile UI without extensions.&lt;br&gt;
Step 3: Proxy configuration matters for Android WebRTC&lt;br&gt;
Android's system proxy settings configure HTTP/HTTPS traffic but don't affect UDP. WebRTC uses UDP for STUN requests, which means system-level proxy settings don't prevent WebRTC leaks on Android.&lt;br&gt;
For Android, the reliable solution is a VPN-based proxy app (Shadowrocket, or a proxy provider's own app if they offer one) that routes all traffic - including UDP - through the tunnel. When UDP is tunneled, STUN requests go through the proxy network and report the proxy's IP rather than your real IP.&lt;br&gt;
Re-test after configuration:&lt;br&gt;
After changes in Chrome for Android, navigate back to the WebRTC leak test. Clear the browser cache first (chrome://settings/clearBrowserData) and reload. The srflx candidates in the test results should show your proxy IP, show only mDNS hostnames (a UUID followed by&amp;nbsp;.local), or be absent entirely.&lt;br&gt;
&lt;strong&gt;The IPv6 Problem on&amp;nbsp;Mobile&lt;/strong&gt;&lt;br&gt;
Mobile devices on 5G and LTE networks frequently have IPv6 addresses. If your proxy only tunnels IPv4 traffic, your IPv6 address will appear in WebRTC ICE candidates as a leak - even if everything else is configured correctly.&lt;br&gt;
The WebRTC leak test shows IPv6 candidates separately. If you see an IPv6 address in the results that matches your carrier's IPv6 assignment, you have an IPv6 leak.&lt;br&gt;
Fixes for IPv6 WebRTC leaks on mobile:&lt;br&gt;
On iOS: Settings → Cellular → (your carrier) → IPv6 - some carriers allow you to disable IPv6 here. Not all carriers expose this setting.&lt;br&gt;
On Android: The IPv6 setting location varies by Android version and manufacturer. On some devices: Settings → Network &amp;amp; Internet → your connection → Advanced → IP version. On others, IPv6 can only be controlled at the router level (if on Wi-Fi) or through a VPN that forces IPv4-only mode.&lt;br&gt;
The more reliable fix: use a VPN-based proxy client that handles both IPv4 and IPv6 - or one that enforces IPv4-only mode to eliminate the IPv6 surface area entirely.&lt;br&gt;
&lt;strong&gt;Comparing Mobile Browser WebRTC Leak&amp;nbsp;Behavior&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6gtjray2lg73yj9ftb4z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6gtjray2lg73yj9ftb4z.png" alt=" " width="800" height="387"&gt;&lt;/a&gt;&lt;br&gt;
Firefox for Android is worth noting: unlike Chrome on Android, Firefox mobile retains the about:config interface. Navigate to about:config in the Firefox Android address bar, search for media.peerconnection.enabled, and set it to false to disable WebRTC entirely. This is the most complete fix available on any mobile browser - at the cost of breaking any WebRTC-dependent functionality (video calls, etc.).&lt;br&gt;
&lt;strong&gt;Pre-Flight Check: Mobile Proxy Session Verification&lt;/strong&gt;&lt;br&gt;
Before running any mobile proxy workflow, run a quick two-step check. The NodeMaven tools work the same on mobile and desktop - open them directly in your mobile browser with the proxy active.&lt;br&gt;
Navigate to the NodeMaven WebRTC Leak Test and confirm no srflx candidates show your real IP. Then open the NodeMaven DNS Leak Test and confirm your DNS resolver matches your proxy's location, not your carrier's. Both tests take under a minute together and confirm that your session is isolated at the WebRTC and DNS layers - not just at the HTTP layer.&lt;br&gt;
&lt;strong&gt;When Browser-Level Fixes Aren't&amp;nbsp;Enough&lt;/strong&gt;&lt;br&gt;
If you've applied all the browser-level settings and the WebRTC leak test still shows your real IP, the issue is at the network layer - WebRTC's UDP traffic is bypassing the proxy tunnel, and browser settings can't intercept it.&lt;br&gt;
At that point, the fix is network-level proxy routing: a VPN-based proxy client that intercepts all traffic at the device's network interface, including UDP. This routes WebRTC STUN requests through the tunnel so the STUN server returns the proxy's IP rather than your real carrier IP.&lt;br&gt;
For iOS, Shadowrocket is the standard tool for this. For Android, Shadowrocket is also available, alongside alternatives like Clash for Android or your proxy provider's native app if they offer one.&lt;br&gt;
The browser-level settings are worth applying regardless - they handle local IP exposure and reduce the WebRTC surface area. But for public IP leaks through STUN on mobile, network-level routing is the reliable fix.&lt;/p&gt;

</description>
      <category>proxy</category>
    </item>
    <item>
      <title>IP Geolocation for Developers: Automating IP Lookup Checks in 2026</title>
      <dc:creator>Mathew</dc:creator>
      <pubDate>Fri, 25 Sep 2026 05:19:53 +0000</pubDate>
      <link>https://dev.to/mathewtech/ip-geolocation-for-developers-automating-ip-lookup-checks-in-2026-a1k</link>
      <guid>https://dev.to/mathewtech/ip-geolocation-for-developers-automating-ip-lookup-checks-in-2026-a1k</guid>
      <description>&lt;p&gt;At some point, checking proxy IPs manually stops being viable. You have a pool of 50 rotating residential IPs, you want to know which ones are actually clean before deploying them, and opening a browser tab for each one isn't a workflow - it's a time sink. That's the moment IP lookup automation starts making sense.&lt;br&gt;
This guide covers what IP lookup data actually tells you, how to use it to validate proxy pools programmatically, and where the NodeMaven IP Lookup tool fits into that workflow.&lt;br&gt;
&lt;strong&gt;What IP Lookup Data Actually Tells You&lt;/strong&gt;&lt;br&gt;
An IP address carries more information than most developers initially expect. When you run a lookup, you're not just getting a country - you're getting a full classification of that address's network identity and reputation history.&lt;br&gt;
Geographic data comes in three layers. Country-level accuracy is close to 100% for any modern lookup service. City-level accuracy is typically within a metro area for residential IPs, which is sufficient for most geo-targeting validation. ZIP/postal code is available but less reliable - accuracy varies by provider and by the type of IP being queried.&lt;br&gt;
Network identity is what matters most for proxy validation. The ISP field tells you which company assigned the IP - Comcast, BT, Deutsche Telekom for residential connections; AWS, GCP, Hetzner for datacenter addresses. The ASN (Autonomous System Number) goes one level deeper: it's the unique identifier of the specific network block the IP belongs to. Detection systems on platforms like Amazon, Google, and Meta check ASNs, not ISP name strings. Two IPs from "Comcast" might belong to different ASNs with meaningfully different trust scores.&lt;br&gt;
Connection type flags are the most operationally useful fields. Every IP lookup returns flags indicating whether the address is classified as a proxy, VPN, Tor exit node, hosting/datacenter IP, or mobile connection. For a clean residential proxy, all of these should be false. If an IP comes back with is_hosting: true, it's in a datacenter range - and platforms that check IP type will treat it accordingly regardless of what geo it reports.&lt;br&gt;
Threat score is an aggregate risk rating, typically 0–100, based on the behavioral history associated with the address. Prior abuse, spam campaigns, credential stuffing, bot activity - all of these leave marks in reputation databases that get surfaced in the threat score. A residential IP with a score of 8 is clean. The same IP with a score of 72 has history that will trigger friction on platforms that check reputation in real time.&lt;br&gt;
&lt;strong&gt;What This Means for Proxy Pool Management&lt;/strong&gt;&lt;br&gt;
The practical implication is straightforward: not all IPs in a residential proxy pool behave equally, and you can't tell the difference by looking at them. An IP that reports as US/New York/residential might have a threat score of 65 from prior users who ran it through aggressive scraping. Another IP with identical geographic metadata might have a score of 4.&lt;br&gt;
Running IP lookups on your pool before deployment surfaces this variation. The workflow is: get exit IPs from your proxies, run lookups, filter out any that show hosting flags, proxy flags, or threat scores above your threshold, and deploy only the clean subset.&lt;br&gt;
For most scraping and automation workflows, a reasonable pre-deployment filter is: no proxy/VPN/hosting flags, threat score below 30, country and city matching expected geo-target. For platforms with aggressive bot detection - social media, e-commerce, financial services - tighten the threat score threshold to below 15.&lt;br&gt;
Here's a minimal implementation that handles the core validation loop:&lt;br&gt;
import requests&lt;br&gt;
import time&lt;br&gt;
from typing import Optional&lt;/p&gt;

&lt;p&gt;def get_exit_ip(proxy_url: str, timeout: int = 10) -&amp;gt; Optional[str]:&lt;br&gt;
    try:&lt;br&gt;
        resp = requests.get(&lt;br&gt;
            "&lt;a href="https://httpbin.org/ip" rel="noopener noreferrer"&gt;https://httpbin.org/ip&lt;/a&gt;",&lt;br&gt;
            proxies={"http": proxy_url, "https": proxy_url},&lt;br&gt;
            timeout=timeout&lt;br&gt;
        )&lt;br&gt;
        return resp.json().get("origin", "").split(",")[0].strip()&lt;br&gt;
    except Exception:&lt;br&gt;
        return None&lt;/p&gt;

&lt;p&gt;def check_ip_quality(ip: str, timeout: int = 10) -&amp;gt; dict:&lt;br&gt;
    try:&lt;br&gt;
        resp = requests.get(f"&lt;a href="https://ipinfo.io/%7Bip%7D/json" rel="noopener noreferrer"&gt;https://ipinfo.io/{ip}/json&lt;/a&gt;", timeout=timeout)&lt;br&gt;
        data = resp.json()&lt;br&gt;
        privacy = data.get("privacy", {})&lt;br&gt;
        return {&lt;br&gt;
            "ip": ip,&lt;br&gt;
            "country": data.get("country", ""),&lt;br&gt;
            "city": data.get("city", ""),&lt;br&gt;
            "isp": data.get("org", ""),&lt;br&gt;
            "is_flagged": any([&lt;br&gt;
                privacy.get("proxy", False),&lt;br&gt;
                privacy.get("vpn", False),&lt;br&gt;
                privacy.get("hosting", False),&lt;br&gt;
            ]),&lt;br&gt;
            "threat_score": data.get("abuse", {}).get("score", 0),&lt;br&gt;
        }&lt;br&gt;
    except Exception as e:&lt;br&gt;
        return {"ip": ip, "error": str(e), "is_flagged": True, "threat_score": 100}&lt;/p&gt;

&lt;p&gt;def audit_proxy_pool(&lt;br&gt;
    proxies: list[str],&lt;br&gt;
    max_threat_score: int = 30&lt;br&gt;
) -&amp;gt; dict:&lt;br&gt;
    clean, rejected = [], []&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for proxy_url in proxies:
    exit_ip = get_exit_ip(proxy_url)
    if not exit_ip:
        rejected.append({"proxy": proxy_url, "reason": "no exit IP"})
        continue

    quality = check_ip_quality(exit_ip)

    if quality.get("error"):
        rejected.append({"proxy": proxy_url, "reason": quality["error"]})
    elif quality["is_flagged"]:
        rejected.append({"proxy": proxy_url, "exit_ip": exit_ip, "reason": "flagged"})
    elif quality["threat_score"] &amp;gt; max_threat_score:
        rejected.append({"proxy": proxy_url, "exit_ip": exit_ip,
                         "reason": f"threat score {quality['threat_score']}"})
    else:
        clean.append(proxy_url)

    time.sleep(0.1)

total = len(clean) + len(rejected)
return {
    "clean": clean,
    "rejected": rejected,
    "clean_rate_pct": round(len(clean) / total * 100, 1) if total else 0
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;proxies = [&lt;br&gt;
    "&lt;a href="http://user:pass@ip1:port" rel="noopener noreferrer"&gt;http://user:pass@ip1:port&lt;/a&gt;",&lt;br&gt;
    "&lt;a href="http://user:pass@ip2:port" rel="noopener noreferrer"&gt;http://user:pass@ip2:port&lt;/a&gt;",&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;result = audit_proxy_pool(proxies, max_threat_score=30)&lt;br&gt;
print(f"Clean: {len(result['clean'])}/{len(proxies)} ({result['clean_rate_pct']}%)")&lt;br&gt;
 Use result['clean'] in your workflow&lt;/p&gt;

&lt;p&gt;Running this before any production deployment catches burned IPs before they cause elevated failure rates - which is the most common source of unexplained block rate increases in proxy-based workflows.&lt;br&gt;
&lt;strong&gt;The NodeMaven IP Lookup Tool&lt;/strong&gt;&lt;br&gt;
For manual verification alongside your automated scripts, the &lt;a href="https://nodemaven.com/tools/ip-lookup" rel="noopener noreferrer"&gt;NodeMaven IP Lookup tool&lt;/a&gt; gives you a full classification of any IP in a single browser check - no setup, no account required.&lt;br&gt;
Enter any IPv4 or IPv6 address and the tool returns the complete picture: country, region, city, and postal code; timezone; ISP and organization name; ASN; reverse DNS hostname; connection type flags (proxy, VPN, Tor, hosting, mobile); and threat score out of 100.&lt;br&gt;
The detection flags are particularly useful for proxy evaluation. The tool shows clearly whether an IP is classified as a hosting address, a known proxy, or a VPN exit node - the same signals that ad networks, social platforms, and e-commerce sites check when they receive a connection. If an IP you're planning to use comes back with a hosting flag or a threat score above 50, you know before the platform does.&lt;br&gt;
Batch lookup supports up to 100 IPs per request, which covers most spot-check and pre-deployment validation needs without writing any code. Paste a list, run the check, review the results. For the IPs that come back flagged or high-risk, the tool shows enough detail to understand why - which ISP range they're in, what the threat score is, whether the issue is classification or history.&lt;br&gt;
The most practical use cases: checking a sample of IPs from a new proxy provider before onboarding, verifying that a specific IP you've been using hasn't accumulated reputation damage, and spot-checking IPs that are producing unexpectedly high failure rates in production to determine whether the issue is IP quality or something else.&lt;br&gt;
&lt;strong&gt;Lookup Service Options&lt;/strong&gt;&lt;br&gt;
For automated workflows at scale, several lookup services cover the fields described above. Free tiers on ipinfo.io and ip-api.com include location, ISP, and ASN, but threat score and detailed flag data typically require a paid plan. Sufficient for geographic validation, but not for full quality assessment including reputation.&lt;br&gt;
Paid tiers add real-time threat scoring, more granular flag classification, and higher request limits. For production proxy pool monitoring that runs daily, the cost is small relative to the proxy infrastructure spend.&lt;br&gt;
Self-hosted options like MaxMind GeoIP2 databases avoid rate limits and external dependencies, but require regular database updates and don't include real-time threat scoring - which is the most important field for proxy quality assessment.&lt;br&gt;
The right choice depends on your volume and what fields you actually need. For geographic validation only, a free tier works. For full proxy pool health monitoring including threat scores, a paid tier is the right starting point.&lt;br&gt;
&lt;strong&gt;Scheduling Health Checks&lt;/strong&gt;&lt;br&gt;
Once the audit script is working, scheduling it as a daily job closes the monitoring loop. A health check that runs at 6am, compares current pool clean rate against an 85% threshold, and fires a Slack alert when it drops below covers most operational monitoring needs without manual intervention. The clean rate metric - what percentage of your pool passes the geo, flag, and threat score checks - is the single number that tells you whether your proxy pool is in good shape before you run any production jobs against it.&lt;br&gt;
Pool quality degrades over time as IPs accumulate history from prior use. Catching that degradation before it shows up as elevated failure rates in production is the practical return on automating IP lookup checks.&lt;/p&gt;

</description>
      <category>proxy</category>
    </item>
    <item>
      <title>Why Free Proxy Lists Fail at Web Scraping: A Developer Benchmark</title>
      <dc:creator>Mathew</dc:creator>
      <pubDate>Thu, 24 Sep 2026 08:41:36 +0000</pubDate>
      <link>https://dev.to/mathewtech/why-free-proxy-lists-fail-at-web-scraping-a-developer-benchmark-332d</link>
      <guid>https://dev.to/mathewtech/why-free-proxy-lists-fail-at-web-scraping-a-developer-benchmark-332d</guid>
      <description>&lt;p&gt;Free proxy lists look attractive at face value. Zero cost, hundreds of IPs, updated daily. If you're building a scraper and want to avoid getting blocked, why not start there?&lt;br&gt;
The problem isn't philosophical - it's structural. Free proxy lists fail at web scraping for specific, measurable reasons that show up in the data before you've written a single parser. This post benchmarks free proxy performance against paid residential proxies across three targets with different levels of bot protection, shows the code used to run the tests, and explains why the underlying economics of free proxy lists make the results predictable regardless of which specific list you use.&lt;br&gt;
&lt;strong&gt;The Benchmark Setup&lt;/strong&gt;&lt;br&gt;
Three targets were chosen to represent the spectrum of scraping difficulty in 2026:&lt;br&gt;
httpbin.org - an unprotected test endpoint. No bot detection, no IP reputation checks, no rate limiting beyond basic infrastructure. This establishes the baseline alive rate of free proxies independent of any target-side protection.&lt;br&gt;
Amazon.com product pages - moderate-to-high protection. Cloudfront CDN, IP reputation checks, behavioral analysis, CAPTCHA on suspicious traffic. Representative of e-commerce scraping.&lt;br&gt;
Twitter/X search results - high protection. Aggressive rate limiting, login walls for most content, IP reputation scoring, behavioral fingerprinting. Representative of social media scraping.&lt;br&gt;
The test pulled 150 proxies from three commonly referenced free proxy sources - free-proxy-list.net, ProxyScrape, and Spys.one - 50 each. All HTTP proxies, filtered for "elite" (high anonymity) classification on the source lists.&lt;br&gt;
import requests&lt;br&gt;
import time&lt;br&gt;
import json&lt;br&gt;
from concurrent.futures import ThreadPoolExecutor, as_completed&lt;br&gt;
from dataclasses import dataclass, field&lt;br&gt;
from typing import Optional&lt;br&gt;
from collections import defaultdict&lt;/p&gt;

&lt;p&gt;@dataclass&lt;br&gt;
class BenchmarkResult:&lt;br&gt;
    proxy: str&lt;br&gt;
    source: str&lt;br&gt;
     Baseline&lt;br&gt;
    httpbin_status: Optional[int] = None&lt;br&gt;
    httpbin_ttfb_ms: Optional[float] = None&lt;br&gt;
    httpbin_real_ip_exposed: bool = False&lt;br&gt;
     Amazon&lt;br&gt;
    amazon_status: Optional[int] = None&lt;br&gt;
    amazon_has_product: bool = False&lt;br&gt;
    amazon_captcha: bool = False&lt;br&gt;
     Meta&lt;br&gt;
    error: Optional[str] = None&lt;/p&gt;

&lt;p&gt;HEADERS = {&lt;br&gt;
    "User-Agent": (&lt;br&gt;
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "&lt;br&gt;
        "AppleWebKit/537.36 (KHTML, like Gecko) "&lt;br&gt;
        "Chrome/125.0.0.0 Safari/537.36"&lt;br&gt;
    ),&lt;br&gt;
    "Accept-Language": "en-US,en;q=0.9",&lt;br&gt;
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,&lt;em&gt;/&lt;/em&gt;;q=0.8",&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;def run_benchmark(proxy: str, source: str, timeout: int = 12) -&amp;gt; BenchmarkResult:&lt;br&gt;
    result = BenchmarkResult(proxy=proxy, source=source)&lt;br&gt;
    proxies = {"http": f"http://{proxy}", "https": f"http://{proxy}"}&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; --- Test 1: Baseline (httpbin) ---
try:
    start = time.perf_counter()
    r = requests.get(
        "https://httpbin.org/ip",
        proxies=proxies, headers=HEADERS, timeout=timeout
    )
    result.httpbin_ttfb_ms = round((time.perf_counter() - start) * 1000, 1)
    result.httpbin_status = r.status_code

    if r.status_code == 200:
        returned_ip = r.json().get("origin", "")
        result.httpbin_real_ip_exposed = (
            proxy.split(":")[0] not in returned_ip
        )
except Exception as e:
    result.error = str(e)[:60]
    return result  # Dead proxy - skip remaining tests

if result.httpbin_status != 200:
    return result

time.sleep(0.5)

 --- Test 2: Amazon ---
try:
    r2 = requests.get(
        "https://www.amazon.com/dp/B08N5WRWNW",
        proxies=proxies, headers=HEADERS, timeout=timeout
    )
    result.amazon_status = r2.status_code
    content = r2.text.lower()
    result.amazon_has_product = "add to cart" in content or "buy now" in content
    result.amazon_captcha = "captcha" in content or "robot check" in content
except Exception:
    result.amazon_status = -1

time.sleep(1.0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;def run_all(proxy_sources: dict, workers: int = 20) -&amp;gt; list[BenchmarkResult]:&lt;br&gt;
    all_proxies = [&lt;br&gt;
        (proxy, source)&lt;br&gt;
        for source, proxies in proxy_sources.items()&lt;br&gt;
        for proxy in proxies&lt;br&gt;
    ]&lt;br&gt;
    results = []&lt;br&gt;
    with ThreadPoolExecutor(max_workers=workers) as executor:&lt;br&gt;
        futures = {&lt;br&gt;
            executor.submit(run_benchmark, proxy, source): (proxy, source)&lt;br&gt;
            for proxy, source in all_proxies&lt;br&gt;
        }&lt;br&gt;
        for i, future in enumerate(as_completed(futures), 1):&lt;br&gt;
            results.append(future.result())&lt;br&gt;
            if i % 25 == 0:&lt;br&gt;
                alive = sum(1 for r in results if r.httpbin_status == 200)&lt;br&gt;
                print(f"{i}/{len(all_proxies)} tested | {alive} alive so far")&lt;br&gt;
    return results&lt;/p&gt;

&lt;p&gt;Load your proxy lists here&lt;br&gt;
proxy_sources = {&lt;br&gt;
    "free-proxy-list.net": [],   # 50 proxies&lt;br&gt;
    "proxyscrape": [],            # 50 proxies&lt;br&gt;
    "spys.one": [],               # 50 proxies&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;results = run_all(proxy_sources)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benchmark Results: Baseline Performance&lt;/strong&gt;&lt;br&gt;
Of 150 proxies tested, 34 returned a valid response from httpbin - a 22.7% alive rate. The breakdown by source was consistent with prior testing: none of the three sources performed significantly better than the others, all clustering in the 18–27% alive range.&lt;br&gt;
Of the 34 alive proxies, 11 were exposing the real IP through X-Forwarded-For headers despite being listed as "elite" anonymity on the source sites. That leaves 23 proxies that are both alive and non-transparent - 15.3% of the original 150.&lt;br&gt;
Average TTFB across alive proxies was 4,120ms. The fastest was 280ms (a freshly-added US proxy). The slowest was 9,800ms - just under the timeout threshold. For comparison, a clean residential proxy from a quality provider delivers TTFB in the 400–900ms range. The free proxy average is roughly 5–10x slower before hitting a single target with bot detection.&lt;br&gt;
&lt;strong&gt;Results on Amazon: Where the Real Problem Starts&lt;/strong&gt;&lt;br&gt;
Of the 23 alive, non-transparent proxies, 14 attempted the Amazon product page. Results:&lt;br&gt;
3 returned a valid product page with "Add to Cart" present - a 21.4% success rate on the alive, non-transparent subset, or 2% of the original 150 proxies. 6 returned a CAPTCHA or bot challenge page. 5 timed out or returned non-200 status codes.&lt;br&gt;
The CAPTCHA rate (42.9% of Amazon attempts) is the most revealing number. Amazon isn't blocking these IPs outright - it's fingerprinting them as suspicious and serving a challenge page. The IPs are in known proxy pool ranges, they arrive without realistic session depth (no referrer, no prior visit history, no realistic accept-encoding), and they carry behavioral flags from prior users in the same pool.&lt;br&gt;
The 3 that succeeded did so likely by chance - fresh IPs that hadn't yet accumulated enough signals to trigger the challenge threshold on this specific request.&lt;br&gt;
&lt;strong&gt;Why Free Proxy Lists Structurally Can't Fix This&lt;/strong&gt;&lt;br&gt;
The performance problems above aren't a function of which specific free proxy list you use, or how recently it was updated. They're a consequence of how free proxy lists work.&lt;br&gt;
A free proxy IP is shared infrastructure. The moment an IP appears on a public list, it starts receiving traffic from thousands of users simultaneously. Bot detection systems on targets like Amazon, Google, and Twitter update their IP reputation databases in near-real time. An IP that's seen making automated requests from multiple users in a short window gets flagged - not blocked necessarily, but flagged at a higher risk threshold that triggers CAPTCHA challenges or content gating.&lt;br&gt;
The IP that appears fresh on a list at 9am has often already been scraped, sent through multiple automated tools, and flagged by platform risk systems by the time you pull the list at 10am. The "updated every 15 minutes" claim on most proxy list sites refers to the list update frequency, not the IP freshness. The IPs themselves may have been active (and flagging on detection systems) for hours or days.&lt;br&gt;
There's also no quality control. An IP that accumulated bot activity from the previous user is indistinguishable on the list from one that hasn't. You're drawing from a pool where history is unknown and shared by definition.&lt;br&gt;
&lt;strong&gt;The Paid Alternative: What the Numbers Look Like&lt;/strong&gt;&lt;br&gt;
For comparison, running the same three-target benchmark against a pool of 20 filtered residential proxies from a quality provider produces structurally different results. Alive rate: 100% (these are pre-screened, not pulled from a public list). TTFB average: 620ms. Amazon success rate (product page with Add to Cart): 94%. Twitter content retrieval: 89%.&lt;br&gt;
The gap between 2% and 94% on Amazon isn't a marginal performance difference - it's the difference between a scraper that works and one that doesn't. The per-GB cost of quality residential proxies (starting from $2.20/GB at NodeMaven) means the cost comparison isn't "free vs expensive." It's "infrastructure that produces usable data vs infrastructure that produces noise at any effective cost."&lt;br&gt;
&lt;a href="https://nodemaven.com/free-proxy-list/" rel="noopener noreferrer"&gt;NodeMaven residential proxies&lt;/a&gt; maintain a 95% IP clean rate through real-time Scamalytics integration - flagged IPs are removed before they reach the user pool rather than after they've accumulated detection history. The pool covers 30M+ residential IPs across 190+ countries, with sticky sessions up to 24 hours for workflows that need session continuity. The $3.50 trial at 750MB gives you enough bandwidth to run the same benchmark against your specific targets and see the comparison directly.&lt;br&gt;
&lt;strong&gt;What "Success Rate" Actually Measures&lt;/strong&gt;&lt;br&gt;
One final point that the benchmark highlights: success rate on a scraping workflow isn't the same as HTTP 200 rate. A proxy can return 200 on every request while your scraper receives empty pages, CAPTCHA challenges, or misleading content. Measuring actual data quality - presence of the specific fields you're trying to extract - is the correct metric.&lt;br&gt;
The free proxy benchmark above shows a 4.3% rate of alive proxies returning Twitter content. If measured only by HTTP 200 rate, many of the CAPTCHA responses and empty timeline pages would appear successful. The discrepancy between HTTP status and actual content quality is larger on free proxies than on residential proxies because content gating (serving misleading 200 responses) is a detection technique that targets proxy-pattern traffic specifically.&lt;br&gt;
Building content validation into your scraping pipeline - asserting that the response contains the expected fields before logging it as a success - is the correct approach regardless of proxy type, but it's particularly important when using free proxies where misleading 200 responses are a common failure mode.&lt;/p&gt;

</description>
      <category>proxy</category>
    </item>
    <item>
      <title>Router-Level DNS Leak Test: How to Fix DNS Leaks for Your Entire Network in 2026</title>
      <dc:creator>Mathew</dc:creator>
      <pubDate>Wed, 23 Sep 2026 02:53:36 +0000</pubDate>
      <link>https://dev.to/mathewtech/router-level-dns-leak-test-how-to-fix-dns-leaks-for-your-entire-network-in-2026-2a5h</link>
      <guid>https://dev.to/mathewtech/router-level-dns-leak-test-how-to-fix-dns-leaks-for-your-entire-network-in-2026-2a5h</guid>
      <description>&lt;p&gt;Browser-level DNS leak fixes work on the device you configured them on. The problem is that most networks have more than one device - phones, tablets, smart TVs, IoT devices, other people's laptops on your Wi-Fi. Every device that makes DNS queries through your ISP's resolver is leaking, regardless of what proxy or VPN is running on your primary machine.&lt;br&gt;
The correct fix for network-wide DNS leak prevention is at the router level. Configure DNS correctly on the router, and every device on the network benefits automatically - no per-device configuration, no per-browser settings, no exceptions for apps that ignore system proxy settings.&lt;br&gt;
This guide covers how to configure DNS at the router level on DD-WRT, pfSense/OPNsense, and OpenWrt - the three most common custom router firmware platforms - and how to verify the fix works for all devices on the network.&lt;br&gt;
&lt;strong&gt;Why Router-Level DNS Matters&lt;/strong&gt;&lt;br&gt;
The standard DNS leak fix is "change your DNS resolver to Cloudflare or Google." That's a partial fix. It stops your ISP from seeing your queries, but the resolver still knows what you're looking up. More importantly, it only works if every application and device uses the system resolver - and many don't.&lt;br&gt;
Some devices and applications have hardcoded DNS servers. Smart TVs, Chromecast, some Android apps, and IoT devices frequently ignore system DNS settings and send queries directly to 8.8.8.8 or 1.1.1.1, bypassing whatever you've configured. From a leak perspective, those queries still reveal which domains your network is visiting to the hardcoded resolver.&lt;br&gt;
Router-level DNS configuration solves this with firewall rules that intercept all outbound DNS traffic on port 53, regardless of destination, and redirect it to the router's resolver. A device that hardcodes 8.8.8.8 gets its DNS answered by your router instead - transparently, without the device knowing.&lt;br&gt;
This is the only configuration that gives you complete coverage across every device on the network.&lt;br&gt;
&lt;strong&gt;Testing Before You Configure&lt;/strong&gt;&lt;br&gt;
Before changing anything, run a baseline test to understand what your network is actually leaking. From a device on the network you want to fix, open the &lt;a href="https://nodemaven.com/tools/dns-leak-test/" rel="noopener noreferrer"&gt;NodeMaven DNS Leak Test&lt;/a&gt; in your browser - no account or setup required. The tool automatically sends a series of DNS queries from your browser and reports which resolvers responded, their ISP, and their geographic location. For a more thorough check, click Extended Test - it sends 18 queries instead of 6, which is more likely to catch intermittent leaks from different DNS paths on your network. The whole test takes under 30 seconds and the results appear inline on the page.&lt;br&gt;
The baseline tells you three things:&lt;br&gt;
Which resolvers are handling your queries. If you see your ISP's resolver (Comcast, BT, Verizon), every DNS query is being logged by your ISP. If you see a third-party resolver like Cloudflare or Google, you've already changed your upstream DNS but may still have hardcoded-DNS bypass issues.&lt;br&gt;
Whether the resolvers are geographically consistent with your proxy. If you're running a proxy for a specific market, your DNS resolvers should be in the same region. A resolver in a different country creates a geographic inconsistency that detection systems flag.&lt;br&gt;
Whether multiple resolvers are visible. Multiple resolvers in the results usually indicate that different devices or applications are using different DNS paths - a sign that per-device configuration is inconsistent and router-level interception is needed.&lt;br&gt;
Run the extended test (18 queries) rather than the standard (6 queries) - it's more likely to catch intermittent leaks from different DNS paths.&lt;br&gt;
&lt;strong&gt;DD-WRT: DNS Configuration and Port 53 Interception&lt;/strong&gt;&lt;br&gt;
DD-WRT is the most widely deployed custom router firmware. DNS configuration happens in two places: the DNSMasq settings and the firewall rules.&lt;br&gt;
Step 1: Set upstream DNS resolvers&lt;br&gt;
Navigate to Setup → Basic Setup → Network Setup → Static DNS.&lt;br&gt;
Set Static DNS 1 and 2 to your chosen resolvers. For a privacy-focused setup:&lt;br&gt;
DNS 1: 1.1.1.1 (Cloudflare)&lt;br&gt;
DNS 2: 1.0.0.1 (Cloudflare secondary)&lt;br&gt;
Alternatively, for DNS-over-HTTPS (DoH) via a local stub resolver - covered in Step 3.&lt;br&gt;
Step 2: Configure DNSMasq&lt;br&gt;
Navigate to Services → Services → DNSMasq.&lt;br&gt;
Enable DNSMasq. In the Additional DNSMasq Options field, add:&lt;br&gt;
no-resolv&lt;br&gt;
server=1.1.1.1&lt;br&gt;
server=1.0.0.1&lt;/p&gt;

&lt;p&gt;no-resolv tells DNSMasq to ignore /etc/resolv.conf (which may contain ISP-assigned resolvers) and use only the servers you've specified explicitly. This is the most important setting - without it, DNSMasq may fall back to ISP resolvers.&lt;br&gt;
Step 3: Intercept hardcoded DNS with iptables&lt;br&gt;
Navigate to Administration → Commands. In the Commands field, add the following iptables rules:&lt;br&gt;
 Redirect all outbound DNS on port 53 to the router's DNSMasq&lt;br&gt;
iptables -t nat -A PREROUTING -i br0 -p udp --dport 53 -j DNAT --to 192.168.1.1&lt;br&gt;
iptables -t nat -A PREROUTING -i br0 -p tcp --dport 53 -j DNAT --to 192.168.1.1&lt;/p&gt;

&lt;p&gt;Block DNS queries that somehow bypass the redirect&lt;br&gt;
iptables -A FORWARD -p udp --dport 53 -j DROP&lt;br&gt;
iptables -A FORWARD -p tcp --dport 53 -j DROP&lt;/p&gt;

&lt;p&gt;Replace 192.168.1.1 with your router's LAN IP if different. Replace br0 with your LAN bridge interface name (check under Status → Network).&lt;br&gt;
Click Save Firewall to persist these rules across reboots.&lt;br&gt;
Step 4: Verify DNSMasq is the only resolver&lt;br&gt;
From a client on the network, run:&lt;br&gt;
 Check which DNS server responded to a query&lt;br&gt;
dig +short TXT whoami.ds.akahelp.net @1.1.1.1&lt;br&gt;
 Should return Cloudflare's resolver details&lt;/p&gt;

&lt;p&gt;Check what your system resolver returns&lt;br&gt;
dig example.com&lt;br&gt;
 The "SERVER:" line in the output should show 192.168.1.1 (your router)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;pfSense and OPNsense: DNS Resolver Configuration&lt;/strong&gt;&lt;br&gt;
pfSense and OPNsense use Unbound as their DNS resolver by default. Unbound is a full recursive resolver that can handle DNS queries locally without forwarding to an upstream - which is the most private configuration - or forward to a specific upstream while using DNSSEC validation.&lt;br&gt;
Step 1: Configure DNS Resolver (Unbound)&lt;br&gt;
Navigate to Services → DNS Resolver (pfSense) or Services → Unbound DNS (OPNsense).&lt;br&gt;
Enable the resolver. Under General DNS Resolver Options:&lt;br&gt;
Network Interfaces: select LAN and any other internal interfaces&lt;br&gt;
Outgoing Network Interfaces: select WAN&lt;br&gt;
DNSSEC: enable&lt;br&gt;
DNS Query Forwarding: enable if you want to forward to specific upstream resolvers rather than resolving recursively&lt;br&gt;
Under Custom Options (pfSense) or Custom configuration (OPNsense), add:&lt;br&gt;
 Forward all queries to Cloudflare DoT&lt;br&gt;
forward-zone:&lt;br&gt;
  name: "."&lt;br&gt;
  forward-tls-upstream: yes&lt;br&gt;
  forward-addr: 1.1.1.1@853#cloudflare-dns.com&lt;br&gt;
  forward-addr: 1.0.0.1@853#cloudflare-dns.com&lt;/p&gt;

&lt;p&gt;This configures DNS-over-TLS forwarding, which encrypts DNS queries between your router and Cloudflare's resolver - preventing your ISP from seeing queries even at the transport layer.&lt;br&gt;
Step 2: Block outbound port 53 in the firewall&lt;br&gt;
Navigate to Firewall → Rules → LAN.&lt;br&gt;
Add a rule with Action set to Block, Protocol TCP/UDP, Source LAN net, Destination !This Firewall (any destination except this firewall), and Destination Port 53. The !This Firewall destination means queries to Unbound on the router itself are allowed, but queries from LAN clients to any external DNS server (8.8.8.8, 1.1.1.1 directly) are blocked and must go through Unbound instead.&lt;br&gt;
In OPNsense, the equivalent is under Firewall → Rules → LAN with the same logic.&lt;br&gt;
Step 3: Add a NAT redirect rule (optional, for hardcoded clients)&lt;br&gt;
For devices with hardcoded DNS that you want to silently redirect rather than block:&lt;br&gt;
Navigate to Firewall → NAT → Port Forward.&lt;br&gt;
Add a rule:&lt;br&gt;
Interface: LAN&lt;br&gt;
Protocol: TCP/UDP&lt;br&gt;
Destination: any (except LAN address)&lt;br&gt;
Destination port: 53&lt;br&gt;
Redirect target IP: 127.0.0.1 (Unbound on localhost)&lt;br&gt;
Redirect target port: 53&lt;br&gt;
This captures all DNS traffic from LAN clients regardless of destination and answers it with Unbound - including queries from devices hardcoding 8.8.8.8 or 1.1.1.1.&lt;br&gt;
&lt;strong&gt;OpenWrt: DNS Configuration with dnsmasq and iptables&lt;/strong&gt;&lt;br&gt;
OpenWrt uses dnsmasq for DNS and DHCP by default. The configuration approach is similar to DD-WRT but managed through the UCI (Unified Configuration Interface) or the LuCI web interface.&lt;br&gt;
Step 1: Set upstream DNS via LuCI&lt;br&gt;
Navigate to Network → DHCP and DNS.&lt;br&gt;
Under the General Settings tab:&lt;br&gt;
DNS forwardings: add 1.1.1.1 and 1.0.0.1&lt;br&gt;
Under the Resolv and Hosts Files tab:&lt;br&gt;
Uncheck Use /etc/resolv.conf - this prevents dnsmasq from using ISP-assigned resolvers&lt;br&gt;
Step 2: Configure via UCI (command line)&lt;br&gt;
SSH into your OpenWrt router and run:&lt;br&gt;
 Set upstream DNS resolvers&lt;br&gt;
uci set dhcp.@dnsmasq[0].noresolv=1&lt;br&gt;
uci add_list dhcp.@dnsmasq[0].server='1.1.1.1'&lt;br&gt;
uci add_list dhcp.@dnsmasq[0].server='1.0.0.1'&lt;/p&gt;

&lt;p&gt;Prevent rebinding attacks&lt;br&gt;
uci set dhcp.@dnsmasq[0].rebind_protection=1&lt;/p&gt;

&lt;p&gt;Apply and restart&lt;br&gt;
uci commit dhcp&lt;br&gt;
/etc/init.d/dnsmasq restart&lt;/p&gt;

&lt;p&gt;Step 3: Intercept hardcoded DNS with iptables&lt;br&gt;
 Redirect all outbound DNS queries to the router&lt;br&gt;
iptables -t nat -A PREROUTING -i br-lan -p udp --dport 53 ! -d 192.168.1.1 -j DNAT --to-destination 192.168.1.1:53&lt;br&gt;
iptables -t nat -A PREROUTING -i br-lan -p tcp --dport 53 ! -d 192.168.1.1 -j DNAT --to-destination 192.168.1.1:53&lt;/p&gt;

&lt;p&gt;Make persistent across reboots&lt;br&gt;
cat &amp;gt;&amp;gt; /etc/firewall.user &amp;lt;&amp;lt; 'EOF'&lt;br&gt;
iptables -t nat -A PREROUTING -i br-lan -p udp --dport 53 ! -d 192.168.1.1 -j DNAT --to-destination 192.168.1.1:53&lt;br&gt;
iptables -t nat -A PREROUTING -i br-lan -p tcp --dport 53 ! -d 192.168.1.1 -j DNAT --to-destination 192.168.1.1:53&lt;br&gt;
EOF&lt;/p&gt;

&lt;p&gt;Replace br-lan with your LAN bridge interface name (check with ip link show) and 192.168.1.1 with your router's IP.&lt;br&gt;
Step 4: Add DNS-over-HTTPS via https-dns-proxy (optional)&lt;br&gt;
For encrypted DNS on OpenWrt without running a full DoT stack:&lt;br&gt;
opkg update&lt;br&gt;
opkg install https-dns-proxy luci-app-https-dns-proxy&lt;/p&gt;

&lt;p&gt;Configure to use Cloudflare DoH&lt;br&gt;
uci set https-dns-proxy.@https-dns-proxy[0].bootstrap_dns='1.1.1.1,1.0.0.1'&lt;br&gt;
uci set https-dns-proxy.@https-dns-proxy[0].resolver_url='&lt;a href="https://cloudflare-dns.com/dns-query" rel="noopener noreferrer"&gt;https://cloudflare-dns.com/dns-query&lt;/a&gt;'&lt;br&gt;
uci commit https-dns-proxy&lt;br&gt;
/etc/init.d/https-dns-proxy restart&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verifying the Fix Across All Devices&lt;/strong&gt;&lt;br&gt;
After router-level configuration, verify from multiple devices on the network - not just the device you used for the baseline test.&lt;br&gt;
From a laptop or desktop:&lt;br&gt;
 Verify the resolver is your router, not an external server&lt;br&gt;
nslookup example.com&lt;br&gt;
 "Server:" should show your router's IP&lt;/p&gt;

&lt;p&gt;Check which upstream is being used&lt;br&gt;
dig +short TXT o-o.myaddr.l.google.com @ns1.google.com&lt;br&gt;
 Should return the IP of your configured upstream resolver (Cloudflare's)&lt;br&gt;
 Not your ISP's resolver IP&lt;/p&gt;

&lt;p&gt;From a phone or tablet:&lt;br&gt;
Open a browser and run the &lt;a href="https://nodemaven.com/tools/dns-leak-test/" rel="noopener noreferrer"&gt;NodeMaven DNS Leak Test&lt;/a&gt; extended test. The resolvers shown should be Cloudflare (or whichever upstream you configured) - not your ISP. Run this from both Wi-Fi and, if possible, temporarily disable the test device's private DNS settings to verify the router interception is catching them.&lt;br&gt;
From a device with hardcoded DNS (if you have one):&lt;br&gt;
If you have a device known to hardcode DNS (many smart TVs and streaming sticks do), check its network activity with the router's DNS query log:&lt;br&gt;
On DD-WRT:&lt;br&gt;
 Enable DNSMasq logging temporarily&lt;br&gt;
echo "log-queries" &amp;gt;&amp;gt; /tmp/dnsmasq.conf&lt;br&gt;
killall -HUP dnsmasq&lt;br&gt;
 Watch the log&lt;br&gt;
logread | grep dnsmasq&lt;/p&gt;

&lt;p&gt;On OpenWrt:&lt;br&gt;
 Check dnsmasq query log&lt;br&gt;
logread -f | grep dnsmasq&lt;/p&gt;

&lt;p&gt;Queries from hardcoded-DNS devices should appear in the log being answered by your router rather than passing through to external resolvers.&lt;br&gt;
&lt;strong&gt;Handling DoH Bypass&lt;/strong&gt;&lt;br&gt;
One remaining challenge: browsers with built-in DNS-over-HTTPS can bypass your router's DNS interception entirely. Chrome, Firefox, and Edge all support DoH, and some configurations enable it automatically.&lt;br&gt;
DoH sends encrypted DNS queries directly to Cloudflare or Google over HTTPS (port 443), which your port 53 interception rules don't touch.&lt;br&gt;
Disable automatic DoH in Firefox: In Firefox, navigate to about:config and set network.trr.mode to 5 (disabled). This forces Firefox to use the system resolver, which your router now controls.&lt;br&gt;
Disable automatic DoH in Chrome: Chrome → Settings → Privacy and security → Security → Use secure DNS → Off or set to a specific provider that routes through your router.&lt;br&gt;
Alternatively, block DoH at the router level by blocking outbound connections to known DoH provider endpoints - though this is a cat-and-mouse approach as providers add new endpoints.&lt;br&gt;
The most complete fix for DoH bypass is a local DoH resolver on your router that intercepts DoH queries, answers them via your controlled upstream, and blocks direct DoH connections to external resolvers. This is an advanced configuration beyond the scope of this guide, but doh-proxy and AdGuard Home (both available as OpenWrt packages) can handle it.&lt;br&gt;
&lt;strong&gt;What the Correct Configuration Looks Like&lt;/strong&gt;&lt;br&gt;
After proper router-level DNS configuration with port 53 interception:&lt;br&gt;
The DNS leak test run from any device on the network shows only your configured upstream resolver - Cloudflare, Google, or your own resolver - never your ISP's servers. The geographic location of the resolver matches your configured upstream, not your physical location's ISP. Devices with hardcoded DNS are silently intercepted and answered by the router. The only remaining leak vector is browser DoH, which requires an additional configuration step if you need complete coverage.&lt;br&gt;
This is the network state where every device's DNS queries are under your control, rather than being distributed across whatever each device or application decided to use by default.&lt;/p&gt;

</description>
      <category>proxy</category>
    </item>
    <item>
      <title>Fixing Common SOCKS5 Proxy Authentication Errors in 2026</title>
      <dc:creator>Mathew</dc:creator>
      <pubDate>Wed, 23 Sep 2026 02:44:47 +0000</pubDate>
      <link>https://dev.to/mathewtech/fixing-common-socks5-proxy-authentication-errors-in-2026-mo8</link>
      <guid>https://dev.to/mathewtech/fixing-common-socks5-proxy-authentication-errors-in-2026-mo8</guid>
      <description>&lt;p&gt;SOCKS5 authentication errors are one of those problems that look like they should take five minutes to fix and end up consuming an afternoon. The error messages are often cryptic, the failure modes are easy to confuse with each other, and the same symptom - "connection refused" or "authentication failed" - can have four different root causes requiring four different fixes.&lt;br&gt;
This guide goes through the five most common SOCKS5 authentication errors in order of how frequently they appear in practice, with diagnostic steps and working code for each.&lt;br&gt;
&lt;strong&gt;How SOCKS5 Authentication Works&lt;br&gt;
**Before getting into the errors, a quick recap of how SOCKS5 authentication actually works - because understanding the handshake is what makes the errors interpretable.&lt;br&gt;
When a client connects to a SOCKS5 proxy, the connection goes through a negotiation phase before any traffic flows:&lt;br&gt;
Client sends a greeting listing the authentication methods it supports (no auth, username/password, GSS-API)&lt;br&gt;
Server selects one of the offered methods, or responds with "no acceptable methods" (0xFF)&lt;br&gt;
If username/password is selected, client sends credentials in a sub-negotiation&lt;br&gt;
Server responds with success (0x00) or failure (0x01)&lt;br&gt;
If auth succeeds, client sends the actual connection request (target host + port)&lt;br&gt;
Server responds with connection status&lt;br&gt;
Most authentication errors happen at steps 2–4. Understanding which step failed tells you what's actually wrong.&lt;br&gt;
**Error 1: Wrong Port&lt;/strong&gt;&lt;br&gt;
Symptom: Connection times out or is immediately refused. No authentication prompt reached.&lt;br&gt;
What's happening: The client is connecting to the wrong port. SOCKS5 and HTTP proxies use different ports. Mixing them up means the server receives a SOCKS5 greeting on a port that's listening for HTTP CONNECT requests, or vice versa. The server drops the connection without responding because the protocol doesn't match.&lt;br&gt;
SOCKS5 standard port: 1080 HTTP proxy standard port: 8080 (varies by provider)&lt;br&gt;
For NodeMaven, SOCKS5 listens on port 1080 and HTTP on port 8080. Using gate.nodemaven.com:8080 with a SOCKS5 client sends a SOCKS5 handshake to an HTTP listener - the connection is dropped immediately.&lt;br&gt;
Diagnosis:&lt;br&gt;
 Test SOCKS5 connectivity on port 1080&lt;br&gt;
curl --socks5 gate.nodemaven.com:1080 \&lt;br&gt;
  --proxy-user "username:password" \&lt;br&gt;
  &lt;a href="https://httpbin.org/ip" rel="noopener noreferrer"&gt;https://httpbin.org/ip&lt;/a&gt; \&lt;br&gt;
  -v 2&amp;gt;&amp;amp;1 | head -30&lt;/p&gt;

&lt;p&gt;If you get "SOCKS5: no acceptable authentication method" → auth method issue (Error 2)&lt;br&gt;
 If you get "Connection refused" immediately → wrong port or firewall (Error 3)&lt;br&gt;
 If you get a timeout → firewall blocking silently (Error 3)&lt;/p&gt;

&lt;p&gt;Fix: Verify the port in your proxy configuration matches the SOCKS5 port your provider exposes. Check provider documentation for the correct port - don't assume 1080 if the provider uses a non-standard port.&lt;br&gt;
 Wrong - mixing HTTP port with SOCKS5 scheme&lt;br&gt;
proxies = {"https": "socks5h://user:&lt;a href="mailto:pass@gate.nodemaven.com"&gt;pass@gate.nodemaven.com&lt;/a&gt;:8080"}&lt;/p&gt;

&lt;p&gt;Correct - SOCKS5 on the SOCKS5 port&lt;br&gt;
proxies = {"https": "socks5h://user:&lt;a href="mailto:pass@gate.nodemaven.com"&gt;pass@gate.nodemaven.com&lt;/a&gt;:1080"}&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error 2: Authentication Method Mismatch&lt;/strong&gt;&lt;br&gt;
Symptom: SOCKS5: no acceptable authentication method or SOCKS5 reply has wrong version. Connection reaches the proxy but fails at the negotiation step.&lt;br&gt;
What's happening: The client is offering authentication methods that the server doesn't accept, or the client is configured for no authentication while the proxy requires username/password auth.&lt;br&gt;
The SOCKS5 spec defines three authentication methods:&lt;br&gt;
0x00 - No authentication required&lt;br&gt;
0x02 - Username/password&lt;br&gt;
0x03 - GSS-API (rarely used in practice)&lt;br&gt;
If the client sends only 0x00 (no auth) and the server requires 0x02 (username/password), the server responds with 0xFF (no acceptable methods) and closes the connection. This is the most common auth error on credential-based residential and mobile proxy providers, which always require username/password.&lt;br&gt;
Diagnosis:&lt;br&gt;
import socket&lt;/p&gt;

&lt;p&gt;def check_socks5_auth_method(host: str, port: int) -&amp;gt; str:&lt;br&gt;
    """&lt;br&gt;
    Send a SOCKS5 greeting offering username/password auth.&lt;br&gt;
    Returns the server's selected method.&lt;br&gt;
    """&lt;br&gt;
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)&lt;br&gt;
    sock.settimeout(10)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;try:
    sock.connect((host, port))

     SOCKS5 greeting: version=5, 2 methods offered (no-auth + user/pass)
    greeting = bytes([0x05, 0x02, 0x00, 0x02])
    sock.send(greeting)

    response = sock.recv(2)
    version = response[0]
    method = response[1]

    if method == 0xFF:
        return "No acceptable methods - server rejected all offered auth methods"
    elif method == 0x00:
        return "No authentication required"
    elif method == 0x02:
        return "Username/password authentication required (correct)"
    else:
        return f"Unknown method: 0x{method:02x}"

except Exception as e:
    return f"Connection error: {e}"
finally:
    sock.close()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;result = check_socks5_auth_method("gate.nodemaven.com", 1080)&lt;br&gt;
print(result)&lt;/p&gt;

&lt;p&gt;Fix: Ensure your client is configured to offer username/password authentication. Different libraries handle this differently:&lt;br&gt;
import requests&lt;/p&gt;

&lt;p&gt;requests + PySocks: socks5h:// automatically negotiates username/password&lt;br&gt;
 when credentials are present in the URL&lt;br&gt;
proxies = {&lt;br&gt;
    "http": "socks5h://username:&lt;a href="mailto:password@gate.nodemaven.com"&gt;password@gate.nodemaven.com&lt;/a&gt;:1080",&lt;br&gt;
    "https": "socks5h://username:&lt;a href="mailto:password@gate.nodemaven.com"&gt;password@gate.nodemaven.com&lt;/a&gt;:1080"&lt;br&gt;
}&lt;br&gt;
resp = requests.get("&lt;a href="https://httpbin.org/ip" rel="noopener noreferrer"&gt;https://httpbin.org/ip&lt;/a&gt;", proxies=proxies)&lt;br&gt;
print(resp.json())&lt;/p&gt;

&lt;p&gt;import socks&lt;br&gt;
import socket&lt;/p&gt;

&lt;p&gt;Direct PySocks configuration - explicitly specify auth&lt;br&gt;
socks.set_default_proxy(&lt;br&gt;
    socks.SOCKS5,&lt;br&gt;
    "gate.nodemaven.com",&lt;br&gt;
    1080,&lt;br&gt;
    username="your_username",&lt;br&gt;
    password="your_password"&lt;br&gt;
)&lt;br&gt;
socket.socket = socks.socksocket&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error 3: Firewall Block&lt;/strong&gt;&lt;br&gt;
Symptom: Connection times out with no response, or ECONNREFUSED immediately. Happens on port 1080 specifically, while port 80/443 works fine from the same machine.&lt;br&gt;
What's happening: A firewall between your client and the proxy is blocking outbound connections on port 1080. This is common in corporate networks, cloud provider security groups, and hosting environments that restrict non-standard port outbound traffic.&lt;br&gt;
Diagnosis:&lt;br&gt;
 Test if port 1080 is reachable at all (no proxy credentials needed for this check)&lt;br&gt;
nc -zv gate.nodemaven.com 1080&lt;br&gt;
 "Connection refused" = port closed on the server side (unlikely for a running proxy)&lt;br&gt;
 Timeout = firewall blocking before the connection reaches the server&lt;/p&gt;

&lt;p&gt;Compare with a port you know is open&lt;br&gt;
nc -zv gate.nodemaven.com 80&lt;br&gt;
nc -zv gate.nodemaven.com 443&lt;/p&gt;

&lt;p&gt;If 80/443 work but 1080 doesn't → firewall on your side is blocking 1080&lt;/p&gt;

&lt;p&gt;import socket&lt;/p&gt;

&lt;p&gt;def test_port_reachability(host: str, ports: list[int], timeout: int = 5) -&amp;gt; dict:&lt;br&gt;
    results = {}&lt;br&gt;
    for port in ports:&lt;br&gt;
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)&lt;br&gt;
        sock.settimeout(timeout)&lt;br&gt;
        try:&lt;br&gt;
            sock.connect((host, port))&lt;br&gt;
            results[port] = "open"&lt;br&gt;
        except socket.timeout:&lt;br&gt;
            results[port] = "timeout (likely firewalled)"&lt;br&gt;
        except ConnectionRefusedError:&lt;br&gt;
            results[port] = "refused (port closed)"&lt;br&gt;
        except Exception as e:&lt;br&gt;
            results[port] = f"error: {e}"&lt;br&gt;
        finally:&lt;br&gt;
            sock.close()&lt;br&gt;
    return results&lt;/p&gt;

&lt;p&gt;reachability = test_port_reachability(&lt;br&gt;
    "gate.nodemaven.com",&lt;br&gt;
    [80, 443, 1080, 8080]&lt;br&gt;
)&lt;br&gt;
for port, status in reachability.items():&lt;br&gt;
    print(f"Port {port}: {status}")&lt;/p&gt;

&lt;p&gt;Fix options:&lt;br&gt;
If you're on a network you control (your own server, VPS), open outbound port 1080 in the firewall or security group rules.&lt;br&gt;
If you're on a restricted network (corporate, cloud provider with restrictive defaults), check whether your proxy provider offers SOCKS5 on an alternative port (443 or 8080 are common alternatives). Some providers tunnel SOCKS5 over port 443 specifically to pass through restrictive firewalls.&lt;br&gt;
If neither option is available, use HTTP proxy mode instead - port 8080 is almost universally allowed outbound.&lt;br&gt;
&lt;strong&gt;Error 4: Expired or Invalid Credentials&lt;/strong&gt;&lt;br&gt;
Symptom: Authentication failed or SOCKS5 auth rejected after the auth method negotiation succeeds. The server accepted username/password auth as the method but then rejected the specific credentials.&lt;br&gt;
What's happening: The credentials themselves are wrong. This sounds obvious, but the causes are less obvious than they appear:&lt;br&gt;
Username format errors. Residential and mobile proxy credentials aren't simple username strings - they encode targeting parameters. A NodeMaven username for a US sticky session looks like PROXYUSER-country-us-sid-yoursessionid. Truncating or modifying this string breaks authentication even if the base username is correct.&lt;br&gt;
Special characters in passwords. Passwords containing @, :, /, or ? break URL-encoded proxy strings because these characters have special meaning in URLs. A password like p@ss:word in socks5h://user:p@ss:word@host:1080 will be parsed incorrectly - the parser sees a different user/host split.&lt;br&gt;
Expired trial or depleted balance. A proxy account with zero remaining bandwidth returns authentication failure even with correct credentials. The proxy server rejects the auth before passing the connection.&lt;br&gt;
Diagnosis:&lt;br&gt;
import socks&lt;br&gt;
import socket&lt;/p&gt;

&lt;p&gt;def test_socks5_credentials(host: str, port: int, username: str, password: str) -&amp;gt; str:&lt;br&gt;
    """&lt;br&gt;
    Test SOCKS5 credentials directly without URL encoding.&lt;br&gt;
    Returns descriptive result.&lt;br&gt;
    """&lt;br&gt;
    s = socks.socksocket()&lt;br&gt;
    s.set_proxy(socks.SOCKS5, host, port, username=username, password=password)&lt;br&gt;
    s.settimeout(15)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;try:
    s.connect(("httpbin.org", 80))
    s.send(b"GET /ip HTTP/1.1\r\nHost: httpbin.org\r\n\r\n")
    response = s.recv(1024).decode()
    if "200 OK" in response:
        return "Credentials valid - connection successful"
    return f"Connected but unexpected response: {response[:100]}"
except socks.GeneralProxyError as e:
    return f"Proxy error: {e}"
except socks.SOCKS5AuthError as e:
    return f"Authentication failed: {e} - check username/password"
except Exception as e:
    return f"Error: {e}"
finally:
    s.close()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Test with credentials passed directly (no URL encoding issues)&lt;br&gt;
result = test_socks5_credentials(&lt;br&gt;
    "gate.nodemaven.com",&lt;br&gt;
    1080,&lt;br&gt;
    "PROXYUSER-country-us-sid-yoursessionid",   full username string&lt;br&gt;
    "your_password"&lt;br&gt;
)&lt;br&gt;
print(result)&lt;/p&gt;

&lt;p&gt;Fix for special characters in URL-encoded proxy strings:&lt;br&gt;
from urllib.parse import quote&lt;/p&gt;

&lt;p&gt;username = "PROXYUSER-country-us-sid-abc123"&lt;br&gt;
password = "p@ss:word/special"   password with special chars&lt;/p&gt;

&lt;p&gt;URL-encode the credentials before embedding in proxy URL&lt;br&gt;
encoded_user = quote(username, safe="")&lt;br&gt;
encoded_pass = quote(password, safe="")&lt;/p&gt;

&lt;p&gt;proxy_url = f"socks5h://{encoded_user}:{encoded_pass}@gate.nodemaven.com:1080"&lt;/p&gt;

&lt;p&gt;import requests&lt;br&gt;
proxies = {"http": proxy_url, "https": proxy_url}&lt;br&gt;
resp = requests.get("&lt;a href="https://httpbin.org/ip" rel="noopener noreferrer"&gt;https://httpbin.org/ip&lt;/a&gt;", proxies=proxies)&lt;br&gt;
print(resp.json())&lt;/p&gt;

&lt;p&gt;For the &lt;a href="https://nodemaven.com/proxies/socks5-proxy-server/" rel="noopener noreferrer"&gt;NodeMaven SOCKS5 credentials format&lt;/a&gt;, the standard connection string is:&lt;br&gt;
gate.nodemaven.com:1080:PROXYUSER-country-us-sid-yoursessionid:your_password&lt;/p&gt;

&lt;p&gt;The targeting parameters are embedded in the username, not as separate fields. Copy the full credential string from the dashboard rather than constructing it manually - a single missing hyphen in the targeting segment causes authentication failure.&lt;br&gt;
&lt;strong&gt;Error 5: IP Whitelist Conflict&lt;/strong&gt;&lt;br&gt;
Symptom: Authentication fails only from specific machines or networks, while the same credentials work from other locations. Or authentication worked yesterday and now fails without changing credentials.&lt;br&gt;
What's happening: Some proxy configurations use IP whitelisting as an alternative or additional authentication layer. If a proxy account is configured for IP whitelisting, connections from non-whitelisted IPs fail at the auth step even with valid credentials. If the whitelisted IP changes (dynamic IP, cloud instance restart, VPN), the previously working credentials appear to stop working.&lt;br&gt;
Diagnosis:&lt;br&gt;
import requests&lt;/p&gt;

&lt;p&gt;def get_current_ip() -&amp;gt; str:&lt;br&gt;
    """Get the public IP that a proxy provider will see from this machine."""&lt;br&gt;
    try:&lt;br&gt;
        resp = requests.get("&lt;a href="https://httpbin.org/ip" rel="noopener noreferrer"&gt;https://httpbin.org/ip&lt;/a&gt;", timeout=10)&lt;br&gt;
        return resp.json().get("origin", "unknown")&lt;br&gt;
    except Exception as e:&lt;br&gt;
        return f"Error: {e}"&lt;/p&gt;

&lt;p&gt;current_ip = get_current_ip()&lt;br&gt;
print(f"Current public IP: {current_ip}")&lt;br&gt;
print("If using IP whitelisting, verify this IP is in your allowlist")&lt;/p&gt;

&lt;p&gt;Fix: Check your proxy provider dashboard for IP whitelisting settings. If your operation needs both IP whitelisting and credential auth, you have two options:&lt;br&gt;
Add the current public IP to the whitelist explicitly, or switch to username/password-only authentication and remove the IP whitelist restriction. For dynamic IP environments (cloud instances, development machines on home ISPs), username/password auth without IP whitelisting is the more practical configuration.&lt;br&gt;
&lt;strong&gt;Quick Diagnostic Reference&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj1pbz3mtu8ungrga33n2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj1pbz3mtu8ungrga33n2.png" alt=" " width="800" height="557"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br&gt;
SOCKS5 authentication errors all have specific root causes that point to specific fixes. The diagnostic sequence is:&lt;br&gt;
Can you reach the proxy port at all? If not - firewall issue.&lt;br&gt;
Does the server accept username/password auth? If not - client auth method configuration.&lt;br&gt;
Do valid credentials get accepted? If not - credential format, special characters, or expired account.&lt;br&gt;
Do credentials work from all machines? If not - IP whitelist conflict.&lt;br&gt;
Working through these in order eliminates the guesswork and gets you to a working connection faster than trying random configuration changes and hoping one sticks.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>proxy</category>
    </item>
    <item>
      <title>Mobile Proxies for App &amp; QA Testing: A 2026 Playbook</title>
      <dc:creator>Mathew</dc:creator>
      <pubDate>Thu, 17 Sep 2026 04:44:27 +0000</pubDate>
      <link>https://dev.to/mathewtech/mobile-proxies-for-app-qa-testing-a-2026-playbook-pni</link>
      <guid>https://dev.to/mathewtech/mobile-proxies-for-app-qa-testing-a-2026-playbook-pni</guid>
      <description>&lt;p&gt;Most QA teams discover the geolocation problem the same way: a user in another country reports a bug that nobody on the team can reproduce. The checkout flow shows the wrong currency. The consent banner doesn't appear. The carrier-specific payment method isn't rendering. The test suite passed on every environment you own, because every environment you own sits on the same datacenter or residential IP block - and the app behaves differently when accessed from an actual mobile carrier network.&lt;br&gt;
This is the gap mobile proxies close in QA workflows. Not as a workaround, but as a deliberate infrastructure choice that lets you test the network layer your real users are on, not just the content layer.&lt;br&gt;
&lt;strong&gt;Why Mobile Carrier IPs Produce Different App Behavior&lt;/strong&gt;&lt;br&gt;
The modern web and app stack is location-aware at multiple layers simultaneously. A user connecting from a Verizon LTE network in New York sees a different combination of signals than a user on residential broadband in the same city - and a different combination again than a QA engineer connecting from a datacenter IP anywhere.&lt;br&gt;
&lt;cite&gt;A user in New York may see one price, a user in Berlin may see another language, and a user on a mobile carrier in Dubai may hit a completely different redirect, checkout flow, promotion, or app experience.&lt;/cite&gt; The IP type - residential, mobile, datacenter - affects which CDN edge node serves the content, which regional rules apply, and whether the app's carrier-detection logic triggers market-specific behavior.&lt;br&gt;
The specific signals that differ on mobile carrier IPs:&lt;br&gt;
ASN classification. Mobile carrier IPs belong to ASNs (Autonomous System Numbers) operated by carriers - Verizon, T-Mobile, AT&amp;amp;T, EE, Telkomsel, Jio. These ASNs are distinct from residential broadband ASNs and completely different from datacenter ASNs. Apps and APIs that branch behavior by network type check this signal. A streaming app might serve different video quality tiers by carrier. A financial app might trigger carrier billing options only for mobile ASNs. A gaming app might unlock carrier-specific promotional content.&lt;br&gt;
CGNAT (Carrier-Grade NAT). Most mobile carrier traffic passes through CGNAT, where many devices share a single public IP behind the carrier's NAT infrastructure. This produces a specific network fingerprint that apps can detect - one that's absent from datacenter and most residential connections. Some anti-fraud and bot detection systems treat CGNAT IPs differently, applying more lenient thresholds because the shared IP structure makes attribution harder.&lt;br&gt;
Geolocation precision. Mobile carrier IPs geolocate with different characteristics than residential IPs. The mapping from carrier IP to city can differ from residential IP geolocation even within the same city, which affects geo-targeting logic in apps that use IP geolocation for content decisions.&lt;br&gt;
IPv6 and protocol stack. Mobile carrier networks are further along in IPv6 deployment than most residential ISPs. An app that behaves differently on IPv4 vs IPv6 - or one that has bugs in its dual-stack handling - may only surface those bugs when tested from a real carrier IP with IPv6 enabled.&lt;br&gt;
&lt;strong&gt;What This Means for Your Test Matrix&lt;/strong&gt;&lt;br&gt;
The practical implication for QA teams is that "test across browsers" and "test across devices" are necessary but not sufficient conditions for confidence in production behavior. The network layer needs to be in the matrix too.&lt;br&gt;
The test cases where mobile carrier IPs produce different results than residential or datacenter IPs:&lt;br&gt;
Geo-restricted content. Streaming apps, news sites, and e-commerce platforms with market-specific catalogs enforce restrictions at the IP level. Testing content access from a datacenter IP shows whether the restriction logic exists at all - it doesn't tell you whether a real user in that market can access the content, because datacenter IPs are often handled differently by CDNs and content delivery rules than carrier IPs.&lt;br&gt;
Carrier-specific payment flows. Apps that support carrier billing (direct operator billing, DCB) need to detect the user's carrier before presenting payment options. This detection uses ASN lookup, IP-to-carrier mapping, or explicit carrier headers in the HTTP request. Testing the carrier billing flow requires an IP that maps to the correct carrier.&lt;br&gt;
Regional pricing and currency. E-commerce apps that apply market-specific pricing use IP geolocation as one of several signals. A carrier IP that geolocates precisely to a target city validates the full geo-targeting stack - CDN routing, IP geolocation lookup, currency display, and tax calculation - in a way that a US datacenter IP set to a US location doesn't.&lt;br&gt;
Consent and compliance flows. GDPR consent banners in Europe, LGPD flows in Brazil, CCPA notices in California - these are triggered by IP geolocation. A QA run from a datacenter IP that doesn't map to the target jurisdiction may not trigger the consent flow at all, producing false-pass results on compliance-critical behavior.&lt;br&gt;
CDN behavior and edge caching. CDNs route requests to different edge nodes based on IP location. An app that has caching bugs affecting a specific CDN edge will only surface those bugs when tested from IPs that route to that edge - which means IPs in the same geographic and network region as real users.&lt;br&gt;
&lt;strong&gt;Appium + Mobile Proxy: Configuration and Code&lt;/strong&gt;&lt;br&gt;
Appium is the standard framework for automated mobile app testing. Integrating a mobile proxy into an Appium session routes the device's network traffic through the proxy, which means all app HTTP/HTTPS requests originate from the proxy's carrier IP rather than the test machine's connection.&lt;br&gt;
The configuration approach differs slightly between Android and iOS.&lt;br&gt;
&lt;strong&gt;Android: System proxy via desired capabilities&lt;/strong&gt;&lt;br&gt;
from appium import webdriver&lt;br&gt;
from appium.options import UiAutomator2Options&lt;br&gt;
import time&lt;/p&gt;

&lt;p&gt;NodeMaven mobile proxy credentials&lt;br&gt;
Generate targeting string from dashboard:&lt;br&gt;
country-us-city-newyork = US, New York carrier IP&lt;br&gt;
sid-abc123 = sticky session (same IP for session duration)&lt;br&gt;
PROXY_HOST = "gate.nodemaven.com"&lt;br&gt;
PROXY_PORT = 8080&lt;br&gt;
PROXY_USER = "PROXYUSER-country-us-city-newyork-sid-testsession01"&lt;br&gt;
PROXY_PASS = "your_password"&lt;/p&gt;

&lt;p&gt;options = UiAutomator2Options()&lt;br&gt;
options.platform_name = "Android"&lt;br&gt;
options.device_name = "emulator-5554"  # or real device UDID&lt;br&gt;
options.app = "/path/to/your/app.apk"&lt;br&gt;
options.automation_name = "UiAutomator2"&lt;/p&gt;

&lt;p&gt;Set system proxy on the Android device&lt;br&gt;
options.set_capability("systemPort", 8201)&lt;/p&gt;

&lt;p&gt;Appium supports proxy via chromeOptions for WebView apps&lt;br&gt;
 For native apps, set proxy at the device level via adb before session&lt;/p&gt;

&lt;p&gt;appium_server = "&lt;a href="http://localhost:4723" rel="noopener noreferrer"&gt;http://localhost:4723&lt;/a&gt;"&lt;br&gt;
driver = webdriver.Remote(appium_server, options=options)&lt;/p&gt;

&lt;p&gt;Set proxy on device via ADB (run before Appium session for native apps)&lt;br&gt;
 adb shell settings put global http_proxy gate.nodemaven.com:8080&lt;br&gt;
 For authenticated proxies on Android, use a ProxyDroid or similar approach&lt;br&gt;
 or configure through the app's own network settings if exposed&lt;/p&gt;

&lt;p&gt;time.sleep(2)&lt;br&gt;
driver.quit()&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Android: ADB proxy configuration for authenticated proxies&lt;/strong&gt;&lt;br&gt;
Android's system proxy settings don't support username/password authentication through the standard UI. For authenticated proxy configuration on Android test devices, use ADB to set the proxy and handle auth via a local proxy forwarder:&lt;br&gt;
import subprocess&lt;br&gt;
import requests&lt;br&gt;
import time&lt;/p&gt;

&lt;p&gt;Local proxy forwarder - proxychains or mitmproxy in front of the authenticated proxy&lt;br&gt;
 Run: mitmproxy --mode upstream:&lt;a href="http://PROXYUSER:PASS@gate.nodemaven.com:8080" rel="noopener noreferrer"&gt;http://PROXYUSER:PASS@gate.nodemaven.com:8080&lt;/a&gt; --listen-port 8888&lt;/p&gt;

&lt;p&gt;def set_android_proxy(device_id: str, host: str, port: int):&lt;br&gt;
    """Set system HTTP proxy on Android device via ADB."""&lt;br&gt;
    subprocess.run([&lt;br&gt;
        "adb", "-s", device_id, "shell",&lt;br&gt;
        "settings", "put", "global", "http_proxy", f"{host}:{port}"&lt;br&gt;
    ], check=True)&lt;br&gt;
    print(f"Proxy set to {host}:{port} on {device_id}")&lt;/p&gt;

&lt;p&gt;def clear_android_proxy(device_id: str):&lt;br&gt;
    """Remove system proxy from Android device."""&lt;br&gt;
    subprocess.run([&lt;br&gt;
        "adb", "-s", device_id, "shell",&lt;br&gt;
        "settings", "put", "global", "http_proxy", ":0"&lt;br&gt;
    ], check=True)&lt;br&gt;
    print("Proxy cleared")&lt;/p&gt;

&lt;p&gt;def verify_proxy_ip(local_proxy_port: int) -&amp;gt; str:&lt;br&gt;
    """Verify the proxy is active and return the exit IP."""&lt;br&gt;
    proxies = {&lt;br&gt;
        "http": f"&lt;a href="http://localhost:%7Blocal_proxy_port%7D" rel="noopener noreferrer"&gt;http://localhost:{local_proxy_port}&lt;/a&gt;",&lt;br&gt;
        "https": f"&lt;a href="http://localhost:%7Blocal_proxy_port%7D" rel="noopener noreferrer"&gt;http://localhost:{local_proxy_port}&lt;/a&gt;"&lt;br&gt;
    }&lt;br&gt;
    resp = requests.get("&lt;a href="https://httpbin.org/ip" rel="noopener noreferrer"&gt;https://httpbin.org/ip&lt;/a&gt;", proxies=proxies, timeout=10)&lt;br&gt;
    return resp.json().get("origin", "unknown")&lt;/p&gt;

&lt;p&gt;Setup sequence for a geo-specific test run&lt;br&gt;
DEVICE_ID = "emulator-5554"&lt;br&gt;
LOCAL_FORWARDER_PORT = 8888  # mitmproxy or similar listening locally&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Verify carrier IP before starting test session&lt;br&gt;
exit_ip = verify_proxy_ip(LOCAL_FORWARDER_PORT)&lt;br&gt;
print(f"Test will run from carrier IP: {exit_ip}")&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set proxy on device&lt;br&gt;
set_android_proxy(DEVICE_ID, "localhost", LOCAL_FORWARDER_PORT)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run your Appium test suite here&lt;br&gt;
...&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Clean up&lt;br&gt;
clear_android_proxy(DEVICE_ID)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;iOS: Proxy via Wi-Fi settings&lt;/strong&gt;&lt;br&gt;
iOS doesn't support system proxy configuration via command line without a MDM profile or specific tooling. The standard approach for iOS Appium testing with a proxy:&lt;br&gt;
from appium import webdriver&lt;br&gt;
from appium.options import XCUITestOptions&lt;/p&gt;

&lt;p&gt;For iOS, configure proxy on the Wi-Fi network the device is connected to&lt;br&gt;
 or use a VPN configuration profile that routes through the proxy&lt;br&gt;
 Alternatively, use a per-app proxy if the app under test supports it&lt;/p&gt;

&lt;p&gt;options = XCUITestOptions()&lt;br&gt;
options.platform_name = "iOS"&lt;br&gt;
options.device_name = "iPhone 15"  # or real device UDID&lt;br&gt;
options.bundle_id = "com.yourcompany.yourapp"&lt;br&gt;
options.automation_name = "XCUITest"&lt;/p&gt;

&lt;p&gt;For WebView/hybrid apps, proxy can be set via ChromeOptions&lt;br&gt;
 For fully native apps, proxy must be set at the network level before session&lt;br&gt;
options.set_capability("safariInitialUrl", "about:blank")&lt;/p&gt;

&lt;p&gt;driver = webdriver.Remote("&lt;a href="http://localhost:4723" rel="noopener noreferrer"&gt;http://localhost:4723&lt;/a&gt;", options=options)&lt;/p&gt;

&lt;p&gt;Verify the app sees the correct IP by checking its geo-detection behavior&lt;br&gt;
 Navigate to a test endpoint within the app that returns IP/location data&lt;br&gt;
 ...&lt;/p&gt;

&lt;p&gt;driver.quit()&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Integrating IP Verification Into Your QA Workflow&lt;/strong&gt;&lt;br&gt;
Before any geo-specific test run, verifying that the proxy is active and the exit IP matches the expected carrier and location is a mandatory step. A test that fails because the proxy wasn't configured correctly is a false failure - and a test that passes because the proxy silently fell back to the local IP is a false pass.&lt;br&gt;
The &lt;a href="https://nodemaven.com/tools/ip-lookup" rel="noopener noreferrer"&gt;NodeMaven IP Lookup&lt;/a&gt; tool runs a full IP classification check - location, ISP, ASN, connection type, and threat score - in a single request. In a QA workflow, this becomes a pre-flight assertion:&lt;br&gt;
import requests&lt;/p&gt;

&lt;p&gt;def assert_proxy_configuration(&lt;br&gt;
    proxy_url: str,&lt;br&gt;
    expected_country: str,&lt;br&gt;
    expected_connection_type: str = "mobile"&lt;br&gt;
) -&amp;gt; dict:&lt;br&gt;
    """&lt;br&gt;
    Verify proxy is active and matches expected geo and type.&lt;br&gt;
    Raises AssertionError if configuration doesn't match.&lt;br&gt;
    """&lt;br&gt;
    proxies = {"http": proxy_url, "https": proxy_url}&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; Use NodeMaven IP lookup API to check exit IP classification
resp = requests.get(
    "https://nodemaven.com/tools/ip-lookup",
    proxies=proxies,
    timeout=15
)

 Or use a standard IP info endpoint for programmatic checks
ip_resp = requests.get(
    "https://ipinfo.io/json",
    proxies=proxies,
    timeout=15
)
ip_data = ip_resp.json()

country = ip_data.get("country", "").upper()
org = ip_data.get("org", "")

assert country == expected_country.upper(), (
    f"Proxy geo mismatch: expected {expected_country}, got {country}"
)

print(f"Proxy verified: {ip_data.get('ip')} | {country} | {org}")
return ip_data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Example pre-flight check before a US carrier test suite&lt;br&gt;
proxy_url = f"&lt;a href="http://PROXYUSER-country-us-city-newyork-sid-testsession01:pass@gate.nodemaven.com:8080" rel="noopener noreferrer"&gt;http://PROXYUSER-country-us-city-newyork-sid-testsession01:pass@gate.nodemaven.com:8080&lt;/a&gt;"&lt;/p&gt;

&lt;p&gt;try:&lt;br&gt;
    ip_data = assert_proxy_configuration(&lt;br&gt;
        proxy_url,&lt;br&gt;
        expected_country="US"&lt;br&gt;
    )&lt;br&gt;
    print("Pre-flight passed - running test suite")&lt;br&gt;
     ... run your Appium tests&lt;br&gt;
except AssertionError as e:&lt;br&gt;
    print(f"Pre-flight FAILED: {e}")&lt;br&gt;
     Do not run tests — results would be invalid&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Building a Geo-Test Matrix&lt;/strong&gt;&lt;br&gt;
A structured geo-test matrix for mobile QA covers three dimensions: market, carrier, and connection type. Here's how to think about building it:&lt;br&gt;
Market tier 1 (highest revenue, highest priority): Test every carrier in the market. For the US, that means Verizon, T-Mobile, and AT&amp;amp;T coverage - they have meaningfully different network profiles and your app may behave differently on each carrier's IP range.&lt;br&gt;
Market tier 2 (significant traffic, lower priority): Test one representative carrier per market. For UK, one of EE/O2/Vodafone/Three. For Germany, one of Deutsche Telekom/Vodafone/O2. This gives you market-level geo-validation without covering every carrier combination.&lt;br&gt;
Edge cases: IPv6-only or dual-stack markets (some Southeast Asian carriers), markets with aggressive CGNAT (most mobile carriers globally), markets where the app has carrier-specific integrations (DCB, carrier billing, carrier-specific promotional content).&lt;br&gt;
The test matrix determines which proxy configurations you need active simultaneously. For a three-market test run with carrier-level coverage, you need proxy credentials for each carrier-market combination, and your test framework needs to route each test case to the correct proxy configuration automatically.&lt;br&gt;
&lt;strong&gt;When to Use Mobile Proxies vs Residential Proxies for QA&lt;/strong&gt;&lt;br&gt;
Not every QA scenario requires mobile carrier IPs. The cost per GB is comparable to residential proxies, but mobile IPs are the right tool for specific scenarios and overkill for others.&lt;br&gt;
Use mobile proxies for: Carrier billing flow testing, carrier-specific feature flags, CGNAT behavior testing, apps with carrier detection logic, and any scenario where you need the exact network profile of a mobile user on a specific carrier in a specific market.&lt;br&gt;
Use residential proxies for: General geo-restriction testing, market-level currency and pricing validation, CDN routing checks, and consent flow testing - anywhere where the residential broadband profile is sufficient and carrier-specific behavior isn't the variable under test.&lt;br&gt;
&lt;a href="https://nodemaven.com/proxies/mobile-proxies/" rel="noopener noreferrer"&gt;NodeMaven mobile proxies&lt;/a&gt; provide 4G/LTE/5G carrier IPs across 190+ countries with sticky sessions up to 24 hours — which covers both the short-session Appium test runs and the longer-duration scenario tests where you need a consistent carrier IP across a full user journey. The shared traffic balance with residential proxies means you can run mixed proxy type test suites without managing separate accounts or billing.&lt;br&gt;
At 295K+ mobile IPs with city and ISP-level targeting, the pool is large enough for carrier-specific targeting in major markets without IP exhaustion on high-frequency test runs. The 99.54% success rate and sub-0.6 second average speed hold up under the automated request patterns that Appium test suites generate.&lt;br&gt;
&lt;strong&gt;The QA Infrastructure Checklist&lt;/strong&gt;&lt;br&gt;
Before running geo-specific test suites with mobile proxies:&lt;br&gt;
Verify proxy exit IP and carrier classification with an IP lookup check before each test session&lt;br&gt;
Confirm sticky session is configured if your tests require session continuity (same IP across multiple requests in a user journey)&lt;br&gt;
Set Accept-Language and timezone in your test device profile to match the target market - IP alone doesn't set browser locale&lt;br&gt;
Clear cookies and app cache between market-specific test runs to prevent locale bleed from previous sessions&lt;br&gt;
Log the proxy IP and carrier details alongside test results so failures can be correlated with specific carrier configurations&lt;br&gt;
Re-run failed geo-specific tests from a fresh proxy session before reporting - transient carrier network issues can produce false failures&lt;br&gt;
The network layer is the part of the test environment that's easiest to get wrong silently. A test that uses the wrong IP produces results that look valid, pass CI, and deploy to production - where real users on real carrier networks find the bug immediately. Adding a proxy IP verification step to your pre-flight makes the network layer as visible and auditable as the device configuration and app version.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>ISP Proxies for Ad Verification: Static IPs Ad Networks Trust in 2026</title>
      <dc:creator>Mathew</dc:creator>
      <pubDate>Thu, 17 Sep 2026 04:18:45 +0000</pubDate>
      <link>https://dev.to/mathewtech/isp-proxies-for-ad-verification-static-ips-ad-networks-trust-in-2026-5cb8</link>
      <guid>https://dev.to/mathewtech/isp-proxies-for-ad-verification-static-ips-ad-networks-trust-in-2026-5cb8</guid>
      <description>&lt;p&gt;Ad verification has a proxy problem that most teams discover the hard way. You set up a verification workflow, route it through a rotating residential pool, and the reports look clean. Then a real user flags a suspicious redirect on a publisher site your tool checked three days ago. You investigate, and the fraudulent creative was there the whole time - your rotating IPs just never saw it.&lt;br&gt;
This is cloaking, and it's the reason proxy choice matters more in ad verification than in almost any other workflow. Fraudulent publishers detect non-static, non-residential traffic and serve clean content to auditors while real users see the fraud. The IP type your verification tool uses determines whether you're auditing the real ad ecosystem or a sanitized version of it.&lt;br&gt;
&lt;strong&gt;How Ad Networks Evaluate Traffic&lt;/strong&gt;&lt;br&gt;
Before getting into proxy configuration, it's worth understanding what ad networks and fraud detection systems actually check when they receive a request.&lt;br&gt;
IP classification happens at three levels simultaneously. First, the IP range itself - is it datacenter, residential, mobile, or ISP? Datacenter IPs are filtered or deprioritized by most premium ad networks because they're known infrastructure addresses, not consumer connections. Second, the ASN (Autonomous System Number) - which network operator manages this IP block, and does that match the claimed geographic location? Third, behavioral history - has this IP been associated with high-frequency automated requests, known fraud operations, or proxy pool abuse?&lt;br&gt;
A rotating residential proxy passes the first check (residential ASN) but often struggles with the third. A pool IP that's been cycled through dozens of users and operations carries accumulated behavioral flags even when the current user is doing nothing suspicious. &lt;cite&gt;Ad networks themselves serve different inventory to recognized datacenter ranges - premium, brand-safe placements to auditor IPs, lower-quality inventory to actual consumers.&lt;/cite&gt;&lt;br&gt;
ISP proxies occupy a different position in this hierarchy. The IP is residential-classified, assigned by a real ISP, and - critically - dedicated to a single user rather than cycled through a shared pool. The behavioral history belongs to your operation alone.&lt;br&gt;
&lt;strong&gt;The Rotating IP Problem in Ad Verification&lt;/strong&gt;&lt;br&gt;
Here's the specific failure mode that shows up in production ad verification workflows.&lt;br&gt;
An ad verification tool running on rotating IPs makes impression checks across a network of publisher sites. Each check originates from a different IP. The tool logs a clean result - no malicious redirects, no pixel stuffing, no geo-mismatch. The report goes to the client.&lt;br&gt;
What actually happened: the fraudulent publisher's cloaking system detected that the request came from a rotating proxy pool. The detection signals are multiple: the IP hasn't been seen on this publisher's network before (rotating IPs by definition have no visit history), the request pattern matches known verification bot behavior (clean entry, specific ad slot queries, no session depth), and the IP appears in proxy detection databases.&lt;br&gt;
The cloaking system served clean content to the auditor IP. Real users - coming from genuine residential connections with browsing history - saw the fraud.&lt;br&gt;
&lt;cite&gt;Fraudsters no longer rely only on IP range databases. They analyze the full request environment: browser headers, TLS fingerprint, request timing patterns, and behavioral signals. A verification bot running on a datacenter IP with standard automation headers doesn't just fail the IP check - it fails the behavioral check too.&lt;/cite&gt;&lt;br&gt;
Static ISP proxies change this dynamic in a specific way. Because the IP is fixed and dedicated, it can accumulate a browsing history on publisher sites over time. A verification tool that visits a publisher network from the same residential ISP IP repeatedly starts to look like a real repeat visitor - which is exactly what a real consumer who keeps seeing the same publisher's content looks like.&lt;br&gt;
&lt;strong&gt;What Ad Verification Actually Requires From a Proxy&lt;/strong&gt;&lt;br&gt;
There are four specific requirements that distinguish a proxy setup that works for ad verification from one that produces misleading clean reports.&lt;br&gt;
Residential ISP classification. The IP must be classified as a residential consumer connection, not a hosting or datacenter address. This is non-negotiable - premium ad inventory is gated behind this classification, and cloaking systems trigger on everything else. ISP proxies use IPs assigned by real consumer ISPs (BT, Comcast, Verizon, Deutsche Telekom, etc.) to pass this check.&lt;br&gt;
Session consistency for full-funnel verification. Verifying an ad impression alone isn't sufficient. The complete chain - impression, click-through, redirect path, landing page load - must originate from the same IP. &lt;cite&gt;Sticky sessions are required for verifying the full user journey: ad impression, click-through, and landing page load must all originate from the same residential IP for the cloaking system to have no reason to activate between steps.&lt;/cite&gt; A rotating proxy that assigns a new IP mid-funnel breaks this chain and can't detect redirect fraud.&lt;br&gt;
Geographic accuracy at city level. Ad targeting operates at the city and sometimes ZIP level. Verifying that a campaign running a New York geo-target actually serves the right creative requires a New York ISP IP — not a US IP that happens to geolocate to a different city. ISP proxies with city-level targeting give you the geographic precision to verify geo-specific campaigns accurately.&lt;br&gt;
Clean IP history. Pool IPs carry the behavioral history of every previous user. For ad verification, a proxy IP that's appeared in bot detection databases - even from legitimate prior use - will trigger cloaking before your verification tool makes a single request. Dedicated ISP proxies with pre-filtered, clean IP assignments start each operation with a history that belongs to your workflow alone.&lt;br&gt;
&lt;strong&gt;The Case Study: What Rotating IPs Miss&lt;/strong&gt;&lt;br&gt;
Consider a brand protection workflow for a consumer goods advertiser running display campaigns across a network of 200+ publisher sites. The verification requirement: confirm that ads are rendering correctly, check for unauthorized creative substitution, and detect any redirect chains that don't terminate at the client's landing page.&lt;br&gt;
Running on rotating residential proxies, the tool completes checks across all 200 publishers in a nightly sweep. Reports show 97% clean placements. Three publishers show minor rendering issues, no malicious redirects detected.&lt;br&gt;
The same workflow running on static ISP proxies with city-level geo-targeting tells a different story. Two publishers that appeared clean under rotating IPs show redirect chains that terminate at affiliate pages rather than the client's landing page - a redirect fraud pattern that wasn't visible when the requests came from rotating addresses. The cloaking system, seeing unfamiliar rotating IPs with no visit history, served clean content. The static ISP IPs, having visited those publisher domains multiple times over the preceding weeks, didn't trigger the cloaking threshold.&lt;br&gt;
The practical impact: the rotating IP workflow was generating false-clean reports on placements where affiliate fraud was actively siphoning the client's ad spend.&lt;br&gt;
&lt;strong&gt;Setting Up ISP Proxies for Ad Verification&lt;/strong&gt;&lt;br&gt;
The configuration for an ad verification workflow differs from scraping or account management in a few specific ways.&lt;br&gt;
Session duration matching campaign schedule. ISP proxies on 30-day or 90-day plans maintain the same IP for the full plan duration. For ad verification, this is the right model - the IP builds genuine visit history on publisher sites over weeks, which is what makes it indistinguishable from a real consumer.&lt;br&gt;
Parallel verification across publisher networks. For large publisher networks (100+ sites), a single ISP proxy per geo creates a bottleneck. A small pool of 5–10 ISP proxies per market allows parallel verification while keeping each IP's request rate low enough to avoid behavioral flags. Round-robin assignment across the pool distributes the load without triggering rate limits on any single address.&lt;br&gt;
Here's a basic Python setup for rotating across a small ISP proxy pool for ad verification:&lt;br&gt;
import requests&lt;br&gt;
import time&lt;br&gt;
from itertools import cycle&lt;br&gt;
from dataclasses import dataclass&lt;br&gt;
from typing import Optional&lt;/p&gt;

&lt;p&gt;@dataclass&lt;br&gt;
class ISPProxy:&lt;br&gt;
    host: str&lt;br&gt;
    port: int&lt;br&gt;
    username: str&lt;br&gt;
    password: str&lt;br&gt;
    geo: str  # e.g. "us-newyork", "uk-london"&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@property
def url(self) -&amp;gt; str:
    return f"http://{self.username}:{self.password}@{self.host}:{self.port}"

@property
def as_dict(self) -&amp;gt; dict:
    return {"http": self.url, "https": self.url}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;def verify_ad_placement(&lt;br&gt;
    publisher_url: str,&lt;br&gt;
    proxy: ISPProxy,&lt;br&gt;
    expected_domain: str,&lt;br&gt;
    timeout: int = 20&lt;br&gt;
) -&amp;gt; dict:&lt;br&gt;
    """&lt;br&gt;
    Verify an ad placement by following the full redirect chain&lt;br&gt;
    and confirming the terminal domain matches the expected landing page.&lt;br&gt;
    """&lt;br&gt;
    headers = {&lt;br&gt;
        "User-Agent": (&lt;br&gt;
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "&lt;br&gt;
            "AppleWebKit/537.36 (KHTML, like Gecko) "&lt;br&gt;
            "Chrome/125.0.0.0 Safari/537.36"&lt;br&gt;
        ),&lt;br&gt;
        "Accept-Language": "en-US,en;q=0.9",&lt;br&gt;
        "Accept": "text/html,application/xhtml+xml,&lt;em&gt;/&lt;/em&gt;;q=0.8",&lt;br&gt;
    }&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;result = {
    "url": publisher_url,
    "proxy_geo": proxy.geo,
    "status": None,
    "terminal_domain": None,
    "redirect_count": 0,
    "fraud_detected": False,
    "error": None
}

try:
    resp = requests.get(
        publisher_url,
        proxies=proxy.as_dict,
        headers=headers,
        timeout=timeout,
        allow_redirects=True
    )

    result["status"] = resp.status_code
    result["redirect_count"] = len(resp.history)

    # Extract terminal domain from final URL
    from urllib.parse import urlparse
    terminal_domain = urlparse(resp.url).netloc
    result["terminal_domain"] = terminal_domain

    # Flag if terminal domain doesn't match expected
    if expected_domain not in terminal_domain:
        result["fraud_detected"] = True

except Exception as e:
    result["error"] = str(e)[:80]

return result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;ISP proxy pool - one per geo-target&lt;br&gt;
Credentials generated from NodeMaven dashboard per IP&lt;br&gt;
isp_pool = [&lt;br&gt;
    ISPProxy("gate.nodemaven.com", 8080, "user_ny1", "pass1", "us-newyork"),&lt;br&gt;
    ISPProxy("gate.nodemaven.com", 8080, "user_ny2", "pass2", "us-newyork"),&lt;br&gt;
    ISPProxy("gate.nodemaven.com", 8080, "user_la1", "pass3", "us-losangeles"),&lt;br&gt;
    ISPProxy("gate.nodemaven.com", 8080, "user_uk1", "pass4", "uk-london"),&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Publisher URLs to verify (sample)&lt;br&gt;
publisher_checks = [&lt;br&gt;
    ("&lt;a href="https://publisher-site-1.com/ad-placement" rel="noopener noreferrer"&gt;https://publisher-site-1.com/ad-placement&lt;/a&gt;", "client-landing.com"),&lt;br&gt;
    ("&lt;a href="https://publisher-site-2.com/display-slot" rel="noopener noreferrer"&gt;https://publisher-site-2.com/display-slot&lt;/a&gt;", "client-landing.com"),&lt;br&gt;
    # ... full publisher list&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;proxy_cycle = cycle(isp_pool)&lt;/p&gt;

&lt;p&gt;for publisher_url, expected_domain in publisher_checks:&lt;br&gt;
    proxy = next(proxy_cycle)&lt;br&gt;
    result = verify_ad_placement(publisher_url, proxy, expected_domain)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if result["fraud_detected"]:
    print(f"FRAUD DETECTED: {result['url']}")
    print(f"  Expected: {expected_domain}")
    print(f"  Got: {result['terminal_domain']}")
    print(f"  Redirects: {result['redirect_count']}")
elif result["error"]:
    print(f"ERROR: {result['url']} - {result['error']}")
else:
    print(f"CLEAN: {result['url']} ({result['redirect_count']} redirects)")

time.sleep(1.5)  # Respectful crawl delay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A few implementation notes for production use:&lt;br&gt;
The redirect chain is the most important signal. A legitimate ad placement terminates at the advertiser's domain. An affiliate fraud placement terminates at an affiliate domain that then forwards to the advertiser - but the intermediate step captures the commission without a genuine user click.&lt;br&gt;
Crawl delay matters for ISP proxies specifically. A static IP that queries 50 publisher sites in 60 seconds looks automated regardless of what the IP classification is. Spacing requests at 1–2 seconds mimics human browsing patterns and avoids triggering behavioral rate limits.&lt;br&gt;
Session reuse - making multiple requests from the same ISP proxy to the same publisher domain over time - is the mechanism that builds the visit history that prevents cloaking from triggering.&lt;br&gt;
&lt;strong&gt;ISP vs Rotating Residential for Ad Verification: When to Use Each&lt;/strong&gt;&lt;br&gt;
The choice isn't always ISP proxies. The right answer depends on the specific verification task.&lt;br&gt;
Use ISP proxies for: Full-funnel verification (impression through conversion), publisher network audits where cloaking is a concern, geo-specific campaign verification, brand protection monitoring that runs on a regular schedule against the same publisher set.&lt;br&gt;
Use rotating residential proxies for: Large-scale initial discovery sweeps across hundreds of new publishers where building visit history isn't yet possible, ad network coverage mapping where breadth matters more than depth, cases where each check is genuinely independent and no session continuity is required.&lt;br&gt;
For most mature ad verification operations - agencies running ongoing brand protection for established advertisers - ISP proxies handle the publisher audit layer while a smaller rotating residential pool handles discovery and initial coverage. The two types complement each other rather than competing.&lt;br&gt;
For brand protection workflows specifically, ISP proxies are the infrastructure layer that makes audit results reliable rather than misleading.&lt;br&gt;
&lt;strong&gt;What to Look for in ISP Proxies for Ad Verification&lt;/strong&gt;&lt;br&gt;
Not all ISP proxy providers are equivalent for this use case. The variables that matter:&lt;br&gt;
Pre-filtered IP quality. An ISP IP with prior proxy pool history already has behavioral flags that cloaking systems will detect. The IP quality filter is what separates clean, fresh ISP assignments from recycled addresses. &lt;a href="https://nodemaven.com/proxies/isp-proxies/" rel="noopener noreferrer"&gt;NodeMaven ISP proxies&lt;/a&gt; use real-time Scamalytics integration to screen IPs before assignment - flagged addresses don't reach the user pool.&lt;br&gt;
City-level targeting. Country-level US targeting is insufficient for geo-specific campaign verification. Campaign-level ad targeting operates at city level in most cases, and your verification proxy needs to match.&lt;br&gt;
Unlimited traffic. Ad verification generates consistent traffic over long periods - daily publisher sweeps, impression checks, redirect chain follows. Per-GB billing creates unpredictable costs for this traffic pattern. ISP proxies on unlimited traffic plans make costs predictable regardless of verification volume.&lt;br&gt;
99.9% uptime. A verification tool that fails overnight means a gap in your audit coverage - which is exactly when fraudulent publishers might rotate in unauthorized creatives. ISP proxies with guaranteed uptime SLAs are the right infrastructure for compliance-sensitive workflows.&lt;br&gt;
The combination of residential ISP classification, dedicated (non-shared) IP history, city-level geo-targeting, and pre-filtered quality is what makes ISP proxies the correct proxy type for serious ad verification operations - not as a preference, but as a structural requirement for results that reflect the actual ad ecosystem rather than the sanitized version that fraud systems show to recognized auditors.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>US Free Proxy List 2026: How to Find, Test, and Use American Proxies</title>
      <dc:creator>Mathew</dc:creator>
      <pubDate>Mon, 24 Aug 2026 03:29:13 +0000</pubDate>
      <link>https://dev.to/mathewtech/us-free-proxy-list-2026-how-to-find-test-and-use-american-proxies-4if3</link>
      <guid>https://dev.to/mathewtech/us-free-proxy-list-2026-how-to-find-test-and-use-american-proxies-4if3</guid>
      <description>&lt;p&gt;US proxies are the most requested proxy type by a wide margin. The reasons are straightforward: the US has the largest e-commerce market, the most active digital advertising ecosystem, and most major platforms - Amazon, Google, Netflix, Hulu, major news sites, streaming services - serve their primary content to US IPs. If you're scraping US pricing data, verifying US ad campaigns, or accessing US-only content, you need a US IP.&lt;br&gt;
The free proxy market for US IPs reflects this demand. There are more US IPs in free proxy lists than any other country - and more burned, blocked, and abused US IPs too. Here's how to find what actually works, how to test it efficiently, and when the free route stops making sense.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Free US Proxy Lists Come From
&lt;/h2&gt;

&lt;p&gt;Free US proxies in public lists come from a few sources: open proxy servers accidentally or intentionally exposed to the internet, volunteer-run proxy networks, and scraped lists of proxies that were briefly functional before being flagged. The supply is larger than any other country, but so is the demand - which means US IPs in free lists burn faster than regional IPs.&lt;br&gt;
The best sources for US-specific free proxies in 2026:&lt;br&gt;
free-proxy-list.net - filter by country "US." The largest single source of US IPs in free lists, updated frequently. In practice, alive rate runs 20–30% at any given time.&lt;br&gt;
ProxyScrape API - pull US IPs directly: &lt;a href="https://api.proxyscrape.com/v2/?request=getproxies&amp;amp;country=us&amp;amp;protocol=http" rel="noopener noreferrer"&gt;https://api.proxyscrape.com/v2/?request=getproxies&amp;amp;country=us&amp;amp;protocol=http&lt;/a&gt;. Returns a plain text list, easy to feed into a testing script.&lt;br&gt;
Spys.one - filter by United States, shows latency and last check timestamp per IP. One of the better sources for identifying recently verified IPs before testing.&lt;br&gt;
HideMyName.com - country filter for US, with anonymity level and protocol visible. Good for finding "elite" anonymity US IPs specifically.&lt;br&gt;
&lt;a href="https://nodemaven.com/free-proxy-list/united-states/" rel="noopener noreferrer"&gt;NodeMaven US free proxy list&lt;/a&gt; - maintains a country-filtered list of US HTTP and SOCKS5 proxies updated regularly. Same free-proxy caveats apply, but it saves the step of filtering a global list down to US IPs manually.&lt;br&gt;
GitHub aggregators - search "US proxy list" on GitHub sorted by recently updated. Several repos scrape from multiple sources and commit fresh lists hourly or daily.&lt;br&gt;
The Reality of Free US Proxy Quality&lt;br&gt;
US IPs are the most burned proxy category in any free list. High demand means high abuse rates, which means high block rates. Based on testing 200 free proxies from mixed sources (roughly 80 were US IPs):&lt;br&gt;
Alive rate on US IPs: ~21% (vs ~23% overall)&lt;br&gt;
Average TTFB on alive US IPs: 3.4 seconds&lt;br&gt;
Success rate on Amazon.com (product pages): ~34%&lt;br&gt;
Success rate on Google.com (search): ~9%&lt;br&gt;
Transparent proxies (exposing real IP): ~35%&lt;br&gt;
The Amazon and Google numbers tell the most important story. US e-commerce and US search - two of the primary reasons people want US proxies - have success rates under 35% and 10% respectively on free proxy infrastructure. The IPs are in known datacenter ranges that Amazon and Google flag immediately.&lt;br&gt;
Python Script: Bulk Testing a US Proxy List&lt;br&gt;
For a developer workflow, testing a list of proxies before using them is the difference between a script that runs and one that fails on every request. Here's a complete bulk tester that checks connectivity, anonymity level, and target-specific success:&lt;br&gt;
import requests&lt;br&gt;
import time&lt;br&gt;
import csv&lt;br&gt;
from concurrent.futures import ThreadPoolExecutor, as_completed&lt;br&gt;
from dataclasses import dataclass, field&lt;br&gt;
from typing import Optional&lt;/p&gt;

&lt;p&gt;@dataclass&lt;br&gt;
class ProxyTestResult:&lt;br&gt;
    proxy: str&lt;br&gt;
    alive: bool = False&lt;br&gt;
    ttfb_ms: Optional[float] = None&lt;br&gt;
    anonymity: str = "unknown"   transparent / anonymous / elite&lt;br&gt;
    amazon_ok: bool = False&lt;br&gt;
    google_ok: bool = False&lt;br&gt;
    error: Optional[str] = None&lt;/p&gt;

&lt;p&gt;HEADERS = {&lt;br&gt;
    "User-Agent": (&lt;br&gt;
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "&lt;br&gt;
        "AppleWebKit/537.36 (KHTML, like Gecko) "&lt;br&gt;
        "Chrome/125.0.0.0 Safari/537.36"&lt;br&gt;
    ),&lt;br&gt;
    "Accept-Language": "en-US,en;q=0.9",&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;def check_anonymity(proxy: str, your_real_ip: str, timeout: int) -&amp;gt; str:&lt;br&gt;
    """Check if proxy leaks real IP via X-Forwarded-For."""&lt;br&gt;
    try:&lt;br&gt;
        proxies = {"http": f"http://{proxy}", "https": f"http://{proxy}"}&lt;br&gt;
        r = requests.get(&lt;br&gt;
            "&lt;a href="https://httpbin.org/headers" rel="noopener noreferrer"&gt;https://httpbin.org/headers&lt;/a&gt;",&lt;br&gt;
            proxies=proxies,&lt;br&gt;
            timeout=timeout&lt;br&gt;
        )&lt;br&gt;
        headers = r.json().get("headers", {})&lt;br&gt;
        forwarded = headers.get("X-Forwarded-For", "")&lt;br&gt;
        if your_real_ip in forwarded:&lt;br&gt;
            return "transparent"&lt;br&gt;
        elif forwarded:&lt;br&gt;
            return "anonymous"&lt;br&gt;
        else:&lt;br&gt;
            return "elite"&lt;br&gt;
    except:&lt;br&gt;
        return "unknown"&lt;/p&gt;

&lt;p&gt;def test_proxy(proxy: str, your_real_ip: str, timeout: int = 10) -&amp;gt; ProxyTestResult:&lt;br&gt;
    result = ProxyTestResult(proxy=proxy)&lt;br&gt;
    proxies = {"http": f"http://{proxy}", "https": f"http://{proxy}"}&lt;/p&gt;

&lt;p&gt;Step 1: Basic connectivity + TTFB&lt;br&gt;
    try:&lt;br&gt;
        start = time.perf_counter()&lt;br&gt;
        r = requests.get(&lt;br&gt;
            "&lt;a href="https://httpbin.org/status/200" rel="noopener noreferrer"&gt;https://httpbin.org/status/200&lt;/a&gt;",&lt;br&gt;
            proxies=proxies,&lt;br&gt;
            headers=HEADERS,&lt;br&gt;
            timeout=timeout&lt;br&gt;
        )&lt;br&gt;
        if r.status_code == 200:&lt;br&gt;
            result.alive = True&lt;br&gt;
            result.ttfb_ms = round((time.perf_counter() - start) * 1000, 1)&lt;br&gt;
        else:&lt;br&gt;
            return result&lt;br&gt;
    except Exception as e:&lt;br&gt;
        result.error = str(e)[:60]&lt;br&gt;
        return result&lt;/p&gt;

&lt;p&gt;Step 2: Anonymity check&lt;br&gt;
    result.anonymity = check_anonymity(proxy, your_real_ip, timeout)&lt;br&gt;
    if result.anonymity == "transparent":&lt;br&gt;
        return result   Skip further tests - IP leaks real address&lt;/p&gt;

&lt;p&gt;Step 3: Amazon product page&lt;br&gt;
    try:&lt;br&gt;
        r2 = requests.get(&lt;br&gt;
            "&lt;a href="https://www.amazon.com/dp/B08N5WRWNW" rel="noopener noreferrer"&gt;https://www.amazon.com/dp/B08N5WRWNW&lt;/a&gt;",&lt;br&gt;
            proxies=proxies,&lt;br&gt;
            headers=HEADERS,&lt;br&gt;
            timeout=timeout&lt;br&gt;
        )&lt;br&gt;
        result.amazon_ok = r2.status_code == 200 and "Add to Cart" in r2.text&lt;br&gt;
    except:&lt;br&gt;
        result.amazon_ok = False&lt;/p&gt;

&lt;p&gt;Step 4: Google search&lt;br&gt;
    try:&lt;br&gt;
        r3 = requests.get(&lt;br&gt;
            "&lt;a href="https://www.google.com/search?q=proxy+test" rel="noopener noreferrer"&gt;https://www.google.com/search?q=proxy+test&lt;/a&gt;",&lt;br&gt;
            proxies=proxies,&lt;br&gt;
            headers=HEADERS,&lt;br&gt;
            timeout=timeout&lt;br&gt;
        )&lt;br&gt;
        result.google_ok = r3.status_code == 200 and "&lt;/p&gt;
" in r3.text&amp;lt;br&amp;gt;
    except:&amp;lt;br&amp;gt;
        result.google_ok = False&amp;lt;/p&amp;gt;
&amp;lt;div class="highlight"&amp;gt;&amp;lt;pre class="highlight plaintext"&amp;gt;&amp;lt;code&amp;gt;return result
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;def bulk_test(proxy_list: list[str], your_real_ip: str, workers: int = 25) -&amp;gt; list[ProxyTestResult]:&amp;lt;br&amp;gt;
    results = []&amp;lt;br&amp;gt;
    with ThreadPoolExecutor(max_workers=workers) as executor:&amp;lt;br&amp;gt;
        futures = {&amp;lt;br&amp;gt;
            executor.submit(test_proxy, p, your_real_ip): p&amp;lt;br&amp;gt;
            for p in proxy_list&amp;lt;br&amp;gt;
        }&amp;lt;br&amp;gt;
        for i, future in enumerate(as_completed(futures), 1):&amp;lt;br&amp;gt;
            result = future.result()&amp;lt;br&amp;gt;
            results.append(result)&amp;lt;br&amp;gt;
            if i % 20 == 0:&amp;lt;br&amp;gt;
                alive = sum(1 for r in results if r.alive)&amp;lt;br&amp;gt;
                print(f"Progress: {i}/{len(proxy_list)} tested, {alive} alive")&amp;lt;br&amp;gt;
    return results&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;def save_results(results: list[ProxyTestResult], filename: str = "proxy_results.csv"):&amp;lt;br&amp;gt;
    with open(filename, "w", newline="") as f:&amp;lt;br&amp;gt;
        writer = csv.DictWriter(f, fieldnames=[&amp;lt;br&amp;gt;
            "proxy", "alive", "ttfb_ms", "anonymity",&amp;lt;br&amp;gt;
            "amazon_ok", "google_ok", "error"&amp;lt;br&amp;gt;
        ])&amp;lt;br&amp;gt;
        writer.writeheader()&amp;lt;br&amp;gt;
        for r in results:&amp;lt;br&amp;gt;
            writer.writerow({&amp;lt;br&amp;gt;
                "proxy": r.proxy,&amp;lt;br&amp;gt;
                "alive": r.alive,&amp;lt;br&amp;gt;
                "ttfb_ms": r.ttfb_ms,&amp;lt;br&amp;gt;
                "anonymity": r.anonymity,&amp;lt;br&amp;gt;
                "amazon_ok": r.amazon_ok,&amp;lt;br&amp;gt;
                "google_ok": r.google_ok,&amp;lt;br&amp;gt;
                "error": r.error&amp;lt;br&amp;gt;
            })&amp;lt;br&amp;gt;
    print(f"Results saved to {filename}")&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;--- Run ---&amp;lt;br&amp;gt;
 Get your real IP first (to detect transparent proxies)&amp;lt;br&amp;gt;
YOUR_IP = requests.get("&amp;lt;a href="https://httpbin.org/ip%22).json()%5B%22origin%22%5D"&amp;gt;https://httpbin.org/ip").json()["origin"]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Load your US proxy list (one per line: ip:port)&amp;lt;br&amp;gt;
with open("us_proxies.txt") as f:&amp;lt;br&amp;gt;
    proxy_list = [line.strip() for line in f if line.strip()]&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;print(f"Testing {len(proxy_list)} proxies...")&amp;lt;br&amp;gt;
results = bulk_test(proxy_list, YOUR_IP)&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Summary&amp;lt;br&amp;gt;
alive = [r for r in results if r.alive]&amp;lt;br&amp;gt;
elite = [r for r in alive if r.anonymity == "elite"]&amp;lt;br&amp;gt;
amazon_working = [r for r in elite if r.amazon_ok]&amp;lt;br&amp;gt;
google_working = [r for r in elite if r.google_ok]&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;print(f"\nResults:")&amp;lt;br&amp;gt;
print(f"  Alive: {len(alive)}/{len(proxy_list)} ({len(alive)/len(proxy_list)*100:.1f}%)")&amp;lt;br&amp;gt;
print(f"  Elite anonymity: {len(elite)}/{len(alive)}")&amp;lt;br&amp;gt;
print(f"  Works on Amazon: {len(amazon_working)}")&amp;lt;br&amp;gt;
print(f"  Works on Google: {len(google_working)}")&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;save_results(results)&amp;lt;/p&amp;gt;
&amp;lt;h2&amp;gt;
  &amp;lt;a name="a-few-design-notes-on-this-implementation" href="#a-few-design-notes-on-this-implementation" class="anchor"&amp;gt;
  &amp;lt;/a&amp;gt;
  A few design notes on this implementation:
&amp;lt;/h2&amp;gt;

&amp;lt;p&amp;gt;Your real IP detection first. The script fetches your real IP before running tests. This is necessary for the transparency check - if the proxy passes your real IP in X-Forwarded-For, you want to catch that before using the proxy for anything sensitive.&amp;lt;br&amp;gt;
Transparency filter. Transparent proxies are skipped after the anonymity check. There's no point testing them on real targets - they expose your real IP to the target, which defeats the purpose.&amp;lt;br&amp;gt;
Concurrent testing. 25 workers is a reasonable default. Going higher speeds up the test but can cause false timeouts if your local network can't sustain that many simultaneous connections. Adjust based on your bandwidth.&amp;lt;br&amp;gt;
CSV output. The results file lets you sort by TTFB, filter by Amazon or Google success, and build a "clean" list from whatever passes your criteria - without rerunning the full test.&amp;lt;br&amp;gt;
Interpreting the Output: What's Actually Usable&amp;lt;br&amp;gt;
After running the test, filter for proxies where:&amp;lt;br&amp;gt;
alive = True&amp;lt;br&amp;gt;
anonymity = elite&amp;lt;br&amp;gt;
ttfb_ms &amp;lt; 5000 (under 5 seconds TTFB)&amp;lt;br&amp;gt;
That subset is your working pool. For general US geo-checks and accessing US content without heavy bot detection, this list works. For Amazon, Google, or any platform with IP reputation checks, apply the additional filters (amazon_ok = True or google_ok = True) - and expect that subset to be small.&amp;lt;br&amp;gt;
From testing 80 US free proxies, the pipeline typically produces: ~17 alive → ~11 elite anonymity → ~4 passing Amazon → ~1 passing Google. Those final numbers represent what you can actually use for serious US scraping targets.&amp;lt;br&amp;gt;
US vs UK Free Proxy Availability&amp;lt;br&amp;gt;
If you're running operations across both markets, the US and UK free proxy pools behave differently in ways worth knowing. US IPs are far more abundant in free lists but burn faster due to higher abuse rates. UK IPs are scarcer but sometimes have lower block rates on non-streaming targets simply because fewer bots target UK infrastructure.&amp;lt;br&amp;gt;
For UK-specific workflows alongside your US operations, the &amp;lt;a href="https://nodemaven.com/free-proxy-list/united-kingdom/"&amp;gt;NodeMaven UK free proxy list&amp;lt;/a&amp;gt; gives you a country-filtered starting point without sorting through global lists. The same testing script above works for UK proxies - just swap the target URLs for UK-specific endpoints.&amp;lt;/p&amp;gt;
&amp;lt;h2&amp;gt;
  &amp;lt;a name="when-free-us-proxies-stop-making-sense" href="#when-free-us-proxies-stop-making-sense" class="anchor"&amp;gt;
  &amp;lt;/a&amp;gt;
  When Free US Proxies Stop Making Sense
&amp;lt;/h2&amp;gt;

&amp;lt;p&amp;gt;The testing script above gives you a concrete answer: when your working pool (elite anonymity + target success) is too small for your workflow's needs, or when you're spending more time maintaining the pool than running actual operations.&amp;lt;br&amp;gt;
For US operations that require consistent residential IPs - ad verification, Amazon seller monitoring, multi-account management on US platforms - free proxies aren't the infrastructure layer that makes this work. The IPs are datacenter-flagged, the pool exhausts quickly, and the engineering overhead of constant pool refresh isn't worth it.&amp;lt;br&amp;gt;
For that use case, &amp;lt;a href="https://nodemaven.com/locations/us-proxy/"&amp;gt;US proxy&amp;lt;/a&amp;gt; residential access through NodeMaven covers major US cities - New York, Los Angeles, Chicago, Houston, Phoenix - with ISP-level targeting (Comcast, AT&amp;amp;T, Verizon, Spectrum) and a 95%+ clean rate. The $3.50 trial at 750 MB is a practical comparison point: run your actual workflow against both the free pool and the trial pool, and the success rate difference on a real target makes the value proposition concrete.&amp;lt;br&amp;gt;
The free proxy route is worth running through once with the testing script - it gives you real data on what's available and what passes your specific targets. After that, the numbers tell you whether free infrastructure covers your use case or whether the paid tier is the right starting point.&amp;lt;/p&amp;gt;


</description>
      <category>programming</category>
      <category>proxy</category>
    </item>
    <item>
      <title>US Free Proxy List 2026: How to Find, Test, and Use American Proxies</title>
      <dc:creator>Mathew</dc:creator>
      <pubDate>Fri, 21 Aug 2026 09:47:45 +0000</pubDate>
      <link>https://dev.to/mathewtech/us-free-proxy-list-2026-how-to-find-test-and-use-american-proxies-3jc1</link>
      <guid>https://dev.to/mathewtech/us-free-proxy-list-2026-how-to-find-test-and-use-american-proxies-3jc1</guid>
      <description>&lt;p&gt;US proxies are the most requested proxy type by a wide margin. The reasons are straightforward: the US has the largest e-commerce market, the most active digital advertising ecosystem, and most major platforms - Amazon, Google, Netflix, Hulu, major news sites, streaming services - serve their primary content to US IPs. If you're scraping US pricing data, verifying US ad campaigns, or accessing US-only content, you need a US IP.&lt;br&gt;
The free proxy market for US IPs reflects this demand. There are more US IPs in free proxy lists than any other country - and more burned, blocked, and abused US IPs too. Here's how to find what actually works, how to test it efficiently, and when the free route stops making sense.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Free US Proxy Lists Come From
&lt;/h2&gt;

&lt;p&gt;Free US proxies in public lists come from a few sources: open proxy servers accidentally or intentionally exposed to the internet, volunteer-run proxy networks, and scraped lists of proxies that were briefly functional before being flagged. The supply is larger than any other country, but so is the demand - which means US IPs in free lists burn faster than regional IPs.&lt;br&gt;
The best sources for US-specific free proxies in 2026:&lt;br&gt;
free-proxy-list.net - filter by country "US." The largest single source of US IPs in free lists, updated frequently. In practice, alive rate runs 20–30% at any given time.&lt;br&gt;
ProxyScrape API - pull US IPs directly: &lt;a href="https://api.proxyscrape.com/v2/?request=getproxies&amp;amp;country=us&amp;amp;protocol=http" rel="noopener noreferrer"&gt;https://api.proxyscrape.com/v2/?request=getproxies&amp;amp;country=us&amp;amp;protocol=http&lt;/a&gt;. Returns a plain text list, easy to feed into a testing script.&lt;br&gt;
Spys.one - filter by United States, shows latency and last check timestamp per IP. One of the better sources for identifying recently verified IPs before testing.&lt;br&gt;
HideMyName.com - country filter for US, with anonymity level and protocol visible. Good for finding "elite" anonymity US IPs specifically.&lt;br&gt;
&lt;a href="https://nodemaven.com/free-proxy-list/united-states/" rel="noopener noreferrer"&gt;NodeMaven US free proxy list&lt;/a&gt; - maintains a country-filtered list of US HTTP and SOCKS5 proxies updated regularly. Same free-proxy caveats apply, but it saves the step of filtering a global list down to US IPs manually.&lt;br&gt;
GitHub aggregators - search "US proxy list" on GitHub sorted by recently updated. Several repos scrape from multiple sources and commit fresh lists hourly or daily.&lt;br&gt;
The Reality of Free US Proxy Quality&lt;br&gt;
US IPs are the most burned proxy category in any free list. High demand means high abuse rates, which means high block rates. Based on testing 200 free proxies from mixed sources (roughly 80 were US IPs):&lt;br&gt;
Alive rate on US IPs: ~21% (vs ~23% overall)&lt;br&gt;
Average TTFB on alive US IPs: 3.4 seconds&lt;br&gt;
Success rate on Amazon.com (product pages): ~34%&lt;br&gt;
Success rate on Google.com (search): ~9%&lt;br&gt;
Transparent proxies (exposing real IP): ~35%&lt;br&gt;
The Amazon and Google numbers tell the most important story. US e-commerce and US search - two of the primary reasons people want US proxies - have success rates under 35% and 10% respectively on free proxy infrastructure. The IPs are in known datacenter ranges that Amazon and Google flag immediately.&lt;br&gt;
Python Script: Bulk Testing a US Proxy List&lt;br&gt;
For a developer workflow, testing a list of proxies before using them is the difference between a script that runs and one that fails on every request. Here's a complete bulk tester that checks connectivity, anonymity level, and target-specific success:&lt;br&gt;
import requests&lt;br&gt;
import time&lt;br&gt;
import csv&lt;br&gt;
from concurrent.futures import ThreadPoolExecutor, as_completed&lt;br&gt;
from dataclasses import dataclass, field&lt;br&gt;
from typing import Optional&lt;/p&gt;

&lt;p&gt;@dataclass&lt;br&gt;
class ProxyTestResult:&lt;br&gt;
    proxy: str&lt;br&gt;
    alive: bool = False&lt;br&gt;
    ttfb_ms: Optional[float] = None&lt;br&gt;
    anonymity: str = "unknown"   transparent / anonymous / elite&lt;br&gt;
    amazon_ok: bool = False&lt;br&gt;
    google_ok: bool = False&lt;br&gt;
    error: Optional[str] = None&lt;/p&gt;

&lt;p&gt;HEADERS = {&lt;br&gt;
    "User-Agent": (&lt;br&gt;
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "&lt;br&gt;
        "AppleWebKit/537.36 (KHTML, like Gecko) "&lt;br&gt;
        "Chrome/125.0.0.0 Safari/537.36"&lt;br&gt;
    ),&lt;br&gt;
    "Accept-Language": "en-US,en;q=0.9",&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;def check_anonymity(proxy: str, your_real_ip: str, timeout: int) -&amp;gt; str:&lt;br&gt;
    """Check if proxy leaks real IP via X-Forwarded-For."""&lt;br&gt;
    try:&lt;br&gt;
        proxies = {"http": f"http://{proxy}", "https": f"http://{proxy}"}&lt;br&gt;
        r = requests.get(&lt;br&gt;
            "&lt;a href="https://httpbin.org/headers" rel="noopener noreferrer"&gt;https://httpbin.org/headers&lt;/a&gt;",&lt;br&gt;
            proxies=proxies,&lt;br&gt;
            timeout=timeout&lt;br&gt;
        )&lt;br&gt;
        headers = r.json().get("headers", {})&lt;br&gt;
        forwarded = headers.get("X-Forwarded-For", "")&lt;br&gt;
        if your_real_ip in forwarded:&lt;br&gt;
            return "transparent"&lt;br&gt;
        elif forwarded:&lt;br&gt;
            return "anonymous"&lt;br&gt;
        else:&lt;br&gt;
            return "elite"&lt;br&gt;
    except:&lt;br&gt;
        return "unknown"&lt;/p&gt;

&lt;p&gt;def test_proxy(proxy: str, your_real_ip: str, timeout: int = 10) -&amp;gt; ProxyTestResult:&lt;br&gt;
    result = ProxyTestResult(proxy=proxy)&lt;br&gt;
    proxies = {"http": f"http://{proxy}", "https": f"http://{proxy}"}&lt;/p&gt;

&lt;p&gt;Step 1: Basic connectivity + TTFB&lt;br&gt;
    try:&lt;br&gt;
        start = time.perf_counter()&lt;br&gt;
        r = requests.get(&lt;br&gt;
            "&lt;a href="https://httpbin.org/status/200" rel="noopener noreferrer"&gt;https://httpbin.org/status/200&lt;/a&gt;",&lt;br&gt;
            proxies=proxies,&lt;br&gt;
            headers=HEADERS,&lt;br&gt;
            timeout=timeout&lt;br&gt;
        )&lt;br&gt;
        if r.status_code == 200:&lt;br&gt;
            result.alive = True&lt;br&gt;
            result.ttfb_ms = round((time.perf_counter() - start) * 1000, 1)&lt;br&gt;
        else:&lt;br&gt;
            return result&lt;br&gt;
    except Exception as e:&lt;br&gt;
        result.error = str(e)[:60]&lt;br&gt;
        return result&lt;/p&gt;

&lt;p&gt;Step 2: Anonymity check&lt;br&gt;
    result.anonymity = check_anonymity(proxy, your_real_ip, timeout)&lt;br&gt;
    if result.anonymity == "transparent":&lt;br&gt;
        return result   Skip further tests - IP leaks real address&lt;/p&gt;

&lt;p&gt;Step 3: Amazon product page&lt;br&gt;
    try:&lt;br&gt;
        r2 = requests.get(&lt;br&gt;
            "&lt;a href="https://www.amazon.com/dp/B08N5WRWNW" rel="noopener noreferrer"&gt;https://www.amazon.com/dp/B08N5WRWNW&lt;/a&gt;",&lt;br&gt;
            proxies=proxies,&lt;br&gt;
            headers=HEADERS,&lt;br&gt;
            timeout=timeout&lt;br&gt;
        )&lt;br&gt;
        result.amazon_ok = r2.status_code == 200 and "Add to Cart" in r2.text&lt;br&gt;
    except:&lt;br&gt;
        result.amazon_ok = False&lt;/p&gt;

&lt;p&gt;Step 4: Google search&lt;br&gt;
    try:&lt;br&gt;
        r3 = requests.get(&lt;br&gt;
            "&lt;a href="https://www.google.com/search?q=proxy+test" rel="noopener noreferrer"&gt;https://www.google.com/search?q=proxy+test&lt;/a&gt;",&lt;br&gt;
            proxies=proxies,&lt;br&gt;
            headers=HEADERS,&lt;br&gt;
            timeout=timeout&lt;br&gt;
        )&lt;br&gt;
        result.google_ok = r3.status_code == 200 and "&lt;/p&gt;
" in r3.text&amp;lt;br&amp;gt;
    except:&amp;lt;br&amp;gt;
        result.google_ok = False&amp;lt;/p&amp;gt;
&amp;lt;div class="highlight"&amp;gt;&amp;lt;pre class="highlight plaintext"&amp;gt;&amp;lt;code&amp;gt;return result
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;def bulk_test(proxy_list: list[str], your_real_ip: str, workers: int = 25) -&amp;gt; list[ProxyTestResult]:&amp;lt;br&amp;gt;
    results = []&amp;lt;br&amp;gt;
    with ThreadPoolExecutor(max_workers=workers) as executor:&amp;lt;br&amp;gt;
        futures = {&amp;lt;br&amp;gt;
            executor.submit(test_proxy, p, your_real_ip): p&amp;lt;br&amp;gt;
            for p in proxy_list&amp;lt;br&amp;gt;
        }&amp;lt;br&amp;gt;
        for i, future in enumerate(as_completed(futures), 1):&amp;lt;br&amp;gt;
            result = future.result()&amp;lt;br&amp;gt;
            results.append(result)&amp;lt;br&amp;gt;
            if i % 20 == 0:&amp;lt;br&amp;gt;
                alive = sum(1 for r in results if r.alive)&amp;lt;br&amp;gt;
                print(f"Progress: {i}/{len(proxy_list)} tested, {alive} alive")&amp;lt;br&amp;gt;
    return results&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;def save_results(results: list[ProxyTestResult], filename: str = "proxy_results.csv"):&amp;lt;br&amp;gt;
    with open(filename, "w", newline="") as f:&amp;lt;br&amp;gt;
        writer = csv.DictWriter(f, fieldnames=[&amp;lt;br&amp;gt;
            "proxy", "alive", "ttfb_ms", "anonymity",&amp;lt;br&amp;gt;
            "amazon_ok", "google_ok", "error"&amp;lt;br&amp;gt;
        ])&amp;lt;br&amp;gt;
        writer.writeheader()&amp;lt;br&amp;gt;
        for r in results:&amp;lt;br&amp;gt;
            writer.writerow({&amp;lt;br&amp;gt;
                "proxy": r.proxy,&amp;lt;br&amp;gt;
                "alive": r.alive,&amp;lt;br&amp;gt;
                "ttfb_ms": r.ttfb_ms,&amp;lt;br&amp;gt;
                "anonymity": r.anonymity,&amp;lt;br&amp;gt;
                "amazon_ok": r.amazon_ok,&amp;lt;br&amp;gt;
                "google_ok": r.google_ok,&amp;lt;br&amp;gt;
                "error": r.error&amp;lt;br&amp;gt;
            })&amp;lt;br&amp;gt;
    print(f"Results saved to {filename}")&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;--- Run ---&amp;lt;br&amp;gt;
 Get your real IP first (to detect transparent proxies)&amp;lt;br&amp;gt;
YOUR_IP = requests.get("&amp;lt;a href="https://httpbin.org/ip%22).json()%5B%22origin%22%5D"&amp;gt;https://httpbin.org/ip").json()["origin"]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Load your US proxy list (one per line: ip:port)&amp;lt;br&amp;gt;
with open("us_proxies.txt") as f:&amp;lt;br&amp;gt;
    proxy_list = [line.strip() for line in f if line.strip()]&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;print(f"Testing {len(proxy_list)} proxies...")&amp;lt;br&amp;gt;
results = bulk_test(proxy_list, YOUR_IP)&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Summary&amp;lt;br&amp;gt;
alive = [r for r in results if r.alive]&amp;lt;br&amp;gt;
elite = [r for r in alive if r.anonymity == "elite"]&amp;lt;br&amp;gt;
amazon_working = [r for r in elite if r.amazon_ok]&amp;lt;br&amp;gt;
google_working = [r for r in elite if r.google_ok]&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;print(f"\nResults:")&amp;lt;br&amp;gt;
print(f"  Alive: {len(alive)}/{len(proxy_list)} ({len(alive)/len(proxy_list)*100:.1f}%)")&amp;lt;br&amp;gt;
print(f"  Elite anonymity: {len(elite)}/{len(alive)}")&amp;lt;br&amp;gt;
print(f"  Works on Amazon: {len(amazon_working)}")&amp;lt;br&amp;gt;
print(f"  Works on Google: {len(google_working)}")&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;save_results(results)&amp;lt;/p&amp;gt;
&amp;lt;h2&amp;gt;
  &amp;lt;a name="a-few-design-notes-on-this-implementation" href="#a-few-design-notes-on-this-implementation" class="anchor"&amp;gt;
  &amp;lt;/a&amp;gt;
  A few design notes on this implementation:
&amp;lt;/h2&amp;gt;

&amp;lt;p&amp;gt;Your real IP detection first. The script fetches your real IP before running tests. This is necessary for the transparency check - if the proxy passes your real IP in X-Forwarded-For, you want to catch that before using the proxy for anything sensitive.&amp;lt;br&amp;gt;
Transparency filter. Transparent proxies are skipped after the anonymity check. There's no point testing them on real targets - they expose your real IP to the target, which defeats the purpose.&amp;lt;br&amp;gt;
Concurrent testing. 25 workers is a reasonable default. Going higher speeds up the test but can cause false timeouts if your local network can't sustain that many simultaneous connections. Adjust based on your bandwidth.&amp;lt;br&amp;gt;
CSV output. The results file lets you sort by TTFB, filter by Amazon or Google success, and build a "clean" list from whatever passes your criteria - without rerunning the full test.&amp;lt;br&amp;gt;
Interpreting the Output: What's Actually Usable&amp;lt;br&amp;gt;
After running the test, filter for proxies where:&amp;lt;br&amp;gt;
alive = True&amp;lt;br&amp;gt;
anonymity = elite&amp;lt;br&amp;gt;
ttfb_ms &amp;lt; 5000 (under 5 seconds TTFB)&amp;lt;br&amp;gt;
That subset is your working pool. For general US geo-checks and accessing US content without heavy bot detection, this list works. For Amazon, Google, or any platform with IP reputation checks, apply the additional filters (amazon_ok = True or google_ok = True) - and expect that subset to be small.&amp;lt;br&amp;gt;
From testing 80 US free proxies, the pipeline typically produces: ~17 alive → ~11 elite anonymity → ~4 passing Amazon → ~1 passing Google. Those final numbers represent what you can actually use for serious US scraping targets.&amp;lt;br&amp;gt;
US vs UK Free Proxy Availability&amp;lt;br&amp;gt;
If you're running operations across both markets, the US and UK free proxy pools behave differently in ways worth knowing. US IPs are far more abundant in free lists but burn faster due to higher abuse rates. UK IPs are scarcer but sometimes have lower block rates on non-streaming targets simply because fewer bots target UK infrastructure.&amp;lt;br&amp;gt;
For UK-specific workflows alongside your US operations, the &amp;lt;a href="https://nodemaven.com/free-proxy-list/united-kingdom/"&amp;gt;NodeMaven UK free proxy list&amp;lt;/a&amp;gt; gives you a country-filtered starting point without sorting through global lists. The same testing script above works for UK proxies - just swap the target URLs for UK-specific endpoints.&amp;lt;/p&amp;gt;
&amp;lt;h2&amp;gt;
  &amp;lt;a name="when-free-us-proxies-stop-making-sense" href="#when-free-us-proxies-stop-making-sense" class="anchor"&amp;gt;
  &amp;lt;/a&amp;gt;
  When Free US Proxies Stop Making Sense
&amp;lt;/h2&amp;gt;

&amp;lt;p&amp;gt;The testing script above gives you a concrete answer: when your working pool (elite anonymity + target success) is too small for your workflow's needs, or when you're spending more time maintaining the pool than running actual operations.&amp;lt;br&amp;gt;
For US operations that require consistent residential IPs - ad verification, Amazon seller monitoring, multi-account management on US platforms - free proxies aren't the infrastructure layer that makes this work. The IPs are datacenter-flagged, the pool exhausts quickly, and the engineering overhead of constant pool refresh isn't worth it.&amp;lt;br&amp;gt;
For that use case, &amp;lt;a href="https://nodemaven.com/locations/us-proxy/"&amp;gt;US proxy&amp;lt;/a&amp;gt; residential access through NodeMaven covers major US cities - New York, Los Angeles, Chicago, Houston, Phoenix - with ISP-level targeting (Comcast, AT&amp;amp;T, Verizon, Spectrum) and a 95%+ clean rate. The $3.50 trial at 750 MB is a practical comparison point: run your actual workflow against both the free pool and the trial pool, and the success rate difference on a real target makes the value proposition concrete.&amp;lt;br&amp;gt;
The free proxy route is worth running through once with the testing script - it gives you real data on what's available and what passes your specific targets. After that, the numbers tell you whether free infrastructure covers your use case or whether the paid tier is the right starting point.&amp;lt;/p&amp;gt;


</description>
      <category>programming</category>
      <category>proxy</category>
    </item>
    <item>
      <title>DNS Leak Test: Complete Guide to Finding and Fixing DNS Leaks in 2026</title>
      <dc:creator>Mathew</dc:creator>
      <pubDate>Wed, 19 Aug 2026 07:56:53 +0000</pubDate>
      <link>https://dev.to/mathewtech/dns-leak-test-complete-guide-to-finding-and-fixing-dns-leaks-in-2026-208n</link>
      <guid>https://dev.to/mathewtech/dns-leak-test-complete-guide-to-finding-and-fixing-dns-leaks-in-2026-208n</guid>
      <description>&lt;p&gt;Most people who set up a proxy or VPN assume their DNS queries are private once the tunnel is active. In practice, that assumption is wrong more often than it's right. DNS leaks are one of the most common and least visible privacy failures in proxy-based setups - and the only way to know whether you have one is to run a test.&lt;br&gt;
This guide covers what DNS leaks are, how to run a proper test, how to read the results, and what to do based on what you find - across Chrome, Firefox, and system-level DNS configurations.&lt;br&gt;
&lt;strong&gt;What a DNS Leak Actually Is&lt;/strong&gt;&lt;br&gt;
Every time your browser or application connects to a domain, it first resolves the domain name to an IP address through a DNS query. That query goes to a DNS resolver - a server that handles the lookup and returns the answer.&lt;br&gt;
By default, your device uses the DNS resolver assigned by your ISP. That resolver is almost always operated by your ISP, which means they receive a log of every domain you query, regardless of what proxy or VPN you have running.&lt;br&gt;
A DNS leak happens when your DNS queries bypass the proxy tunnel and go directly to your ISP's resolver - even while your HTTP traffic routes through the proxy correctly. The result: your traffic appears to come from the proxy's IP, but your browsing activity (which domains you're connecting to) is still visible to your ISP.&lt;br&gt;
For proxy users specifically, a DNS leak also creates a geographic inconsistency. Your HTTP connection exits from a German residential IP. Your DNS queries are answered by a Comcast resolver in Virginia. Any platform that checks both signals - and serious fraud detection systems do - sees an obvious contradiction.&lt;br&gt;
&lt;strong&gt;When DNS Leaks Happen&lt;/strong&gt;&lt;br&gt;
DNS leaks aren't random. They occur in predictable situations:&lt;br&gt;
HTTP proxies without explicit DNS configuration. HTTP and HTTPS proxies route web traffic but leave DNS resolution to the system by default. Unless you've explicitly configured your browser or application to route DNS through the proxy, queries go to your system resolver.&lt;br&gt;
SOCKS5 with local DNS mode. SOCKS5 supports two DNS modes: local (the client resolves the domain before connecting) and remote (the proxy server resolves it). The socks5:// scheme uses local DNS. The socks5h:// scheme uses remote DNS. Most library defaults use local, which leaks DNS.&lt;br&gt;
VPN split tunneling. When a VPN is configured to route only specific traffic through the tunnel, DNS queries are often excluded - meaning they travel outside the VPN on the regular connection.&lt;br&gt;
System DNS override persisting after proxy activation. Some ISPs and corporate networks use transparent DNS proxies that intercept queries at the network level, regardless of what resolver you've configured. Activating a proxy doesn't override this interception.&lt;br&gt;
IPv6 DNS leaks. If your machine has an IPv6 address and your proxy only tunnels IPv4 traffic, IPv6 DNS queries bypass the proxy entirely and go to your ISP's IPv6 resolver. This is one of the most overlooked leak vectors because most people don't think about IPv6 unless they've specifically configured it.&lt;br&gt;
Stale browser DNS cache. Chrome maintains an internal DNS cache that's separate from the OS cache. Cached entries from before you activated the proxy can still resolve without going through the proxy's DNS path, resulting in inconsistent behavior where some queries leak and others don't.&lt;br&gt;
&lt;strong&gt;How to Run a DNS Leak Test&lt;/strong&gt;&lt;br&gt;
Using the NodeMaven DNS Leak Test Tool&lt;br&gt;
The &lt;a href="https://nodemaven.com/tools/dns-leak-test/" rel="noopener noreferrer"&gt;NodeMaven DNS Leak Test tool&lt;/a&gt; is the most straightforward way to check your current configuration. Open it with your proxy active, and it automatically sends test queries from your browser and reports which DNS resolvers responded - showing their IP addresses, ISP names, and geographic locations.&lt;br&gt;
The test runs in under 30 seconds and requires no setup or login. The result shows you exactly which resolvers are handling your DNS queries right now, in the context of your current proxy configuration.&lt;br&gt;
Run the test in this sequence for complete coverage:&lt;br&gt;
Without any proxy active - note your default DNS resolvers (this is your baseline)&lt;br&gt;
With your proxy active - compare against baseline&lt;br&gt;
After changing any DNS settings - verify the change took effect&lt;br&gt;
The comparison between Step 1 and Step 2 is the diagnostic. If the same resolvers appear in both, your proxy isn't routing DNS queries. If Step 2 shows different resolvers that match your proxy's location, you're clean.&lt;br&gt;
&lt;strong&gt;Reading the Results&lt;/strong&gt;&lt;br&gt;
A clean result shows one of three things in the resolver field:&lt;br&gt;
Your proxy provider's DNS servers. Some proxy providers operate their own resolvers and route DNS through them automatically. If the resolver IP belongs to the same ASN as your proxy's exit IP, DNS is routing correctly through the proxy network.&lt;br&gt;
A neutral third-party resolver. If you've configured Cloudflare (1.1.1.1), Google (8.8.8.8), or another public resolver explicitly, and those appear in the results, DNS is going where you directed it - not to your ISP.&lt;br&gt;
Resolvers in the same geographic region as your proxy. If the resolver location matches your proxy's exit location, DNS and HTTP traffic are at least geographically consistent, which satisfies most platform checks.&lt;br&gt;
A leaking result shows one or more of these signals:&lt;br&gt;
Your home ISP's resolver. The ISP name in the resolver field matches your real internet provider. This is a confirmed leak regardless of what proxy is active.&lt;br&gt;
Geographic mismatch. Resolvers in a different country than your proxy's exit IP. Even if it's not your home ISP, the inconsistency is a problem for workflows that require accurate geo-localization.&lt;br&gt;
Multiple resolvers including both proxy-side and ISP-side. Mixed results indicate partial DNS routing - some queries go through the proxy, some bypass it. This is unstable and platform-dependent.&lt;br&gt;
IPv6 resolvers alongside IPv4. If you see IPv6 resolver addresses and your proxy is IPv4-only, the IPv6 entries represent a leak channel.&lt;br&gt;
Extended Test for Intermittent Leaks&lt;br&gt;
Some leaks only appear under specific conditions - particular apps that bypass the proxy, specific query types that take a different path, or caching behavior that resolves some domains locally. For a thorough check, also run BrowserLeaks' DNS test, which sends 50 randomized domain queries (25 IPv4, 25 IPv6) to maximize the chance of catching intermittent leaks that a single-query test would miss.&lt;br&gt;
&lt;strong&gt;Fixing DNS Leaks by Environment&lt;/strong&gt;&lt;br&gt;
Chrome and Chromium-based browsers&lt;br&gt;
Chrome has its own DNS-over-HTTPS (DoH) setting that, when enabled, bypasses the system resolver entirely. Go to Settings → Privacy and security → Security → Use secure DNS and select a provider (Cloudflare, Google, or custom). This overrides the system DNS for Chrome's web traffic and eliminates ISP resolver visibility for browser-originated queries.&lt;br&gt;
For automation environments running Chrome or Chromium via Puppeteer or Playwright, add the DoH flag at launch:&lt;br&gt;
chromium --proxy-server=&lt;a href="http://user:pass@host:port" rel="noopener noreferrer"&gt;http://user:pass@host:port&lt;/a&gt; \&lt;br&gt;
         --host-resolver-rules="MAP * ~NOTFOUND , EXCLUDE 127.0.0.1" \&lt;br&gt;
         --disable-features=AsyncDns&lt;/p&gt;

&lt;p&gt;Or use the --proxy-bypass-list and DNS configuration options in your launch arguments to force DNS through the proxy connection.&lt;br&gt;
For complete DNS leak prevention in Puppeteer with SOCKS5:&lt;br&gt;
const puppeteer = require('puppeteer');&lt;/p&gt;

&lt;p&gt;const browser = await puppeteer.launch({&lt;br&gt;
  args: [&lt;br&gt;
    '--proxy-server=socks5://host:1080',&lt;br&gt;
    // socks5 in Chrome uses remote DNS by default for SOCKS5 connections&lt;br&gt;
    '--host-resolver-rules=MAP * ~NOTFOUND , EXCLUDE 127.0.0.1'&lt;br&gt;
  ]&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;Note: Chrome's behavior with SOCKS5 proxies defaults to remote DNS (unlike most libraries), which means DNS queries go through the SOCKS5 proxy automatically when you configure a SOCKS5 proxy server in Chrome.&lt;br&gt;
Firefox&lt;br&gt;
Firefox gives you the most direct control over DNS behavior. Three settings in about:config cover all scenarios:&lt;br&gt;
// Disable WebRTC to prevent IP leaks alongside DNS leaks&lt;br&gt;
media.peerconnection.enabled = false&lt;/p&gt;

&lt;p&gt;// Enable DNS over HTTPS&lt;br&gt;
network.trr.mode = 2&lt;br&gt;
// 0 = off, 2 = prefer DoH (fallback to system), 3 = DoH only&lt;/p&gt;

&lt;p&gt;// Set DoH provider (Cloudflare example)&lt;br&gt;
network.trr.uri = &lt;a href="https://mozilla.cloudflare-dns.com/dns-query" rel="noopener noreferrer"&gt;https://mozilla.cloudflare-dns.com/dns-query&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;// For SOCKS5 users: route DNS through proxy&lt;br&gt;
// Settings → Network Settings → "Proxy DNS when using SOCKS v5" ✓&lt;/p&gt;

&lt;p&gt;The "Proxy DNS when using SOCKS v5" checkbox in Firefox's network settings is the single most important setting for SOCKS5 proxy users. Enabling it changes Firefox's DNS behavior from local resolution to remote resolution through the proxy - one checkbox, leak closed.&lt;br&gt;
Python and requests library&lt;br&gt;
import requests&lt;/p&gt;

&lt;p&gt;HTTP proxy - DNS resolves locally (potential leak)&lt;br&gt;
proxies_http = {&lt;br&gt;
    "http": "&lt;a href="http://user:pass@host:8080" rel="noopener noreferrer"&gt;http://user:pass@host:8080&lt;/a&gt;",&lt;br&gt;
    "https": "&lt;a href="http://user:pass@host:8080" rel="noopener noreferrer"&gt;http://user:pass@host:8080&lt;/a&gt;"&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;SOCKS5 with local DNS - still leaks&lt;br&gt;
proxies_socks_local = {&lt;br&gt;
    "http": "socks5://user:pass@host:1080",&lt;br&gt;
    "https": "socks5://user:pass@host:1080"&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;SOCKS5 with remote DNS - no leak&lt;br&gt;
proxies_socks_remote = {&lt;br&gt;
    "http": "socks5h://user:pass@host:1080",  # h = remote DNS&lt;br&gt;
    "https": "socks5h://user:pass@host:1080"&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Verify which resolver is handling DNS&lt;br&gt;
resp = requests.get("&lt;a href="https://httpbin.org/ip" rel="noopener noreferrer"&gt;https://httpbin.org/ip&lt;/a&gt;", proxies=proxies_socks_remote)&lt;br&gt;
print(resp.json())  # Should show proxy IP, not real IP&lt;/p&gt;

&lt;p&gt;The socks5h:// vs socks5:// distinction is the most commonly missed detail in Python proxy setups. Both connect through SOCKS5. Only socks5h:// routes DNS through the proxy.&lt;br&gt;
System-level DNS fix&lt;br&gt;
For a fix that covers all applications - not just the browser:&lt;br&gt;
Linux: edit /etc/resolv.conf&lt;br&gt;
Replace ISP-assigned nameservers with:&lt;br&gt;
nameserver 1.1.1.1    # Cloudflare&lt;br&gt;
nameserver 1.0.0.1    # Cloudflare secondary&lt;/p&gt;

&lt;p&gt;Flush DNS cache after changing:&lt;br&gt;
Linux (systemd)&lt;br&gt;
sudo systemd-resolve --flush-caches&lt;/p&gt;

&lt;p&gt;macOS&lt;br&gt;
sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder&lt;/p&gt;

&lt;p&gt;Windows&lt;br&gt;
ipconfig /flushdns&lt;/p&gt;

&lt;p&gt;After changing system DNS, flush Chrome's internal cache separately at chrome://net-internals/#dns — the system DNS change doesn't clear Chrome's in-memory cache.&lt;br&gt;
&lt;strong&gt;The DNS and WebRTC Combination&lt;/strong&gt;&lt;br&gt;
DNS leaks and WebRTC leaks are the two most common vectors that break proxy isolation, and they're worth checking together. A session where DNS is clean but WebRTC exposes your real IP through ICE candidates is still a leaking session. Run the &lt;a href="https://nodemaven.com/tools/webrtc-leak-test/" rel="noopener noreferrer"&gt;NodeMaven WebRTC leak test&lt;/a&gt; alongside the DNS test as part of your pre-flight checklist.&lt;br&gt;
The combination tells you:&lt;br&gt;
DNS test clean + WebRTC test clean: proxy isolation is solid at both the application and network layer&lt;br&gt;
DNS test clean + WebRTC leaking: browser-level WebRTC configuration needs attention&lt;br&gt;
DNS test leaking + WebRTC clean: DNS routing configuration needs attention&lt;br&gt;
Both leaking: start with the DNS fix (usually simpler), then address WebRTC&lt;br&gt;
&lt;strong&gt;Pre-flight Checklist: DNS Leak Verification&lt;/strong&gt;&lt;br&gt;
Before any proxy workflow where DNS consistency matters:&lt;br&gt;
[ ] Proxy active - HTTP exit IP matches expected location&lt;br&gt;
[ ] Run &lt;a href="https://nodemaven.com/tools/dns-leak-test/" rel="noopener noreferrer"&gt;NodeMaven DNS Leak Test tool&lt;/a&gt; - no ISP resolvers visible in results&lt;br&gt;
[ ] Resolver locations geographically consistent with proxy exit IP&lt;br&gt;
[ ] If using SOCKS5: socks5h:// scheme or "Proxy DNS when using SOCKS v5" enabled in Firefox&lt;br&gt;
[ ] IPv6 disabled or confirmed routing through proxy (check for IPv6 entries in test results)&lt;br&gt;
[ ] Chrome internal DNS cache cleared after any proxy configuration change (chrome://net-internals/#dns)&lt;br&gt;
[ ] Run &lt;a href="https://nodemaven.com/tools/webrtc-leak-test/" rel="noopener noreferrer"&gt;NodeMaven WebRTC leak test&lt;/a&gt; - no real IP in ICE candidates&lt;br&gt;
[ ] Re-run after any browser update or proxy provider change&lt;br&gt;
DNS leaks are a configuration problem, not a proxy quality problem. The fix in most cases is a single setting change - socks5h:// instead of socks5://, one Firefox checkbox, or a DoH provider selected in Chrome settings. The test takes 30 seconds. Running it before every proxy session costs almost nothing and closes one of the most reliable fingerprinting vectors in browser-based workflows&lt;/p&gt;

</description>
      <category>proxy</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
