Signal · signalsVersion 14

emoji_metrics

Width and ink bounding box of 30 emoji from Unicode 8 to 16, including the newest code points, measured twice on a canvas, as a digest. Not in either id.

emoji_metrics at a glance (from the library code, signalsVersion 14)
Component nameemoji_metrics
In the visitorIdno (reported, kept out of both ids)
structuredId groupnone
Hashingalways a digest (first 128 bits of SHA-256)
Excluded underBrave (brave_farbling)
Inner timeout1000 ms
Added insignalsVersion 11
Collector revision1 (reported as revision with every result)
In plain words

Emoji look different on every system, and each operating system update brings new ones. An emoji the system does not know yet is shown as an empty box or as its separate parts. WhiskerJS measures 30 emoji, old and new, and turns the sizes into one short code that reflects which emoji font, and which version of it, the device has.

What it reads

CanvasRenderingContext2D.measureText() in 32px sans-serif, which falls back to the system emoji font, for 30 fixed emoji: from Unicode 8 to Unicode 16, including zero-width-joiner sequences (for example the phoenix and the lime), a skin-tone modifier, a flag and the newest code points of Unicode 16. From each it takes width and the ink box: actualBoundingBoxLeft, actualBoundingBoxRight, actualBoundingBoxAscent and actualBoundingBoxDescent.

How the technique works

Each number is rounded to three decimals, one line per emoji, and the 30 lines are hashed together. The whole measurement runs twice; if the passes differ the component is noisy / read_varies. Only the generic family sans-serif is named, so no web font of the page is used and nothing is downloaded.

Why it helps

A ZWJ sequence that the emoji font supports measures as one glyph; one it does not support measures as several. The newest emoji draw as a box on older systems. Together the 30 measurements separate operating system versions and emoji fonts (Apple, Google Noto, Microsoft, Samsung and others) more finely than the user agent does.

Stability

Stable until the operating system or its emoji font updates. In the hosted CI runs of PR #29 each browser gave the same value in every collection and on both runners; Firefox reported the same value with and without its privacy settings. Reported outside both ids until measured on real devices. Added in library PR #29 (2026-10-27) at signalsVersion 11: it is outside both ids, so adding it changed no id and needed no version bump.

Browser support and what blocks it

  • ok wherever a 2D canvas exists; Chromium, Chrome, Firefox and WebKit in CI.
  • Brave: excluded / brave_farbling, as for the other font measurements.
  • unavailable / no_context without a 2D canvas.

Privacy

It reveals the emoji font, which says roughly which operating system version is in use. The value leaves the library only as a digest. No prompt and no request.

How WhiskerJS handles noise and failures

Status ruleId When
ok a digest
noisy read_varies the two passes gave different numbers
unavailable no_document, no_api, no_context no document, canvas or 2D context
unavailable no_value the metrics held no numbers
unavailable no_digest no Web Crypto
blocked threw, security_error measureText threw
excluded brave_farbling, caller_excluded exclusion table or your exclude list
timed_out timeout, aborted budget or abort

Example value

"emoji_metrics": { "status": "ok", "value": "2b7f0e9c4a61d83e5c0b7a2f9d4e1c68", "hashed": true, "durationMs": 1.6, "revision": 1 }

Questions and answers

Why measure emoji?

Every operating system ships its own emoji font and adds new emoji with updates. Newer emoji that the system does not know are drawn as a box or as separate pieces, which measure differently, so the measurements say which emoji font and version is installed.

Does it draw emoji on the page?

No. measureText only measures; nothing is drawn and nothing is added to the page.