Appy
← Back to Blog
Guide

Chrome Tells Every Server Your Phone Runs Android 10

Since 2023, Chrome on Android sends the same user agent from every phone: Android 10, model K. What that did to deferred deep link matching, why we didn’t fix it with Critical-CH, and how Appy link domains now get the real version and model back. Plus the iOS 26 version of the same problem.

October 1, 2026•7 min read

Every Android phone is a “K” now

Take a Pixel on the latest Android and a Galaxy that is four years old. Open the same page in Chrome on both. Apart from the Chrome version, the User-Agent header they send is identical: Android 10, device model K.

That isn’t a bug. It is user-agent reduction, a Chrome privacy change that froze the parts of the string that helped fingerprint a device. On Android it came with Chrome 110. According to the Chromium project’s timeline, the rollout began on February 7, 2023 and reached every Android client on May 11, 2023.

Most websites never noticed. Anything that matched app installs to clicks did.

The same header, before and after

Before Chrome 110

Mozilla/5.0 (Linux; Android 9; SM-A205U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.0.0 Mobile Safari/537.36

Chrome 110 and later

Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.0.0 Mobile Safari/537.36
The example pair from chromium.org/updates/ua-reduction. The Android version is frozen at 10 and the model at K; only the Chrome major version still changes.

What it broke for deferred deep links

A deferred deep link has to survive an install. When the store can carry a token, it does: Google Play and Huawei AppGallery both hand the new app an install referrer, and that settles the match exactly. When it can’t, because the install started from a store search, a sideload or a store without a referrer, all that is left is a guess. Find a recent click from the same network and ask whether it looks like the same phone.

“Looks like” used to lean on the user agent. A click from Android 14 was a poor candidate for a phone that reports Android 15 on its first launch, and a click from a Galaxy was a poor candidate for a Pixel. After the reduction, every Chrome click said Android 10 and K. The version stopped narrowing anything down, and on a busy network, an office or a campus, every Android phone in the building looked like every other one.

Appy reads Android 10; K as what it is: no version and no model. With nothing else on the click, every Android click from the same network looked the same, and Appy couldn’t tell your new user’s phone apart from the others.

The textbook fix counts every click twice

Chrome didn’t delete the information. It moved it into User-Agent Client Hints. A few low-entropy hints come with every request: the browser brand and major version, whether the device is mobile, and the platform name. The two that matter here, Sec-CH-UA-Platform-Version and Sec-CH-UA-Model, are high-entropy. Chrome sends them only after the site asks with an Accept-CH response header, so the first request to a site never carries them.

For data a page needs on the very first load, Google’s Privacy Sandbox guide to the Android reduction (February 27, 2023) points to Critical-CH. The server names the hints it can’t work without; Chrome sees they were missing, drops the response and sends the request again with the hints attached.

“Again” is the catch. For a redirect service, that retry is a second navigation to the same link: every Android tap would be counted twice and leave two click records behind. We would rather do a little more work than put wrong numbers in every customer’s dashboard, so Appy doesn’t use Critical-CH.

What Appy link domains do instead

Two mechanisms: one for the first tap from a browser, one for every tap after it.

Chrome on the phone

acme.appy.to

  1. 01First tap on a link
    GET /spring HTTP/2
    Host: acme.appy.to
    User-Agent: Mozilla/5.0 (Linux; Android 10; K) … Chrome/154.0.0.0 Mobile Safari/537.36
    Sec-CH-UA-Mobile: ?1
    Sec-CH-UA-Platform: "Android"

    Low-entropy hints only. The user agent says Android 10, model K.

  2. 02Hand-off page
    HTTP/2 200
    Accept-CH: Sec-CH-UA-Platform-Version, Sec-CH-UA-Model
    Content-Type: text/html; charset=utf-8

    The page that opens the app or the store. Accept-CH asks for both hints on every later request.

  3. 03Before the hand-off
    const hints = await navigator.userAgentData
      .getHighEntropyValues(["platformVersion", "model"])
    → {platformVersion: "16.0.0", model: "Pixel 9", …}
    navigator.sendBeacon(…)

    The page reads the real values, attaches them to this click’s record, then hands off.

  4. 04Every later tap
    GET /summer HTTP/2
    Host: acme.appy.to
    Sec-CH-UA-Platform-Version: "16.0.0"
    Sec-CH-UA-Model: "Pixel 9"

    Chrome remembers the request for this origin until the user clears site data, so the hints now travel as headers. No script, no retry.

One navigation per tap, so one click in the statistics. Header values are examples.

What the real version and model change

With the real version and model on the click, the click and the phone have to agree on both. The SDK reports the phone’s model from Build.MODEL when the app first opens, so the two can be compared. A Pixel 9 click can no longer be taken for a Galaxy install, and a click from Android 15 no longer fits a phone on Android 16.

The difference shows most on crowded networks. On an office network with forty phones, clicks from other models drop out, and the Pixel’s own click is often the only one left.

All of this is about installs that arrive without a token. On Android, the Google Play and AppGallery install referrers still settle most installs first, and Client Hints are there for the rest. Without a referrer or a click id, Appy can’t verify the install, so with strict attribution on, it counts as organic however well the click fits.

One office network, before and after

A Pixel 9 on a busy office network opens the app for the first time, four minutes after its owner tapped a link. They closed the store page the link opened and installed the app from a Play Store search instead, so no referrer arrives.

Android version on the click
Before: “Android 10; K”10, the frozen value
After: Client Hints16
Phone model on the click
Before: “Android 10; K”K, which means unknown
After: Client HintsPixel 9
Checked against the phone on first launch
Before: “Android 10; K”Nothing to check against Android 16 and Pixel 9
After: Client HintsSame version and model on both
Other Android clicks from the office
Before: “Android 10; K”Look exactly like the Pixel’s
After: Client HintsOnly other Pixel 9s on Android 16 still fit
Result
Before: “Android 10; K”Could be matched to another Android user’s click
After: Client HintsMatched to the Pixel’s own click
Same install, same network. Once the click carries the real version and model, clicks from other phones stop competing with the Pixel’s own.

iOS froze its own number

Safari reached the same place by another road. Apple’s Safari 26.0 release notes say Safari now reports a frozen OS version in its user agent on iOS 26 and iPadOS 26, the last version released before iOS 26. In practice an iPhone on iOS 26 calls itself “iPhone OS 18_6”. The Version/26.0 token further along the string still follows Safari itself.

Safari doesn’t support User-Agent Client Hints, so there is nothing to ask for. Appy handles it in matching instead: when the phone runs iOS 26 or later, a click that says iOS 18.6 is read as “26 or later”, not as an exact version, because Safari no longer says which one.

If you match installs yourself

None of this is specific to Appy.

01

Treat “Android 10; K” as unknown

Parse it and set it aside. A frozen value that looks like data does more harm than an empty field.

02

Ask for hints on the domain that serves the click

Send Accept-CH: Sec-CH-UA-Platform-Version, Sec-CH-UA-Model from your link domain, and read navigator.userAgentData on the first visit, when the headers can’t be there yet.

03

Count what a retry does before you add Critical-CH

A retried navigation is a second request. If you count requests, deduplicate them or leave the retry out.

04

Map iOS 18.6 to “26 or later”

Don’t reject an iOS 26 install because its click said 18.6. Treat it as iOS 26 or later, not as an exact version.

05

Prefer tokens to guesses

Install referrers and click ids beat any user agent. Guess only when nothing deterministic arrived, and say that it is a guess.

Read next

Frequently asked questions

Why does Chrome say Android 10 on every phone?

User-agent reduction. Since Chrome 110, rolled out between February and May 2023, Chrome on Android freezes the OS version at 10 and the device model at K in the User-Agent string. The real values are available through User-Agent Client Hints.

How do I get the real Android version in Chrome?

Ask for the Sec-CH-UA-Platform-Version hint with an Accept-CH response header, or call navigator.userAgentData.getHighEntropyValues(["platformVersion"]) in the page. The header only arrives on requests made after Chrome has seen your Accept-CH.

Does Critical-CH fix the first request?

It gets you the hints by making Chrome repeat the request. That works for ordinary pages. For anything that counts requests, such as redirects or click tracking, the repeat looks like a second visit unless you deduplicate it.

What does Safari report on iOS 26?

A frozen OS version. On iOS 26 and iPadOS 26 Safari reports the last version released before iOS 26, in practice 18_6, while the Version/26 token still follows Safari. Safari doesn’t support User-Agent Client Hints.

Are Android WebViews and in-app browsers reduced too?

Not by default yet. Google has said the default WebView user agent will get the same treatment starting with Android 17, and apps that set their own user agent keep it.

Continue exploring

Guide
Aug 14, 2026
11 min read

Deferred Deep Linking Without an SDK: How It Actually Works Under the Hood

You can carry link intent across an app install without embedding an attribution SDK. What actually survives the store boundary on Android and iOS, what breaks, and what each workaround costs in privacy.

deferred deep linking
install referrer
ios
android
Read article
Product
Oct 1, 2026
8 min read

Know Which Link Brought Every Install: Appy’s iOS and Android SDK

Appy now follows your links past the app store: installs, in-app events and revenue for every link, QR code and campaign, and new users who open on the right screen.

install attribution
deferred deep linking
install referrer
mobile attribution
Read article
Guide
May 14, 2026
9 min read

Deferred Deep Linking: How It Works and When to Use It

Understand how deferred deep linking carries the original link intent across install so new users land on the right in-app screen, not a generic home tab.

deferred deep linking
install referrer
deep linking
mobile attribution
Read article

Looking for something else? Browse all topics on the blog.

Match installs on evidence, not on “Android 10”

Appy link domains now ask for Client Hints. Deferred deep linking and install attribution come with the SDK on the Enterprise plan, and smart links start free.