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.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file accept_ch_parse-0.1.2.tar.gz.
File metadata
- Download URL: accept_ch_parse-0.1.2.tar.gz
- Upload date:
- Size: 6.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
023b9d2d07431b750dc6b864fba7cc442a13c357f508883f9d15cb19719f163a
|
|
| MD5 |
2ee0c2d03a4d77a628c10631c46973e2
|
|
| BLAKE2b-256 |
890a449c5d53334c841a6160d23c23f70389b141cf172849d712bd020630ba59
|
File details
Details for the file accept_ch_parse-0.1.2-py3-none-any.whl.
File metadata
- Download URL: accept_ch_parse-0.1.2-py3-none-any.whl
- Upload date:
- Size: 6.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ff57b858465beb41005ee1da3070161c015a1fe15252f923925ccea999d1f14b
|
|
| MD5 |
9dc0078a831eccbb2a662a61a28d9260
|
|
| BLAKE2b-256 |
f3a32d7352867674177b434611d2f9087a032c679ea46c6e45d3c384c2ad4f5b
|