# Sec-CH-UA-Model header on Android, and why we got it wrong

> Chrome on Android freezes the model out of the User-Agent but still sends it in Sec-CH-UA-Model. Our first Android patch sent an empty one.

Source: https://mosaicbrowser.com/blog/sec-ch-ua-model-header-android

## Sec-CH-UA-Model is empty on a desktop and a phone's name on Android

Chrome on Android freezes the model out of the User-Agent but still sends it in Sec-CH-UA-Model. Our first Android patch sent an empty one.

![SM-S918U: The model a phone sends when a site asks for it](https://mosaicbrowser.com/covers/sec-ch-ua-model-header-android.webp)

On a desktop, Chrome sends `Sec-CH-UA-Model` as an empty string. On Android it sends the phone's model name, `SM-S918U` or `moto g05`, to any site that asks for it with `Accept-CH: Sec-CH-UA-Model`. The User-Agent string no longer carries that name, which is why the header matters. Our first Android patch sent an empty model, and it took a second patch to send the phone's.

## What the Sec-CH-UA-Model header carries on Android

Chrome's User-Agent reduction froze the Android part of the string. Every Chrome on every Android phone now writes `Linux; Android 10; K`, whatever the real version and whatever the device. Before the freeze a site could parse the model straight out of the string. After it, the `K` tells you nothing.

The model did not go away. It moved into the client hints, behind an explicit request. A site that wants it sends `Accept-CH: Sec-CH-UA-Model` on a response, and from then on Chrome adds the header to its requests over HTTPS. A script can read the same field with `navigator.userAgentData.getHighEntropyValues(['model'])`. Low-entropy hints such as `Sec-CH-UA-Mobile` and `Sec-CH-UA-Platform` arrive without asking. The model is high-entropy, so it waits to be asked, and that is the privacy gain of the reduction.

Chromium's own `BuildModelInfo()` explains the desktop side: on a release Android build it returns the hardware model, and everywhere else it returns nothing. So a desktop profile's honest answer is `""`, and a phone that answers `""` contradicts itself.

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)

## The patch that read the freeze the wrong way

`0137-android-platform.patch` taught Tesseract Chrome, our engine, to claim Android on every path a phone is read by. There are six of them: the platform token, the frozen unified string, the client-hint metadata, `Mobile Safari/537.36` in place of `Safari/537.36`, the UA-CH mobile bit (which a desktop build compiles out), and `navigator.platform` as `Linux armv81`.

For the model, 0137 wrote `metadata->model = ""`. The reasoning was in the patch description: Chrome 110 and later report the literal `Android 10; K` and no device name, so a real model string would be "a value no Chrome emits". The first half was right about the string. It was wrong about the header, because the reduction moved the model rather than deleting it.

The result was a profile answering `mobile: true`, `platform: "Android"` and `model: ""` in one object. A detector can read all three in one call, and no phone gives that combination.

We did not fix it from memory, because reasoning about what Chrome reports was how the bug got in. The fix in `0138-android-ua-model.patch` rests on three checks. Chromium's source returns the hardware model on Android unconditionally. Its `GetCpuBitness()` returns an empty string on a non-desktop Android, so our claim was also wrong about bitness: it reported the host Mac's `64` beside an empty architecture. And three phones read directly:

```
SM-S918U  {"architecture":"","bitness":"","model":"SM-S918U", ...}
moto g05  {"architecture":"","bitness":"","model":"moto g05", ...}
SM-S936U  {"architecture":"","bitness":"","model":"SM-S936U", ...}

```

Every one has a model, and every one has an empty architecture and an empty bitness. 0138 sets the model from a new switch, `--fingerprint-ua-model`, and sets bitness to empty for a claimed Android. `form_factors` needed nothing: Chromium computes it from the mobile bit, which 0137 already answered, so it reads `["Mobile"]`.

## Why the model comes from a captured phone

The model is a switch, not a table keyed on the platform, because it belongs to one device. Mosaic's Android catalogue holds those three captured phones, whole: screen, pixel ratio, thread count, memory, touch points, Android version, the GPU renderer with that renderer's own extension list, and the fonts. A profile draws a row and takes all of it. The model it sends is the name that row was captured under.

A model name drawn on its own would recreate the fault the catalogue exists to prevent. A Samsung model code beside another phone's GPU and screen is a phone nobody makes, and a site holding a device table can see it. (The same rule for desktop machines is on [real fingerprints](https://mosaicbrowser.com/features/real-fingerprints).)

On a desktop profile the switch is never sent. Mosaic passes `--fingerprint-ua-model` only when the profile has a model, so desktop profiles report `""` like every desktop Chrome.

## What a site sees from a Mosaic Android profile

The model and the platform are set in C++, so they hold in every frame and worker, the same as the [User-Agent string itself](https://mosaicbrowser.com/blog/user-agent-launch-order). We measured one freshly drawn Android profile on an Apple Silicon Mac, with no proxy. Pixelscan passed and named the browser as Chrome on Android, IPHey read Trustworthy at 100/100, bot.sannysoft showed 58 of 58 green, and CreepJS reported 0% headless and 0% stealth.

That profile is still desktop Chromium in device mode, not a phone. It has no app store and no cellular radio, and sites that need the TikTok or Instagram app rather than their websites need a real device. What the profile does is answer a website's questions the way the captured phone answered them, model included. The values a page reads first are listed under [browser fingerprint](https://mosaicbrowser.com/glossary/browser-fingerprint).

## Questions

### What does Sec-CH-UA-Model contain on Android?

The device's model name, such as SM-S918U or moto g05. Chrome only sends it after the site asks for it with an Accept-CH response header, and a page can read the same value through navigator.userAgentData.getHighEntropyValues.

### Why is Sec-CH-UA-Model empty on my computer?

Because desktop Chrome has no model to report. Chromium fills the hint from the hardware model only on an Android build, so every desktop Chrome sends an empty string.

### Is the device model still in the Android User-Agent string?

No. Since User-Agent reduction, Chrome on Android writes Android 10; K in the string whatever the phone is. The model moved behind the client hint rather than disappearing.

### Can I set Sec-CH-UA-Model from JavaScript?

No. Headers that start with Sec- are forbidden to page scripts, so the value comes from the browser itself. In Mosaic it is set in the engine, from the phone the profile was drawn as.

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

[A fingerprint that depended on launch order](https://mosaicbrowser.com/blog/user-agent-launch-order): Chrome's --user-agent flag left Sec-CH-UA-Bitness empty, and a cache empty at every app start decided when we sent it. One profile wore two identities.

[Not_A Brand: how Chrome's GREASE brand is computed](https://mosaicbrowser.com/blog/not-a-brand-grease): The Not A Brand entry in Chrome's user agent is computed from the major version by a fixed formula, so a label that doesn't fit the claimed major is a tell.









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