# Browser location does not match IP: a bug we shipped

> Browser location does not match IP: a no-proxy profile made in Austria claimed New York. One failed lookup was never retried, and a table filled the gap.

Source: https://mosaicbrowser.com/blog/austria-claimed-new-york

## A profile in Austria claimed New York

Browser location does not match IP: a no-proxy profile made in Austria claimed New York. One failed lookup was never retried, and a table filled the gap.

![6: Six profiles, one machine, six countries, beside a screenshot: a Mosaic leak test: every surface a site reads, checked from inside the profile page](https://mosaicbrowser.com/covers/austria-claimed-new-york.webp)

On 29 September 2026 a profile with no proxy, made on a computer in Austria, came out with the timezone `America/New_York`. A browser location that does not match the IP is the first thing a consistency check looks at, and this one was off by an ocean. The cause was one lookup at app start that failed and was never tried again.

## Why a no-proxy profile has to match this computer

A profile with no proxy does not browse from anywhere special. It leaves from the operator's own address, the same one every other app on the machine uses. So its timezone, language and geolocation have to describe that address, or the page sees an Austrian IP beside a clock set to New York.

That comparison costs a site almost nothing. It already has the IP; reading the timezone is one line of script. It is the cheapest contradiction there is, which is why we draw every profile for its exit, proxy or not (how the rest of the machine is drawn to match is on [real fingerprints](https://mosaicbrowser.com/features/real-fingerprints)).

## The code was already there

None of this was missing. A function resolved the computer's own address, another handed it to the generator, and a create with no proxy was drawn for it. Straight after a fresh start we made six profiles and got `de-AT` six times, each one reporting a match.

The flaw was when it ran. The lookup happened once, at app start, and nobody waited for it. If that single request failed, the cached answer stayed empty for as long as the app was open. A laptop waking before its wifi, a geolocation service rate-limiting us, an app launched on a train: any of those was enough.

With nothing cached, the generator fell through to its last resort, a table of locales weighted by share of web traffic. That table leans American.

Mosaic is a desktop app

Email yourself the link and open it on your computer.

[How it works: Machines that exist](https://mosaicbrowser.com/features/real-fingerprints)

## Reproducing it

We pointed the lookup at a dead port and made six profiles on the same machine:

```
Europe/Paris  America/New_York  America/New_York
America/Chicago  Europe/Dublin  Europe/Berlin

```

Six profiles, six countries, one computer. That is not a weak match. Two draws that disagree with each other cannot both describe one address, so none of them did.

It got worse when we read the response. Every one of the six reported `exitMatch: { matched: true }`. The branch for profiles with no proxy returned that value as a literal, beside a comment saying the store would pair it with the machine's resolved exit later. It never did. The API told the caller a profile had been pinned to a measured address while its location was being drawn at random.

## What we changed

Three changes, all in the code that resolves the direct exit.

1. The create resolves the address itself instead of trusting that start-up already did. Creating a profile behind a proxy already waits for that proxy's exit, on the grounds that nothing is waiting on a create. The same holds with no proxy.
2. A failed lookup is retried, at most once a minute. Retrying per profile would turn one dead network into hundreds of eight-second timeouts in a batch of 500.
3. When the address genuinely cannot be found, the profile takes the computer's own timezone, never the table. A machine that cannot reach a geolocation service still knows what its clock is set to.

Run again with the lookup still dead, the same six creates gave `Europe/Brussels` six times, which is that machine's setting. Each came back `matched: false`, with a reason saying the timezone came from the computer rather than a measured address. We would rather report an honest "not measured" than a match that never happened.

![Creating a profile in Mosaic with its proxy checked and the locale drawn for the exit](https://mosaicbrowser.com/shots/profile-editor.png)
*The editor says what the locale was drawn for*

## A cache filled once is a guess

Nothing at the call site looked wrong. Whenever anyone tested it, it returned a good answer, because they tested on a machine whose start-up lookup had worked. A value fetched once and read for the life of the process stops being a measurement the moment that one fetch fails, and nothing tells you when that happened.

The fix generalises past timezones. Resolve where the value is used. Retry a failure on its own clock, not per item. And when the answer is unknown, fall back to something true about the machine, then label it as that, so nothing downstream mistakes it for a measurement.

## When browser location does not match IP: check the profile

The leak test runs from inside the profile's own page. It prints the exit address the page sees, the timezone it reads, and whether the two agree. A no-proxy profile should show this computer's address and its local timezone; a profile behind a proxy should show the proxy's.

![A Mosaic leak test: exit address, timezone and language read from inside the profile](https://mosaicbrowser.com/shots/leak-test.png)
*Timezone checked against the exit, from inside the page*

The same mismatch is how accounts on one computer end up looking related, which is the subject of [keeping accounts from getting linked](https://mosaicbrowser.com/guides/how-to-manage-multiple-accounts-without-getting-linked). What the timezone is one part of is in [browser fingerprint](https://mosaicbrowser.com/glossary/browser-fingerprint), and why profiles stay on this computer at all is on [local-first](https://mosaicbrowser.com/features/local-first).

## Questions

### Why does my browser location not match my IP address?

Usually because the timezone, language or geolocation the browser reports was set from somewhere other than the address the site sees. In our case a profile with no proxy was drawn from a share-weighted table when one lookup of the machine's own address failed.

### What does a site compare first?

The IP's location against the browser's timezone. It needs no script beyond reading the clock, and in the bug described here it disagreed by an ocean: an Austrian address and America/New_York.

### What does Mosaic do with a profile that has no proxy?

It browses from your own address, so it is drawn for that address. The create resolves the address itself, and if the lookup fails it uses the computer's own timezone and says the match was not measured.

### How do I see what my profile reports?

Run the leak test on the profile. It reads the exit address, the timezone and the language from inside the profile's own page and says whether the timezone agrees with the exit location.

## Related

[Machines that exist: fingerprints drawn from real hardware](https://mosaicbrowser.com/features/real-fingerprints): Mosaic draws each profile's GPU, screen, CPU, memory and fonts from one real device, so the parts of a fingerprint agree with each other and with the host.

[Browser fingerprint: what a site can read about your machine](https://mosaicbrowser.com/glossary/browser-fingerprint): A browser fingerprint is the set of values a site reads about your browser and computer, which together recognize you without cookies. What goes into one.

[How to manage multiple accounts without getting them linked](https://mosaicbrowser.com/guides/how-to-manage-multiple-accounts-without-getting-linked): Accounts get linked by shared cookies, IPs, fingerprints and habits. Give each its own profile, exit and history, then test it before you trust it.

[Local first: your profiles stay on your computer](https://mosaicbrowser.com/features/local-first): Mosaic has no cloud copy of your profiles. Profiles, cookies and proxies stay on your computer, encrypted on disk, with app lock, daily backups and a trash.

[The RTT client hint, read off the wire](https://mosaicbrowser.com/blog/rtt-on-the-wire): ECT, RTT and Downlink headers behind a proxy, measured: a claimed round trip moved JavaScript to 300 and left the RTT header at 50. So we claim neither.

[fingerprint.com wouldn't load through our proxy, and that was a result](https://mosaicbrowser.com/blog/fingerprint-demo-not-loading): Through one residential exit the FingerprintJS demo hung; from the same Mac with no proxy it loaded. Our runner blamed itself. The exit was why.

[Same IPHey score, opposite reasons](https://mosaicbrowser.com/blog/iphey-same-score-different-signal): IPHey Unreliable on a normal Chrome is usually the exit. Our profile and a stock Chrome both got MX 90, for a browser signal and a location signal.

[Why IPHey's location card can be greener on a profile than on Chrome](https://mosaicbrowser.com/blog/iphey-location-card): On one US exit in one minute, stock Chrome got IPHey's masked or inconsistent location data and our profile got green. The difference was the timezone.

## Mosaic, on your own computer

The browser this blog is about: its own Chromium, fingerprints from real machines and a proxy exit per profile. Free holds 3 profiles. Pro is $49 a month for any number.

Mosaic is a desktop app

Email yourself the link and open it on your computer.
