# Chrome OnDeviceHeadSuggest - Complete Technical Analysis ## Overview **OnDeviceHeadSuggest** is Chrome's offline autocomplete system. It provides search query suggestions in the omnibox without any network connection, using a compressed radix tree (trie) stored locally as a binary file. - **Component ID**: `obedbbhbpmojnkanicioggnmelmoomoc` - **Previous Component ID** (before July 2019): `feejiaigafnbpeeogmhmjfmkcjplcneb` - **Source**: `components/component_updater/installer_policies/on_device_head_suggest_component_installer.cc` - **Model reader**: `components/omnibox/browser/on_device_head_model.h` - **Provider**: `components/omnibox/browser/on_device_head_provider.cc` --- ## Architecture ### Single Component, Multiple Locales There is **one single component ID** for all locales. The locale is communicated via an `accept_locale` installer attribute in the update request. Google's server returns the locale-specific CRX file. ``` Component ID: obedbbhbpmojnkanicioggnmelmoomoc ├── accept_locale=FR → cr_fr_100000_index.bin (100K, ~1.2 MB) ├── accept_locale=FR500000 → cr_fr_500000_index.bin (500K, ~7.4 MB) ├── accept_locale=ENUS → cr_en-us_100000_index.bin (100K, ~1.3 MB) ├── accept_locale=ENUS500000 → cr_en-us_500000_index.bin (500K, ~7.7 MB) ├── accept_locale=DE → cr_de_100000_index.bin (100K, ~1.3 MB) ├── accept_locale=DE500000 → cr_de_500000_index.bin (500K, ~7.6 MB) └── ... (19 languages × 2 tiers + country variants) ``` ### Locale Normalization Chrome normalizes the browser locale before requesting: - Removes hyphens and underscores - Converts to uppercase - Appends model size constraint (default: `500000`) | Browser Locale | Normalized | Manifest Name | |---|---|---| | `fr` | `FR` | `OnDeviceHeadSuggestFR500000` | | `en-US` | `ENUS` | `OnDeviceHeadSuggestENUS500000` | | `pt-BR` | `PTBR` | `OnDeviceHeadSuggestPTBR500000` | | `zh-TW` | `ZHTW` | `OnDeviceHeadSuggestZHTW500000` | ### Locale Exclusions Korean (`ko`, `ko-KR`) is **explicitly disabled** in Chromium source: ```cpp bool OmniboxFieldTrial::IsOnDeviceHeadSuggestEnabledForLocale( const std::string& locale) { if (IsKoreanLocale(locale)) return false; return IsOnDeviceHeadSuggestEnabledForAnyMode(); } ``` ### Chrome Stable vs Canary The OnDeviceHeadSuggest model is **identical bit-for-bit** between Chrome Stable and Chrome Canary. Verified on 2026-03-15: | | Chrome Canary | Chrome Stable | |---|---|---| | **Path** | `AppData/Local/Google/Chrome SxS/User Data/components/OnDeviceHeadSuggestModel/` | `AppData/Local/Google/Chrome/User Data/OnDeviceHeadSuggestModel/` | | **Version** | `20251024.824731831.14` | `20251024.824731831.14` | | **File** | `cr_fr_500000_index.bin` (7,578,989 bytes) | `cr_fr_500000_index.bin` (7,578,989 bytes) | | **MD5** | `3203842440b708ef7a3ccc70425d2681` | `3203842440b708ef7a3ccc70425d2681` | **Note**: In Chrome Stable, the component lives directly under `User Data/OnDeviceHeadSuggestModel/`, not under `User Data/components/` as might be expected. The same model version and binary are served to both channels. ### Model Tiers: 100K vs 500K Each locale is available in **two tiers**: | Tier | accept_locale example | Manifest name | Suggestions | Typical size | |---|---|---|---|---| | **100K** (default) | `FR`, `ENUS`, `DE` | `OnDeviceHeadSuggestFR` | ~100,000 | 0.7 - 3.2 MB | | **500K** (full) | `FR500000`, `ENUS500000`, `DE500000` | `OnDeviceHeadSuggestFR500000` | 500,000 | 4.2 - 15.3 MB | - The **100K tier** is what Chrome downloads by default (smaller, faster) - The **500K tier** is the full model installed locally by Chrome (the one found in `User Data/OnDeviceHeadSuggestModel/`) - The volume suffix (`500000`) is appended by the client based on locale configuration. The server decides which tier to serve based on the `accept_locale` value - File naming: `cr_{locale}_{volume}_index.bin` (e.g., `cr_fr-fr_100000_index.bin` for 100K, `cr_fr_500000_index.bin` for 500K) --- ## Binary Format Specification Source: `components/omnibox/browser/on_device_head_model.h` ### File Header (2 bytes) ``` Offset 0: [address_size: 1 byte] - Size of address pointers in bytes Offset 1: [score_size: 1 byte] - Size of score values in bytes Offset 2: [root_node] - Root of the radix tree starts here ``` For the FR 500K model: `address_size = 4`, `score_size = 3` ### Node Structure Each node in the radix tree: ``` [max_score_as_root block] [child_0] [child_1] ... [child_N] [0x00 terminator] ``` ### max_score_as_root Block ``` ┌─────────────────────────────────────────────┐ │ score_size bytes, little-endian │ │ bit 0: has_leaf_score flag │ │ bits 1+: maximum score in this subtree │ ├─────────────────────────────────────────────┤ │ if has_leaf_score: │ │ score_size more bytes = leaf_score │ │ (this prefix IS a complete suggestion) │ └─────────────────────────────────────────────┘ ``` - **score_max** (bits 1+): Used for **pruning** - Chrome skips entire subtrees where score_max < threshold - **leaf_score**: The actual popularity score if this exact prefix is a suggestion - **has_leaf_score** (bit 0): Indicates whether this node represents a complete query ### Child Structure ``` ┌───────────────────────────────────────┐ │ [text_length: 1 byte] │ │ [text: text_length bytes, UTF-8] │ │ [indicator block] │ └───────────────────────────────────────┘ ``` **Indicator block** (first byte determines type): ``` bit 0 = 0 → LEAF child Remaining: score_size - 1 bytes Full block value >> 1 = leaf_score bit 0 = 1 → INTERMEDIATE child Remaining: address_size - 1 bytes Full block value >> 1 = address (offset in file to child node) ``` ### Visual Example ``` File offset 2 (root): [max_score_as_root: 0xFF FF FE] → has_leaf=0, score_max=8388607 Child "d": text_length=1, text="d" first_byte=0x05, remaining=[0x00, 0x00] is_leaf=0 (bit0=1→intermediate), address=0x000002 >> 1 = ... → points to subtree for prefix "d" Child "decathlon": text_length=9, text="decathlon" first_byte=0xFE, remaining=[0xFF, 0x3F] is_leaf=1 (bit0=0→leaf), score = 0x3FFFFE >> 1 = 8388607 → "decathlon" with score 8,388,607 (maximum) [0x00] terminator ``` --- ## Score System ### Score Parameters (FR 500K) | Parameter | Value | |---|---| | Score size | 3 bytes (24 bits) | | Usable bits | 23 (1 bit reserved for has_leaf flag) | | Max possible score | 8,388,607 (2^23 - 1) | | Score range (observed) | 1 - 8,388,607 | ### What the Score Represents The score is a **quantized popularity index** derived from Google Search query frequency data: - **Higher score** = more popular search query - **Score 8,388,607** (max) = most popular query for that locale - Values are **relative within the locale** - not comparable across locales - Not raw search volume counts, but a normalized ranking metric ### Score_Max_Subtree (Pruning) Each intermediate node stores the **maximum score** among all descendants: ``` "dec" (score_max = 8,388,607) ├── "athlon" → leaf_score 8,388,607 ← (this is the max) ├── "oration" → leaf_score 3,200,000 ├── "embre" → leaf_score 2,800,000 └── "laration" → leaf_score 1,500,000 ``` **Purpose**: When Chrome traverses the tree looking for suggestions: 1. If a subtree's `score_max` < minimum display threshold → **skip entire branch** 2. This reduces search from O(500K) to exploring only high-scoring branches 3. Critical for real-time autocomplete performance (< 10ms response) ### How Chrome Uses Scores From `on_device_head_provider.cc`: 1. User types a prefix in the omnibox 2. Chrome walks the radix tree to find the matching node 3. Collects top-N suggestions from that subtree (pruning low score_max branches) 4. Ranks suggestions by leaf_score descending 5. Returns top matches (typically 3-5 suggestions) --- ## Model Statistics (FR 500K) | Metric | Value | |---|---| | File | `cr_fr_500000_index.bin` | | Size | 7.23 MB | | Address size | 4 bytes (31-bit addresses) | | Score size | 3 bytes (23-bit scores) | | Total suggestions | 500,000 | | Extraction time | ~0.7 seconds | | Shannon entropy | 6.66 bits/byte | | Primary script | Latin (~99%) | ### Top 20 Suggestions (FR) | Rank | Score | Suggestion | |---|---|---| | 1 | 8,388,607 | decathlon | | 2 | 8,388,606 | leboncoin | | 3 | 8,388,605 | youtube | | 4 | 8,388,604 | amazon | | 5 | 8,388,603 | google maps | | 6 | 8,388,602 | traducteur | | 7 | 8,388,601 | meteo | | 8 | 8,388,600 | netflix | | 9 | 8,388,599 | chatgpt | | 10 | 8,388,598 | facebook | *(Full list of 500,000 entries exported to `chrome_headsuggest_fr_500k.xlsx`)* --- ## Component Update Protocol ### Endpoint ``` POST https://update.googleapis.com/service/update2/json ``` ### Request Format (Omaha Protocol 3.1) **Minimal working request** (verified 2026-03-15): ```json { "request": { "protocol": "3.1", "dedup": "cr", "acceptformat": "crx3", "prodversion": "131.0.6778.86", "sessionid": "{UUID}", "requestid": "{UUID}", "@os": "win", "arch": "x64", "nacl_arch": "x86-64", "os": {"platform": "Windows", "version": "10.0.19045", "arch": "x86_64"}, "updater": { "name": "Chrome", "version": "131.0.6778.86", "prodversion": "131.0.6778.86", "ismachine": false, "autoupdatecheckenabled": true, "updatepolicy": -1 }, "hw": {"physmemory": 16}, "app": [{ "appid": "obedbbhbpmojnkanicioggnmelmoomoc", "version": "0.0.0.0", "installedby": "policy", "accept_locale": "FR500000", "enabled": true, "updatecheck": {}, "ping": {"r": -1} }] } } ``` ### Key Fields | Field | Description | |---|---| | `appid` | Always `obedbbhbpmojnkanicioggnmelmoomoc` | | `accept_locale` | Normalized locale + optional volume (e.g., `FR`, `ENUS`, `FR500000`, `ENUS500000`) | | `version` | Set to `"0.0.0.0"` to force download, or current version to check for updates | | `installedby` | **CRITICAL**: Must be `"policy"` for the server to respond with download URLs | | `prodversion` | Chrome version string (e.g., `"131.0.6778.86"`) - **required** | | `updater.name` | Must be `"Chrome"` (not `"Chromium"`) | | `acceptformat` | `crx3` (signed Chrome extension format) | > **Important discovery**: Without `"installedby": "policy"` and `"prodversion"` in the request, the server always returns `"noupdate"` regardless of locale. These two fields are essential for the API to return actual download URLs. ### Response The server returns a JSON response with: - `status`: `"ok"` (update available) or `"noupdate"` - `urls.url.codebase`: Base URL for CRX download - `manifest.version`: Version string (e.g., `20251024.824731831.14`) - `manifest.packages.package`: Filename, hash, size ### Download URLs CRX files are served from Google CDN: ``` https://edgedl.me.gvt1.com/edgedl/release2/chrome_component/{hash}_{version}/{filename}.crx3 ``` ### CRX3 Structure The downloaded `.crx3` file is a signed Chrome extension containing: - `manifest.json` with name and version - `_metadata/verified_contents.json` (integrity hashes) - `cr_{locale}_{count}_index.bin` (the actual model file) --- ## Available Locales (verified 2026-03-15) ### 100K Tier (default/lightweight) **39 locale models downloaded** (56.01 MB total). Contains ~100,000 suggestions each. Most at version `20251024.824731831.14`, two at newer `20251029.826691377.14`. | Locale | Language | Version | CRX Size | |---|---|---|---| | `EN` | English (generic) | 20251024.824731831.14 | 1.24 MB | | `ENUS` | English (US) | 20251024.824731831.14 | 1.29 MB | | `ENGB` | English (GB) | 20251024.824731831.14 | 1.29 MB | | `ENAU` | English (AU) | 20251024.824731831.14 | 1.30 MB | | `ENIN` | English (India) | 20251024.824731831.14 | 1.35 MB | | `ENZA` | English (South Africa) | 20251024.824731831.14 | 1.42 MB | | `FR` | French | 20251024.824731831.14 | 1.21 MB | | `FRFR` | French (France) | 20251024.824731831.14 | 1.24 MB | | `DE` | German | 20251024.824731831.14 | 1.28 MB | | `DEDE` | German (Germany) | 20251024.824731831.14 | 1.30 MB | | `ES` | Spanish | 20251024.824731831.14 | 1.27 MB | | `ESES` | Spanish (Spain) | 20251024.824731831.14 | 1.30 MB | | `ESMX` | Spanish (Mexico) | 20251024.824731831.14 | 1.36 MB | | `IT` | Italian | 20251024.824731831.14 | 1.33 MB | | `ITIT` | Italian (Italy) | 20251024.824731831.14 | 1.34 MB | | `PTBR` | Portuguese (Brazil) | 20251024.824731831.14 | 1.30 MB | | `JA` | Japanese | 20251024.824731831.14 | 1.40 MB | | `JAJP` | Japanese (Japan) | 20251024.824731831.14 | 1.40 MB | | `RU` | Russian | 20251024.824731831.14 | 1.86 MB | | `RURU` | Russian (Russia) | 20251024.824731831.14 | 1.94 MB | | `AR` | Arabic | 20251024.824731831.14 | 1.83 MB | | `ARAE` | Arabic (UAE) | 20251024.824731831.14 | 1.81 MB | | `AREG` | Arabic (Egypt) | 20251024.824731831.14 | 1.90 MB | | `HI` | Hindi | 20251024.824731831.14 | 1.74 MB | | `HIIN` | Hindi (India) | 20251024.824731831.14 | 1.74 MB | | `TH` | Thai | 20251024.824731831.14 | 1.15 MB | | `THTH` | Thai (Thailand) | 20251024.824731831.14 | 1.15 MB | | `VI` | Vietnamese | 20251024.824731831.14 | 0.75 MB | | `VIVN` | Vietnamese (Vietnam) | 20251024.824731831.14 | 0.74 MB | | `ID` | Indonesian | 20251024.824731831.14 | 0.69 MB | | `IDID` | Indonesian (ID) | 20251024.824731831.14 | 0.66 MB | | `PL` | Polish | 20251024.824731831.14 | 1.33 MB | | `PLPL` | Polish (Poland) | **20251029.826691377.14** | 1.33 MB | | `TR` | Turkish | 20251024.824731831.14 | 1.47 MB | | `TRTR` | Turkish (Turkey) | 20251024.824731831.14 | 1.48 MB | | `RO` | Romanian | 20251024.824731831.14 | 1.31 MB | | `RORO` | Romanian (Romania) | **20251029.826691377.14** | 1.32 MB | | `BN` | Bengali | 20251024.824731831.14 | 3.00 MB | | `BNBD` | Bengali (Bangladesh) | 20251024.824731831.14 | 3.18 MB | ### 500K Tier (full model) **19 locale models available** (~160 MB total estimated). Contains 500,000 suggestions each. These are the full models that Chrome installs locally. Discovered 2026-03-15. | accept_locale | Language | CRX Size | .bin Size (approx) | |---|---|---|---| | `ENUS500000` | English (US) | 7.75 MB | 7.93 MB | | `ENGB500000` | English (GB) | 7.74 MB | ~7.9 MB | | `FR500000` | French | 7.41 MB | 7.58 MB | | `DE500000` | German | 7.61 MB | ~7.8 MB | | `ES500000` | Spanish | 7.77 MB | ~7.9 MB | | `ESMX500000` | Spanish (Mexico) | 8.24 MB | ~8.4 MB | | `IT500000` | Italian | 8.00 MB | ~8.2 MB | | `PTBR500000` | Portuguese (Brazil) | 7.91 MB | ~8.1 MB | | `RU500000` | Russian | **10.97 MB** | ~11.2 MB | | `JA500000` | Japanese | 7.90 MB | ~8.1 MB | | `AR500000` | Arabic | **10.61 MB** | ~10.8 MB | | `HI500000` | Hindi | 9.17 MB | ~9.4 MB | | `TH500000` | Thai | 6.49 MB | ~6.6 MB | | `VI500000` | Vietnamese | 4.60 MB | ~4.7 MB | | `PL500000` | Polish | 7.97 MB | ~8.1 MB | | `TR500000` | Turkish | 8.66 MB | ~8.8 MB | | `ID500000` | Indonesian | 4.23 MB | ~4.3 MB | | `RO500000` | Romanian | 7.82 MB | ~8.0 MB | | `BN500000` | Bengali | **15.27 MB** | ~15.6 MB | > **Note**: The 500K tier is available for **both** base locale codes (`FR500000`) and country-specific variants (`FRFR500000`, `DEDE500000`, etc.). All 23 country-specific 500K variants tested were available. Only `AR500000` had a different version (`20251029.826691377.14`); all others match `20251024.824731831.14`. ### 500K Tier - Country-Specific Variants (verified 2026-03-15) | accept_locale | Language | CRX Size | |---|---|---| | `ENUS500000` | English (US) | 7.57 MB | | `ENGB500000` | English (GB) | 7.56 MB | | `ENAU500000` | English (AU) | 7.56 MB | | `ENIN500000` | English (India) | 7.90 MB | | `ENZA500000` | English (South Africa) | 8.25 MB | | `FRFR500000` | French (France) | 7.31 MB | | `DEDE500000` | German (Germany) | 7.51 MB | | `ESES500000` | Spanish (Spain) | 7.67 MB | | `ESMX500000` | Spanish (Mexico) | 8.05 MB | | `ITIT500000` | Italian (Italy) | 7.84 MB | | `PTBR500000` | Portuguese (Brazil) | 7.72 MB | | `JAJP500000` | Japanese (Japan) | 7.71 MB | | `RURU500000` | Russian (Russia) | **11.20 MB** | | `ARAE500000` | Arabic (UAE) | 10.19 MB | | `AREG500000` | Arabic (Egypt) | **10.74 MB** | | `HIIN500000` | Hindi (India) | 8.95 MB | | `THTH500000` | Thai (Thailand) | 6.34 MB | | `VIVN500000` | Vietnamese (Vietnam) | 4.44 MB | | `IDID500000` | Indonesian (ID) | 3.98 MB | | `PLPL500000` | Polish (Poland) | 7.81 MB | | `TRTR500000` | Turkish (Turkey) | 8.50 MB | | `RORO500000` | Romanian (Romania) | 7.68 MB | | `BNBD500000` | Bengali (Bangladesh) | **16.09 MB** | ### Not Available (79 locales tested, no model) `ENCA`, `ENNZ`, `ENSG`, `ENHK`, `ENPH`, `FRBE`, `FRCH`, `FRCA`, `DEAT`, `DECH`, `ES419`, `ESAR`, `ESCO`, `ESCL`, `ESPE`, `PTPT`, `PT`, `ARSA`, `BNIN`, `NL`, `NLNL`, `NLBE`, `SV`, `SVSE`, `DA`, `DADK`, `FI`, `FIFI`, `NO`, `NBNO`, `NB`, `CS`, `CSCZ`, `UK`, `UKUA`, `HU`, `HUHU`, `EL`, `ELGR`, `BG`, `BGBG`, `HR`, `HRHR`, `SK`, `SKSK`, `SL`, `SLSI`, `HE`, `HEIL`, `ZH`, `ZHCN`, `ZHTW`, `ZHHK`, `KO` (blocked in source), `KOKR` (blocked in source), `FA`, `FAIR`, `MS`, `MSMY`, `TA`, `TAIN`, `TE`, `TEIN`, `KN`, `KNIN`, `ML`, `MLIN`, `MR`, `MRIN`, `GU`, `GUIN`, `PA`, `PAIN`, `SW`, `SWKE`, `FIL`, `FILPH`, `UR`, `URPK` ### Version Notes - Most locales: `20251024.824731831.14` (October 24, 2025) - `PLPL` and `RORO`: `20251029.826691377.14` (October 29, 2025 - 5 days newer) - `AR500000`: `20251029.826691377.14` (October 29, 2025) - No Chinese, Korean, Dutch, Scandinavian, or Eastern European models available --- ## Chromium Source References | File | Purpose | |---|---| | `components/component_updater/installer_policies/on_device_head_suggest_component_installer.cc` | Component registration, locale handling, CRX verification | | `components/component_updater/installer_policies/on_device_head_suggest_component_installer.h` | Header with public API | | `components/omnibox/browser/on_device_head_model.h` | Binary format spec, tree reader | | `components/omnibox/browser/on_device_head_model.cc` | Tree traversal implementation | | `components/omnibox/browser/on_device_head_provider.cc` | Omnibox integration, suggestion provider | | `components/omnibox/browser/on_device_model_update_listener.cc` | Model update handler | | `components/omnibox/browser/omnibox_field_trial.cc` | Feature flags, locale eligibility | | `components/omnibox/common/omnibox_features.cc` | Feature definitions | ### Feature Flags | Flag | Default | Description | |---|---|---| | `OmniboxOnDeviceHeadProviderNonIncognito` | ENABLED | Use OnDeviceHead in normal browsing | | `OmniboxOnDeviceHeadProviderIncognito` | ENABLED | Use OnDeviceHead in incognito | --- ## Security & Privacy ### CRX3 Integrity Each CRX3 file includes: - **RSA signature** from Google (publisher proof) - **TreeHash** (SHA-256 Merkle tree) for content integrity - **verified_contents.json** with per-file hashes ### Privacy Considerations - The model contains **aggregated, anonymized** search query frequency data - No user-specific data is included - Suggestions are generated **entirely offline** - no network requests - The model is a snapshot of popular queries at the time of model generation - Score values reveal relative popularity rankings of search terms in that locale ### Data Sensitivity The 500K suggestions dataset effectively reveals: - Top 500,000 most popular search queries per locale - Relative popularity ranking of each query - Cultural and linguistic search patterns per country - Trending topics at the time of model creation (October 2024 snapshot) --- ## Tools & Files | Tool | Description | |---|---| | `extract_headsuggest.py` | Full radix tree parser, exports to XLSX with metadata | | `analyze_headsuggest.ps1` | Binary analysis (hex dump, entropy, byte frequency) | | `download_headsuggest_all.ps1` | Downloads all available 100K locale models from Google servers | | `chrome_headsuggest_fr_500k.xlsx` | Exported FR 500K dataset (500K rows, 24.1 MB) | | `headsuggest_models/` | Directory with 39 CRX3 files for 100K locales + 1 CRX3 for ENUS500000 | | `headsuggest_models/available_models.csv` | CSV with all 100K locale metadata (URLs, hashes, sizes) | | `headsuggest_models/unavailable_locales.csv` | CSV of tested locales that returned no model | | `headsuggest_models/extract_crx3.ps1` | PowerShell script to extract .bin files from CRX3 packages | | `headsuggest_models/ENUS500000/` | Extracted ENUS 500K model (`cr_en-us_500000_index.bin`, 7.93 MB) | | `headsuggest_models/cr_fr-fr_100000_index.bin` | Extracted FR-FR 100K model (1.23 MB) | --- ## Open Questions / TODO ### Not yet investigated 1. **500K tier not bulk-downloaded**: Only ENUS500000 has been downloaded and extracted. The remaining 18 500K models (~150 MB) could be downloaded using the same Omaha protocol method with `accept_locale` set to `{LOCALE}500000`. 2. **Cross-locale comparison**: No analysis has been done comparing suggestions across languages. Questions: - How many universal queries appear in all locales? (e.g., "youtube", "amazon", "netflix") - Are scores comparable across locales or independently scaled? - What percentage of queries in the EN model appear as transliterations in other locales? 3. **100K vs 500K content overlap**: The 100K model is presumably a subset of the 500K model (top 100K by score), but this has not been verified by extracting and comparing both tiers for the same locale. 4. **Score calibration**: The scoring system uses 23 bits (max 8,388,607) but the relationship between score values and actual search volume is unknown. Is it linear? Logarithmic? A rank-based quantization? 5. **Temporal freshness**: The model version is from October 2024. How often are models updated? Do newer Chrome versions get newer models? Is there a way to request historical versions? 6. ~~**Country-specific 500K**~~: **RESOLVED** - Country-specific 500K variants (`FRFR500000`, `DEDE500000`, etc.) are all available. 23/23 tested successfully. Sizes differ slightly from base locales (e.g., `FRFR500000` = 7.31 MB vs `FR500000` = 7.41 MB), confirming they contain locale-tuned data. --- *Analysis performed: 2026-03-15* *Updated: 2026-03-15 (added Chrome stable comparison, 500K tier discovery, API requirements)* *Chrome Canary version: 148.0.7733.0* *Chrome Stable: verified identical model* *Model version: 20251024.824731831.14* *Component ID: obedbbhbpmojnkanicioggnmelmoomoc*