# fonts_canvas

> The same 54 font families, detected with canvas text measurement instead of page layout.

Source: https://whiskerjs.com/signals/fonts-canvas/ (last updated 2026-10-26)

**fonts_canvas at a glance (from the library code, signalsVersion 9)**

| Field | Value |
| --- | --- |
| Component name | `fonts_canvas` |
| In the visitorId | yes |
| structuredId group | [fonts](https://whiskerjs.com/docs/identifiers/#structuredid) |
| Hashing | always a digest, except the plain value none when nothing is found |
| Excluded under | Brave (brave_farbling) |
| Inner timeout | 1000 ms |
| Added in | [signalsVersion 3](https://whiskerjs.com/whats-new/) |

> **In plain words:**
>
> This is a second way of checking which fonts are installed. Instead of placing text in the page, WhiskerJS asks an invisible canvas how wide a word would be in each font. If a font is missing, the browser falls back to a plain font and the width is the same as the plain font’s. Only a short code of the found fonts is kept.

## What it reads

It creates a detached `<canvas>` and its 2D context. For each of the same 54 families used by [`fonts`](https://whiskerjs.com/signals/fonts/), it sets `ctx.font` to `72px '<family>', <fallback>` for the fallbacks `monospace`, `sans-serif` and `serif`, calls `measureText('mmmmmmmmmmlliWWQ@#0OfiflK')` and compares the width with the fallback alone.

## How the technique works

1. Measure the sample text width in each of the three generic fallbacks.
2. For each family and each fallback, measure the text with the family first in the font stack.
3. A family is present when any of its three widths differs from the matching fallback width.
4. Found families are sorted, joined and hashed; with none found the plain word `none` is reported.

Because `measureText` uses the font engine directly, no element is added to the page and the page’s CSS cannot change the measurement. If all fallback widths are zero or not numbers, there is no usable text layout and the result is `unavailable` / `no_layout`.

## Why it helps

It sees the same font differences as `fonts` through a different path. Canvas text measurement does not depend on the document’s layout or styles, so it still works when the page CSS would disturb span measurement. It sits in the `fonts` group.

## Stability

Like `fonts`: it changes when one of the 54 families is installed or removed, or when an update changes which system fonts the browser exposes.

## Browser support and what blocks it

- `ok` in all browsers with a 2D canvas.
- [Brave](https://whiskerjs.com/browsers/brave/): `excluded` / `brave_farbling` (added to the Brave row in signalsVersion 3), because Brave randomises the visible font set.
- Not excluded under [Firefox resistFingerprinting](https://whiskerjs.com/browsers/firefox-rfp-and-tor/).

## Privacy

Same as `fonts`: it shows which of 54 common families are present, as a digest only. Nothing is drawn on screen, no permission, no prompt, no request.

## How WhiskerJS handles noise and failures

| Status | ruleId | When |
| --- | --- | --- |
| `ok` | none | digest of the found list, or plain `none` |
| `unavailable` | `no_document`, `no_api`, `no_context` | no document, no `getContext`, no 2D context with `measureText` |
| `unavailable` | `no_layout` | the fallback widths were zero or invalid |
| `unavailable` | `no_digest` | no Web Crypto |
| `blocked` | `security_error`, `threw` | a canvas call threw |
| `excluded` | `brave_farbling`, `caller_excluded` | exclusion table or your list |
| `timed_out` | `timeout`, `aborted` | 1000 ms inner timeout, budget, abort |

## Example value

From headless Chromium, Firefox and WebKit test browsers in a container (all three found the same families):

```json
"fonts_canvas": { "status": "ok", "value": "e2727c20c7bf4d2b9aa270f3427907a0", "hashed": true }
```

## Questions and answers

### Why measure fonts twice?

The span method in fonts depends on page layout and CSS; the canvas method does not touch the DOM. Two independent methods make the fonts group more robust, and a difference between them can itself be telling.

### Can fonts and fonts_canvas give the same digest?

Yes. Both hash the sorted list of found families in the same form, so when both methods find the same families the digests are equal, as in the container test runs used for these pages.

## Related pages

- [fonts](https://whiskerjs.com/signals/fonts/): The span-width method.
- [font_preferences](https://whiskerjs.com/signals/font-preferences/): Default font settings.
- [canvas](https://whiskerjs.com/signals/canvas/): The 2D canvas image.
- [Font fingerprinting](https://whiskerjs.com/glossary/#font-fingerprinting): The technique.
