# color_scheme

> Whether the user prefers a light or a dark colour scheme, from the prefers-color-scheme media query. Reported, not in either id.

Source: https://whiskerjs.com/signals/color-scheme/ (last updated 2026-10-27)

**color_scheme at a glance (from the library code, signalsVersion 14)**

| Field | Value |
| --- | --- |
| Component name | `color_scheme` |
| In the visitorId | no (reported, kept out of both ids) |
| structuredId group | none |
| Hashing | plain value; a digest only when longer than 128 characters or not printable ASCII |
| Excluded under | no browser class |
| Inner timeout | 1000 ms |
| Added in | [signalsVersion 11](https://whiskerjs.com/whats-new/) |
| Collector revision | [1](https://whiskerjs.com/docs/api/#component) (reported as `revision` with every result) |

> **In plain words:**
>
> Most systems let people choose a light or a dark look, and browsers pass that choice to web pages so they can match it. WhiskerJS records `light` or `dark`.

## What it reads

The CSS `prefers-color-scheme` media feature through `window.matchMedia()`.

## How the technique works

| Order | Query | Value reported |
| --- | --- | --- |
| 1 | `(prefers-color-scheme: dark)` | `dark` |
| 2 | `(prefers-color-scheme: light)` | `light` |

The first match is reported; no match gives `unavailable` with `no_match`.

## Why it helps

On its own it splits users into two large groups, so it says little. For your server it is context: a result whose other preference signals and colour scheme suddenly change together points to a settings change rather than a different device.

## Stability

Low. Users switch themes, and many operating systems switch automatically between day and night. That is why it is outside both ids and is not expected to join them. 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

Every current engine answers the query. In the hosted CI runs of PR #29 every headless browser reported `light` in every collection. Firefox with resistFingerprinting may report `light` whatever the system setting is. No browser class excludes it.

## Privacy

A theme preference is a low-risk setting, but it is a setting of the user. Leave it out with `collect({ exclude: ['color_scheme'] })` if you do not need it; no id changes.

## How WhiskerJS handles noise and failures

| Status | ruleId | When |
| --- | --- | --- |
| `ok` |   | `light` or `dark` |
| `unavailable` | `no_api` | no `matchMedia` |
| `unavailable` | `no_match` | neither query matched |
| `blocked` | `threw`, `security_error` | `matchMedia` throws |
| `excluded` | `caller_excluded` | you excluded it |
| `timed_out` | `timeout`, `aborted` | budget or abort |

## Example value

```json
"color_scheme": { "status": "ok", "value": "dark", "hashed": false, "durationMs": 0.1, "revision": 1 }
```

## Questions and answers

### Why is the colour scheme not in the visitorId?

Many people switch between light and dark mode, and many systems switch automatically at sunset. An id built on it would change with the time of day.

### What does WhiskerJS report when no preference is set?

Browsers report light when the user has not chosen dark, so the value is light or dark; unavailable with no_match is only expected in very old engines.

## Related pages

- [forced_colors](https://whiskerjs.com/signals/forced-colors/): A forced colour mode, in the id.
- [prefers_contrast](https://whiskerjs.com/signals/prefers-contrast/): The contrast preference, in the id.
- [Component fields](https://whiskerjs.com/docs/api/#component): Status, value, durationMs and revision.
