Proxy location validation in a browser: 3 checks
How do you run proxy location validation in a browser? Check the exit IP and ASN, then compare WebRTC, DNS, timezone and locale. Learn each check's limits.
- proxy validation
- webrtc
- geo ip
- residential proxies
- playwright
On this page
- Why can a proxy’s location differ from where it exits?
- IP-level vs browser-level proxy location validation: what does each prove?
- How do you validate a proxy’s location from the exit IP?
- How do you run proxy location validation in a browser with Playwright?
- How do you validate a location before the browser connects?
- Wayfern residential exits
- Your own proxy
- What the browser reports
- When should you repeat proxy location validation browser checks?
- What can proxy location validation browser checks not guarantee?
- Frequently asked questions
- How do I validate proxy location in a browser?
- Why does my browser timezone not match my proxy’s country?
- Can WebRTC leak my real IP through a proxy?
- How often should I re-check a rotating residential proxy?
- Does Wayfern check my own proxy’s location?
- Next steps for validating proxy location
- Sources
Proxy location validation in a browser is a layered check: look up the exit IP and its ASN, then load a page through the proxy and compare WebRTC candidates, DNS resolver path, timezone, locale and Geolocation permission state against that IP. No single lookup proves location, because geo IP databases disagree. Repeat the check whenever the exit can change, such as on residential rotation.
Your Playwright or Puppeteer job runs through a proxy, an IP checker says the exit is in Germany, and the site still serves US prices in English. One lookup cannot explain that gap.
The answer is three proxy location validation browser checks: one on the exit IP, one inside the browser and one before the browser connects. Each proves something different, and each has a limit you need to know.
Key Takeaways
- Playwright’s
geolocation,timezoneIdandlocaleemulation options change what the page reads, not the exit IP.- An unknown Wayfern location code is refused with close code 4007, not replaced.
- A sticky
sessionid holds one residential IP; a rotating exit can change location between requests.- The catalog check covers residential codes only; with your own proxy, run both checks yourself.
Why can a proxy’s location differ from where it exits?
A proxy’s advertised location is a label from the provider or a geo IP database. The exit can route through a different city or ISP than that label says. Databases are updated on a schedule, IP blocks get reassigned, and databases disagree with each other.

Three separate layers are involved:
- The provider’s label: the city or ISP named in the dashboard or on the endpoint.
- The database’s record: what a geo IP database returns for the exit IP, a snapshot published on a schedule.
- The network path: where your packets actually enter the internet, which only the exit itself shows.
ProxyVero’s verification guide puts the first gap this way: “advertised location ≠ actual routing location”. It adds that “A proxy can show the correct country while city, ZIP, ISP, ASN, or carrier data is wrong”.
Country is the coarsest of these fields, so it survives errors that break finer ones. A block of addresses can move to a new operator or city while a database still holds the old record. The country stays right and the city turns wrong.
Two databases are built and refreshed independently, so they can return different cities for the same IP. Neither one is ground truth, and the checker you use is only one of them.
Time adds a second problem:
- A rotating residential exit gives you a new IP on each rotation, so each one needs its own check.
- A sticky session id holds one IP only for as long as the session lasts.
A lookup from last week, or from your laptop’s network, says little about the exit your browser is using now.
IP-level vs browser-level proxy location validation: what does each prove?
IP-level validation reads a record about the exit address. Browser-level validation reads what a page receives through the proxy. The first proves who owns and labels the exit. The second proves whether the browser’s signals agree with it.
| Check | Level | Tool | Proves | Cannot prove |
|---|---|---|---|---|
| IP lookup | IP | Geo IP database | What the database records for the exit | That the record is current |
| ASN and RDAP | IP | RDAP query | Network owner and type | City of the exit |
| Reverse DNS | IP | PTR query | Hostname hints | Anything, if no PTR record exists |
| WebRTC candidates | Browser | RTCPeerConnection in a page | Which addresses the page can see | That the exit is in the right city |
| DNS resolver path | Browser | Resolver test page | Which resolver answers the browser | The exit’s location |
| Timezone, locale, Geolocation permission | Browser | Intl and navigator.permissions | Whether the browser’s story fits the exit | Where the exit really is |
Query more than one geo database and treat a split answer as unresolved.
A server-side checker sees the IP that reaches it from its own network path. That path may not match the one your browser takes through the proxy, so a hosted checker can report an address your page never presents. Run the check from a page loaded in the browser itself.
Browser signals show whether WebRTC, DNS, timezone and locale agree with the exit. They say nothing about whether the exit’s database record is right.
Give each level of your proxy location validation browser workflow its own job:
- IP-level checks: vet an exit’s network type and owner before a job starts.
- Browser-level checks: confirm that the page, and not a lookup service, sees one consistent location.
How do you validate a proxy’s location from the exit IP?
Start your proxy location validation browser workflow with the exit IP. Fetch it through the proxy, check who owns it, and compare at least two geo IP databases before you decide.
Get the exit IP through the proxy, using the same network path your job will use.
curl -s -x "PROXY_URL" https://api.ipify.orgSuccess is one address. Don’t look up the proxy hostname, because the exit often differs from the entry point. With a rotating pool, run the command twice and expect different addresses.
Look the IP up in two geo databases.
curl -s https://ipinfo.io/EXIT_IP/json curl -s https://ipwho.is/EXIT_IPTreat disagreement on city as a reason to investigate, not as a failure by itself. Entries go stale when blocks are reassigned.
Check the ASN and registration data.
whois EXIT_IP curl -s https://rdap.org/ip/EXIT_IPRDAP is the JSON successor to legacy WHOIS, with response formats defined in IETF RFC 7483 and its related RFCs. Each regional internet registry documents its own RDAP service.
The ASN shows who announces the range, which separates a consumer ISP from a hosting company. It doesn’t give a city.
Check reverse DNS.
dig -x EXIT_IP +shortA hostname that names an ISP or a hosting brand supports the ASN result. An empty or generic answer proves nothing, because the range owner sets these records.
Compare against what the browser reports. Open the same echo URL in a browser through the proxy and confirm it prints the address from step 1. The timezone, locale and WebRTC checks build on this one.
Repeat steps 1 and 2 during a long run, because a rotating exit changes address and a sticky session can still end.
How do you run proxy location validation in a browser with Playwright?
You run proxy location validation in a browser by connecting Playwright over CDP, reading every location signal a page can read, and comparing each with the exit you looked up.
- Record the exit: fill
exitwith theip,countryandtimezonefrom the IP lookup. - Connect and read from an HTTPS page, because the Geolocation API needs a secure context.
- Run
compare()and treat every returned string as a mismatch to investigate.
import { chromium } from "playwright";
const exit = { ip: "203.0.113.7", country: "DE", timezone: "Europe/Berlin" };
const browser = await chromium.connectOverCDP(
"wss://api.wayfern.com/ws?token=LINK_TOKEN&country=DE",
);
const page = await browser.contexts()[0].newPage();
await page.goto("https://example.com");
const seen = await page.evaluate(async () => {
const geo = await navigator.permissions.query({ name: "geolocation" });
const candidates = await new Promise((resolve) => {
const out = [];
const pc = new RTCPeerConnection({
iceServers: [{ urls: "stun:stun.l.google.com:19302" }],
});
pc.createDataChannel("x");
pc.onicecandidate = (e) =>
e.candidate ? out.push(e.candidate.candidate) : resolve(out);
pc.createOffer().then((o) => pc.setLocalDescription(o));
setTimeout(() => resolve(out), 4000);
});
return {
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
language: navigator.language,
languages: navigator.languages,
geolocation: geo.state, // prompt, granted or denied
candidates,
};
});
function compare(seen, exit) {
const flags = [];
if (seen.timezone !== exit.timezone)
flags.push(`timezone ${seen.timezone} vs ${exit.timezone}`);
const region = seen.language.split("-")[1];
if (region && region !== exit.country)
flags.push(`locale region ${region} vs ${exit.country}`);
if (seen.geolocation === "granted")
flags.push("geolocation granted: compare coordinates with the exit");
for (const c of seen.candidates.filter((c) => c.includes(" typ srflx"))) {
const ip = c.split(" ")[4];
if (ip !== exit.ip) flags.push(`srflx ${ip} vs exit ${exit.ip}`);
}
return flags;
}
console.log(compare(seen, exit)); The Playwright emulation docs list geolocation, timezoneId and locale as context options. Set timezoneId: "America/New_York" on a context whose exit is in Germany, and Intl.DateTimeFormat reports New York while the IP lookup still says DE. The script flags that, so an emulated value can’t hide a real mismatch.
The Geolocation API only reports a position after consent: MDN’s Geolocation API page says “the user is asked for permission to report location information.” Without a grant, a page gets a denial or no position, so prompt or denied is not a mismatch.
Chromium hides host candidates behind mDNS hostnames, a mechanism the IETF describes in “Using Multicast DNS to protect privacy when exposing ICE candidates”.
MDN lists srflx as a candidate type, and it comes from a STUN server, so it can still carry a public address. Chrome’s privacy API documents the webRTCIPHandlingPolicy setting for controlling this.
To check the DNS path, request a hostname you control through the proxy. Then read the resolver address in your authoritative server’s query log.
For a hosted exit, see our guide to anti-detect browser sessions over CDP.
How do you validate a location before the browser connects?
You validate a location before the browser connects by checking each requested code against a catalog and refusing any code the catalog doesn’t know. Wayfern’s residential exits and your own proxy need different handling.
Wayfern residential exits
- Fetch the valid values. In the Wayfern API reference,
GET /api/proxy/locationsreturns the validcountry,region,cityandispvalues. - Connect with the codes and a sticky
sessionid, which holds one residential IP for the flow. - Treat a refusal as final: an unknown location is refused with close code 4007 instead of falling back, so a bad city never lands you in a different one.
import { chromium } from "playwright";
const url =
"wss://api.wayfern.com/ws?token=LINK_TOKEN&country=US®ion=CA&session=run42";
try {
const browser = await chromium.connectOverCDP(url);
// run your job
} catch (err) {
// An unknown location closes the socket with code 4007.
console.error("Location refused, aborting:", err.message);
process.exit(1);
} If you send a valid country with an invalid city, the socket closes with 4007. Reproduce it from the /docs/api reference.
Your own proxy
Save an http, https or socks5 proxy on a link with proxyMode set to own, then choose it per connection with proxy=own, proxy=residential or proxy=none. The catalog check covers residential location codes, so run the exit IP and browser checks yourself.
What the browser reports
The browser identity is applied inside Wayfern’s Chromium build. width and height on the /ws URL resize the real window, and nothing is emulated. Wayfern has no per-vector overrides, so compare the signals instead of tuning them.
Allow for the cold start: it takes about 45 to 50 seconds, longer with a residential exit, according to Wayfern’s limits page.
To try it, open a residential session by country and city and send one invalid city on purpose.
When should you repeat proxy location validation browser checks?
Repeat them whenever the exit might have changed, not once at startup, because proxy location belongs to a session.
With a rotating residential exit, two connections can leave from two different IPs. Wayfern’s session id on the /ws URL holds one residential IP for a flow. Without it, the exit can differ between connections, so a check at the start says nothing about later requests.
Re-run the proxy location validation browser checks on these triggers:
- A new connection opens.
- The
sessionid changes. - A navigation starts failing or serves a different locale.
- The proxy reconnects.
Put these proxy location validation browser checks in one function and call it right after connectOverCDP() and again from your retry path.
const browser = await chromium.connectOverCDP(url);
const page = await browser.contexts()[0].newPage();
await assertExit(page, expected); // IP lookup, timezone, locale
async function gotoChecked(page, target) {
const res = await page.goto(target);
if (!res || res.status() >= 400) await assertExit(page, expected);
return res;
} A cookie issued to one IP and replayed from another is an easy signal for a site to read. Keep the cookie jar, locale and exit together, as in Wayfern’s authenticated scraping flows.
Wayfern has no persistent profiles, so save and restore cookies in your own code. A pooled instance is reused only for the same link token, workload and exit, so changing any of the three gives you a different instance to check.
What can proxy location validation browser checks not guarantee?
Proxy location validation can show that your signals agree with each other, but it cannot guarantee that the exit is where a database says it is, or that a site will let you in.
A geo IP lookup returns a database record, not a measurement of the route, and the record only reflects when the database was last built. When two databases agree, you have learned that the databases agree.
Proxy location validation browser checks have a limit too. Values you set on a context, such as timezone, locale or geolocation, aren’t measurements of the network. They can pass a comparison that the real network path would fail.
A consistent country, timezone and locale removes one class of mismatch. Detection is an arms race, and Wayfern doesn’t guarantee unblocked access, so test each check against your own targets.
Frequently asked questions
How do I validate proxy location in a browser?
Look up the exit IP and check ASN and RDAP for network type. Then load a page through the proxy and read WebRTC candidates, DNS resolver, Intl timezone, navigator.language and Geolocation permission state. Every signal should agree with the exit.
Why does my browser timezone not match my proxy’s country?
A proxy changes the network path and leaves the browser’s clock alone. The page reads its timezone from the browser, so it reports the host’s zone until you set one. Set timezone and locale for the exit’s country, then read them back.
Can WebRTC leak my real IP through a proxy?
It can, so test it. Collect ICE candidates with RTCPeerConnection in a page loaded through the proxy, and compare every public address with the exit IP. Any other public address is a leak.
How often should I re-check a rotating residential proxy?
Re-check on every new connection, because a rotating exit can change IP between them. With a sticky session id, re-check if the flow restarts.
Does Wayfern check my own proxy’s location?
Not for a proxy you bring. Every residential code is checked against the live catalog, and an unknown location is refused with close code 4007. Run the IP and browser checks on your own proxy’s exit yourself.
Next steps for validating proxy location
Start today with one exit: run the IP-level workflow (lookup, ASN, reverse DNS and a second geo database) and save the results as your baseline.
This week, add the browser-level comparison to your CDP setup. Read WebRTC candidates, timezone, locale and Geolocation permission state, compare each with the saved exit, and fail the run on any mismatch.
After that, wire the check into every new connection and every new session id, since either one can land on a different exit.
To see proxy location validation in a browser run end to end, start a location-targeted session. Get a link token from the Wayfern developer quickstart, connect over CDP with country, region and city targeting, and run your comparison against a live exit. A mismatch fails the run before it collects any data, so a wrong location costs you one session.
Sources
How to Verify Proxy Geolocation (Complete 2026 Guide) · Emulation | Playwright · Anti-Detect Browser Sessions over CDP | Wayfern · RFC 7483: JSON Responses for the Registration Data Access… · Geolocation API - Web APIs | MDN · Using Multicast DNS to protect privacy when exposing ICE… · RTCIceCandidate: type property | MDN · Wayfern API reference. Every other source is linked where the article cites it.
See us more often in Google
One click marks Wayfern as a preferred source in Google, so our posts can show up more often in your Top Stories, AI Mode and AI Overviews.