Anti-Bot

What Is a WebRTC IP Leak?

What Is a WebRTC IP Leak? — conceptual illustration
On this page

A WebRTC IP leak is when your browser quietly reveals your real IP address — even though you set up a proxy to hide it. It is the most-overlooked failure mode in browser-based scraping in 2026. WebRTC (the browser feature behind video calls and peer-to-peer connections) finds your real local and public IP using STUN servers, and it does this even when all your HTTP traffic is routed through a proxy. The leak happens because WebRTC works at the network layer below the HTTP proxy — it talks directly to STUN servers from your real network interface, so the proxy never sees it. Anti-bots use this leaked IP as one input in a five-vector coherence test that all major vendors run.

Quick facts

How it leaksRTCPeerConnection ICE candidates expose local + STUN-discovered IPs
Bypassed proxy?Yes — HTTP proxy does not route STUN
Vendors checking itCloudflare, PerimeterX, DataDome, Akamai
Coherence testIP country + timezone + Accept-Language + WebRTC ICE + DNS resolver must all agree
Best fixCamoufox with geoip=True — auto-aligns all 5 vectors

How the leak works

WebRTC is the browser API for peer-to-peer audio, video, and data connections — think browser video chat. For two peers to connect when both sit behind a home router (NAT — the address translation that lets many devices share one public IP), WebRTC needs to discover the addresses they can be reached at. It does this with the ICE protocol, which gathers candidate IPs from three places: your local network interface, your public IP via STUN servers (servers whose only job is to tell you what your public IP looks like from the outside), and TURN relays. Any web page can run this:

const pc = new RTCPeerConnection({ iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] });
pc.createDataChannel('');
pc.createOffer().then(o => pc.setLocalDescription(o));
pc.onicecandidate = (e) => { if (e.candidate) console.log(e.candidate.candidate); };

The returned ICE candidates include your real IP, even if all your HTTP traffic is going through a proxy. The proxy hides your HTTP requests, but WebRTC went around it.

The 5-vector coherence test

Modern anti-bots check whether five different signals all tell the same geographic story. If you claim to be in one place, all five should agree:

  1. IP country — the country of your proxy's exit IP.
  2. Timezone — what the browser reports via Intl.DateTimeFormat().resolvedOptions().timeZone.
  3. Accept-Language header — your stated language preferences.
  4. WebRTC ICE candidate — the network the browser is actually connecting from (the leaked IP).
  5. DNS resolver location — which DNS server looked up the page's domain.

Picture a US proxy paired with an Accept-Language of ur-PK (Urdu, Pakistan), a timezone of Asia/Karachi, and a Pakistani WebRTC candidate — it fails immediately. It does not matter how good the proxy is; the contradiction between the vectors is itself the signal. This is why "use a US datacenter proxy and call it a day" stopped working around 2021.

Mitigation by tool

Camoufox with geoip=True looks up the country of your proxy exit IP, then sets timezone, locale, language, WebRTC ICE policy, and DNS to all match it. That one flag fixes the most common coherence failure in seconds. Playwright / Puppeteer need you to do this by hand — set locale, timezone_id, and Accept-Language yourself, and either disable WebRTC explicitly or route it through the proxy. HTTP scraping (curl_cffi, tls-client) has no WebRTC at all, so this vector never fires — part of why HTTP scraping beats browser scraping on many targets. Self-test: browserleaks.com/webrtc shows you exactly what WebRTC exposes from your setup. Run your browser context against it before you deploy.

Code example

python
from camoufox.sync_api import Camoufox

# geoip=True aligns IP, WebRTC, DNS, timezone, and Accept-Language
# with the proxy exit country — fixes the 5-vector coherence test.
with Camoufox(
    headless=True,
    geoip=True,
    proxy={
        "server": "http://us-residential:port",
        "username": "user",
        "password": "pass",
    },
) as browser:
    page = browser.new_page()
    page.goto("https://browserleaks.com/webrtc")
    print(page.content())  # confirm no leak to your real IP

Related terms

Concept map

How WebRTC IP Leak connects

The terms most directly tied to this one. Hover a node to see its neighbours, click to preview, drag to rearrange.

0 terms · 0 connections
You are here · Anti-Bot
Building map…

Frequently asked questions

Does a VPN protect against WebRTC leaks?

It depends on the VPN — some force WebRTC traffic through the tunnel, but many do not. For scraping, do not rely on VPNs at all. Configure WebRTC at the browser layer instead (Camoufox geoip=True, or explicit Playwright settings) so the behaviour is predictable every time.

Can I just disable WebRTC entirely?

You can, but turning it off is itself a tell. Real browsers ship with WebRTC enabled, so a browser with no WebRTC stands out and creates a new anomaly. It is better to make WebRTC agree with your proxy than to switch it off.

Why does the proxy not route WebRTC?

HTTP proxies only carry HTTP and HTTPS traffic. WebRTC opens UDP connections (a faster, connectionless network protocol) straight to STUN servers from your real network interface, skipping the HTTP layer completely. SOCKS5 proxies can carry UDP, but most consumer scraping proxies are HTTPS-only.

How do I test my own setup?

Open browserleaks.com/webrtc using the same browser context your scraper mimics. The page lists every ICE candidate the browser would expose. If you spot your real public IP, or a local IP from a different country than your proxy's exit, you have a leak.

Last updated: 2026-05-31