Chrome dit à chaque serveur que votre téléphone tourne sous Android 10
Depuis 2023, Chrome sur Android envoie le même user agent depuis tous les téléphones : Android 10, modèle K. Ce que cela a changé pour le matching des deferred deep links, pourquoi nous ne l’avons pas corrigé avec Critical-CH, et comment les domaines de liens Appy récupèrent désormais la vraie version et le vrai modèle. En prime, la variante iOS 26 du même problème.
Désormais, tout téléphone Android est un « K »
Prenez un Pixel sous la dernière version d’Android et un Galaxy vieux de quatre ans. Ouvrez la même page dans Chrome sur les deux. À la version de Chrome près, l’en-tête User-Agent qu’ils envoient est identique : Android 10, modèle d’appareil K.
Ce n’est pas un bug. C’est la réduction du user agent (user-agent reduction), un changement apporté à Chrome pour protéger la vie privée, qui a figé les parties de la chaîne utiles au fingerprinting d’un appareil. Sur Android, elle est arrivée avec Chrome 110. D’après le calendrier du projet Chromium, le déploiement a commencé le 7 février 2023 et a atteint tous les clients Android le 11 mai 2023.
La plupart des sites web n’ont rien remarqué. Tout ce qui associait des installations d’app à des clics, si.
Le même en-tête, avant et après
Avant Chrome 110
Mozilla/5.0 (Linux; Android 9; SM-A205U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.0.0 Mobile Safari/537.36Chrome 110 et suivants
Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.0.0 Mobile Safari/537.36Ce que ça a cassé pour les deferred deep links
Un deferred deep link doit survivre à une installation. Quand le store peut transporter un jeton, il le fait : Google Play et Huawei AppGallery remettent tous deux un install referrer à la nouvelle app, et la correspondance est établie à coup sûr. Quand il ne le peut pas, parce que l’installation est partie d’une recherche dans le store, d’un sideload ou d’un store sans referrer, il ne reste qu’à deviner : trouver un clic récent venu du même réseau et se demander s’il ressemble au même téléphone.
Pour juger de cette ressemblance, on s’appuyait autrefois sur le user agent. Un clic venu d’Android 14 était un mauvais candidat pour un téléphone qui annonce Android 15 à son premier lancement, et un clic venu d’un Galaxy, un mauvais candidat pour un Pixel. Après la réduction, chaque clic Chrome annonçait Android 10 et K. La version ne permettait plus de départager personne, et sur un réseau très fréquenté, dans un bureau ou sur un campus, chaque téléphone Android du bâtiment ressemblait à tous les autres.
Appy lit Android 10; K pour ce que c’est : ni version, ni modèle. Sans autre information dans le clic, tous les clics Android venus du même réseau se ressemblaient, et Appy ne pouvait pas distinguer le téléphone de votre nouvel utilisateur des autres.
La solution d’école compte chaque clic deux fois
Chrome n’a pas supprimé l’information : il l’a déplacée dans les User-Agent Client Hints. Quelques indices à faible entropie accompagnent chaque requête : la marque et la version majeure du navigateur, le fait que l’appareil soit mobile ou non, et le nom de la plateforme. Les deux qui comptent ici, Sec-CH-UA-Platform-Version et Sec-CH-UA-Model, sont à entropie élevée. Chrome ne les envoie qu’après que le site les a demandés avec un en-tête de réponse Accept-CH : la première requête vers un site ne les contient donc jamais.
Pour les données dont une page a besoin dès le tout premier chargement, le guide Privacy Sandbox de Google consacré à la réduction sur Android (27 février 2023) renvoie vers Critical-CH. Le serveur nomme les indices sans lesquels il ne peut pas travailler ; Chrome constate qu’ils manquaient, jette la réponse et envoie la requête une seconde fois, indices compris.
« Une seconde fois », voilà le hic. Pour un service de redirection, ce nouvel essai est une deuxième navigation vers le même lien : chaque clic sur Android serait compté deux fois et laisserait deux enregistrements de clic. Nous préférons faire un peu plus de travail plutôt que d’afficher des chiffres faux dans le tableau de bord de chaque client : Appy n’utilise donc pas Critical-CH.
Ce que font les domaines de liens Appy à la place
Deux mécanismes : l’un pour le premier clic depuis un navigateur, l’autre pour tous les clics suivants.
Chrome sur le téléphone
acme.appy.to
- 01Premier clic sur un lien
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"Uniquement les indices à faible entropie. Le user agent annonce Android 10, modèle K.
- 02Page intermédiaire
HTTP/2 200 Accept-CH: Sec-CH-UA-Platform-Version, Sec-CH-UA-Model Content-Type: text/html; charset=utf-8La page qui ouvre l’app ou le store. Accept-CH demande les deux indices pour chaque requête suivante.
- 03Avant la redirection
const hints = await navigator.userAgentData .getHighEntropyValues(["platformVersion", "model"]) → {platformVersion: "16.0.0", model: "Pixel 9", …} navigator.sendBeacon(…)La page lit les vraies valeurs, les rattache à l’enregistrement de ce clic, puis passe la main.
- 04Chaque clic suivant
GET /summer HTTP/2 Host: acme.appy.to Sec-CH-UA-Platform-Version: "16.0.0" Sec-CH-UA-Model: "Pixel 9"Chrome retient la demande pour cette origine jusqu’à ce que l’utilisateur efface les données du site : les indices voyagent désormais dans les en-têtes. Pas de script, pas de nouvel essai.
Ce que changent la vraie version et le vrai modèle
Avec la vraie version et le vrai modèle dans le clic, le clic et le téléphone doivent concorder sur les deux. Le SDK remonte le modèle du téléphone depuis Build.MODEL au premier lancement de l’app : on peut donc les comparer. Un clic de Pixel 9 ne peut plus passer pour une installation sur un Galaxy, et un clic venu d’Android 15 ne correspond plus à un téléphone sous Android 16.
C’est sur les réseaux très fréquentés que la différence se voit le plus. Sur le réseau d’un bureau de quarante téléphones, les clics des autres modèles sont écartés, et il ne reste souvent que le clic du Pixel lui-même.
Tout ceci ne concerne que les installations qui arrivent sans jeton. Sur Android, les install referrers de Google Play et d’AppGallery règlent toujours en premier la plupart des installations ; les Client Hints servent pour le reste. Sans referrer ni click ID, Appy ne peut pas vérifier l’installation : avec l’attribution stricte, elle compte comme organique, même si le clic correspond parfaitement.
Un réseau de bureau, avant et après
Un Pixel 9 sur un réseau de bureau très fréquenté ouvre l’app pour la première fois, quatre minutes après que son propriétaire a cliqué sur un lien. Celui-ci a fermé la fiche du store ouverte par le lien, puis installé l’app via une recherche dans le Play Store : aucun referrer n’arrive.
iOS a figé son propre numéro
Safari est arrivé au même point par un autre chemin. D’après les notes de version de Safari 26.0 publiées par Apple, Safari indique désormais dans son user agent une version d’OS figée sur iOS 26 et iPadOS 26 : la dernière version publiée avant iOS 26. En pratique, un iPhone sous iOS 26 se présente comme « iPhone OS 18_6 ». Le jeton Version/26.0, plus loin dans la chaîne, suit toujours la version de Safari.
Safari ne prend pas en charge les User-Agent Client Hints : il n’y a donc rien à demander. Appy le gère plutôt au moment du matching : si le téléphone est sous iOS 26 ou ultérieur, un clic qui annonce iOS 18.6 est lu comme « 26 ou ultérieur », et non comme une version exacte, car Safari ne dit plus laquelle.
Si vous faites vous-même le matching des installations
Rien de tout cela n’est propre à Appy.
Traitez « Android 10; K » comme une valeur inconnue
Analysez-la, puis mettez-la de côté. Une valeur figée qui ressemble à une donnée fait plus de mal qu’un champ vide.
Demandez les indices sur le domaine qui reçoit le clic
Envoyez Accept-CH: Sec-CH-UA-Platform-Version, Sec-CH-UA-Model depuis votre domaine de liens, et lisez navigator.userAgentData lors de la première visite, quand les en-têtes ne peuvent pas encore être là.
Mesurez l’effet d’un nouvel essai avant d’ajouter Critical-CH
Une navigation relancée est une deuxième requête. Si vous comptez les requêtes, dédupliquez-les ou renoncez au nouvel essai.
Traduisez iOS 18.6 par « 26 ou ultérieur »
Ne rejetez pas une installation iOS 26 parce que son clic indiquait 18.6. Traitez-la comme iOS 26 ou ultérieur, et non comme une version exacte.
Préférez les jetons aux estimations
Les install referrers et les click IDs battent n’importe quel user agent. N’estimez que si rien de déterministe n’est arrivé, et dites que c’est une estimation.
À lire ensuite
Questions fréquentes
Pourquoi Chrome annonce-t-il Android 10 sur tous les téléphones ?
À cause de la réduction du user agent. Depuis Chrome 110, déployé entre février et mai 2023, Chrome sur Android fige la version de l’OS à 10 et le modèle de l’appareil à K dans la chaîne User-Agent. Les vraies valeurs restent disponibles via les User-Agent Client Hints.
Comment obtenir la vraie version d’Android dans Chrome ?
Demandez l’indice Sec-CH-UA-Platform-Version avec un en-tête de réponse Accept-CH, ou appelez navigator.userAgentData.getHighEntropyValues(["platformVersion"]) dans la page. L’en-tête n’arrive que sur les requêtes faites après que Chrome a reçu votre Accept-CH.
Critical-CH règle-t-il le problème de la première requête ?
Il vous fournit les indices en obligeant Chrome à répéter la requête. Pour des pages ordinaires, cela fonctionne. Pour tout ce qui compte des requêtes, comme les redirections ou le suivi des clics, cette répétition ressemble à une deuxième visite, sauf si vous la dédupliquez.
Qu’annonce Safari sur iOS 26 ?
Une version d’OS figée. Sur iOS 26 et iPadOS 26, Safari annonce la dernière version publiée avant iOS 26, en pratique 18_6, tandis que le jeton Version/26 suit toujours la version de Safari. Safari ne prend pas en charge les User-Agent Client Hints.
Le user agent des WebView Android et des navigateurs in-app est-il réduit lui aussi ?
Pas encore par défaut. Google a indiqué que le user agent par défaut de WebView recevra le même traitement à partir d’Android 17, et les apps qui définissent leur propre user agent le conservent.
Continuer à explorer
Deferred deep linking sans SDK : comment ça marche vraiment sous le capot
On peut transporter le contexte d’un lien à travers une installation sans embarquer de SDK d’attribution. Voici ce qui survit réellement à la frontière du store sur Android et iOS, ce qui casse, et le coût de chaque contournement en matière de vie privée.
Identifiez le lien derrière chaque installation : le SDK iOS et Android d’Appy
Appy suit désormais vos liens au-delà du store. Le nouveau SDK montre les installations, les événements in-app et les revenus de chaque lien, QR code et campagne, et ouvre l’app des nouveaux utilisateurs sur le bon écran.
Deferred deep linking : comment ça marche et quand l’utiliser
Transportez l’intention initiale du lien à travers l’installation pour que les nouveaux utilisateurs arrivent sur la bonne page et non sur la home par défaut.
Vous cherchez autre chose ? Parcourez tous les sujets sur le blog.
Attribuez vos installations sur des preuves, pas sur « Android 10 »
Les domaines de liens Appy demandent désormais les Client Hints. Le deferred deep linking et l’attribution des installations sont fournis avec le SDK dans l’offre Enterprise, et les smart links démarrent gratuitement.