You route your browser through a residential proxy, load a leak-test page, and there it is: your real home IP address, printed next to the proxy IP you paid for. Nothing failed. Your proxy is working exactly as configured. What you are looking at is a WebRTC leak — the most common way a browser exposes its real IP address, and the one that defeats proxies and VPNs by design rather than by accident.
A WebRTC IP leak is not a bug. WebRTC (Web Real-Time Communication) is the browser API behind video calls, voice chat, and peer-to-peer file transfer, and to do its job it deliberately discovers every network path to your machine — including the public IP of your actual internet connection. Any webpage can trigger that discovery with a few lines of JavaScript, no permission prompt, no camera access, no visible indication at all.
This article explains exactly how the leak happens at the protocol level, why a proxy or VPN alone cannot prevent a WebRTC leak, the three ways of handling it (only one of which is correct for multi-account work), how DNS leaks differ, and a complete step-by-step proxy leak test procedure with a table showing what a clean result looks like.
What WebRTC is actually for
WebRTC exists to move audio, video, and data directly between two browsers with the lowest possible latency. When you join a Google Meet or Zoom web call, your video does not bounce through a central web server the way an HTTP request does — the browsers try to talk to each other peer-to-peer.
That goal creates a hard networking problem. Most machines sit behind NAT (your router) and sometimes multiple layers of it. Your browser does not know its own public IP address; only the outside world can see it. So before two peers can connect, each one has to answer the question: "What are all the addresses someone could possibly reach me at?"
The mechanism that answers it is called ICE — Interactive Connectivity Establishment — and ICE is precisely where the leak lives.
ICE candidates: how your browser enumerates its own addresses
When a page creates an RTCPeerConnection, the browser starts gathering ICE candidates. Each candidate is one potential network route, and there are three types:
- Host candidates — the IP addresses of your local network interfaces: your LAN address (e.g.
192.168.1.34), a VPN adapter's address, a Docker bridge, IPv6 interface addresses. These come straight from the operating system. - Server-reflexive (srflx) candidates — your public IP as seen from the outside. The browser sends a small UDP packet to a STUN server (Session Traversal Utilities for NAT), and the STUN server replies: "you appear to be coming from 84.112.x.x:54321." That address becomes an srflx candidate. Chrome's default is Google's public STUN server, and any page can specify its own.
- Relay candidates — addresses on a TURN server (a relay the traffic can bounce through when a direct connection is impossible). These reveal the relay's IP, not yours, and are the least interesting to a tracker.
The critical detail: the STUN request is UDP traffic sent by the browser's network stack, not an HTTP request. Your HTTP/HTTPS/SOCKS proxy sees none of it. The packet exits through your real internet connection, the STUN server reads the source address, and your real public IP comes back as an srflx candidate — which the page can read.
What about mDNS candidates?
Around 2019, Chrome and other browsers patched the local-address half of this problem. Instead of exposing 192.168.1.34 as a host candidate, modern Chrome emits an mDNS candidate — an opaque name like 4f2d8a9c-....local that only devices on your LAN can resolve. That was a real privacy win: pages can no longer read your LAN IP by default.
But mDNS obfuscation only hides host candidates. The srflx candidate — your real public IP from the STUN round-trip — is still delivered in full, because hiding it would break the very connectivity WebRTC exists to provide. If you are behind a proxy, that srflx candidate is the leak.
The leak in practice: a few lines of JavaScript
Nothing about harvesting candidates is exotic. This is the entire attack:
const pc = new RTCPeerConnection({
iceServers: [{ urls: "stun:stun.l.google.com:19302" }]
});
pc.createDataChannel("x"); // any channel forces gathering
pc.createOffer().then(o => pc.setLocalDescription(o));
pc.onicecandidate = (e) => {
if (e.candidate) {
// candidate string contains the IP, e.g.:
// "candidate:842163049 1 udp 1677729535 84.112.x.x 54321 typ srflx ..."
console.log(e.candidate.candidate);
}
};
No permission prompt fires — permission is only required to access your camera or microphone, not to open a data-channel peer connection. The whole gather completes in well under a second, runs silently on page load, and works inside iframes and third-party scripts. Every serious anti-fraud stack and plenty of ad-tech scripts run some variant of this. If your real IP appears in a candidate, the site now has it, tied to the same page view your proxy IP appeared on — which is worse than either IP alone, because the mismatch proves you are deliberately masking your location.
Why a proxy or VPN alone does not stop it
It helps to be precise about what each tool actually covers:
- An HTTP/HTTPS/SOCKS proxy configured in the browser handles the protocols the browser routes through it — page loads, XHR/fetch, WebSockets. WebRTC's STUN/TURN traffic is raw UDP handled by a separate code path in the browser. It ignores the proxy settings entirely and goes straight out your real interface.
- A system-wide VPN does better in theory: it captures all traffic, so STUN sees the VPN's exit IP. But VPNs fail this in practice more often than you would think — split-tunnel configurations exempt UDP or specific apps, IPv6 frequently bypasses IPv4-only tunnels, and a brief VPN drop mid-session exposes candidates gathered during the gap. And for multi-account work a VPN is the wrong shape anyway: it gives every profile on the machine the same exit IP, when the entire point is one distinct IP per account (see residential vs datacenter proxies for how to pick those IPs).
The blunt version: the proxy protects the traffic that asks to be proxied. WebRTC never asks.
The three ways to handle a WebRTC leak
There are exactly three strategies, and they are not equally good.
1. Disable WebRTC entirely
Firefox exposes media.peerconnection.enabled; extensions can neuter RTCPeerConnection in Chrome. This stops the leak — and creates two new problems. First, video calls, voice chat, and every WebRTC-dependent feature break: Meet, Discord in the browser, WhatsApp Web calls, many live-support widgets. Second, and worse for anyone managing accounts: a missing or broken WebRTC API is itself a fingerprinting signal. Real consumer browsers in 2026 all have working WebRTC. A detector that probes RTCPeerConnection and finds it undefined, stubbed, or throwing has learned that you modified your browser — precisely the conclusion you were trying to avoid. Disabling the API trades an IP leak for a tamper flag.
2. Block only the leak
Extensions like "WebRTC Network Limiter" and Chrome's own policy settings can restrict candidate gathering — for example, "only use the default route" or "disable non-proxied UDP." This keeps the API alive and stops the real IP from appearing. It is a genuine improvement over disabling. But it still leaves a detectable oddity: the peer connection produces no usable public candidate at all, or only mDNS names. A checker sees a browser that claims to be a normal residential user yet cannot complete a STUN round-trip. That pattern correlates strongly with privacy tooling. It also still breaks or degrades real calls, since the browser can no longer establish most peer-to-peer routes.
3. Replace the candidate IPs with the proxy exit IP (the correct approach)
The right answer is not to hide the answer but to give the expected one: WebRTC stays fully functional, candidates are gathered normally, and the public IP inside the srflx candidates is rewritten to the proxy's exit IP before any page script can read it. From the website's perspective everything is boringly consistent — the HTTP connection comes from 84.201.x.x, and WebRTC reports 84.201.x.x. There is no mismatch to flag, no missing API to probe, no silent candidate list to raise suspicion.
This is hard to do reliably with an extension or injected JavaScript, because scripts can detect patched APIs (a toString() on a wrapped RTCPeerConnection method gives the game away, and injected patches often miss Web Workers and iframes). It is best done natively, inside the browser engine, below the level any page script can inspect. This is how Dual Login handles it: each profile's WebRTC is masked to that profile's proxy exit IP in the browser core, not by a script — so the candidate an anti-fraud check reads is the proxy IP, the API surface is untouched, and the mask holds in workers and iframes too. If you want the broader picture of why native beats injected for every spoofed surface, see browser fingerprinting explained.
DNS leaks: the quieter cousin
A DNS leak is a different failure with a similar consequence. Before your browser connects to example.com, something has to resolve that name to an IP. Two things can go wrong behind a proxy:
- Local resolution. With some proxy setups (notably SOCKS without remote DNS, or misconfigured system proxies), the name lookup happens on your machine using your ISP's DNS servers, and only the subsequent connection goes through the proxy. Your ISP — and anyone measuring which resolver queried the site's authoritative DNS — sees your real location's resolver.
- Resolver mismatch. Even when resolution is remote, the resolver's location can betray you. If your proxy exit is in Amsterdam but every DNS query for your session arrives from a resolver in your real country, a correlating service can infer that the "Amsterdam user" is not really in Amsterdam.
The difference from WebRTC matters: a WebRTC leak hands a webpage your literal IP address in one API call. A DNS leak leaks resolver location metadata, visible mainly to infrastructure-level observers and dedicated test pages. WebRTC is the acute wound; DNS is the slow one. Fix both: use proxies with remote DNS resolution (SOCKS5 with remote lookup, or HTTP proxies where the proxy performs resolution — the default in a properly built antidetect setup), and confirm with the test procedure below.
Other leak vectors worth checking
Plugging WebRTC and DNS is necessary but not sufficient. These consistency checks catch the rest:
- Timezone vs IP. Your proxy says Frankfurt;
Intl.DateTimeFormat().resolvedOptions().timeZonesaysAsia/Karachi. One JavaScript call, instant contradiction. The timezone must be derived from the exit IP, not the host machine. - Locale and language.
navigator.languagesand theAccept-Languageheader should be plausible for the IP's country. A German residential IP sendingen-USonly is not fatal, but combined with other mismatches it adds weight. - Geolocation API. If a site requests location and the browser returns GPS-grade coordinates from your real city while your IP says another continent, that is a hard contradiction. The geolocation answer must match the proxy exit's coordinates.
- HTTP header order. Chrome, Firefox, and Safari each emit headers in a characteristic order. Tools and crude proxies that reassemble requests can reorder them, so a "Chrome" user-agent with non-Chrome header order flags a middlebox or automation stack.
- IPv6. The forgotten path. If your machine has IPv6 connectivity and your proxy tunnels only IPv4, sites reachable over IPv6 — and WebRTC candidates on IPv6 interfaces — can bypass the proxy entirely. Either your tooling must mask IPv6 the same way, or IPv6 should be absent from the profile's view of the network.
A profile whose WebRTC, DNS, timezone, locale, and geolocation all agree with the proxy exit IP is coherent. A profile where even one disagrees invites the closer scrutiny that surfaces the rest — the same consistency principle covered in what is an antidetect browser.
Step-by-step: a complete proxy leak test
Run this audit on every new proxy-plus-profile combination before it touches a real account, and re-run it after any proxy or network change.
- Establish your baseline. With no proxy, note your real public IPv4, your IPv6 (if any), and your real timezone. You cannot recognize a leak if you do not know what leaking looks like.
- Launch the proxied profile and confirm the basics: visit an IP echo service and verify the shown IP is the proxy exit, in the expected country.
- Run a WebRTC leak test. Use browserleaks.com/webrtc or an equivalent, or paste the JavaScript snippet from earlier into DevTools. Read every candidate line. You are looking for your baseline IP — v4 or v6 — anywhere in the list.
- Run a DNS leak test (dnsleaktest.com, "Extended test"). Every resolver listed should belong to the proxy provider's infrastructure or a public resolver in the exit region — never your ISP.
- Check IPv6 explicitly (test-ipv6.com). Either no IPv6 connectivity, or IPv6 that also resolves to the proxy side. Your real IPv6 appearing anywhere is a fail.
- Verify timezone and locale. In the proxied profile's console:
Intl.DateTimeFormat().resolvedOptions().timeZoneandnavigator.languages. Both should fit the exit IP's region. - Test the geolocation API on any site that requests location. Grant it once and confirm the coordinates land near the proxy exit city, not your desk.
- Run a full fingerprint sweep. A combined checker such as the free Dual Login fingerprint checker shows WebRTC, timezone, languages, and the rest of the fingerprint surface in one pass, so you can eyeball the whole profile for contradictions.
- Record the results per profile. If you run many accounts, keep a pass/fail line per profile and re-check after proxy rotation — a proxy swap silently changes the "correct" answer for timezone, locale, and geolocation all at once.
What a clean result looks like
| Check | Clean result | Leak / red flag |
|---|---|---|
| HTTP IP echo | Proxy exit IP, expected country | Real IP, or wrong country |
| WebRTC srflx candidate | Proxy exit IP (or absent with API intact) | Your baseline public IP in any candidate |
| WebRTC host candidates | mDNS .local names only |
Raw LAN IPs (192.168.x.x) or real IPv6 |
| WebRTC API presence | RTCPeerConnection defined, calls work |
API missing, stubbed, or throwing |
| DNS resolvers | Proxy-side or exit-region resolvers | Your ISP's resolvers |
| IPv6 | None, or proxy-side IPv6 | Your real IPv6 address |
| Timezone | Matches exit IP region | Host machine's timezone |
| Languages / Accept-Language | Plausible for exit country | Obvious mismatch with everything else |
| Geolocation API | Coordinates near exit city | Coordinates near your real location |
Nine rows, and every one must pass. Eight out of nine is not a privacy setup; it is a privacy setup with one hole, and one hole is all a correlation engine needs.
Where antidetect browsers fit
If you manage one personal browser, an extension-based blocker plus discipline gets you most of the way. The math changes when you run twenty profiles for twenty accounts, each on its own proxy: now the "correct" WebRTC answer is different for every profile, and so are the correct timezone, locale, and geolocation. Maintaining that per profile by hand — and re-verifying after every proxy change — does not scale, which is exactly the problem antidetect browsers exist to solve (a deeper treatment lives in how to manage multiple accounts).
Dual Login binds a proxy to each profile — HTTP, HTTPS, or SOCKS5, with or without auth — and then derives the environment from it: WebRTC is masked to that proxy's exit IP natively in the engine, and timezone, locale, and geolocation auto-match the same exit IP. Storage is sealed per profile, so the isolation covers state as well as network identity. The result is that step 3 through step 7 of the audit above pass by construction rather than by maintenance — though you should still run the audit; trust is not a substitute for verification. How this compares to configuring the same protections in other tools is covered on the comparison page.
FAQ
Does a WebRTC leak reveal my exact identity?
It reveals your real public IP, which maps to your ISP and approximate location, and — decisively for multi-account work — it links your "anonymous" proxied session to the same IP your other sessions use. Websites do not need your name when they can join your sessions together.
I use a VPN. Am I safe from WebRTC leaks?
Usually safer than with a browser-level proxy, because a full-tunnel VPN captures UDP too — STUN then sees the VPN exit. But split tunneling, IPv6 bypass, and reconnect gaps all still leak, and every profile behind one VPN shares one IP. Test it; do not assume it.
Is it suspicious to have WebRTC disabled?
Yes, mildly but measurably. A browser where RTCPeerConnection is missing or crippled differs from stock consumer browsers, and detectors probe for exactly that. Replacing the leaked IP with the proxy IP is stronger than removing the API, because it leaves nothing anomalous to find.
Do mDNS candidates mean Chrome already fixed the leak?
No. mDNS hides your local (LAN) addresses behind .local names. The server-reflexive candidate carrying your public IP from the STUN lookup is untouched — and that public IP is the leak that matters behind a proxy.
How often should I re-run a proxy leak test?
On every new profile/proxy pairing, after any proxy rotation or network change, after browser or OS updates, and periodically (monthly is reasonable) on long-lived profiles. Rotating proxies deserve special attention: the exit changes, so the correct timezone and geolocation answers change with it.
Can a website detect that my WebRTC IP is being masked?
If the masking is done with injected JavaScript, often yes — patched functions betray themselves under toString() inspection and frequently miss workers and iframes. Native, engine-level replacement leaves the API surface stock: the page sees ordinary candidates containing the proxy IP, indistinguishable from a user genuinely located there.
Final thoughts
A WebRTC leak is the cheapest deanonymization on the web: a few lines of script, no permission prompt, and your real IP is sitting next to your proxy IP in someone's fraud-scoring pipeline. The fix hierarchy is clear — disabling WebRTC is a blunt instrument that breaks calls and flags tampering, blocking the leak is better but leaves a detectable silence, and replacing the candidate IP with the proxy exit IP natively is the approach that survives inspection. Pair it with remote DNS, an IPv6 check, and matching timezone, locale, and geolocation, then prove it with the nine-row audit above.
If you would rather have that consistency enforced per profile instead of maintained by hand, Dual Login's free plan gives you 10 fully isolated profiles with native WebRTC masking, proxy-matched timezone and geolocation, and no credit card required — create an account or download the app for Windows, macOS, or Linux, and run your own leak audit against it before you trust it with anything real.