accept-ch-parse
Zero-dependency parser for the HTTP Accept-CH Client Hints header (RFC 8942) — for Node.js and Python.
- Parses
Accept-CHinto a list of tokens with quality (q) values - Sorts output by descending
q(stable: ties keep input order) - Token names are case-sensitive per RFC 8942
- Forward-compatible: unregistered tokens are still parsed
- Empty / whitespace-only headers yield
[](not an error) - Zero runtime dependencies on both platforms
Why
HTTP Client Hints (RFC 8942) let servers request device / connection information via the Accept-CH response header. Example:
Accept-CH: Width, Viewport-Width, Content-DPR;q=0.8
When this library was first published (2026-08-08), no zero-dependency
parser for Accept-CH existed on either registry — the names were free:
- npm
accept-ch-parse— confirmed 404 at build time (2026-08-08) - PyPI
accept-ch-parse— confirmed 404 at build time (2026-08-08)
This library fills that gap. It is small, dual-language, has zero runtime
deps, and gets out of your way. If you are reading this README after
2026-08-08 and the names are no longer 404, someone has published a
typosquat or fork — please verify the package you install matches the
GitHub repo at prasad-a-abhishek/accept-ch-parse before depending on it.
Install
Node.js (≥18)
npm install accept-ch-parse
ESM:
import { parseAcceptCH, serializeAcceptCH, getAcceptCHTokens } from 'accept-ch-parse';
CJS:
const { parseAcceptCH, serializeAcceptCH, getAcceptCHTokens } = require('accept-ch-parse');
Python (≥3.11)
pip install accept-ch-parse
from accept_ch_parse import parse_accept_ch, serialize_accept_ch, get_accept_ch_tokens
Usage
Basic parse
import { parseAcceptCH } from 'accept-ch-parse';
parseAcceptCH('Viewport-Width, Width, Content-DPR');
// → [
// { token: 'Viewport-Width', q: 1.0, raw: 'Viewport-Width' },
// { token: 'Width', q: 1.0, raw: 'Width' },
// { token: 'Content-DPR', q: 1.0, raw: 'Content-DPR' }
// ]
from accept_ch_parse import parse_accept_ch
parse_accept_ch('Viewport-Width, Width, Content-DPR')
# → [AcceptCHToken(token='Viewport-Width', q=1.0, raw='Viewport-Width'),
# AcceptCHToken(token='Width', q=1.0, raw='Width'),
# AcceptCHToken(token='Content-DPR', q=1.0, raw='Content-DPR')]
Quality weights — sorted by descending q
parseAcceptCH('Width;q=0.5, Viewport-Width, Content-DPR;q=0.8');
// → [
// { token: 'Viewport-Width', q: 1.0, raw: 'Viewport-Width' },
// { token: 'Content-DPR', q: 0.8, raw: 'Content-DPR;q=0.8' },
// { token: 'Width', q: 0.5, raw: 'Width;q=0.5' }
// ]
Serialize
import { serializeAcceptCH } from 'accept-ch-parse';
serializeAcceptCH([
{ token: 'Viewport-Width', q: 1.0, raw: 'Viewport-Width' },
{ token: 'Width', q: 0.5, raw: 'Width' }
]);
// → 'Viewport-Width, Width;q=0.5'
Just the token names
import { getAcceptCHTokens } from 'accept-ch-parse';
getAcceptCHTokens('Width;q=0.5, Viewport-Width, Content-DPR;q=0.8');
// → ['Viewport-Width', 'Content-DPR', 'Width'] (already q-sorted)
Recognized Client Hints
The parser is forward-compatible — any syntactically valid token is accepted. The eight registered per RFC 8942 are:
| Token | Meaning |
|---|---|
Viewport-Width |
Layout viewport width in CSS pixels |
Width |
Resource width in CSS pixels |
Content-DPR |
Resource's intrinsic DPR (paired with Content-Length) |
DPR |
Current device pixel ratio |
Device-Memory |
Approximate device RAM in GiB |
ECT |
Effective connection type (slow-2g, 2g, 3g, 4g) |
RTT |
Round-trip time in ms |
Downlink |
Downlink speed in Mbps |
API
Node.js
parseAcceptCH(header: string): AcceptCHToken[]
serializeAcceptCH(tokens: AcceptCHToken[]): string
getAcceptCHTokens(header: string): string[]
interface AcceptCHToken {
token: string; // case-sensitive
q: number; // 0..1, default 1.0
raw: string; // exact substring parsed (trimmed)
}
Throws TypeError if header is not a string (including null / undefined).
Python
parse_accept_ch(header: str) -> list[AcceptCHToken]
serialize_accept_ch(tokens: list[AcceptCHToken]) -> str
get_accept_ch_tokens(header: str) -> list[str]
class AcceptCHToken(NamedTuple):
token: str
q: float
raw: str
Raises TypeError if header is not a string (including None).
Errors
| Input | Behaviour |
|---|---|
'' / ' ' |
Returns [] |
null / undefined / non-string (Node) |
TypeError |
None / non-str (Python) |
TypeError |
Width;q=0.5 |
Parsed; q = 0.5 |
Width;Q=0.5 |
Parsed; param names are case-insensitive (RFC 7230) |
Width;q=0, X |
Width sorts last; q clamped to [0, 1] |
Width;q=2.5 |
Clamped to 1.0 |
Width;q=-0.5 |
Clamped to 0.0 |
Width;q= (malformed) |
Treated as q = 1.0 (forgiving) |
Width,,X |
Empty entry dropped; Width and X parsed |
viewport-width |
Parsed as-is (case-sensitive, NOT folded to Viewport-Width) |
Run the tests
# Node
npm install
npm test
# Python
pip install -e .[test]
python -m pytest
The full suite is 60 Node.js tests + 61 Python tests, all green.
Limitations / Non-goals
Out of scope for this library (intentionally, per spec):
- Sending
Accept-CHor any other HTTP header — this library parses only. Save-Dataheader parsing — different header, different spec.Varyheader parsing — different header, different semantics.- A token registry — unregistered tokens are still accepted (forward compatibility). If you need to reject unknown tokens, do that at a higher layer.
- Quality value arithmetic (sum, threshold checks, etc.) — just parse and sort.
- Browser or HTTP client implementation.
References
- RFC 8942 — HTTP Client Hints
- MDN — Accept-CH
- MDN — Client Hints infrastructure
- Chrome Platform Status — Client Hints
- Web.dev — Responsive images with Client Hints
License
MIT — see LICENSE.
Metadata
Release files for accept-ch-parse 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| accept_ch_parse-0.1.2.tar.gz | 6.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| accept_ch_parse-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 13.0 kB
Release files / accept_ch_parse-0.1.2.tar.gz
| Download URL | accept_ch_parse-0.1.2.tar.gz |
|---|---|
| Size | 6.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
023b9d2d07431b750dc6b864fba7cc442a13c357f508883f9d15cb19719f163a
|
|
BLAKE2b-256 checksum How to use checksums |
890a449c5d53334c841a6160d23c23f70389b141cf172849d712bd020630ba59
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|
Release files / accept_ch_parse-0.1.2-py3-none-any.whl
| Download URL | accept_ch_parse-0.1.2-py3-none-any.whl |
|---|---|
| Size | 6.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ff57b858465beb41005ee1da3070161c015a1fe15252f923925ccea999d1f14b
|
|
BLAKE2b-256 checksum How to use checksums |
f3a32d7352867674177b434611d2f9087a032c679ea46c6e45d3c384c2ad4f5b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|