The EyeDropper API: How Chrome's Native Color Picker Works
Quick answer
The EyeDropper API is a native browser interface (Chrome/Edge 95+) that lets web code open a system eyedropper and read the color of any pixel on screen. You create an EyeDropper, call open(), and receive an sRGBHex value. It must be triggered by a real user gesture, returns only the single pixel the user clicks (never a screen feed), and is not supported in Firefox or Safari.
Since Chrome 95, the web platform has had a native way to pick colors from the screen: the EyeDropper API. It is the engine behind modern color picker extensions, including Keynou Colorpicker. Here is what it does, how to use it, and the sharp edges we learned building on it.
The whole API is one class
const dropper = new EyeDropper();
try {
const result = await dropper.open(); // user picks a pixel
console.log(result.sRGBHex); // "#10b0b8"
} catch (err) {
// user pressed Esc, or no user gesture - see below
}
Calling open() switches the whole screen into pick mode with a built-in zoom loupe, and resolves with a single property: sRGBHex. That is the entire surface area - no options for the loupe, no continuous sampling, no format choice. Anything else (clipboard, history, conversions) is your code's job.
It sees the whole screen
Unlike DOM-based tricks (canvas readback, getImageData), the EyeDropper is implemented by the browser process talking to the OS. The picked pixel can come from another tab, another application, or the desktop - things a web page can normally never read. That is also why the API returns only what the user explicitly clicks: the page never sees a live screen feed, just one pixel per pick. Privacy-wise it is a well-designed capability.
The user-gesture requirement (the big gotcha)
open() throws NotAllowedError unless it is called during transient user activation - a real click or keypress in the calling document. This has a consequence that bites every extension author: you cannot auto-start the eyedropper from a popup's load event, because the user's click landed on the browser toolbar, not on the popup document.
It is tempting to work around this by injecting the eyedropper into the page with chrome.scripting.executeScript, but that does not help: executeScript does not propagate transient activation into the injected code, so open() still throws NotAllowedError. The reliable pattern is the simplest one - keep the "Pick a color" button inside the popup and call open() directly from its click handler. Because the EyeDropper samples the entire screen, a pick launched from the popup works on every site, from a blank new tab to any web page.
Browser support
| Browser | EyeDropper API |
|---|---|
| Chrome / Edge 95+ | Yes |
| Opera, Brave, Vivaldi (Chromium) | Yes |
| Firefox | No (position: negative) |
| Safari | No |
Feature-detect before you show a pick button:
if ("EyeDropper" in window) {
// show the pick UI
}
Practical tips from production
- Always catch. Esc rejects with
AbortError; treat it as a normal path, not an error state. - Do the conversions yourself. You get sRGB hex only - keep small, tested helpers for RGB/HSL/HSV/CMYK.
- Copy inside the same activation. The pick click counts as fresh user activation, so
navigator.clipboard.writeText()right after resolving works without extra permission prompts. - An
AbortSignalis supported (dropper.open({ signal })) if you need to cancel programmatically - useful when your UI can be dismissed while a pick is pending.
A complete, production-ready example
Here is the full pattern with feature detection, cancellation handling, and a clipboard copy inside the same user activation:
async function pickAndCopy() {
if (!("EyeDropper" in window)) {
alert("Your browser does not support the eyedropper.");
return;
}
const dropper = new EyeDropper();
try {
const { sRGBHex } = await dropper.open();
await navigator.clipboard.writeText(sRGBHex);
return sRGBHex; // e.g. "#10b0b8"
} catch (err) {
// AbortError = user pressed Esc; treat as a normal cancel
if (err.name !== "AbortError") console.error(err);
}
}
button.addEventListener("click", pickAndCopy); // real gesture
The clipboard write succeeds without a permission prompt because the pick click counts as fresh user activation - the same reason the open() call is allowed in the first place.
What you get back, and what you don't
The resolved object has exactly one property, sRGBHex, a 7-character string in the sRGB color space. There is no alpha channel, no coordinates, and no continuous feed - the page learns only the single color the user deliberately clicked. If you need RGB, HSL or other formats, convert from that hex yourself; if you need alpha, the API cannot provide it. An optional AbortSignal (dropper.open({ signal })) lets you cancel a pending pick programmatically.
Why extensions exist if the API is built in
The raw API gives you one hex string per gesture and nothing else - no history, no format conversion, no clipboard, no UI. Extensions like Keynou Colorpicker wrap it with the parts real workflows need: automatic copy in your chosen format, a color wheel, and a 20-color history. See how to pick a color from any website for the end-user view.
Sources
See the MDN EyeDropper API reference and the WICG EyeDropper API specification for the full contract, and caniuse for current browser support.
Frequently asked questions
Which browsers support the EyeDropper API?
Chrome, Edge and other Chromium browsers (Opera, Brave, Vivaldi) from version 95. Firefox and Safari do not implement it, so always feature-detect with 'EyeDropper' in window before showing a pick button.
Why does EyeDropper.open() throw NotAllowedError?
The call must run during transient user activation - a genuine click or keypress in the calling document. Calling it on page load, from a timer, or from a popup that never received the click will reject. Extensions work around this by injecting the picker into the active page during the icon click.
Can a website secretly read my screen with it?
No. The API returns only the single pixel the user deliberately clicks; the page never receives a live screen feed and the picker requires an explicit user gesture each time.
Pick colors the fast way
Keynou Colorpicker is a free Chrome extension: one click opens a zoomed eyedropper that grabs any color on your screen and copies it in HEX, RGB, HSL and more.
Add Keynou Colorpicker to Chrome