All posts
TutorialsSoraiaJul 18, 20266 min read

How to Extract a Website's Color Palette Programmatically

Two working ways to get a site's color palette in code - screenshot quantization vs reading the CSS - and which one returns the actual brand colors.

There are two fundamentally different ways to extract a color palette from a website in code: quantize the pixels of a screenshot, or read the colors out of the CSS. They give different answers, and one of them is usually wrong for what you want. The short version: pixel methods find what a page looks like; CSS methods find what the brand is. If you want brand colors, read the CSS.

Here are both, working, then the comparison.

Method 1: quantize a screenshot (fast, misleading)

The classic approach - screenshot the page, run color quantization:

pip install playwright colorthief
playwright install chromium
from io import BytesIO
from colorthief import ColorThief
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page(viewport={"width": 1440, "height": 900})
    page.goto("https://stripe.com", wait_until="networkidle")
    shot = page.screenshot()
    browser.close()

palette = ColorThief(BytesIO(shot)).get_palette(color_count=6)
print(['#%02x%02x%02x' % c for c in palette])

Works in ten lines. The problem is that a screenshot has no idea what is UI and what is content. A hero photo dominates the pixel math, anti-aliased text contributes hundreds of blend colors that exist nowhere in the stylesheet, and the accent color that defines the brand might be forty pixels of button. Use this method for artwork and photos; do not use it for brand palettes.

Method 2: read the CSS (the right answer)

Ask the browser what colors the stylesheet actually applies:

from collections import Counter
from playwright.sync_api import sync_playwright

COLLECT = """
() => [...document.querySelectorAll('body *')].slice(0, 5000).flatMap(el => {
  const s = getComputedStyle(el);
  return [s.color, s.backgroundColor, s.borderTopColor];
})
"""

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.goto("https://stripe.com", wait_until="networkidle")
    values = page.evaluate(COLLECT)
    browser.close()

skip = {"rgba(0, 0, 0, 0)", "rgb(0, 0, 0)", "rgb(255, 255, 255)"}
for color, count in Counter(v for v in values if v not in skip).most_common(8):
    print(f"{count:>5}  {color}")

Frequency ranking does the rest: the most-used saturated color is almost always the brand primary. For the full version with fonts, spacing, and the cleanup steps, see the design tokens guide.

Checking one site by hand? Use the console

Paste this in DevTools on any page:

Object.entries([...document.querySelectorAll('body *')].reduce((acc, el) => {
  const c = getComputedStyle(el).backgroundColor;
  if (c !== 'rgba(0, 0, 0, 0)') acc[c] = (acc[c] || 0) + 1;
  return acc;
}, {})).sort((a, b) => b[1] - a[1]).slice(0, 8)

Fastest palette check that exists. It just does not scale past the tab you are in.

Screenshot vs CSS vs API

Screenshot quantizationCSS computed stylesMiroMiro API
Finds brand accent colorsPoorly (pixel-count bias)YesYes
Affected by photos in the pageBadlyNoNo
Invents colors (anti-aliasing)YesNoNo
GradientsSort of (as pixels)Needs backgroundImage tooYes, as gradient strings
Output formatRGB tuplesrgb() stringsHex, ranked, plus the rest of the token set
Runs without your own browser infraNoNoYes

Or use one API call

curl "https://miromiro.app/api/v1/extract?url=stripe.com&fields=colors,gradients" \
  -H "Authorization: Bearer $MIROMIRO_API_KEY"

Ranked palette with gradients included, normalized, 10 credits a call. There is also a free color palette extractor that runs the same engine in the browser if you want to eyeball a site before writing any code. Free key here - 100 credits a month, no card.

Summary

Read the CSS, not the pixels. Screenshot quantization answers "what does this image look like", which is the wrong question for a brand palette, and it will confidently hand you the colors of a stock photo. The console snippet for one site, Playwright for a script, the API when it needs to run inside something.

Frequently asked questions

How do I get a website's color palette in Python?

Playwright plus getComputedStyle counting (code above). Skip ColorThief-on-screenshot for brand work - it measures content, not identity.

Why does screenshot extraction give wrong brand colors?

Pixel counts reward photos and anti-aliasing blends, not the forty pixels of button that carry the actual accent color.

Can I do this in the browser console?

Yes - the snippet above ranks background colors on any page you have open.

How do I get hex instead of rgb() strings?

Three parseInt calls per channel, or use an API that normalizes for you.

Skip the maintenance - one API call

Design tokens, brand data, fonts, SVGs, images, and section code from any URL. 100 free credits a month, no card.

S

Soraia · Founder, MiroMiro

Building MiroMiro: a browser extension and API that extract design tokens, assets, and production-ready code from any live website. The gotchas in these posts come from the extraction engine's own commit history.

Follow on X
color palettepythonjavascriptcolorsextraction