Intl and CLDR Locale Data: The Quiet Way Your Region Leaks Through Formatting
Imagine a QA team checking a Japanese storefront before launch. The test profile routes through a Japan proxy and its timezone is Asia/Tokyo, yet prices and dates on the page come out American-style, so the test isn't showing what a shopper in Japan would see. One line of JavaScript explains it:
new Intl.NumberFormat().resolvedOptions()
It returns { locale: "en-US", numberingSystem: "latn" }. The browser is formatting numbers American-style — comma for thousands, period for decimals — while the rest of the profile says it is in Japan. Any script on the page can read that, without canvas analysis or anything else elaborate. The Intl API volunteers it.
This is a surface that gets little attention. Plenty of writing covers canvas and WebGL fingerprinting. Meanwhile, the ECMAScript Intl API reports your regional formatting preferences through three objects: Intl.DateTimeFormat, Intl.NumberFormat, and Intl.Collator. Each one has a resolvedOptions() method that tells any script on the page how the browser is configured.
This matters to three groups: site owners who want to understand what their visitors' browsers report, QA teams testing localised pages, and anyone running several profiles for accounts they are allowed to hold, who wants each profile to be coherent. By the end of this tutorial, you'll know how to align Intl settings with a profile's proxy region, so a German IP actually formats dates like a German would.
Check your own fingerprint first. We built a public checker at justbrowser.app/fingerprint-checker that runs client-side, with no signup. It grades what it claims rather than guessing: WebRTC candidates are compared against your public IP, and the IP's location is graded on whether its UTC offset actually agrees with your browser's timezone. Worth running before you read the rest of this, so the signals below have your numbers attached to them.
Prerequisites
Before we get into it:
- JustBrowser installed — the 7-day trial (card required) is plenty for this walkthrough
- A configured proxy — you need to know the target country
- Browser developer console familiarity — we'll run JavaScript to verify configurations
- 15 minutes — once you understand the concepts, the actual setup takes five
If you haven't set the profile's timezone yet, do that first. Intl settings build on top of geographic consistency. No point fixing Intl if your timezone is still wrong.
Step 1: Understand What the Intl API Actually Exposes
The Intl object in JavaScript provides three main formatters. Each one reports regional information.
Intl.DateTimeFormat — Formats dates and times according to locale conventions.
new Intl.DateTimeFormat('de-DE').format(new Date())
// "7.7.2026" (German: day.month.year)
new Intl.DateTimeFormat('en-US').format(new Date())
// "7/7/2026" (American: month/day/year)
new Intl.DateTimeFormat('ja-JP').format(new Date())
// "2026/7/7" (Japanese: year/month/day)
Intl.NumberFormat — Formats numbers including decimals and currency.
new Intl.NumberFormat('de-DE').format(1234567.89)
// "1.234.567,89" (German: period for thousands, comma for decimals)
new Intl.NumberFormat('en-US').format(1234567.89)
// "1,234,567.89" (American: comma for thousands, period for decimals)
Intl.Collator — Sorts strings according to locale-specific rules.
['ä', 'z', 'a'].sort(new Intl.Collator('de').compare)
// German sorts ä near a
['ä', 'z', 'a'].sort(new Intl.Collator('sv').compare)
// Swedish sorts ä after z
Here's the kicker: each of these has a resolvedOptions() method that returns the actual settings in use:
new Intl.DateTimeFormat().resolvedOptions()
// Returns: { locale: "en-US", calendar: "gregory", numberingSystem: "latn", timeZone: "America/New_York", ... }
Any script on the page can read this. It doesn't need to make you format anything — it just asks the browser what settings it would use. If those settings don't match the proxy's region, the profile contradicts itself.
The other piece is CLDR — the Common Locale Data Repository. This is the Unicode database that defines all those formatting rules. Browsers embed a specific CLDR version, and the exact formatting output can vary slightly between versions. It's a small signal on its own, but it adds to the picture when other settings disagree.
Step 2: Diagnose Your Current Intl Configuration
Before changing anything, check what your profile currently exposes. Open a JustBrowser profile and run these in the developer console:
Check DateTimeFormat:
console.log(Intl.DateTimeFormat().resolvedOptions());
Look at the locale field. Is it what you'd expect for your proxy's country?
Check NumberFormat:
console.log(Intl.NumberFormat().resolvedOptions());
The locale and numberingSystem fields matter here. Most Western locales use "latn" (Latin numerals), but the locale itself should match.
Check Collator:
console.log(Intl.Collator().resolvedOptions());
This shows locale and collation rules.
Quick formatting test:
console.log('Date:', new Intl.DateTimeFormat().format(new Date()));
console.log('Number:', new Intl.NumberFormat().format(1234567.89));
console.log('Currency:', new Intl.NumberFormat(undefined, {style: 'currency', currency: 'EUR'}).format(1234.56));
If you're using a German proxy but see "7/7/2026" instead of "7.7.2026", or "1,234,567.89" instead of "1.234.567,89", your Intl settings are reporting your machine's region rather than the profile's.
Step 3: Configure Intl Locale in JustBrowser
Open the profile's settings in JustBrowser. Two settings matter here:
- Languages — drives
navigator.language/navigator.languages, the Accept-Language header and the Intl default locale together - Timezone — set it to match the proxy region before you start
In JustBrowser one languages setting covers both navigator.language and the Intl locale, so they cannot drift apart — set the first language to the proxy's region and both follow.
Set the languages list to match your proxy region:
- Germany proxy →
de-DE - France proxy →
fr-FR - Japan proxy →
ja-JP - UK proxy →
en-GB - US proxy →
en-US - Brazil proxy →
pt-BR
Why one setting is the point:
A mismatch — navigator.language saying "de-DE" but Intl returning "en-US" — is the inconsistency a page can read directly, and it's what you get when the two are wired separately.
JustBrowser's native Chromium engine handles this at the C++ level. When you set a German locale, the identity parameters that depend on it align: navigator.language, the Accept-Language header and the Intl defaults. (For how public checkers compare signals like these, see what BrowserScan, IPHey and Pixelscan each measure.) Extension-based tools can override navigator.language easily, but they often can't touch the underlying Intl system locale — it's too deep in the browser.
That's the difference between extension-based and native engine modifications. Extensions operate in JavaScript userland. The Intl API calls down into Chromium's ICU (International Components for Unicode) library, which uses embedded CLDR data. You can't intercept that from an extension, so it takes engine-level support.
Step 4: Verify the Configuration
After saving your profile settings, relaunch the profile and run the diagnostics again:
// Full verification script
console.log('=== Intl Configuration Test ===');
console.log('navigator.language:', navigator.language);
console.log('navigator.languages:', navigator.languages);
console.log('');
console.log('DateTimeFormat resolved:', Intl.DateTimeFormat().resolvedOptions());
console.log('NumberFormat resolved:', Intl.NumberFormat().resolvedOptions());
console.log('Collator resolved:', Intl.Collator().resolvedOptions());
console.log('');
console.log('Date format:', new Intl.DateTimeFormat().format(new Date()));
console.log('Number format:', new Intl.NumberFormat().format(1234567.89));
For a German proxy, you should see:
navigator.language: "de-DE" or "de"- DateTimeFormat locale: "de-DE" or "de"
- Date format: "7.7.2026" (day.month.year with periods)
- Number format: "1.234.567,89" (period for thousands, comma for decimals)
Run an external inspector too:
- BrowserLeaks — Look at JavaScript → Intl section
If the Intl section agrees with your target region and your formatted outputs match expectations, you're done. Move on.
Step 5: Handle Edge Cases
Mixed language preferences
Real users often have secondary languages. A German user might have ["de-DE", "de", "en-US", "en"] — German primary, English fallback. If your site picks a language from that list, test with the kinds of lists your users actually have, not only single-language ones. JustBrowser lets you specify the full language list.
Numbering systems
Most locales use "latn" (Latin digits: 0-9). But some don't:
- Arabic locales might use "arab" (Arabic-Indic digits)
- Some Asian locales might use native scripts
If you're testing a region where some users see non-Latin numerals, check how your pages render both ways. For most Western regions, "latn" is expected. Check what your users in that region actually see.
Calendar systems
Most locales use "gregory" (Gregorian calendar). Some use others:
- Japan: "japanese" calendar alongside gregorian
- Islamic countries: "islamic" variants
- Thailand: "buddhist" calendar
Know the region you are testing. Japanese users may see either the Gregorian or the Japanese calendar depending on their settings, so a date-heavy page is worth testing with both.
Currency formatting
If you're testing with currency formatters, know the expected format:
- EUR in Germany: "1.234,56 €" (symbol after, with space)
- USD in US: "$1,234.56" (symbol before, no space)
- JPY in Japan: "¥1,235" (full-width yen sign before, no decimals)
Site owners and fraud-prevention teams can render a price in the visitor's locale and compare it with regional expectations, and ad verification teams do the same when they check how a page displays in each market.
Common Errors and How to Fix Them
resolvedOptions() shows wrong locale after configuration
Cause: Profile wasn't fully restarted, or the setting didn't save properly.
Fix: Close the profile completely in JustBrowser (not just the browser window). Relaunch. Check again. If still wrong, verify the setting is actually saved in your profile config.
navigator.language is correct but Intl locale is different
Cause: These are separate settings in some tools. navigator.language was changed but the system locale wasn't.
Fix: In JustBrowser, set the profile's languages list with the target region first — navigator.language and the Intl locale are derived from the same setting — then relaunch the profile. If you're using a different tool that can't set the system locale, that's the limitation of extension-based architecture.
Different Intl objects report different locales
Cause: One of the Intl objects is returning a different locale than the others, or the locale doesn't match the timezone or language settings.
Fix: Run the verification script from Step 4. Check all three — DateTimeFormat, NumberFormat, and Collator. They should all return the same locale. Also verify your timezone matches.
Number formatting uses wrong separators
Cause: The locale is set correctly but the browser's built-in locale data doesn't cover it fully. Rare, but possible with stripped-down browser builds.
Fix: Run the same formatter in stock Chrome. If it formats correctly there and not in your profile, report it to the tool's vendor with the locale and the output you got.
Currency symbol positioning is wrong
Cause: Currency formatting rules are locale-specific and sometimes surprising. EUR displayed in Germany vs France vs Ireland all have slightly different conventions.
Fix: Match the exact locale, not just the language. "de-DE" and "de-AT" (Germany vs Austria) format some things differently. Know your target.
Next Steps
With Intl settings aligned, each profile reports one coherent region instead of several, and a localisation test shows what users in that region actually see. It is an easy surface to overlook, because nobody thinks about number formatting as part of a browser's identity until a price renders wrong in a test.
For the complete fingerprinting picture, check out our audio and hardware fingerprinting guide. And if you're running automation through these profiles — Playwright, Puppeteer, Selenium — the REST API integration guide covers driving these profiles from code through the local API.
Localised QA often covers email too. If you test the order and shipping emails a regional storefront sends, check that their dates and prices follow the same locale. JustEmails, our custom-domain email service, includes a transactional email API.
If a platform restricts an account, use its own support and appeal route, and keep to what its rules allow.
Frequently Asked Questions
What is CLDR and why does it matter for browser fingerprinting?
CLDR (Common Locale Data Repository) is the Unicode Consortium's database that defines how dates, numbers, currencies, and text sorting work for every locale. Browsers embed CLDR data, and the specific version they ship affects formatting output. When you call Intl.DateTimeFormat('de-DE').format(), the browser uses CLDR rules for German formatting. A script on a page can read that output, so a profile that pairs a Tokyo proxy with en-US formatting reports two different regions at once.
Can resolvedOptions() reveal my real locale even after changing navigator.language?
Yes, in tools that set the two separately. navigator.language can be changed independently of the Intl system locale. If navigator.language says 'ja-JP' but the underlying system locale is still en-US, Intl.DateTimeFormat().resolvedOptions() returns the locale the formatter is actually using, which might be 'en-US'. A page that calls resolvedOptions() therefore sees two different answers. You want both aligned with the region the profile is meant to represent.
How do NumberFormat and Collator contribute to fingerprinting?
Intl.NumberFormat reveals decimal separators (1,000 vs 1.000), currency positioning, and digit grouping conventions that vary by locale. Intl.Collator exposes string sorting rules — German treats 'ä' differently than Swedish. Both expose resolvedOptions() with locale, numbering system, and collation rules. If your proxy is German but your NumberFormat uses US conventions (comma for thousands, period for decimals) and your Collator sorts with English rules, the profile reports mixed regions. None of these is dramatic on its own, but together with timezone and language they make a profile read as either coherent or contradictory.
Does the Intl API expose my operating system's locale settings?
It depends on how the browser is configured. Stock browsers inherit from the OS locale — a Windows machine set to German will have German Intl defaults. A multi-account browser like JustBrowser sets these values at the engine level, so you can choose a locale per profile independent of your system. Extension-based tools often can't reach this deep, which is why a Mac set to en-US can still show American formatting conventions through a Japan proxy. Engine-level support is the reliable approach.
Try JustBrowser
Native Chromium multi-account browser for teams — not extension-based. Real C++ engine patches at the canvas / WebGL / audio / font / screen layer, so 40+ identity parameters are genuine, not faked. Local REST API + CDP for Playwright, Puppeteer, Selenium. $9.99/month or $99.99/year. 7-day free trial, card required — cancel any time in the seven days and you are not charged. Unlimited profiles.
Get started → · How it differs from Multilogin / GoLogin / AdsPower
Ready to manage multiple accounts?
Seven days free, then $9.99/month — one plan, everything included.