L’agent utilisateur ou l’« User-Agent »
Les développeurs Web utilisent depuis toujours l’« User-Agent » (agent utilisateur) pour récupérer des informations sur l’équipement de l’utilisateur. Comme le navigateur, la version, le système d’exploitation, la langue, la résolution, etc. Le tout envoyé au serveur par le navigateur via ce qu’on appelle l’entête de la requête HTTP.
L’« User-Agent » donne aux serveurs la possibilité d’optimiser l’expérience utilisateur. Rappelez-vous les différences incroyables entre Netscape 3 et Internet Explorer 3 à l’ère du DHTML. Que dire de la révolution de Netscape 6 ou d’Internet Explorer 5 avec ses nombreuses fonctionnalités inédites que la W3C a reprises par la suite. Un vrai défi à l’époque! Si la compatibilité est aujourd’hui "plus facile" (il y a encore beaucoup d’Internet Explorer...), la méthode reste toujours très utilisée pour optimiser et personnaliser l’expérience utilisateur, notamment les images adaptées à la résolution ou à la vitesse de connexion.
Mais voilà, le développement de Chromium et Mozilla, derrière la plupart des navigateurs Web, gèle maintenant les chaînes « User-Agent » (agent utilisateur) envoyées par le navigateur. Leurs navigateurs n’enverront jamais « Windows NT 11.0 » pour indiquer que le navigateur fonctionne sous Windows 11. La raison, selon la W3C « La valeur de cet en-tête expose beaucoup plus d’informations sur l’appareil de l’utilisateur que ce qui semble approprié par défaut, d’une part, et obscurcit intentionnellement le véritable agent utilisateur afin de contourner les heuristiques côté serveur erronées, d’autre part. »
Il y a un sens temporaire dans l’expression « geler »! D’autre part, il est vrai que l’User-Agent donne beaucoup d’information, une véritable signature, emmagasinée en clair dans les fichiers journaux des serveurs. Ou encore capturé par les statistiques comme Google Analytics pour être ensuite exploité par le département du SEO. C’est aussi vrai que l’User-Agent sert aussi pour tromper les serveurs, manipulée. Il est très facile de modifier la chaîne « User-Agent et les fraudeurs s’en donnent d’ailleurs à cœur joie sans parler des engins de recherches...
Il faut quand même extraire l’information de l’User-Agent, souvent codée pour des contraintes de développement internes, il faut souvent deviner. Par exemple :
- x11 = Linux
- kde = konqueror
- ppc = Mac PowerPC
- 68k ou 68000 = Macintosh
- windows nt 4.0 = Windows NT
- windows nt 5.0 = Windows 2000
- windows nt 5.1 et Windows nt 5.2 = Windows XP
- windows nt 6.0 = Windows Vista
- windows nt 6.1 et windows nt 7.0 = Windows 7...
Windows est vraiment un champion, mais que dire des moteurs (Gecko, Mozilla, MSIE, Safari, Chrome...) derrières les navigateurs, à en perdre son latin! Exemple d’une chaine User-Agent de Windows 11 avec Edge. Voir mon vieux code « twCompteur, mesure d’audience en ASP » pour vous donner une bonne idée du défi!
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML; like Gecko) Chrome/99.0.4844.74 Safari/537.36 Edg/99.0.1150.46 » C’est un navigateur Mozilla, Apple, Gecko, Chrome, Safari ou Edge? // Code pour récupérer l’User-Agent <script> console.log(navigator.userAgent); </script>
Personnellement, je n’utilise pas l’User-Agent pour personnaliser l’expérience utilisateur. Je développe toujours pour tous les navigateurs. Je teste une fonctionnalité JavaScript et même CSS avant de l’utiliser, etc. Que dire de Polyfill.io, une librairie spécialement conçue pour ça. Et le site Caniuse.com pour comparer la compatibilité des navigateurs.
J’utilise l’User-Agent dans mes statistiques pour justifier la compatibilité, pour prouver que telle résolution est largement utilisée ou tel navigateur est encore utilisé, ou que 50% des visiteurs utilisent un téléphone mobile... En d’autres mots, je pourrais me passer de ces données intrusives sans problème et me contenter de consulter un site comme whatismybrowser.com pour avoir une très bonne idée des outils en circulation.
Client Hints ou réduire les informations de l’User-Agent!
L’User-Agent est mort, vive le Client Hints
Avec autant d’informations sur l’utilisateur sinon davantage!
C’est pourquoi ils ont créé une approche dite « plus respectueuse de la vie privée » pour accéder aux informations du navigateur, le « Client Hints »! Hum, je ne suis pas convaincu d’obtenir moins d’informations personnelles comparées à la signature de l’User-Agent de ma vieille tablette Samgsung « Mozilla/5.0 (Android 7.1.1; Mobile; rv:98.0) Gecko/98.0 Firefox/98.0 »! En principe oui, on a même un exemple qui démontre bien le principe de l’offre et la demande du jeu des entêtes. Mais pour l’instant, mes scripts retournent la total, exactement comme l’exemple de browserleaks.com peu importe le niveau de « Protection contre le suivi » de mon navigateur Edge ou Chrome... Espérons, on n’est pas à une tentative près!
Selon Chrome « Feature: Reduce User Agent string information » :
La définition officiel de mdn web docs « Indications du client (client hints) » :
Les indications du client sont un ensemble d’en-têtes de requêtes HTTP qu’un serveur peut demander de façon proactive à un client afin de connaître les caractéristiques spécifiques à l’appareil du client et aux préférences utilisées dans l’agent utilisateur. L’ensemble des en-têtes pour ces « indications » sont listées dans En-têtes HTTP > Indications du client.
Un serveur doit annoncer sa prise en charge de telles indications via l’en-tête Accept-CH (en-US) qui contiendra les indications du client qui l’intéressent. Lorsqu’un client qui prend en charge cette fonctionnalité reçoit cet en-tête Accept-CH, il ajoute les en-têtes d’indication correspondantes aux requêtes suivantes.
Ainsi, après avoir reçu l’en-tête Accept-CH suivant dans une réponse. Le client pourrait ajouter les en-têtes Width (en-US), Viewport-Width (en-US), et Downlink (en-US) aux requêtes suivantes.
Accept-CH: Width, Viewport-Width, Downlink
L’idée consiste à envoyer dans l’entête du document une demande d’information au navigateur.
- Le navigateur demande une page
- Le serveur retourne dans l’entête une demande d’information supplémentaire, le Client Hints
- Le navigateur retourne le Client Hints avec les données, s’il le veut bien (de là le meilleur respect de la vie privée)
Vous pouvez définir ces en-têtes dans n’importe quel langage backend. Et même avec l’attribut http-equiv de la balise :
Exemple de Chrome en HTML Le serveur demande la largeur de la fenêtre et la vitesse de connexion <meta http-equiv="Accept-CH" content="Viewport-Width, Downlink" /> Pour identifier le navigateur et le système d’exploitation : <meta http-equiv="Accept-CH" content="UA, UA-Platform, UA-Arch, UA-Model, UA-Mobile, UA-Full-Version" /> Exemple en PHP header("accept-ch: Sec-Ch-Ua-Platform,Sec-Ch-Ua-Platform-Version"); Exemple en .NET <script runat="server"> private void Page_Load(object sender, System.EventArgs e) { Response.AddHeader("Accept-CH","Sec-Ch-Ua-Platform,Sec-Ch-Ua-Platform-Version"); } </script> Exemple en ASP Response.AddHeader "Accept-CH", "Sec-Ch-Ua-Platform,Sec-Ch-Ua-Platform-Version" Exemple fichier web.config sous IIS <?xml version="1.0" encoding="UTF-8"?> <configuration> <system.webServer> <httpProtocol> <customHeaders> <add name="accept-ch" value="Sec-Ch-Ua-Platform,Sec-Ch-Ua-Platform-Version" /> </customHeaders> </httpProtocol> </system.webServer> </configuration> Exemple en Django class ClientHintsMiddleware(MiddlewareMixin): def process_response(self, request, response): response[’accept-ch’] = "Sec-Ch-Ua-Platform,Sec-Ch-Ua-Platform-Version" return response
Processus
Par défaut, le navigateur envoie l’entête Sec-CH-UA dans sa requête au serveur sans les champs d’ « entropie plus élevée ». Un Client Hints partiel. Le serveur doit alors lui transmettre dans l’entête de sa réponse la demande « Accept-CH ». Par exemple Accept-CH: sec-ch-ua-platform. Lors de cette requête initiale, le navigateur enregistrera les préférences Accept-CH et lors des requêtes ultérieures inclura sec-ch-ua-platform par défaut.
À partir de Microsoft Edge version 96, vous pouvez utiliser le nouvel entête Critical-CH pour recevoir les en-têtes à haute entropie souhaités avec des performances optimisées.
N’oubliez pas que les préférences Critical-CH et Accept-CH persistent jusqu’à ce que les cookies de session soient effacés, ou jusqu’à ce qu’un utilisateur efface les données du site ou les cookies pour une origine donnée. Pour plus d’informations sur Critical-CH, reportez-vous à la section Fiabilité de l’indice client.
Le code : La collecte de données
La collecte des données est quant à moi plus simple avec le Client Hints, l’information n’a pas à être extraite et analysée. À part un petit ajustement à faire avec la version de Windows (platformVersion) qui nous sert, fidèle à son habitude, les versions 1 à 12 pour identifier Windows 10 et les versions 13 ou plus pour Windows 11, il suffit de savoir manipuler un fichier Json.
Bon, il y a effectivement un petit détail embêtant qui peut en rebuter plusieurs. Il suffit de lire sur le web les commentaires des développeurs qui se plaignent de la difficulté d’intégrer cette fonctionnalité à leur programme. Essentiellement en raison du délai de l’entête. Il faut attendre la deuxième réponse du navigateur avant d’avoir accès aux données! Vous pouvez utiliser la réponse du serveur « Critical-CH » (voir plus haut), mais nous verrons plus bas comment accéder à ces informations dès le premier chargement de la page en utilisant une seconde requête asynchrone en JavaScript (Ajax)...
Un autre détail important, Firefox n’offre pas cette fonctionnalité et donc pour répondre à la question chaude à l’heure d’écrire ces lignes, non c’est impossible de détecter Windows 11 avec Firefox. J’ai donc dans mon nouveau système de statistiques deux nouveaux systèmes d’exploitation « Windows 11 » et « Windows 10 ou 11 »! Il semblerait que la méthode pressentie par l’équipe de Firefox ne puisse répondre au "caractère changeant" du Client Hints « Cap Windows version in the User-Agent to 10.0 - Bugzilla ».
À part Firefox qui ne supporte pas encore le Client Hints, mais qui semble sérieux dans la démarche, laissons les majors faire semblant de se préoccuper de la vie privée. Et entrons dans les détails des données d’or et déjà disponibles! Tout part de l’API « navigator »!
L’objet « connection »
La propriété navigator.connection
retourne l’objet « NetworkInformation » concernant des informations sur la connexion du système, comme la bande passante. Ça reste quant à moi une façon d’augmenter la précision de la signature d’un utilisateur, mais en théorie, c’est pour servir une page adaptée au type de connexion de l’utilisateur :
downlink : Renvoie l’estimation de la bande passante effective en mégabits par seconde, arrondie au multiple le plus proche de 25 kilobits par seconde.
downlinkMax : Renvoie la vitesse de liaison descendante maximale, en mégabits par seconde (Mbps), pour la technologie de connexion sous-jacente./p>
effectiveType : Renvoie le type effectif de la connexion, c’est-à-dire ’slow-2g’, ’2g’, ’3g’ ou ’4g’. Cette valeur est déterminée à l’aide d’une combinaison de valeurs de temps d’aller-retour et de liaison descendante récemment observées.
rtt : Renvoie le temps d’aller-retour effectif estimé de la connexion actuelle, arrondi au multiple de 25 millisecondes le plus proche.
saveData : Renvoie vrai si l’utilisateur a défini une option d’utilisation réduite des données sur l’agent utilisateur.
type : Renvoie le type de connexion qu’un appareil utilise pour communiquer avec le réseau. Ce sera l’une des valeurs suivantes : bluetooth, cellular, ethernet, none, wifi, wimax, other, unknown.
Exemple :
<script> if ("connection" in navigator) { console.log(`Vitesse de connexion : ${navigator.connection.downlink} Mbps`); console.log(`Vitesse de connexion maximale : ${navigator.connection.downlinkMax} Mbps`); console.log(`Type de connexion : ${navigator.connection.effectiveType}`); console.log(`Temps de parcours : ${navigator.connection.rtt} ms`); console.log(`Sauvegarde autorisation : ${navigator.connection.saveData}`); console.log(`Type : ${navigator.connection.type}`); console.log(`Mémoire : ${navigator.deviceMemory}`); } else { console.log('ERREUR : connection n’est pas défini'); } </script>
Performance Timeline API
L’API Performance Timeline permet de récupérer les paramètres concernant la performance de la connexion. La durée, le type de chargement, nouvelle visite ou actualisation de la page, poids de la page... Noter qu’il s’agit d’une matrice (array).
Exemple :
<script> if (window.performance && performance.getEntriesByType) { let navTiming = performance.getEntriesByType('navigation'); console.log(`Type de chargement : ${navTiming[0].entryType}`); console.log(`Page :${navTiming[0].name}`); console.log(`Durée : ${navTiming[0].duration}`); console.log(`Arrivée : ${navTiming[0].type}`); //reload ou navigate console.log(`Poids encodé : ${navTiming[0].encodedBodySize}`); console.log(`Poids décodé : ${navTiming[0].decodedBodySize}`); } else { console.log('ERREUR : performance n’est pas défini'); } </script>
Navigator.geolocation
Navigator.geolocation est une propriété qui retoune un objet Geolocation donnant accès aux contenus web de localisation de l’appareil. Ceci permet à un site Internet ou à une application d’offrir des résultats personnalisés basés sur la localisation des utilisateurs comme la devise, etc. Particulièrement « Geolocation.getCurrentPosition() » compatible avec tous les navigateurs! Personnellement, je trouve l’expérience tellement intrusive, voire agressive, que je ne l’utilise jamais... Mais au moins, le navigateur demande l’autorisation. C’est la seule information que le navigateur semble protéger!
<script> // Source mdn web docs var options = { enableHighAccuracy: true, timeout: 5000, maximumAge: 0 }; function success(position) { console.log(`Latitude : ${position.coords.latitude}`); console.log(`Longitude : ${position.coords.longitude}`); console.log(`Précision : ${position.coords.accuracy} mètres.`); console.log(`Altitude : ${position.coords.altitude} mètres.`); console.log(`Précision d’altitude : ${position.coords.altitudeAccuracy} mètres.`); } function error(err) { console.warn(`ERREUR (${err.code}): ${err.message}`); } navigator.geolocation.getCurrentPosition(success, error, options); </script>
L’objet « userAgentData »
Exemple de la réponse du navigateur par défaut, sans information sur la version du système d’exploitation :
Sec-CH-UA: "Chromium";v="92", "Microsoft Edge";v="92", "Placeholder;Browser Brand";v="99" Sec-CH-UA-Mobile: ?0 Sec-CH-UA-Platform: "Windows"
Le Client Hints complets (voir la liste complète). Le tableau suivant montre tous les entêtes de réponse du serveur Accept-CH disponibles avec exemples. C’est à dire la version 91 du navigateur Edge sous windows 10 avec une Surface Pro :
Sec-CH-UA | "Chromium";v="91", "Microsoft Edge";v="91", "GREASE";v="99" |
Sec-CH-UA-Mobile | ?0 |
Sec-CH-UA-Full-Version | 91.0.866.0 |
Sec-CH-UA-Platform | Windows |
Sec-CH-UA-Platform-Version | 10.0 |
Sec-CH-UA-Arch | x86 |
Sec-CH-UA-Bitness | 64 |
Sec-CH-UA-Model | Surface Pro |
HTTPS
.Comme je disais plus tôt, il y a deux difficultés pour accéder aux données des conseils client. Le premier c’est l’objet navigator.userAgentData retourne une chaine JSON. Exemple du noeud « brands » :
{
"brands": [
{
"brand": "Chromium",
"version":"91"
},
{
"brand": "Microsoft Edge",
"version":"91"
},
{
"brand": "GREASE",
"version":"99"
}
],
"mobile": false
}
Le deuxième c’est le délai avant d’obtenir les données. Contrairement aux User-Agent, les conseils client ne sont pas disponibles lors du premier chargement de la page. Il faut attendre la réponse du client. C’est pourquoi tant de développeurs ont de la difficulté à l’intégrer dans leur programmation. Certain parle d’une boucle, d’autres de la directive defer
, async
ou encore await
. Je sais, j’ai aussi essayé. Ça fonctionne, mais pas toujours! Le temps de réponse est tellement imprévisible qu’il est impossible de prévoir le coup!
// NE FONCTIONNE PAS
let ua = await navigator.userAgentData.getHighEntropyValues(["platformVersion"])
Extraire les informations
La seule solution est effectivement d’attendre les données, mais avec un Ajax, idéalement avec une promesse de retour, c’est-à-dire Promise
. Commençons par le début, et laissons la console du navigateur faire tous le travail :
<script> if (!’userAgentData’ in navigator) { console.log(’userAgentData n’est pas défini!’); } else { console.log(’userAgentData est défini!’); navigator.userAgentData.getHighEntropyValues([ "architecture", "model", "platform", "platformVersion", "uaFullVersion", ]).then((ua) => { // Une fois le résultat reçu, afficher l’objet complet : console.log(ua) }); } </script>
Résultat :
{ "architecture": "x86", "brands": [ { "brand": " Not A;Brand", "version": "99" }, { "brand": "Chromium", "version": "99" }, { "brand": "Microsoft Edge", "version": "99" } ], "mobile": false, "model": "", "platform": "Windows", "platformVersion": "14.0.0", "uaFullVersion": "99.0.1150.46" }
Wow, voilà l’identification de notre foutu Windows 11! Bon, vous remarquerez que c’est indiqué la version 14. Microsoft parle de version 13 et plus!! On n’est pas encore sortie des limbes des majors, mais avouons que c’est plus clair que le vieux User-Agent. Et pas si compliqué que ça en fin de compte! Voici le code suggéré par Microsoft pour extraire l’information, toujours à l’aide d’une promesse de réponse :
<script> navigator.userAgentData.getHighEntropyValues(["platformVersion"]) .then(ua => { // Une fois le résultat reçu, extraire l'info : if (navigator.userAgentData.platform === "Windows") { // Dans ce cas-ci, seulement si c'est Windows const majorPlatformVersion = parseInt(ua.platformVersion.split('.')[0]); if (majorPlatformVersion >= 13) { console.log("Windows 11 ou plus"); } else if (majorPlatformVersion > 0) { console.log("Windows 10"); } else { console.log("Avant Windows 10"); } } else { console.log("Ce n'est pas Windows"); } }); </script>
Version | platformVersion |
---|---|
Win7/8/8.1 | 0 |
Win10 1507 | 1 |
Win10 1511 | 2 |
Win10 1607 | 3 |
Win10 1703 | 4 |
Win10 1709 | 5 |
Win10 1803 | 6 |
Win10 1809 | 7 |
Win10 1903 | 8 |
Win10 1909 | 8 |
Win10 2004 | 10 |
Win10 20H2 | 10 |
Win10 21H1 | 10 |
Win10 21H2 | 10 |
Win11 | 13+ |
Petit bout de mon code perso
Ma technique personnelle consiste à créer une classe JavaScript avec les informations disponibles dès la réception de la page. En l’occurrence tout ce que l’User-Agent permet encore, les informations de connexion, etc. Et surtout d’ajouter à ma classe des fonctions pour modifier certaines valeurs, notamment la version du système d’exploitation que le navigateur recevra éventuellement à l’aide de la promesse de données de Client hints :
<script> // Fichier : twjournaux.js // Ma classe twUserAgent conventionnelle à l’aide du User-Agent (partiel) // Avec les 4 fonctions pour modifier le navigateur et l’OS var twUserAgent = (function() { this.setOs = function (sOsTemp) {this.twOs = sOsTemp;}; this.setOsV = function (sOsVTemp) {this.twOsV = sOsVTemp;}; this.setNav = function (sNavTemp) {this.twNav = sNavTemp;}; this.setNavV = function (sNavVTemp) {this.twNavV = sNavVTemp;}; this.twSw = screen.width; this.twSh = screen.height; this.twSc = window.screen.colorDepth; //... debogue = function() { // Trace pour prouver que les données ont bien été reçues console.log(`OS : ${twUserAgent().twOs}`); console.log(`OS version : ${twUserAgent().twOsV}`); console.log(`Navigateur : ${twUserAgent().twNav}`); console.log(`Navigateur version : ${twUserAgent().twNavV}`); console.log(`Largeur de l'écran : ${twUserAgent().twSw}`); console.log(`Hauteur de l'écran : ${twUserAgent().twSh}`); console.log(`Couleurs : ${twUserAgent().twSc}); } return this; }); var uADPlatforme,uADArchitecture,uADVersionPlateforme,uADVersionApp,uADModel; if (navigator.userAgentData) { uADPlatforme = navigator.userAgentData.platform; navigator.userAgentData.getHighEntropyValues(["architecture","platform","platformVersion","model","uaFullVersion","fullVersionList","bitness","mobile"]) .then(uaPV => { // Exécuté seulement quand les données sont disponibles // Extraction des données à partir de la réponse Json let sVersionPlateforme = parseInt(uaPV.platformVersion.split('.')[0]); // Conversion du numéro de version si Windows(!) if (uADPlatforme=="Windows") { if (sVersionPlateforme >= 13) { sVersionPlateforme = 11 } else if (sVersionPlateforme > 0) { sVersionPlateforme = 10 } else { sVersionPlateforme = "" } } let sNavigateurTemp; let sNavigateurVersionTemp; const brands = [... Object.entries(navigator.userAgentData.brands)]; // Petite passe pour détecter le navigateur parmi la liste « brands » retournée // « userAgentData.brands » contient des valeurs variables dans un ordre variable, // on ne peu se fier à un certain index. // Mais le nom du navigateur est claire. Il suffit de le comparer : // (un code qui demande un peu d’amélioration!) brands.forEach((brand) => { if (/chrome/i.test(brand[1].brand)){sNavigateurTemp = brand[1].brand;sNavigateurVersionTemp = brand[1].version;} if (/opera/i.test(brand[1].brand)){sNavigateurTemp = brand[1].brand;sNavigateurVersionTemp = brand[1].version;} // En principe, Firefox est impossible... if (/firefox/i.test(brand[1].brand)){sNavigateurTemp = brand[1].brand;sNavigateurVersionTemp = brand[1].version;} if (/samsung/i.test(brand[1].brand)){sNavigateurTemp = brand[1].brand;sNavigateurVersionTemp = brand[1].version;} if (/vivaldi/i.test(brand[1].brand)){sNavigateurTemp = brand[1].brand;sNavigateurVersionTemp = brand[1].version;} if (/brave/i.test(brand[1].brand)){sNavigateurTemp = brand[1].brand;sNavigateurVersionTemp = brand[1].version;} if (/maxthon/i.test(brand[1].brand)){sNavigateurTemp = brand[1].brand;sNavigateurVersionTemp = brand[1].version;} if (/avast/i.test(brand[1].brand)){sNavigateurTemp = brand[1].brand;sNavigateurVersionTemp = brand[1].version;} if (/avant/i.test(brand[1].brand)){sNavigateurTemp = brand[1].brand;sNavigateurVersionTemp = brand[1].version;} if (/edge/i.test(brand[1].brand)){sNavigateurTemp = brand[1].brand;sNavigateurVersionTemp = brand[1].version;} }); // Modification des données de ma classe « twUserAgent » avec les nouvelles données du Client Hints. twUserAgent().setOs(uADPlatforme); twUserAgent().setOsV(sVersionPlateforme); twUserAgent().setNav(sNavigateurTemp); twUserAgent().setNavV(sNavigateurVersionTemp); if (document.getElementById("oCompteur").getAttribute(’data-debogue’)=="1") { // Trace du résultat final en mode débogage twUserAgent().debogue(); } // Vous pouvez ajouter ici un code pour emmagasiner les données sur un serveur // Par exemple, ce code qui respecte le (Content-Security-Policy)... // var oScript = document.createElement("script"); // oScript.async = true; // oScript.src = ’script.php?s=[données]’; // document.body.appendChild(oScript); }); } else { // Méthode conventionnel pour détecter le navigateur et le système d'exploitation... // Seulement pour l’exemple twUserAgent().setOs("Plateforme"); twUserAgent().setOsV("Version de la plateforme"); twUserAgent().setNav("Navigateur"); twUserAgent().setNavV("Version du navigateur"); if (document.getElementById("oCompteur").getAttribute(’data-debogue’)=="1") { // Trace du résultat final en mode débogage twUserAgent().debogue(); } } </script> // Fichier HTML // Balise pour afficher un compteur par exemple avec paramètre // ici pour activer un mode débogage <div id="oCompteur" data-debogue="1"></div> <script defer src="/neural/js/twjournaux.js?v3.6.0"></script>
Il y a évidemment d’autres données de disponibles, je vais au fil du temps bonifier ce script. Pour vous donner une bonne idée, consulter le page Client Hints de Browserleaks.com qui extrait toutes les données.
Conclusions
Voilà, il ne vous reste plus qu’à utiliser ou stocker ses données dans vos fichiers journaux! Je ne saurais dire ce qu’il y a de vraiment nouveau, mais on n’a pas le choix, c’est tout! Il y a tas de capitaines dans un seul navire! Sinon, ça reste encore Beta comme outils, la compatibilité n’est pas au rendez-vous. Certes Firefox, mais aussi côté serveur. Un exemple sous IIS en ASP classique. Voilà tout ce qu’on a sous la main. Comme vous pouvez le constater, j’ai beau actualiser la page, la version du système d’exploitation n’est jamais disponible, peu importe le navigateur :
HTTP_SEC_CH_UA : <%=Request.ServerVariables("HTTP_SEC_CH_UA")%><br /> HTTP_SEC_CH_UA_MOBILE : <%=Request.ServerVariables("HTTP_SEC_CH_UA_MOBILE")%><br /> HTTP_SEC_CH_UA_PLATFORM : <%=Request.ServerVariables("HTTP_SEC_CH_UA_PLATFORM")%><br /> HTTP_Sec_CH_UA_Full_Version : <%=Request.ServerVariables("HTTP_Sec_CH_UA_Full_Version")%><br /> HTTP_Sec_CH_UA_Full_Version_List : <%=Request.ServerVariables("HTTP_Sec_CH_UA_Full_Version_List")%><br />Ce qui retourne avec un navigateur compatible :
HTTP_SEC_CH_UA : " Not A;Brand";v="99", "Chromium";v="99", "Microsoft Edge";v="99" HTTP_SEC_CH_UA_MOBILE : ?0 HTTP_SEC_CH_UA_PLATFORM : "Windows" HTTP_Sec_CH_UA_Full_Version : HTTP_Sec_CH_UA_Full_Version_List :
Merci à Brett de whatismybrowser.com pour son aide!
Références
- Learn about Client Hints par WhatIsMyBrowser Developers
- Feature: Reduce User Agent string information - Chrome Status
- Client hints: What they are? How do they work? Why do we need them? - The Publishing Project
- Client Hints Infrastructure
- User-Agent Client Hints - W3C
- Adapting to Users with Client Hints par Jeremy Wagner (WebFundamentals)
- Detect Windows 11 using User-Agent Client Hints - Microsoft Docs
- Accept-CH - mdn web docs
- Cap Windows version in the User-Agent to 10.0 - Bugzilla
- Polyfill.io
- Detecting Microsoft Edge from your website - Microsoft Docs
- Detect Windows 11 using User-Agent Client Hints - Microsoft Docs
- En-têtes HTTP - mdn web docs
- NetworkInformation - mdn web docs
- NetworkInformation - W3cubDocs
- Performance Timeline API - mdn web docs
- Navigator.geolocation - mdn web docs
- Geolocation.getCurrentPosition() - mdn web docs
- Geolocation API - W3C
- Promise - mdn web docs
- Client Hints - BrowserLeaks