You set up a proxy, open an IP lookup, and it shows the proxy’s IP. Job done? Not always. A page can still find your real IP through WebRTC, a browser feature that ignores your browser’s proxy settings by design. If you use residential proxies to see a site as a local visitor would, a WebRTC leak can undo that without any visible sign.
This guide explains how the leak works, how to test for it in two minutes, and how to close it in Chrome, Firefox and automated browsers.
How the leak happens
WebRTC lets browsers make calls and send data directly to each other. To do that, each browser collects “ICE candidates”: addresses where it might be reached. One step is asking a STUN server, over UDP, “what public address do you see me coming from?” The answer goes into a candidate that the page’s JavaScript can read.
The problem is the path that question takes. A typical HTTP proxy only carries your web requests, not UDP. So the STUN request leaves through your own connection, and the answer is your real public IP. RFC 8828, the IETF standard on WebRTC address handling, says it plainly: STUN checks can bypass a proxy and reveal a client’s public IP if direct internet access is allowed. It also recommends that WebRTC traffic is not sent through proxies by default, because of call quality.
Two details matter:
- Local addresses are mostly hidden now. Chrome and Firefox replace your private network address with a random
.localname for most pages. In Firefox this is themedia.peerconnection.ice.obfuscate_host_addressessetting, on by default. Your public IP is the real risk. - The page needs no permission. Collecting candidates does not require camera or microphone access, so there is no prompt.
Test it in two minutes
You do not need a third-party test site. Open the page you care about, or any page, with your proxy on, open the developer console (F12), and paste this:
const pc = new RTCPeerConnection({ iceServers: [{ urls: "stun:stun.l.google.com:19302" }] });
pc.createDataChannel("t");
pc.onicecandidate = (e) => e.candidate && console.log(e.candidate.candidate);
pc.createOffer().then((o) => pc.setLocalDescription(o));
Look at the lines that contain typ srflx. The address in that line is the public IP the STUN server saw.
- If it matches your home or office IP, WebRTC is leaking.
- If it matches the proxy’s IP, or there is no
srflxline at all, you are fine. - Lines with
typ hostand a.localname are your hidden local address, and they are expected.
Then compare with an IP lookup such as IP Info in the same browser. It should show the proxy’s IP and location. If the lookup shows the proxy but the srflx line shows you, the proxy works and WebRTC goes around it.
Fix it in Chrome
Easiest: use an extension that manages it. The Shifter browser extension turns on WebRTC leak protection by default while you are connected. Under the hood, Chrome extensions control this through the webRTCIPHandlingPolicy privacy setting. If another extension already controls WebRTC, only one of them can win, and the Shifter extension tells you when its protection is not active. Remove or disable the other one.
Managed computers: Chrome has an enterprise policy, WebRtcIPHandling, with four values:
| Value | What WebRTC uses |
|---|---|
default | All available network interfaces |
default_public_and_private_interfaces | The public-facing interface, private addresses allowed |
default_public_interface_only | The public-facing interface only, no private addresses |
disable_non_proxied_udp | TCP through the proxy; UDP only if the proxy supports it |
Only disable_non_proxied_udp stops the public IP leak behind a proxy. The two “public interface” values still ask the STUN server over your own connection.
Fix it in Firefox
The Shifter extension handles it in Firefox too. To do it by hand, open about:config and set:
media.peerconnection.ice.proxy_only_if_behind_proxytotrue: WebRTC only uses the proxy when one is configured. This is the targeted fix.media.peerconnection.ice.default_address_onlytotrue: only the default route is used. This hides extra local addresses, but on its own it does not stop the public IP leak.media.peerconnection.enabledtofalse: turns WebRTC off entirely. It is the bluntest option and breaks calls in that browser.
Then run the console test again: the srflx line should be gone or show the proxy’s IP.
Fix it in automated browsers
Playwright, Puppeteer and Selenium start a real browser, so they leak the same way. For Chromium, start it with:
--force-webrtc-ip-handling-policy=disable_non_proxied_udp
For Firefox, set the same about:config preferences in the profile your framework launches. Then run the console test above from your script and check the srflx result as part of your setup checks. Our guide to residential proxies in Selenium and Playwright shows where these options go.
WebRTC is not the only leak
Close the related gaps while you are here:
- DNS. Name lookups can bypass the proxy and resolve from your own network. Our guide on preventing DNS leaks covers
socks5hand how to check. - IPv6. If your proxy path is IPv4 only, a browser that also has IPv6 may use it for some requests.
- Time zone and language. These do not reveal your IP, but they can contradict your proxy’s location.
The bottom line
A WebRTC leak happens because the browser asks a STUN server for your address over UDP, and most proxies only carry web traffic. Test it with the console snippet: if the srflx address is yours, the page can see it too. Turn on leak protection in the Shifter extension, or set disable_non_proxied_udp in Chrome and proxy_only_if_behind_proxy in Firefox, then test again.