# Pixelscan timezone mismatch: one round answers nothing

> We changed only the timezone on one profile behind a Slovak exit. Pixelscan flagged masking on the Vienna row, the correct one, and the controls disagreed.

Source: https://mosaicbrowser.com/blog/pixelscan-timezone-sweep

## We broke the timezone on purpose and Pixelscan liked it better

We changed only the timezone on one profile behind a Slovak exit. Pixelscan flagged masking on the Vienna row, the correct one, and the controls disagreed.

![Europe/Vienna versus America/New_York, each name in its own tile: Masking detected landed on the right timezone](https://mosaicbrowser.com/covers/pixelscan-timezone-sweep.webp)

A Pixelscan timezone mismatch means the timezone your browser reports does not agree with where Pixelscan places your IP address, and the fix is to take the timezone from the proxy's exit rather than from your own computer. What we learnt is the part after that: one Pixelscan run is not enough to tell you whether the timezone was ever the problem. When we broke the timezone on purpose, the masking verdict landed on the one row where it was correct.

## A FAIL that scrolled past

It started with our detector runner, which loads about fifty public detection pages in one profile and writes a report. One run put `fail` on the Pixelscan line, with "fingerprint inconsistent, masking detected". It wrote the report, exited 0, and twelve more rows scrolled past. Somebody reading the terminal caught it and asked whether we had noticed. We had not, because nothing in the process said a detector had failed.

So the first fix was to the runner. A `fail` now makes the run exit non-zero and is listed by name at the end. The other statuses do not: `unreachable` is the site's problem and `unread` is our extractor's. Only `fail` says that a detector read the profile and did not like it.

## Pixelscan timezone mismatch, tested one field at a time

Then the question: was it the timezone? The exit was in Slovakia and the profile's timezone was `Europe/Vienna`, the same offset from UTC under a neighbouring country's name. That looked like a plausible trigger. So we kept one profile, changed only `locale.timezone` in place, and ran the honest value first and last as controls:

| Timezone | Against the exit | Pixelscan |
| --- | --- | --- |
| Europe/Vienna | agrees (control) | fail: inconsistent, masking detected |
| America/New_York | deliberately wrong | fail: inconsistent, no masking |
| Asia/Tokyo | deliberately wrong | fail: inconsistent, no masking |
| Europe/Vienna | agrees (control) | pass: consistent, no masking |

Read the controls first. The same profile with the same value, minutes apart, answered `fail` and then `pass`. When the controls disagree, the rows between them measured nothing. And masking detected landed on a row whose timezone agreed with the exit, not on either row we had broken. The hypothesis that a Slovak exit under an Austrian zone name caused it was dead.

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)

## Three rounds of the same configuration

We then ran Pixelscan alone, three rounds, with nothing changed between them:

| Round | Pixelscan |
| --- | --- |
| 1 | fail: inconsistent, masking detected |
| 2 | pass: consistent, no masking |
| 3 | pass: consistent, no masking |

And the control that settles whether a verdict is about the profile at all: three paired rounds on an exit that agreed with the profile, our engine beside an untouched Google Chrome from the same machine. All six readings were the same: fail, inconsistent, no masking. On that afternoon "inconsistent" was something a stock Chrome earned too, and masking detected had appeared twice in about fifteen measurements without reproducing on the configuration that produced it. Neither was a finding about the profile, and any single round of those sweeps would have given a confident answer in whichever direction it happened to fall.

So the runner grew `--rounds N` and an outcome of its own, `flaky`, which counts as neither pass nor fail. Recording a disagreement as a failure sends the next person after a regression that does not exist. Recording it as a pass is worse.

## The tool that told us to delete a defence

The same afternoon caught a second tool. Our GPU check brackets its sweep with the host's own chip at both ends and voids the run if the two disagree. That afternoon they agreed, and both failed:

| GPU claimed | Pixelscan |
| --- | --- |
| the host's own chip (control) | fail |
| a second Apple chip | fail |
| a third Apple chip | fail |
| the host's own chip (control) | fail |

Its conclusion was that the GPU pin was doing nothing and could stop constraining the draw. Nothing in those four rows says anything about the chip: Pixelscan was failing every configuration, an untouched Chrome included, so the experiment had no range to move in. The check now refuses to conclude unless the control passes, and exits with a code that says so.

## What to do with your own timezone mismatch

Start with the boring check. Find where your proxy's exit is, compare it with the timezone your browser reports, and make them agree. In Mosaic a profile's timezone, language and geolocation are drawn for its proxy's measured exit, and with no proxy they follow the computer's own location. Then run Pixelscan three times, and once more in a plain Chrome on the same proxy. If the plain Chrome gets the same verdict, it is not a finding about your profile.

The bisect that did find a real cause, and a real fix, for Pixelscan's masking verdict is in [Pixelscan's masking verdict, bisected to one surface](https://mosaicbrowser.com/blog/pixelscan-masking-bisected). A scan that never finishes is a different symptom, covered in [when Pixelscan never stops scanning](https://mosaicbrowser.com/blog/pixelscan-stuck-on-scanning). How CreepJS decides that a value is a lie, which is a different method again, is in [what a CreepJS lie is](https://mosaicbrowser.com/blog/what-a-creepjs-lie-is), and the values the engine changes per profile are listed under [real fingerprints](https://mosaicbrowser.com/features/real-fingerprints).

## Questions

### What does a Pixelscan timezone mismatch mean?

The timezone your browser reports does not agree with where Pixelscan places your IP address. The usual cause is a proxy in one place and a timezone taken from your own computer in another. Set the timezone from the proxy's exit, then run the scan again.

### Why does Pixelscan give a different result each time?

Its verdict is computed on its own server from what the page collects, and we have seen it disagree with itself on an unchanged profile minutes apart: fail, then pass. Run it at least three times and treat a split result as flaky, not as a finding.

### Does a wrong timezone cause masking detected on Pixelscan?

Not in our sweep. With two deliberately wrong timezones, Pixelscan said no masking. Masking detected appeared on a row whose timezone agreed with the exit, and did not reproduce when the same configuration ran again.

### How does Mosaic set a profile's timezone?

From the proxy's measured exit. When a profile is drawn for a proxy, its timezone, language and geolocation follow where the exit is. With no proxy, they follow the computer's own location.

## Related

[Pixelscan's masking verdict, bisected to one surface](https://mosaicbrowser.com/blog/pixelscan-masking-bisected): We bisected Pixelscan's masking detected verdict on one profile. Canvas, WebGL, audio and client rects were fine. Hiding about 2% of font families caused it.

[When Pixelscan never stops scanning](https://mosaicbrowser.com/blog/pixelscan-stuck-on-scanning): Pixelscan stuck on scanning for 90 seconds was, in our runs, a profile claiming Windows on a Mac. A scan that never returns is a non-verdict, not a slow pass.

[What a CreepJS lie is, and why stock Chrome has none](https://mosaicbrowser.com/blog/what-a-creepjs-lie-is): CreepJS lies detected means an API behaved unlike the native one: wrong toString, wrong descriptor, or a worker that disagrees. Stock Chrome has none.

[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.

[A Russian exit and a profile speaking Mexican Spanish](https://mosaicbrowser.com/blog/accept-language-and-proxy-country): A profile matched to a Russian exit kept sending es-MX in Accept-Language. Leaving the language alone was right. Saying nothing about it was the bug.

[IPHey's score moved with the address, not the browser](https://mosaicbrowser.com/blog/iphey-score-moves-with-address): IPHey score changes even on an untouched Chrome: 100, 100, 70 and 0 in one afternoon. The score follows the exit and the moment; the browser card does not.

[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.

[Why hCaptcha gives some browsers a puzzle every time](https://mosaicbrowser.com/blog/hcaptcha-image-challenge-every-time): hCaptcha's challenge is its score. A puzzle every time usually means blocked cookies, a crowded VPN exit or a browser whose values disagree with each other.

## 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.
