How to extract design tokens from any website
Updated 3 November 2026. Every command and output on this page is real.
To extract design tokens from a website, run npx designlang <url>: it loads the page in a headless browser, reads the computed styles of every element, and writes the colours, type, spacing, radii, shadows and motion as W3C DTCG tokens plus CSS, Tailwind and Figma files.
Steps
- Run the extractor on a URL. Run npx designlang stripe.com. The first run downloads a Chromium build; add --system-chrome to use the Chrome you already have.
- Open the tokens file. Open design-extract-output/stripe-com-design-tokens.json. It holds primitive tokens (raw values) and semantic tokens (roles that point at primitives).
- Pick the format you need. Use the CSS variables, Tailwind config, Figma variables or shadcn theme written next to the tokens file, or add --platforms all for iOS, Android, Flutter and WordPress.
- Hand the tokens to your AI editor. Add --emit-agent-rules to write Cursor and Claude Code rules, or run designlang mcp so the editor can query the tokens directly.
Design tokens are the named values a design system is built from: colours, font families, a type scale, spacing steps, corner radii, shadows and motion timings. Most teams want them for one of three reasons. They are rebuilding a site and need the real values, they are building something that has to match an existing brand, or they want an AI coding tool to stop inventing colours. In 2026 the third reason is the common one: AI writes most new UI, and without the real tokens it writes generic UI.
You can copy values out of DevTools one element at a time, but a real site has thousands of elements and hundreds of CSS variables. designlang does the reading for you. It opens the page in a headless browser, walks the rendered DOM, reads what the browser actually computed, clusters the values and names them.
Run it
You need Node.js 20 or later. The CLI is free and MIT licensed, with no signup.
npx designlang stripe.comHere is the end of a real run against stripe.com. Captured with designlang 13.3.2 on 3 November 2026.
Saved to ./design-extract-output
Summary:
Colors: 31 unique colors
Fonts: sohne-var
Spacing: 13 values (base: 2px)
Shadows: 4 unique shadows
Radii: 5 unique values
Components: 11 patterns detected
CSS Vars: 724 custom properties
Layout: 57 grids, 376 flex containers
Design Score: 87/100 (B) — 3 issues
Z-Index: 6 layers
Icons: 127 SVG icons (filled)
A11y: 75% WCAG score (3 failing pairs)
Completed in 9.2sThe run writes about 35 files. The ones you will reach for first:
| File | What it is |
|---|---|
stripe-com-design-tokens.json | W3C DTCG tokens with primitive and semantic tiers. |
stripe-com-variables.css | Every value as a CSS custom property. |
stripe-com-tailwind.config.js | A Tailwind v3 theme. stripe-com-tailwind-v4.css is the v4 @theme version. |
stripe-com-figma-variables.json | Import into Figma as variables. |
stripe-com-DESIGN.md | A single-file summary written for AI agents, with YAML front matter. |
stripe-com-design-language.md | The long report: palette with usage counts, type scale, spacing, components, accessibility and a quality score. |
What the tokens look like
The tokens file follows the W3C Design Tokens Community Group format. Primitive tokens hold raw values. Semantic tokens give them a job and point back at the primitive with a reference, so changing the primitive updates every role that uses it. A trimmed slice of the stripe.com file:
{
"$metadata": {
"generator": "designlang",
"spec": "https://design-tokens.github.io/community-group/format/",
"source": "https://stripe.com",
"generatedAt": "2026-11-03T18:52:36.797Z"
},
"primitive": {
"color": {
"brand": {
"primary": { "$value": "#533afd", "$type": "color" },
"secondary": { "$value": "#061b31", "$type": "color" }
},
"background": {
"bg0": { "$value": "#ffffff", "$type": "color" },
"bg1": { "$value": "#e5edf5", "$type": "color" }
}
}
},
"semantic": {
"color": {
"action": {
"primary": { "$value": "{primitive.color.brand.primary}", "$type": "color" },
"onPrimary": { "$value": "#ffffff", "$type": "color" },
"accent": { "$value": "#00d66f", "$type": "color" }
},
"surface": {
"page": { "$value": "#ffffff", "$type": "color" },
"raised": { "$value": "#e5edf5", "$type": "color" }
}
},
"typography": {
"heading": {
"$value": { "fontFamily": "sohne-var", "fontSize": "48px", "fontWeight": "300", "lineHeight": "55.2px" },
"$type": "typography"
}
}
}
}Because it is standard DTCG, the file works with Style Dictionary, Tokens Studio and other tools that read the format.
Flags that change what you get
| Flag | Effect |
|---|---|
--dark | Also reads the dark mode and pairs light and dark values. |
--depth 3 | Crawls three internal links as well as the homepage. |
--palette 12 | Compresses the palette to 12 perceptually distinct colours. |
--platforms all | Adds iOS SwiftUI, Android Compose, Flutter and WordPress output. |
--interactions | Records hover, focus and active states. |
--cookie name=value | Reads pages behind a login. |
--json | Prints the raw result to stdout for scripts and CI. |
The full list is in the CLI reference.
Read a whole site, not one page
npx designlang site stripe.comSanity-check the result
- Compare
primitive.color.brand.primarywith what you see on the page. On stripe.com it is#533afd, the purple of the main buttons. - Open
stripe-com-preview.htmlin a browser. It renders the palette, type scale and components from the tokens, so a wrong value is easy to spot. - Check the accessibility section of the design-language report. stripe.com had 3 failing contrast pairs, including white text on
#e3ecf7at 1.19:1. - If a cookie banner or chat widget leaked into the palette, rerun with
--ignore-widgets.
Give the tokens to your AI
Tokens in a folder do not change what your AI editor writes. Add --emit-agent-rules to write .cursor/rules/designlang.mdc, a Claude Code skill and an agents.md, or connect the MCP server so the editor can look tokens up while it writes code. The MCP guide covers both.
Questions
Is it legal to extract design tokens from someone else’s website?
Does it work on single-page apps?
--lazy; for slow pages add --wait 2000.