Skip to main content

accept-ch-parse

Zero-dependency parser for the HTTP Accept-CH Client Hints header (RFC 8942) — for Node.js and Python.

  • Parses Accept-CH into 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 you build responsive-image servers, adaptive CDNs, or device-aware middleware, you need to parse this header to know which hints the client is willing to send. No zero-dependency parser exists on either registry:

  • npm accept-ch-parse — confirmed 404 (2026-08-08)
  • PyPI accept-ch-parse — confirmed 404 (2026-08-08)

This library fills that gap. It is small, dual-language, has zero runtime deps, and gets out of your way.

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-CH or any other HTTP header — this library parses only.
  • Save-Data header parsing — different header, different spec.
  • Vary header 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

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

accept_ch_parse-0.1.1.tar.gz (6.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

accept_ch_parse-0.1.1-py3-none-any.whl (6.5 kB view details)

Uploaded Python 3

File details

Details for the file accept_ch_parse-0.1.1.tar.gz.

File metadata

  • Download URL: accept_ch_parse-0.1.1.tar.gz
  • Upload date:
  • Size: 6.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for accept_ch_parse-0.1.1.tar.gz
Algorithm Hash digest
SHA256 009abc54e2c97868242a5df5afa851cad27faacb6b9fe44cb9c2d59741430f5a
MD5 2fc904e60c78c69b9d183941707414ca
BLAKE2b-256 b8e5e43b65c6ed9899f3a41212108329381ed8ef887034f59581bcbbb45c3041

See more details on using hashes here.

File details

Details for the file accept_ch_parse-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for accept_ch_parse-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 6e4fc298e43e898c5a8827e9c212df7d7526e61c8756d3e6e91222bd944d4cfc
MD5 ab81022c3d97846ba613a3d8a25b1e12
BLAKE2b-256 e7277fc738884d213ff1e817f19a67695652080dbca34ec256f304185ee60e42

See more details on using hashes here.

Release history Release notifications | RSS feed

0.1.2

2 files

This release

0.1.1 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page