Skip to content
On this page

CSS media query fingerprinting reads operating-system and device preferences through window.matchMedia(). A media query is a yes/no question about the environment, such as "is dark mode on?" Modern CSS lets a page ask about the user's color-scheme preference, reduced-motion and reduced-transparency settings, contrast level, forced-colors mode, the primary pointer type (mouse vs touch), hover capability, and display metrics like screen size. Each answer is low-entropy on its own - meaning it only slightly narrows down who you are - but together they describe a device class and a user configuration that must be coherent with the platform. Headless browsers (browsers run by automation, with no visible window) return revealing defaults that real users rarely all share.

Quick facts

APIwindow.matchMedia(query).matches
Readsprefers-color-scheme, prefers-reduced-motion, contrast, forced-colors, pointer, hover
Pointer/hoverpointer:coarse + hover:none = touch device; pointer:fine = mouse
Coherence trapA phone UA must report coarse pointer and no hover
Headless defaultUniform light scheme, fine pointer, hover - same across a fleet

What media queries expose

matchMedia() answers yes/no to environment questions that come from the OS and the device:

  • prefers-color-scheme - light or dark, set by the OS theme.
  • prefers-reduced-motion and prefers-reduced-transparency - accessibility settings.
  • prefers-contrast and forced-colors - high-contrast / Windows high-contrast mode.
  • pointer and any-pointer - fine (mouse/stylus) vs coarse (finger).
  • hover and any-hover - whether the primary input can hover.
  • display metrics - resolution, aspect ratio, orientation.

Each answer is one bit or a small set of choices, so any single feature reveals little (its entropy - how much it narrows down the device - is low). The real value is in the combination, and in whether it stays consistent with the rest of the device's story.

The coherence and uniformity tells

This catches scrapers in two ways. First, device coherence - the values have to agree with the device the browser claims to be. A request with an Android or iPhone User-Agent (the browser/device string sent with each request) must report pointer: coarse and hover: none, because phones have no fine pointer and cannot hover. A "phone" that reports pointer: fine and hover: hover is really a desktop headless browser wearing a mobile UA. Likewise a touch tablet and a mouse-driven desktop have different pointer/hover signatures, and these must match the claimed device and the touch/hardware signals.

Second, fleet uniformity - bots tend to look identical to each other. Headless browsers default to a light color scheme, no reduced motion, a fine pointer, and hover enabled. Real human traffic is a mix: a meaningful fraction use dark mode, some enable reduced motion, mobile users report coarse pointers. A population of visitors that all report the same headless-default media profile stands out against that natural spread. Anti-bot systems look at the distribution across many visitors, not just the values from one.

Code example

javascript
// OS/device preferences read via matchMedia
const mq = q => window.matchMedia(q).matches;
const cssProfile = {
  dark:        mq('(prefers-color-scheme: dark)'),
  reduceMotion:mq('(prefers-reduced-motion: reduce)'),
  forcedColors:mq('(forced-colors: active)'),
  coarse:      mq('(pointer: coarse)'),
  noHover:     mq('(hover: none)')
};

// Coherence check (pseudo):
//   /iPhone|Android/.test(ua) && (!cssProfile.coarse || !cssProfile.noHover)
//     -> mobile UA but desktop pointer/hover  = headless wearing a phone UA
// Distribution check:
//   entire visitor fleet reporting {dark:false, coarse:false, noHover:false}
//     -> headless default profile, anomalous vs real-user spread

Next in Environment and display signals · 3 of 7

How the browser now declares itself in headers.

What Is Client Hints Fingerprinting?

Related terms

Concept map

Concept map

How CSS Media Query Fingerprinting connects

The terms most directly tied to this one. Hover a node to see its neighbours, click to preview, drag to rearrange.

0 terms · 0 connections
You are here · Anti-Bot
Building map…

Frequently asked questions

How much does a single media query reveal?

Very little on its own - most are just one bit (dark mode on or off, hover yes or no). The signal comes from combining them and checking they are coherent with the device the browser claims to be, plus comparing them across a whole population of visitors. A phone that reports a fine pointer, or an entire fleet sharing the identical headless-default profile, is what stands out.

What pointer and hover values should a mobile scraper report?

A real phone reports pointer: coarse and hover: none (and any-pointer: coarse, any-hover: none). If you present a mobile User-Agent, these values must match it, along with touch support and screen metrics. Reporting a fine pointer or hover capability under a phone UA is a direct contradiction that gives the bot away.

Should I randomize prefers-color-scheme to look human?

Setting a realistic mix instead of always-light helps you avoid fleet uniformity, but the value must stay coherent and stable within a session and match any theme actually rendered on the page. The goal is to resemble the natural distribution of real users, not to flip the value at random - random flipping can itself look anomalous.

Last updated: 2026-05-31