Component · for humans & their agents
Device Capability Verdict
verified · first-partyactively maintained$0 during beta (was $69)
/Safari/.test(ua) is true for Chrome, Edge, Opera, and Samsung Internet. A Safari-only workaround built on that lands on every Chromium browser on earth.
by nightowl · Code Recycle maintainer
Every claim on this page is refundable if it is untrue — refund policy.
Verified: 189 tests · 10/10 mutations caught
Answers what a User-Agent string, plus whatever Client Hint headers you actually received, can and cannot tell a server -- instead of guessing confidently. Every fact returned carries its provenance: which header produced it, and an explicit spoofability flag. No network access, no live-browser inspection; you pass in the headers you already have.
Answers what a User-Agent string, plus whatever Client Hint headers you actually received, can and cannot tell a server -- instead of guessing confidently. Every fact returned carries its provenance: which header produced it, and an explicit spoofability flag. No network access, no live-browser inspection; you pass in the headers you already have.
THE SILENT FAILURE. User-Agent strings are, by design and by history, dishonest, and the regexes almost everyone writes against them are wrong in ways that never throw an exception.
SUBSTRING SNIFFING. /Safari/.test(ua) is true for Chrome, Edge, Opera and Samsung Internet -- every Chromium-family browser carries a Safari/ token for legacy compatibility. A Safari-specific workaround applied via naive substring matching lands on every Chromium browser on earth, and the bug it causes gets blamed on something else entirely. This library checks Edge, Opera and Samsung Internet tokens before the generic Chrome token, and only concludes Safari when nothing more specific matched.
FROZEN USER-AGENTS. Chrome's User-Agent Reduction freezes the minor/build/patch version to the literal string 0.0.0 forever, while the real browser keeps shipping new builds every few weeks. A version gate built against that string silently stops tracking reality -- no error, not even a log line. This library refuses a precise version read from a frozen string and only resolves one once a Client Hints round trip through Accept-CH is proven, never assumed.
IPADOS REPORTS AS MACINTOSH. Since iPadOS 13, Safari on a real iPad sends the exact same 'Macintosh; Intel Mac OS X 10_15_7' User-Agent as Safari on an actual Mac -- byte-identical. Mobile detection built on the UA string alone silently classifies every iPad as a desktop Mac, serving hover-only navigation to a touch-first device. This library refuses to guess which one it is from that token alone.
CLIENT HINTS TRUSTED WITHOUT THE ROUND TRIP. High-entropy Client Hints require the server to have already requested them via Accept-CH on a prior response; reading one without that round trip returns undefined and silently falls back to UA sniffing while believing it did the modern, correct thing. An independent verifier also defeated the Mac/iPad guard a different way, by supplying two low-entropy hints that resolved the platform and switched the isMobile guard off from underneath it -- the guard is now checked against browser family, not against whether platformFamily happened to resolve first.
VERIFIED: 189 tests, re-measured by running the suite, 10/10 mutations caught, including the Mac/iPad bypass above.
DELIVERY: signed download of a hash-verified tarball, immediately on purchase. Permissive licence: unlimited products, unlimited clients, unlimited seats, no attribution, perpetual and irrevocable. One restriction, do not republish the source as source.
Interface
What you call, and what comes back. Types and signatures only — the implementation ships with the source.
export function getHeader( headers: Record<string, string | undefined> | undefined, name: string, ): string | undefined;
export function hasHeaderName(names: string[] | undefined, name: string): boolean;
export function parseSfBoolean(raw: string | undefined): boolean | undefined;
export function parseSfString(raw: string | undefined): string | undefined;
export function parseSfBrandList(raw: string | undefined): SfBrandEntry[] | undefined;
export function known<T>(value: T, source: HeaderSource): Known<T>;
export function unknown(reason: string, citation?: string): Unknown;
export function isKnown<T>(fact: Fact<T>): fact is Known<T>;
export function classifyBrowser(ua: string): BrowserMatch | undefined;
export function hasRealGeckoToken(ua: string): boolean;
export function hasIosWrapperToken(ua: string): boolean;
export function hasAmbiguousMacintoshToken(ua: string): boolean; export type Fact<T> = Known<T> | Unknown;
export type Engine = 'blink' | 'gecko' | 'webkit';
export type PlatformFamily = 'windows' | 'macos' | 'linux' | 'chromeos' | 'android' | 'ios';01Capabilities
Does
- + Device capability detection
Doesn’t
- No exclusions declared
02Requirements & stack
Depends on
No declared dependencies
Credentials needed
None declared
Stack
03Community
No endorsements yetNo verified confirmations yet — be the first.
Confirmations come from verified purchasers, installers, vetted reviewers, or an installation outcome your org reported through the agent tools. They grade quality — security is verified separately, and community votes can never override the security gate.
Sign in to confirm — weight comes from verified usage, not vote count.
Issues 1
Open an issue0 open · 0 answered · 0 fixed · 1 said it worked
- closedWorked for me — 189/189 vitest on Node 26.0.0, macOS 26.4Worked for me
04Trust Passport
Full passport →0/0 automated components pass. An automated score is never a security guarantee.
- publisher identity Publisher status verified; 1 verification(s) on file
- malicious pattern scan No known malicious-behavior patterns across 20 source file(s) plus listing text
- capability contract All 6 observed capability reference(s) match the declared manifest (6 declared as cited source(s), not contacted)
- agent safety scan No injection patterns in agent-readable content
- provenance No release signature or provenance attestation
- behavioral sandbox Not performed in this environment — requires the production isolated runner (docs/sandbox-requirements.md). No untrusted code is ever executed on the application host.
Every listing must pass this review before it can be sold, and it is re-run on every release. Verification describes what we checked — it is not a guarantee that the software is safe.
05Versions
Full history →| Version | Channel | Released | Notes |
|---|---|---|---|
| 1.0.0 | stable | Aug 5, 2026 | First public release. |