User-Agent Client Hints — Modern Browser Detection Without UA Sniffing
User-Agent Client Hints replace UA string parsing with structured HTTP headers. Learn how Sec-CH-UA headers work, how to request high-entropy hints, and how to use the...
User-Agent Client Hints (UA-CH) are structured HTTP headers that replace the opaque User-Agent string. Browsers send basic hints by default; servers must request additional detail.
Parse traditional user agent strings with the User-Agent Parser.
Default Client Hints (sent automatically)
Chromium browsers send these on every HTTPS request:
# Browser brand and version (low-entropy):
Sec-CH-UA: "Google Chrome";v="120", "Chromium";v="120", "Not-A.Brand";v="99"
Sec-CH-UA-Mobile: ?0 # 0 = desktop, 1 = mobile (boolean)
Sec-CH-UA-Platform: "Windows" # OS name only
These three headers replace most UA-based detection for:
- “Is this Chrome/Edge/Firefox?” →
Sec-CH-UA - “Is this a mobile device?” →
Sec-CH-UA-Mobile - “What OS?” →
Sec-CH-UA-Platform
Request high-entropy hints via Accept-CH
For more detail (OS version, architecture, full version), respond with Accept-CH:
# Server response: tell browser to send additional hints on next request
HTTP/1.1 200 OK
Accept-CH: Sec-CH-UA-Full-Version-List, Sec-CH-UA-Platform-Version, Sec-CH-UA-Arch
# On subsequent requests, browser sends:
Sec-CH-UA-Full-Version-List: "Google Chrome";v="120.0.6099.109", "Chromium";v="120.0.6099.109"
Sec-CH-UA-Platform-Version: "10.0.0" # Windows 10
Sec-CH-UA-Arch: "x86"
Express middleware to set Accept-CH:
app.use((req, res, next) => {
res.set('Accept-CH', [
'Sec-CH-UA-Full-Version-List',
'Sec-CH-UA-Platform-Version',
'Sec-CH-UA-Arch',
'Sec-CH-UA-Model', // Device model (mobile only)
'Sec-CH-UA-Bitness', // "64" or "32"
'Device-Memory', // RAM in GB (rounded)
].join(', '));
next();
});
All high-entropy Client Hint headers
Low-entropy (sent by default):
Sec-CH-UA Brand list (e.g., Chrome, Chromium)
Sec-CH-UA-Mobile ?0 or ?1
Sec-CH-UA-Platform OS name ("Windows", "macOS", "Android")
High-entropy (require Accept-CH):
Sec-CH-UA-Full-Version-List Full browser versions with minor/patch
Sec-CH-UA-Platform-Version OS version ("10.0.0" for Win10)
Sec-CH-UA-Arch CPU architecture ("x86", "arm")
Sec-CH-UA-Bitness "64" or "32"
Sec-CH-UA-Model Device model (mobile: "Pixel 7")
Sec-CH-UA-WoW64 ?1 if 32-bit browser on 64-bit OS
Device-Memory RAM in GB: 0.25, 0.5, 1, 2, 4, 8
Downlink Network speed in Mbps (estimate)
ECT Connection type: "4g", "3g", "2g", "slow-2g"
RTT Round-trip time in ms (rounded)
Save-Data "on" if user enabled data saver
JavaScript: navigator.userAgentData
In the browser, access client hints without parsing strings:
// Low-entropy data (synchronous):
const uaData = navigator.userAgentData;
uaData.brands;
// [{ brand: 'Google Chrome', version: '120' }, { brand: 'Chromium', version: '120' }, ...]
uaData.mobile; // false
uaData.platform; // "Windows"
// High-entropy data (asynchronous, requires user permission in some browsers):
const highEntropy = await navigator.userAgentData.getHighEntropyValues([
'architecture',
'model',
'platform',
'platformVersion',
'fullVersionList',
'bitness',
'uaFullVersion',
]);
// {
// architecture: "x86",
// bitness: "64",
// brands: [...],
// fullVersionList: [{ brand: 'Google Chrome', version: '120.0.6099.109' }],
// mobile: false,
// model: "",
// platform: "Windows",
// platformVersion: "10.0.0",
// uaFullVersion: "120.0.6099.109"
// }
Browser support and fallback
async function getBrowserInfo() {
// Use Client Hints if available:
if (navigator.userAgentData) {
const data = await navigator.userAgentData.getHighEntropyValues(['platform', 'platformVersion']);
return {
browser: navigator.userAgentData.brands[0]?.brand,
mobile: navigator.userAgentData.mobile,
os: data.platform,
};
}
// Fallback: parse User-Agent string
const ua = navigator.userAgent;
return {
browser: /Chrome\//.test(ua) ? 'Chrome' : /Firefox\//.test(ua) ? 'Firefox' : 'Other',
mobile: /Mobi|Android/i.test(ua),
os: /Windows/.test(ua) ? 'Windows' : /Mac/.test(ua) ? 'macOS' : 'Other',
};
}
Critical: Client Hints only work on HTTPS
HTTPS required for:
- Server-side Accept-CH to be honored
- navigator.userAgentData to work
- High-entropy hints to be sent
HTTP: browsers send only minimal/no client hints
localhost: treated as secure origin (works in development)
Privacy implications
Client hints are designed to reduce fingerprinting compared to the full UA string. High-entropy hints require explicit server opt-in per page/origin, and browsers may prompt users in future versions. The information is available in structured form rather than one long opaque string, making over-collection more visible.
Related tools
- User-Agent Parser — parse traditional UA strings
- HTTP User-Agent Header — understand UA string format
- HTTP Status Codes — HTTP headers reference
Related posts
- Bot Detection Using User Agent Strings — Googlebot, Bingbot, and Crawlers — Identify search engine crawlers, social media bots, and malicious scrapers from …
- Browser Detection in JavaScript — Feature Detection vs User Agent Parsing — Detect browsers, OS, and device type in JavaScript using user agent strings, fea…
- Device Type Detection — Mobile, Tablet, Desktop in JavaScript — Detect whether a user is on mobile, tablet, or desktop using user agent strings,…
- HTTP User-Agent Header — Format, Parsing, and Common Values — The User-Agent header identifies the client making an HTTP request. Learn its fo…
Related tool
Parse any User-Agent string into browser, OS, device, and engine. Or detect your own. Built on the maintained ua-parser-js dataset.
Written by Mian Ali Khalid. Part of the Dev Productivity pillar.