Kann man dem User-Agent-String noch vertrauen?
Erfahren Sie, welche User-Agent-Angaben zuverlässig bleiben, welche Browser einfrieren und wie Chromium Client Hints und Feature-Erkennung fehleranfälliges Parsing ersetzen.
Teilweise. Der User-Agent-String verrät nach wie vor zuverlässig die Browserfamilie, die Hauptversion, ob es sich um ein Mobil- oder Desktopgerät handelt, sowie die Betriebssystemfamilie. Die Betriebssystemversion, das Gerätemodell, die CPU-Architektur und (in Chromium-Browsern) die Minor-Version des Browsers verrät er dagegen nicht.
Wenn in Ihren Logs Android 10; K von einem Smartphone auftaucht, auf dem offensichtlich kein Android 10 läuft, oder Mac OS X 10_15_7 von einem MacBook mit M-Chip, ist nichts kaputt. Diese Werte sind Platzhalter, und die Browser senden sie absichtlich.
Dieser Artikel zerlegt einen aktuellen Chrome-String und zeigt, welche Felder in den einzelnen Engines eingefroren sind. Anschließend geht es darum, was den String in Chromium ersetzt und wann sich das Parsen noch lohnt.
Die wichtigsten Erkenntnisse
- Jeder große Browser beginnt seinen User-Agent-String weiterhin mit
Mozilla/5.0. Dieses Kompatibilitäts-Token sagt nichts über den sendenden Browser aus. - Chrome meldet unabhängig vom tatsächlichen Betriebssystem-Release
Windows NT 10.0; Win64; x64,Macintosh; Intel Mac OS X 10_15_7,X11; Linux x86_64oderLinux; Android 10; K. Minor-, Build- und Patch-Nummer lauten immer0.0.0. - Ab Safari 26 meldet Safari unter iOS, iPadOS und visionOS eine eingefrorene Betriebssystemversion. Safari auf dem Mac friert die macOS-Version bereits seit 2017 ein.
- User-Agent Client Hints gibt es nur in Chromium-basierten Browsern. Firefox und Safari senden keine
Sec-CH-UA-*-Header. - Jeder Client kann einen beliebigen User-Agent senden. Der Header filtert daher nur Bots heraus, die sich selbst zu erkennen geben.
Was verrät ein Chrome-User-Agent-String tatsächlich?
In einem aktuellen UA-String von Chrome für Desktop ändert sich zwischen den Releases nur ein Segment: die Hauptversion. Alles andere ist entweder ein festes Kompatibilitäts-Token oder ein eingefrorener Plattformwert. So sieht Chrome 154 unter Windows aus:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/154.0.0.0 Safari/537.36
| Segment | Was es behauptet | Stimmt das? |
|---|---|---|
Mozilla/5.0 | Ein Mozilla-kompatibler Browser | Bedeutungslos. Jeder Browser sendet es |
(Windows NT 10.0; Win64; x64) | Windows 10, 64-Bit-x86 | Eingefroren. Windows 11 und ARM-Rechner senden denselben Wert |
AppleWebKit/537.36 (KHTML, like Gecko) | Eine WebKit-Engine, die von KHTML abstammt und Gecko ähnelt | Kompatibilitätsrelikt. Die Engine von Chrome ist Blink |
Chrome/154.0.0.0 | Chrome 154.0.0.0 | Die Hauptversion ist echt. 0.0.0 ist ein Platzhalter |
Safari/537.36 | Safari | Kein Safari. Das Token bleibt erhalten, damit Code, der nach „Safari“ sucht, weiterhin greift |
Die Firefox-Referenz von MDN beschreibt Mozilla/5.0 als generisches Token, das Mozilla-Kompatibilität beansprucht und das nahezu jeder Browser sendet, unabhängig von seiner Engine. Die User-Agent-Referenz von MDN bestätigt, dass Blink-basierte Browser KHTML, like Gecko und Safari ausschließlich als Kompatibilitäts-Tokens mitführen. In einem Chrome-String beschreiben AppleWebKit/537.36 (KHTML, like Gecko) und Safari/537.36 weder die Engine von Chrome noch Safari. Es handelt sich um feste Tokens, die erhalten bleiben, damit alter Sniffing-Code weiterhin greift. Um dieselbe Aufschlüsselung für Ihren eigenen String zu sehen, fügen Sie ihn in den User-Agent-Parser von OpenReplay ein.
Welche User-Agent-Felder sind eingefroren und welche sind noch aussagekräftig?
Alle drei Engines haben die hochentropischen Teile des Strings eingefroren: Betriebssystemversion, Gerätemodell und CPU-Architektur. Chromium setzt zusätzlich die Minor-Version des Browsers auf null. Die niedrigentropischen Teile spiegeln weiterhin den tatsächlichen Browser wider. Mit Chrome 101 (2022) begann Chromes User-Agent-Reduction-Plan, Minor-, Build- und Patch-Nummer fest auf 0.0.0 zu setzen. Seit dem Ende des Deprecation Trials am 23. September 2023, mit dem Websites den vollständigen String weiterhin erhalten konnten, liefert jeder Seitenaufruf den reduzierten String. Der Leitfaden von MDN zur UA-Reduktion führt die festen Plattformwerte auf, darunter Android 10; K unter Android.
| Chrome / Edge | Firefox | Safari | |
|---|---|---|---|
| Browserfamilie, Hauptversion | Echt | Echt | Echt (Version/) |
| Mobil vs. Desktop, Betriebssystemfamilie | Echt | Echt | Echt |
| Betriebssystemversion | Eingefroren | Gedeckelt (macOS 10.15, Android 10) | Eingefroren (macOS; iOS seit 26) |
| Gerätemodell | K unter Android | Wird nie gesendet | Wird nie gesendet |
| CPU-Architektur | Eingefroren | Eingefroren | Mac immer „Intel“ |
| Minor-Version | 0.0.0 | Nicht offengelegt | Echt (Version/) |
| UA Client Hints | Ja | Nein | Nein |
Edge verwendet dieselben eingefrorenen Tokens wie Chrome und ergänzt Edg/. Seit Firefox 87 meldet Firefox jedes macOS-Release ab Big Sur als 10.15 und kennzeichnet Macs mit Apple Silicon als Intel. Seit Firefox für Android 122 meldet der Browser unabhängig von der tatsächlichen Version Android 10. Laut dem WebKit-Blogbeitrag zu Safari 26.0 sendet Safari auf dem Mac seit 2017 denselben Wert Intel Mac OS X 10_15_7. Ab Safari 26 (September 2025) melden auch Safari unter iOS, iPadOS und visionOS statt der tatsächlichen Version eine eingefrorene iOS-18-Version. Safari 26.0 sendete 18_6. Ab Safari 26.2 fixiert WebKit den Wert auf das letzte iOS-18-Release, sodass aktuelle Strings 18_7 senden. Das Version/-Token wird weiterhin mit jedem Release aktualisiert.
Die Reduktion in Chromium umfasst Chrome unter Windows, macOS, Linux, ChromeOS und Android. Android WebView und Chrome für iOS sind davon nicht betroffen. In der Praxis bedeutet das:
- Windows 10 und Windows 11 sind nicht voneinander zu unterscheiden.
- Macs mit Apple Silicon melden in allen drei Engines „Intel“.
- Ein String von Chrome für Android mit
Android 10; Kbeschreibt kein Android-10-Gerät. Jede Chrome-Installation unter Android sendet diese Version und das PlatzhaltermodellK.
Warum ist Feature Detection besser als Browsererkennung?
Der Name eines Browsers sagt nichts Verlässliches darüber aus, was er kann. Feature Detection prüft die Fähigkeit direkt, und das galt schon, bevor irgendein String eingefroren wurde. Eine UA-Prüfung versagt, wenn der String lügt, wenn ein neuer Browser die API ausliefert oder wenn einer älteren Version die API fehlt. Baseline liefert Ihnen einen browserübergreifenden Überblick darüber, ab wann Sie sich auf ein Feature verlassen können. Wo das nicht der Fall ist, schließt eine Laufzeitprüfung die Lücke:
// Brittle: guesses capability from a name
if (/Chrome\/\d+/.test(navigator.userAgent)) enableShareButton();
// Direct: asks the browser
if ('share' in navigator) enableShareButton();
Wie funktionieren User-Agent Client Hints?
User-Agent Client Hints sind eine Reihe von Sec-CH-UA-*-Request-Headern, die Chromium-basierte Browser anstelle der Details senden, die der UA-String nicht mehr enthält. Chrome und Edge senden standardmäßig Sec-CH-UA, Sec-CH-UA-Mobile und Sec-CH-UA-Platform. Firefox und Safari senden keinen davon. MDN stuft Sec-CH-UA-Platform als niedrigentropischen Hint ein. Der Browser sendet ihn daher, ohne dass der Server ihn anfordern muss, sofern keine Permissions Policy ihn blockiert. Alle anderen Hints müssen angefordert werden.
Dazu listet der Server die gewünschten Hints in Accept-CH auf, und der Browser fügt sie bei nachfolgenden sicheren Requests an diesen Origin hinzu.
Auf den ersten Request hat Accept-CH keine Wirkung. Um einen hochentropischen Hint bereits beim allerersten Request zu erhalten, nennt der Server ihn zusätzlich zu Accept-CH auch in Critical-CH. Statt diese erste Antwort zu rendern, sendet der Browser den Request erneut, diesmal mit dem Hint. Der Server sollte den Hint außerdem in Vary aufnehmen, damit Caches jede Variante separat speichern.
import https from 'node:https';
import { readFileSync } from 'node:fs';
https.createServer(
{ key: readFileSync('key.pem'), cert: readFileSync('cert.pem') },
(req, res) => {
const platform = req.headers['sec-ch-ua-platform']; // default hint
const version = req.headers['sec-ch-ua-platform-version']; // opt-in only
res.setHeader('Accept-CH', 'Sec-CH-UA-Platform-Version, Sec-CH-UA-Arch');
res.setHeader('Critical-CH', 'Sec-CH-UA-Platform-Version');
res.setHeader('Vary', 'Sec-CH-UA-Platform-Version, Sec-CH-UA-Arch');
res.setHeader('Content-Type', 'text/plain');
res.end(`platform=${platform ?? 'n/a'} version=${version ?? 'n/a'}\n`);
}
).listen(8443);
Node wandelt Header-Namen in Kleinbuchstaben um. Die Werte kommen als in Anführungszeichen gesetzte Structured-Field-Strings wie "Windows" an. Im Browser liefert navigator.userAgentData.getHighEntropyValues() dieselben Daten, ganz ohne Header-Konfiguration. MDN kennzeichnet uaFullVersion als veraltet und empfiehlt stattdessen fullVersionList.
async function describeClient() {
const uaData = navigator.userAgentData;
if (!uaData) return { source: 'ua', ua: navigator.userAgent }; // Firefox, Safari
const high = await uaData.getHighEntropyValues([
'platformVersion', 'architecture', 'model', 'fullVersionList',
]);
return { source: 'ua-ch', brands: uaData.brands, mobile: uaData.mobile, ...high };
}
Wann ist das Parsen des User-Agent-Strings noch sinnvoll?
Das Parsen ist weiterhin sinnvoll, wenn Sie nur die verlässlichen Felder benötigen und ein Irrtum wenig kostet.
Analytics-Segmente. Das Parsen des User-Agents liefert genaue Ergebnisse für Analytics-Segmente wie „Chrome 154, Desktop, Windows“. Ein Segment „Windows 10“ oder „Android 10“ dagegen nicht: Es schluckt stillschweigend neuere Releases und sollte daher nur als Betriebssystemfamilie interpretiert werden. Prüfen Sie auf Edg/ vor Chrome/ und auf Chrome/ vor Safari/, denn jeder String enthält die Tokens, die in dieser Reihenfolge nach ihm kommen.
Bot-Filterung. RFC 9110 definiert User-Agent als Header, den der Client selbst liefert, und nichts überprüft ihn. Jeder Client kann einen beliebigen Wert senden. Der Header erfasst Crawler, die sich zu erkennen geben, ist aber wirkungslos gegen Bots, die das nicht tun.
Support-Tickets. Wenn ein Nutzer einen Fehler meldet, müssen Sie in der Regel nur ungefähr wissen, was er verwendet hat, nicht den exakten Build. Session-Replay-Tools zeichnen den UA mit jeder Session auf. Das reicht aus, um zu erkennen, dass sich ein Fehler in Firefox unter macOS reproduzieren lässt, nicht aber in Chrome. Wenn Sie zusätzlich die Ergebnisse Ihrer Feature-Prüfungen protokollieren, lässt sich das Problem weiter eingrenzen.
Fazit
Dem User-Agent-String können Sie bei Browserfamilie, Hauptversion, Mobil- oder Desktopgerät und Betriebssystemfamilie vertrauen. Alles andere darin sollten Sie als Platzhalter betrachten. Um diese Erkenntnisse umzusetzen, prüfen Sie Ihren Code auf alle Verzweigungen, die eine Betriebssystemversion, ein Gerätemodell oder eine Minor-Version aus dem String auslesen. Ersetzen Sie UA-basierte Fähigkeitsprüfungen durch Feature Detection, und verlagern Sie echten Bedarf an Plattformdetails auf Client Hints, mit einem Fallback für Firefox und Safari, die diese nicht senden.
FAQs
Wie unterscheide ich Windows 11 von Windows 10, wenn der User-Agent Windows NT 10.0 meldet?
Fordern Sie den Client Hint platformVersion an, entweder mit navigator.userAgentData.getHighEntropyValues(['platformVersion']) oder indem Sie Accept-CH: Sec-CH-UA-Platform-Version senden. Microsoft dokumentiert Werte von 1.0.0 bis 10.0.0 als Windows 10 und Werte ab 13.0.0 als Windows 11. Der Beispielcode von Microsoft behandelt eine Hauptversion ab 13 als Windows 11. Firefox sendet keine Client Hints und kann die beiden Versionen daher nicht unterscheiden.
Wie lange sendet ein Browser Hints weiter, die per Accept-CH angefordert wurden?
Chrome speichert die Accept-CH-Einstellungen jedes Origins auf der Festplatte, und seit Chrome 103 haben sie kein festes Ablaufdatum mehr. Sie bleiben bestehen, bis der Nutzer die Cookies oder Websitedaten für diesen Origin löscht, und werden außerdem zusammen mit Session-Cookies entfernt. Ein Server kann Accept-CH erneut senden, um die Liste zu ersetzen, ein leeres Accept-CH senden, um alle Hints zu beenden, oder Clear-Site-Data: 'clientHints' senden.
Warum enthält der Sec-CH-UA-Header eine Marke wie Not A;Brand?
Es handelt sich um einen absichtlich gefälschten Eintrag, bekannt als GREASE. Chromium fügt eine bewusst falsche Marke mit niedriger Versionsnummer hinzu und variiert deren Zeichensetzung und Position in der Liste. So werden Server gezwungen, den Header korrekt zu parsen, statt einen festen String oder eine feste Markenliste abzugleichen. Parsen Sie Sec-CH-UA als Structured-Field-Liste, suchen Sie nach der benötigten Marke, etwa Chromium, Google Chrome oder Microsoft Edge, und ignorieren Sie alle Einträge, die Sie nicht kennen.
Warum erkennt mein User-Agent-Parser Chrome auf dem iPhone als Safari?
Chrome für iOS sendet den User-Agent-String von Mobile Safari, allerdings mit einem CriOS/-Token anstelle von Version/, sodass der String kein Chrome/-Token enthält. Firefox für iOS macht dasselbe mit FxiOS/. Ein Parser, der nur nach Chrome/ und Firefox/ sucht, landet am Ende bei Safari. Prüfen Sie daher zuerst auf CriOS/ und FxiOS/. Die UA-Reduktion von Chromium gilt nicht für Chrome für iOS.