Color Gamut, HDR, and Media-Query Fingerprinting: Your Display Gives You Away
Last month I burned a batch of mobile profiles — ten accounts, all claiming to be iPhone 14 devices, all linked and banned within 72 hours. Three weeks of warmup. Gone.
The fingerprints looked solid. Canvas matched. WebGL matched. User-agent, screen resolution, device pixel ratio — all consistent with an iPhone 14. Passed CreepJS. Passed FingerprintJS. I was confident. (I was wrong.)
Except I'd missed a fingerprint surface I didn't know existed. And honestly, I should've known better — I've been doing this for years and I still get caught by stuff like this.
The profiles reported color-gamut: srgb and dynamic-range: standard through CSS media queries. Real iPhone 14s report color-gamut: p3 and dynamic-range: high. My "iPhones" were running on a Dell monitor that couldn't display P3 or HDR. The display hardware was leaking through a CSS API nobody told me about.
Ten accounts. Gone. Because of a media query.
If you're spoofing mobile devices from a desktop setup — or even just running multiple profiles on different display configurations — you've got a fingerprint leak you probably haven't checked. This tutorial covers what CSS media features expose, why they're hard to spoof, and how to test whether your profiles are vulnerable.
What We're Building
By the end of this walkthrough, you'll understand:
- Which CSS media features create fingerprinting surfaces (color-gamut, dynamic-range, prefers-color-scheme, prefers-reduced-motion, forced-colors)
- How
screen.colorDepthcombines with media queries to identify display classes - Why desktop-to-mobile spoofs fail on these signals
- How to test your profiles for media query leaks
- Configuration approaches that actually pass detection
This is the display fingerprint surface that sits next to screen resolution — which we covered in the screen resolution and window metrics guide. Resolution is about size. This is about color capability.
Prerequisites
- Chrome or Chromium-based browser (any recent version)
- An antidetect browser with configured profiles — JustBrowser gives you the full feature set on a 7-day trial, so you can test this without committing
- Basic familiarity with CSS media queries (you don't need to be an expert, but you should know what
@mediadoes) - Dev tools open
Step 1: Understanding What Media Queries Expose
Open your browser console and paste this:
function getMediaFingerprint() {
const checks = {
colorGamut: {
srgb: matchMedia('(color-gamut: srgb)').matches,
p3: matchMedia('(color-gamut: p3)').matches,
rec2020: matchMedia('(color-gamut: rec2020)').matches
},
dynamicRange: {
standard: matchMedia('(dynamic-range: standard)').matches,
high: matchMedia('(dynamic-range: high)').matches
},
colorScheme: {
dark: matchMedia('(prefers-color-scheme: dark)').matches,
light: matchMedia('(prefers-color-scheme: light)').matches
},
reducedMotion: matchMedia('(prefers-reduced-motion: reduce)').matches,
forcedColors: matchMedia('(forced-colors: active)').matches,
colorDepth: screen.colorDepth,
pixelDepth: screen.pixelDepth
};
console.log('Display Fingerprint:', checks);
return checks;
}
getMediaFingerprint();
On my desktop with a standard sRGB monitor, I get:
Display Fingerprint: {
colorGamut: { srgb: true, p3: false, rec2020: false },
dynamicRange: { standard: true, high: false },
colorScheme: { dark: true, light: false },
reducedMotion: false,
forcedColors: false,
colorDepth: 24,
pixelDepth: 24
}
On an iPhone 14 Pro (actual device), you'd see:
Display Fingerprint: {
colorGamut: { srgb: true, p3: true, rec2020: false },
dynamicRange: { standard: true, high: true },
colorScheme: { dark: true, light: false },
reducedMotion: false,
forcedColors: false,
colorDepth: 30,
pixelDepth: 30
}
See the difference? P3 gamut support. HDR. 30-bit color depth. These values come from the actual display hardware, not from JavaScript you can intercept.
And here's the problem: if you're running a profile that claims to be an iPhone 14 Pro but your actual display only supports sRGB at 24-bit, your profile is lying. Detectably. This drove me nuts when I first figured it out — I'd spent so much time perfecting my canvas fingerprints and it turns out the display itself was ratting me out the whole time.
Step 2: Why This Is Harder to Spoof Than Canvas
Canvas fingerprinting happens in JavaScript. Your antidetect browser intercepts the canvas API calls and returns modified values. Same with WebGL, audio context, font enumeration. These are JavaScript surfaces.
Media queries work differently.
When a site checks matchMedia('(color-gamut: p3)'), the browser queries the operating system's display capabilities. The OS asks the display hardware. The result bubbles back up. There's no JavaScript layer where an extension can intercept and modify the response.
Some antidetect browsers try to override matchMedia at the JavaScript level. That works for direct JavaScript calls. But CSS-only fingerprinting bypasses it entirely.
A site can do this:
@media (color-gamut: p3) {
.fingerprint-pixel { background-image: url('/pixel/p3.gif'); }
}
@media (color-gamut: srgb) and (not (color-gamut: p3)) {
.fingerprint-pixel { background-image: url('/pixel/srgb.gif'); }
}
No JavaScript executes. The browser fetches one URL or the other based on actual display capabilities. The server logs which file was requested. Your display class is fingerprinted purely through CSS.
Extension-based antidetect tools can't catch this. The CSS engine runs at a lower level than JavaScript interception allows. Frustrating? Absolutely. I wasted two months on an extension-based setup before accepting this.
This is why native antidetect browsers — the ones that modify Chromium source code — reach display signals that extensions never touch. JustBrowser sets screen dimensions, device pixel ratio and color depth in C++, so screen.* and the device-width/device-height media features agree. Color-gamut and dynamic-range are not spoofed today — keep profiles on a display class that matches the host (sRGB/SDR on a standard monitor). The comparison breakdown between native and extension-based browsers covers where each approach fails.
Step 3: The Display Class Fingerprint
Quick entropy math.
Individual media features don't uniquely identify you. But combined:
- Color gamut: 3-4 classes (srgb-only, p3, rec2020)
- Dynamic range: 2 classes (standard, high)
- Color depth: 3 common values (24, 30, 48)
- Color scheme: 2 states (dark, light)
- Reduced motion: 2 states
- Forced colors: 2 states
That's 3 × 2 × 3 × 2 × 2 × 2 = 144 combinations just from display-related signals. Not enough to uniquely identify anyone — but enough to create device classes. And that's the whole game, really. Device classes.
Real fingerprinting combines display signals with everything else: canvas, WebGL, fonts, audio, TLS fingerprint, screen dimensions, timezone. The browser fingerprinting statistics breakdown shows how these vectors stack.
Display signals matter most for consistency checking. A profile claiming to be an iPhone 14 should have the iPhone 14's display profile. If it doesn't match, that's a lie. Detection services look for lies.
The problem is that most antidetect operators configure screen resolution and device pixel ratio but forget about color capabilities. You end up with a profile that's dimensionally correct but chromatically wrong.
I've seen this exact pattern break accounts on Amazon, Meta, and TikTok. They're not fingerprinting you uniquely through color gamut — they're catching the inconsistency. And look, I get it: when you're setting up 50 profiles you're not thinking about color gamut. You're thinking about proxies and cookies and whether your card info is getting flagged. But the platforms are checking everything now.
Step 4: Testing Your Profiles for Media Query Leaks
Here's a quick audit.
Step 4a: Check JavaScript media query response
const isP3 = matchMedia('(color-gamut: p3)').matches;
const isHDR = matchMedia('(dynamic-range: high)').matches;
const depth = screen.colorDepth;
console.log(`P3: ${isP3}, HDR: ${isHDR}, Depth: ${depth}`);
Step 4b: Check what your profile claims to be
If your profile is configured as:
- iPhone 14 Pro: should report P3 + HDR + 30-bit
- MacBook Pro (2021+): should report P3 + HDR + 30-bit
- Standard Windows laptop: should report sRGB + standard + 24-bit
- Gaming monitor with HDR: varies, but likely sRGB/P3 + HDR + 30-bit
Mismatch? You're leaking.
Step 4c: Check the CSS path
This is trickier. You need a server-side test. For a quick check:
- Open BrowserLeaks.com's CSS section
- Check what display capabilities they detect
- Compare against your profile configuration
Alternatively, set up a local test page with CSS background-image rules that load different pixels based on media queries, then check your server logs. If you're seeing the wrong image requested, CSS-level fingerprinting is leaking your real display.
Step 4d: Check screen.colorDepth alignment
Color depth should match gamut capability:
- sRGB displays: usually 24-bit (8 bits per channel × 3)
- P3/HDR displays: usually 30-bit (10 bits per channel × 3) or sometimes 48-bit
A profile claiming 30-bit depth but sRGB-only gamut is suspicious. That combination exists on some displays — but it's rare enough to be notable.
Step 5: Configuration Approaches That Work
Option 1: Use an antidetect browser with native screen-level spoofing
JustBrowser spoofs screen.colorDepth and screen geometry at the engine level. Gamut/HDR media queries follow the host display, so match the profile's claimed display class to the machine it runs on.
Option 2: Match profiles to your actual hardware
If you're running all profiles on the same desktop, configure them all for your actual display class. Don't spoof mobile devices from a desktop unless your antidetect browser handles media queries natively.
This limits your device diversity — but consistent lies are better than inconsistent truths. I learned this the hard way.
Option 3: Use hardware that matches target profiles
Some operators run mobile profiles on actual mobile devices, or use MacBooks for P3/HDR profiles. The hardware matches the claimed capabilities. No spoofing needed.
Expensive and operationally complex. Honestly? Overkill for most people. But bulletproof if you've got the budget.
Common Errors and How to Fix Them
Error: "Profile claims iPhone but shows sRGB gamut"
Cause: Your desktop display only supports sRGB. The profile correctly spoofs screen size and device pixel ratio but the media query surface isn't handled.
Fix: Use a native antidetect browser with media query patching, or switch to profiles that match your actual display capabilities.
Error: "screen.colorDepth is 24 but profile targets HDR device"
Cause: HDR devices report 30-bit or higher color depth. Your profile is claiming HDR capability but the color depth leaks your real display.
Fix: Ensure your antidetect browser spoofs screen.colorDepth alongside media queries. These need to match.
Error: "prefers-color-scheme doesn't match OS setting"
Cause: Some antidetect browsers let you force dark/light mode per profile, but the OS-level setting leaks through CSS.
Fix: Less critical than gamut/HDR for device classification, but still a consistency signal. Native spoofing or accepting your OS setting both work.
Error: "Profile passes CreepJS but fails on platform"
Cause: CreepJS and FingerprintJS focus on common vectors. Platform detection scripts may query less-common surfaces like forced-colors or reduced-motion.
Fix: Check all media query surfaces manually with the code snippets above. Test against multiple detection services — BrowserScan has been adding media query checks since early 2026.
Next Steps
Media queries are one display surface among several. If you've got this handled:
- Screen resolution and window metrics — the dimension mismatch guide covers the other half of display fingerprinting
- WebGL and GPU fingerprinting — display capabilities tie into GPU detection. The audio and font fingerprinting guide shows how these vectors interconnect.
- TLS fingerprinting — JA4 fingerprints are device-class signals too. The JA4 TLS guide covers detection and spoofing.
For the broader antidetect setup, our best practices checklist runs through the full surface. And if you're running campaigns that need click-quality monitoring, ClickzProtect pairs well with isolated antidetect profiles for ad verification. For analytics on user behavior patterns across profiles, JustAnalytics provides session tracking without the fingerprinting leakage of third-party scripts.
Display fingerprinting through media queries isn't the highest-entropy surface. But it's the one that catches desktop-to-mobile spoofs. If you're running mobile profiles from desktop hardware without native media query spoofing, you've got a leak. Period.
I lost ten accounts figuring this out. Could've been avoided with a five-minute check. Learn from my mistake — or don't, and figure it out the same way I did. Your call.
Frequently Asked Questions
What CSS media features expose fingerprinting signals?
The main fingerprinting surfaces are color-gamut (srgb, p3, rec2020), dynamic-range (standard vs high for HDR), prefers-color-scheme (dark/light mode), prefers-reduced-motion (accessibility setting), and forced-colors (high contrast mode). Combined with screen.colorDepth and window.matchMedia() behavior, these create a display-class fingerprint that varies between device types.
Why do media queries break desktop-to-mobile spoofing?
Desktop monitors and mobile screens have different display characteristics. Most desktop monitors report srgb gamut and standard dynamic range, while newer phones report p3 gamut and high dynamic range. A profile claiming to be an iPhone 14 but reporting srgb gamut and 24-bit color depth is internally inconsistent. Detection services check these values against expected hardware configurations.
Can CSS-only fingerprinting detect antidetect browsers?
Yes. Sites can use CSS-only fingerprinting by loading different resources based on media query matches. No JavaScript required. A CSS rule like @media (color-gamut: p3) loads one image, @media (color-gamut: srgb) loads another. The server sees which resource was requested and knows your display class without any client-side code executing.
How do I check if my antidetect profile spoofs media queries correctly?
Run window.matchMedia('(color-gamut: p3)').matches in the console, along with checks for dynamic-range and prefers-color-scheme. Compare the results against what the profile claims to emulate. If you're spoofing an iPhone 14 Pro, you should see p3 gamut and high dynamic range. Check screen.colorDepth too — it should be 30 for HDR displays, 24 for standard.
Try JustBrowser
Native Chromium antidetect browser — not extension-based. Real C++ engine patches at the canvas / WebGL / audio / font / screen layer, so 40+ identity parameters are genuine, not faked. REST API for Playwright, Puppeteer, Selenium. $9.99/month or $99.99/year. 7-day free trial, card required — cancel any time in the seven days and you are not charged. Unlimited profiles.
Get started → · How it differs from Multilogin / GoLogin / AdsPower
Related Posts
Ready to manage multiple accounts?
Seven days free, then $9.99/month — one plan, everything included.