[{"data":1,"prerenderedAt":1947},["ShallowReactive",2],{"api-blog-best-design-to-code-apis-2026":3,"api-blog-related-best-design-to-code-apis-2026":436},{"id":4,"title":5,"author":6,"body":7,"category":404,"date":405,"dateModified":406,"description":407,"extension":408,"faqs":409,"image":406,"meta":420,"navigation":421,"path":422,"readingTime":423,"relatedSlugs":424,"seo":428,"stem":429,"tags":430,"__hash__":435},"apiBlog/api-blog/best-design-to-code-apis-2026.md","Best Design-to-Code APIs and Tools in 2026","Soraia",{"type":8,"value":9,"toc":389},"minimark",[10,14,17,22,51,73,77,87,104,108,118,135,139,147,198,205,222,226,335,339,352,356,361,364,368,371,375,378,382,385],[11,12,13],"p",{},"\"Design to code\" means four different products depending on what goes in: a Figma file, a screenshot, a prompt, or a live URL. Most listicles mix them together and compare a Figma plugin against an AI app builder, which helps nobody. Here is the landscape sorted by input, with an honest read on each.",[11,15,16],{},"Disclosure up front: we build the URL-to-code entry. The others are genuinely good at their own input type, and I will say so.",[18,19,21],"h2",{"id":20},"input-a-figma-file","Input: a Figma file",[11,23,24,34,35,42,43,50],{},[25,26,27],"strong",{},[28,29,33],"a",{"href":30,"rel":31},"https://www.animaapp.com",[32],"nofollow","Anima"," and ",[25,36,37],{},[28,38,41],{"href":39,"rel":40},"https://www.locofy.ai",[32],"Locofy"," are the established Figma-to-code plugins - React/HTML output, component mapping, years of production use. ",[25,44,45],{},[28,46,49],{"href":47,"rel":48},"https://www.builder.io",[32],"Builder.io's Visual Copilot"," is the newer AI take on the same job.",[52,53,54,61,67],"ul",{},[55,56,57,60],"li",{},[25,58,59],{},"Good:"," if your designs live in Figma with proper auto-layout, these produce real component code and preserve design intent.",[55,62,63,66],{},[25,64,65],{},"Bad:"," they need a Figma file. Messy layers produce messy code, and there is no path from \"site I saw\" to code - someone has to design it first.",[55,68,69,72],{},[25,70,71],{},"Use when:"," your team designs in Figma and wants the handoff automated.",[18,74,76],{"id":75},"input-a-screenshot","Input: a screenshot",[11,78,79,86],{},[25,80,81],{},[28,82,85],{"href":83,"rel":84},"https://github.com/abi/screenshot-to-code",[32],"screenshot-to-code"," (open source, very popular) and the screenshot modes of various AI tools take a picture and ask a vision model to write matching HTML/Tailwind.",[52,88,89,94,99],{},[55,90,91,93],{},[25,92,59],{}," works on anything you can see. Zero setup for the OSS version. Genuinely impressive first drafts.",[55,95,96,98],{},[25,97,65],{}," every value is a guess. The model approximates colors from pixels, eyeballs spacing, and invents font stacks. Two runs give two different answers. Fine for a prototype, dangerous as a source of truth.",[55,100,101,103],{},[25,102,71],{}," speed matters more than fidelity.",[18,105,107],{"id":106},"input-a-prompt","Input: a prompt",[11,109,110,117],{},[25,111,112],{},[28,113,116],{"href":114,"rel":115},"https://v0.dev",[32],"v0"," (Vercel) and its peers generate UI from a text description. Strictly speaking that is prompt-to-code, not design-to-code, but it is where much of the category's attention went.",[52,119,120,125,130],{},[55,121,122,124],{},[25,123,59],{}," the fastest way to get a decent generic component that never existed before.",[55,126,127,129],{},[25,128,65],{}," the output looks like v0 output. If the goal is \"match this existing brand\", a prompt cannot carry a design system's worth of values.",[55,131,132,134],{},[25,133,71],{}," greenfield UI with no reference to match.",[18,136,138],{"id":137},"input-a-live-url","Input: a live URL",[11,140,141,142,146],{},"This is the gap. When the reference already exists as a website - a client's current site, a competitor's pricing page, a section your PM screenshotted - none of the above reads the real CSS. Our ",[28,143,145],{"href":144},"/api/docs/code","/v1/code"," endpoint does:",[148,149,154],"pre",{"className":150,"code":151,"language":152,"meta":153,"style":153},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","curl \"https://miromiro.app/api/v1/code?url=stripe.com&format=tailwind\" \\\n  -H \"Authorization: Bearer $MIROMIRO_API_KEY\"\n","bash","",[155,156,157,181],"code",{"__ignoreMap":153},[158,159,162,166,170,174,177],"span",{"class":160,"line":161},"line",1,[158,163,165],{"class":164},"sBMFI","curl",[158,167,169],{"class":168},"sMK4o"," \"",[158,171,173],{"class":172},"sfazB","https://miromiro.app/api/v1/code?url=stripe.com&format=tailwind",[158,175,176],{"class":168},"\"",[158,178,180],{"class":179},"sTEyZ"," \\\n",[158,182,184,187,189,192,195],{"class":160,"line":183},2,[158,185,186],{"class":172},"  -H",[158,188,169],{"class":168},[158,190,191],{"class":172},"Authorization: Bearer ",[158,193,194],{"class":179},"$MIROMIRO_API_KEY",[158,196,197],{"class":168},"\"\n",[11,199,200,201,204],{},"It parses the live page's actual cascade - specificity, media queries, nested ",[155,202,203],{},"var()"," chains - and returns the section as Tailwind, JSX, Vue, or plain HTML, with the extracted token set alongside. Auto-detects the hero if you do not pass a selector; 25 credits a call.",[52,206,207,212,217],{},[55,208,209,211],{},[25,210,59],{}," the values are real, not guessed - the exact colors, spacing, and fonts the site ships. It is an API, so it runs inside agents and products, which almost nothing else in this category does.",[55,213,214,216],{},[25,215,65],{}," section-level, not whole-app cloning - it will not produce a working multi-page app from a URL. Static HTML + CSS; fully client-rendered apps can come back thin.",[55,218,219,221],{},[25,220,71],{}," an agent or product needs faithful code from a page that already exists.",[18,223,225],{"id":224},"the-whole-landscape-in-one-table","The whole landscape in one table",[227,228,229,251],"table",{},[230,231,232],"thead",{},[233,234,235,239,242,245,248],"tr",{},[236,237,238],"th",{},"Tool",[236,240,241],{},"Input",[236,243,244],{},"Output",[236,246,247],{},"API available",[236,249,250],{},"Values real or guessed?",[252,253,254,272,287,303,319],"tbody",{},[233,255,256,260,263,266,269],{},[257,258,259],"td",{},"Anima / Locofy",[257,261,262],{},"Figma file",[257,264,265],{},"React/HTML components",[257,267,268],{},"Limited",[257,270,271],{},"Real (from Figma)",[233,273,274,277,279,282,285],{},[257,275,276],{},"Builder.io Visual Copilot",[257,278,262],{},[257,280,281],{},"Components",[257,283,284],{},"Yes (Builder ecosystem)",[257,286,271],{},[233,288,289,291,294,297,300],{},[257,290,85],{},[257,292,293],{},"Image",[257,295,296],{},"HTML/Tailwind draft",[257,298,299],{},"Self-host",[257,301,302],{},"Guessed",[233,304,305,307,310,313,316],{},[257,306,116],{},[257,308,309],{},"Prompt",[257,311,312],{},"React/Tailwind",[257,314,315],{},"Yes",[257,317,318],{},"Invented",[233,320,321,324,327,330,332],{},[257,322,323],{},"MiroMiro /v1/code",[257,325,326],{},"Live URL",[257,328,329],{},"Tailwind/JSX/Vue + tokens",[257,331,315],{},[257,333,334],{},"Real (from the site's CSS)",[18,336,338],{"id":337},"the-verdict","The verdict",[11,340,341,342,346,347,351],{},"Match the tool to the input you actually have. Figma file: Anima or Locofy. Nothing yet: v0. A picture and low stakes: screenshot-to-code. A live site that must be matched faithfully, inside a pipeline: that is URL-to-code, and it is the lane we picked precisely because the others do not drive in it. ",[28,343,345],{"href":344},"/api/dashboard/keys","Free key"," (100 credits a month, no card) or try a URL in the ",[28,348,350],{"href":349},"/api/demo","playground",".",[18,353,355],{"id":354},"frequently-asked-questions","Frequently asked questions",[357,358,360],"h3",{"id":359},"what-is-the-best-way-to-turn-an-existing-website-into-code","What is the best way to turn an existing website into code?",[11,362,363],{},"If fidelity matters, read the live CSS (URL-to-code). If speed matters more, screenshot-to-code gives a fast approximation.",[357,365,367],{"id":366},"can-ai-convert-a-screenshot-to-code-accurately","Can AI convert a screenshot to code accurately?",[11,369,370],{},"Plausibly, not accurately. Every color, spacing, and font value is a model's guess from pixels.",[357,372,374],{"id":373},"figma-to-code-vs-url-to-code","Figma-to-code vs URL-to-code?",[11,376,377],{},"Input: a design file you own vs any live website. The first automates handoff; the second works when no design file exists.",[357,379,381],{"id":380},"which-of-these-have-real-apis","Which of these have real APIs?",[11,383,384],{},"v0 and Builder.io within their platforms, and MiroMiro as a plain REST endpoint. The Figma plugins are primarily apps - a hard filter if you are building a pipeline.",[386,387,388],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":153,"searchDepth":183,"depth":183,"links":390},[391,392,393,394,395,396,397],{"id":20,"depth":183,"text":21},{"id":75,"depth":183,"text":76},{"id":106,"depth":183,"text":107},{"id":137,"depth":183,"text":138},{"id":224,"depth":183,"text":225},{"id":337,"depth":183,"text":338},{"id":354,"depth":183,"text":355,"children":398},[399,401,402,403],{"id":359,"depth":400,"text":360},3,{"id":366,"depth":400,"text":367},{"id":373,"depth":400,"text":374},{"id":380,"depth":400,"text":381},"Comparisons","2026-07-18",null,"The design-to-code landscape in 2026 sorted by input - Figma files, screenshots, prompts, or live URLs - and which tool honestly wins for each job.","md",[410,412,414,417],{"question":360,"answer":411},"Depends on fidelity needs. For a quick approximation, screenshot-to-code tools work from a picture. For code that uses the site's real CSS values - exact colors, spacing, fonts - you need something that reads the live page's stylesheets, which is what a URL-to-code API does.",{"question":367,"answer":413},"It produces plausible code fast, but the model guesses every value: colors approximated from pixels, spacing eyeballed, fonts inferred. Great for prototypes; risky when the output must match a real design system.",{"question":415,"answer":416},"What is the difference between Figma-to-code and URL-to-code?","Input. Figma-to-code tools (Anima, Locofy, Builder.io) need a Figma file and turn design layers into components. URL-to-code starts from any live website - no design file required - and derives the code from the real rendered CSS.",{"question":418,"answer":419},"Which design-to-code tools have an actual API?","Fewer than the category suggests. Most are plugins or apps. If you need code generation inside your own product or agent pipeline, check for a documented REST endpoint first - that requirement alone eliminates most of the list.",{},true,"/api-blog/best-design-to-code-apis-2026",7,[425,426,427],"best-design-token-extraction-tools-2026","best-firecrawl-alternatives-2026","how-to-extract-design-tokens-from-any-website-in-python",{"title":5,"description":407},"api-blog/best-design-to-code-apis-2026",[431,432,433,434],"design to code","tailwind","code generation","comparison","Ds8Hb1IY5fXrd4oGyzAN3SLgbiC7wqiv79mad9KMYu8",[437,873,1229],{"id":438,"title":439,"author":6,"body":440,"category":404,"date":405,"dateModified":406,"description":848,"extension":408,"faqs":849,"image":406,"meta":861,"navigation":421,"path":862,"readingTime":423,"relatedSlugs":863,"seo":866,"stem":867,"tags":868,"__hash__":872},"apiBlog/api-blog/best-design-token-extraction-tools-2026.md","Best Design Token Extraction Tools in 2026",{"type":8,"value":441,"toc":832},[442,445,449,457,475,479,487,504,508,516,533,537,548,565,569,577,594,598,601,631,651,655,768,770,780,782,786,789,793,808,812,819,823,830],[11,443,444],{},"There are six honest ways to get design tokens out of a live website in 2026, and the right one depends on whether you are doing this once, weekly, or inside a product. Here is the list, with the tradeoffs stated plainly. Yes, our own API is on it - ranked where I would rank it if it were not ours.",[18,446,448],{"id":447},"_1-css-stats-fastest-free-look","1. CSS Stats - fastest free look",[11,450,451,456],{},[28,452,455],{"href":453,"rel":454},"https://cssstats.com",[32],"cssstats.com"," has been the \"paste a URL, see the CSS\" tool for a decade. It reports every color, font size, and font family the stylesheet declares, plus specificity graphs nobody asks for but everyone screenshots.",[52,458,459,464,469],{},[55,460,461,463],{},[25,462,59],{}," free, no signup, instant.",[55,465,466,468],{},[25,467,65],{}," it reads declared CSS, not used CSS. A site shipping a big framework stylesheet reports hundreds of colors that never render. There is no export worth automating against.",[55,470,471,474],{},[25,472,473],{},"Use it when:"," you want a two-minute overview of a site's CSS health, not a token set.",[18,476,478],{"id":477},"_2-project-wallace-the-analyzer-that-kept-evolving","2. Project Wallace - the analyzer that kept evolving",[11,480,481,486],{},[28,482,485],{"href":483,"rel":484},"https://www.projectwallace.com",[32],"Project Wallace"," does what CSS Stats does but deeper: color counts, typography breakdowns, and change tracking over time if you create an account.",[52,488,489,494,499],{},[55,490,491,493],{},[25,492,59],{}," the most thorough free CSS analysis on the web, actively maintained.",[55,495,496,498],{},[25,497,65],{}," same fundamental limit - declared, not rendered. Still a report you read, not a token file you use.",[55,500,501,503],{},[25,502,473],{}," auditing your own CSS over time, or studying how a site's stylesheet is put together.",[18,505,507],{"id":506},"_3-superposition-tokens-on-your-desktop","3. Superposition - tokens on your desktop",[11,509,510,515],{},[28,511,514],{"href":512,"rel":513},"https://superposition.design",[32],"Superposition"," is a desktop app that crawls a page and exports design tokens to CSS variables, Sass, JS, and even Adobe XD. It was ahead of its time.",[52,517,518,523,528],{},[55,519,520,522],{},[25,521,59],{}," genuine token export formats, one-click, offline app.",[55,524,525,527],{},[25,526,65],{}," desktop-only, so there is nothing to call from code or CI. Development has been quiet for a while - check that the export you need still works.",[55,529,530,532],{},[25,531,473],{}," you are a designer who wants tokens from a reference site without touching a terminal.",[18,534,536],{"id":535},"_4-a-diy-playwright-script-full-control","4. A DIY Playwright script - full control",[11,538,539,540,543,544,351],{},"Load the page in a headless browser, read ",[155,541,542],{},"getComputedStyle"," off every element, count what repeats. We wrote the complete walkthrough in ",[28,545,547],{"href":546},"/api/blog/how-to-extract-design-tokens-from-any-website-in-python","How to Extract Design Tokens from Any Website in Python",[52,549,550,555,560],{},[55,551,552,554],{},[25,553,59],{}," free, sees exactly what renders (including runtime CSS-in-JS), infinitely customizable.",[55,556,557,559],{},[25,558,65],{}," you now run browser infrastructure. Cookie banners, lazy fonts, and viewport-dependent styles are your problem, and the script that worked in April breaks in July.",[55,561,562,564],{},[25,563,473],{}," one-off extractions, research, or when you need something no tool exposes.",[18,566,568],{"id":567},"_5-miromiro-browser-extension-point-and-click","5. MiroMiro browser extension - point and click",[11,570,571,572,576],{},"Our ",[28,573,575],{"href":574},"/features/design-tokens","extension"," shows a site's tokens live as you browse: colors, typography, spacing, assets. Click an element, see its resolved styles, export what you want.",[52,578,579,584,589],{},[55,580,581,583],{},[25,582,59],{}," zero setup, visual, great for picking tokens from a specific component rather than the whole page.",[55,585,586,588],{},[25,587,65],{}," it is a human tool. Nothing to automate, no JSON endpoint, and it extracts what you look at, not a thousand URLs.",[55,590,591,593],{},[25,592,473],{}," hand-picking design decisions from reference sites during design or build.",[18,595,597],{"id":596},"_6-miromiro-extract-api-tokens-as-an-endpoint","6. MiroMiro extract API - tokens as an endpoint",[11,599,600],{},"One GET request returns the ranked token set as JSON, CSS variables, or a Tailwind theme block:",[148,602,604],{"className":150,"code":603,"language":152,"meta":153,"style":153},"curl \"https://miromiro.app/api/v1/extract?url=stripe.com&format=tailwind\" \\\n  -H \"Authorization: Bearer $MIROMIRO_API_KEY\"\n",[155,605,606,619],{"__ignoreMap":153},[158,607,608,610,612,615,617],{"class":160,"line":161},[158,609,165],{"class":164},[158,611,169],{"class":168},[158,613,614],{"class":172},"https://miromiro.app/api/v1/extract?url=stripe.com&format=tailwind",[158,616,176],{"class":168},[158,618,180],{"class":179},[158,620,621,623,625,627,629],{"class":160,"line":183},[158,622,186],{"class":172},[158,624,169],{"class":168},[158,626,191],{"class":172},[158,628,194],{"class":179},[158,630,197],{"class":168},[52,632,633,641,646],{},[55,634,635,637,638,640],{},[25,636,59],{}," deduped and ranked (not raw declared values), covers colors, type scale, spacing, radii, shadows, gradients, and motion, resolves ",[155,639,203],{}," chains and every declared breakpoint. It is the only option on this list you can put inside a product.",[55,642,643,645],{},[25,644,65],{}," it parses static HTML + CSS and does not execute JavaScript, so a fully client-rendered app can come back thin. Costs credits past the free 100 a month.",[55,647,648,650],{},[25,649,473],{}," tokens need to arrive programmatically - agent pipelines, onboarding flows, bulk analysis.",[18,652,654],{"id":653},"the-comparison-in-one-table","The comparison in one table",[227,656,657,674],{},[230,658,659],{},[233,660,661,663,665,668,671],{},[236,662,238],{},[236,664,244],{},[236,666,667],{},"Rendered or declared?",[236,669,670],{},"Automatable",[236,672,673],{},"Price",[252,675,676,693,708,722,738,752],{},[233,677,678,681,684,687,690],{},[257,679,680],{},"CSS Stats",[257,682,683],{},"Web report",[257,685,686],{},"Declared",[257,688,689],{},"No",[257,691,692],{},"Free",[233,694,695,697,700,702,705],{},[257,696,485],{},[257,698,699],{},"Web report + tracking",[257,701,686],{},[257,703,704],{},"Partially",[257,706,707],{},"Free tier",[233,709,710,712,715,718,720],{},[257,711,514],{},[257,713,714],{},"Token files (CSS/Sass/JS)",[257,716,717],{},"Rendered",[257,719,689],{},[257,721,692],{},[233,723,724,727,730,732,735],{},[257,725,726],{},"DIY Playwright",[257,728,729],{},"Whatever you build",[257,731,717],{},[257,733,734],{},"Yes, you maintain it",[257,736,737],{},"Your time",[233,739,740,743,746,748,750],{},[257,741,742],{},"MiroMiro extension",[257,744,745],{},"Visual + export",[257,747,717],{},[257,749,689],{},[257,751,707],{},[233,753,754,757,760,763,765],{},[257,755,756],{},"MiroMiro API",[257,758,759],{},"JSON / CSS vars / Tailwind",[257,761,762],{},"Parsed + resolved",[257,764,315],{},[257,766,767],{},"100 credits/mo free, then from €19/mo",[18,769,338],{"id":337},[11,771,772,773,776,777,779],{},"For a quick look, Project Wallace. For hand-picking from a reference site, the extension. For anything that runs on a schedule or inside a product, the API - and I would say that even if it were someone else's, because it is the only entry here that returns a token file over HTTP. You can ",[28,774,775],{"href":344},"get a free API key"," (100 credits a month, no card) or poke it in the ",[28,778,350],{"href":349}," first.",[18,781,355],{"id":354},[357,783,785],{"id":784},"what-is-the-fastest-free-way-to-extract-design-tokens-from-a-website","What is the fastest free way to extract design tokens from a website?",[11,787,788],{},"Paste the URL into CSS Stats or Project Wallace. Seconds, no signup. Expect raw declared values, not a cleaned token set.",[357,790,792],{"id":791},"can-i-get-tokens-as-css-variables-or-a-tailwind-config-directly","Can I get tokens as CSS variables or a Tailwind config directly?",[11,794,795,796,799,800,803,804,351],{},"Yes - ",[155,797,798],{},"format=css"," returns custom properties, ",[155,801,802],{},"format=tailwind"," returns a theme block. Details in the ",[28,805,807],{"href":806},"/api/docs/design-tokens","design tokens docs",[357,809,811],{"id":810},"do-these-tools-work-on-tailwind-sites","Do these tools work on Tailwind sites?",[11,813,814,815,818],{},"The ones reading real CSS or computed styles do; ",[155,816,817],{},"bg-indigo-600"," is just CSS once shipped. Tools that only look for CSS custom properties miss most of a Tailwind site's system.",[357,820,822],{"id":821},"what-is-the-difference-between-a-token-set-and-a-color-palette","What is the difference between a token set and a color palette?",[11,824,825,826,351],{},"A palette is one token group. A full token set adds the type scale, spacing, radii, shadows, motion, and z-index layers - see the ",[28,827,829],{"href":828},"/api/blog/design-token-types-reference","design token types reference",[386,831,388],{},{"title":153,"searchDepth":183,"depth":183,"links":833},[834,835,836,837,838,839,840,841,842],{"id":447,"depth":183,"text":448},{"id":477,"depth":183,"text":478},{"id":506,"depth":183,"text":507},{"id":535,"depth":183,"text":536},{"id":567,"depth":183,"text":568},{"id":596,"depth":183,"text":597},{"id":653,"depth":183,"text":654},{"id":337,"depth":183,"text":338},{"id":354,"depth":183,"text":355,"children":843},[844,845,846,847],{"id":784,"depth":400,"text":785},{"id":791,"depth":400,"text":792},{"id":810,"depth":400,"text":811},{"id":821,"depth":400,"text":822},"Six real ways to pull design tokens from a live website in 2026 - free analyzers, a DIY script, a browser extension, and an API - honestly ranked.",[850,852,855,858],{"question":785,"answer":851},"Paste the URL into a CSS analyzer like CSS Stats or Project Wallace. You get colors, font sizes, and specificity data in seconds with no signup. The output is raw declared values rather than a cleaned token set, so expect to filter it by hand.",{"question":853,"answer":854},"Can I get design tokens as CSS variables or a Tailwind config directly?","Yes. The MiroMiro extract endpoint takes format=css to return CSS custom properties or format=tailwind to return a theme config block, so the tokens drop straight into a codebase without a conversion step.",{"question":856,"answer":857},"Do design token extractors work on Tailwind sites?","Tools that read the site's actual CSS or computed styles do, because bg-indigo-600 is just CSS once shipped. Tools that look for CSS variables only will miss most of a Tailwind site's system, since utility-first sites often define few custom properties.",{"question":859,"answer":860},"What is the difference between extracting design tokens and extracting a color palette?","A palette is one token group. A design token set also covers the type scale, spacing, radii, shadows, motion, and z-index layers - the full set of decisions you need to rebuild UI in the site's style.",{},"/api-blog/best-design-token-extraction-tools-2026",[427,864,865],"design-token-types-reference","best-design-to-code-apis-2026",{"title":439,"description":848},"api-blog/best-design-token-extraction-tools-2026",[869,870,434,871],"design tokens","tools","css analysis","GhGcQEA8Q7VmKm_mMFRSpL45k0PaBwatHPzBRiFUK9g",{"id":874,"title":875,"author":6,"body":876,"category":404,"date":405,"dateModified":406,"description":1204,"extension":408,"faqs":1205,"image":406,"meta":1217,"navigation":421,"path":1218,"readingTime":423,"relatedSlugs":1219,"seo":1221,"stem":1222,"tags":1223,"__hash__":1228},"apiBlog/api-blog/best-firecrawl-alternatives-2026.md","5 Best Firecrawl Alternatives in 2026",{"type":8,"value":877,"toc":1189},[878,881,884,888,896,914,918,930,947,951,963,980,984,992,1009,1013,1020,1050,1056,1073,1077,1145,1147,1157,1159,1163,1166,1170,1173,1177,1180,1184,1187],[11,879,880],{},"\"Firecrawl alternative\" usually means one of five different complaints: it costs too much at volume, you want open source, you need heavier browser automation, you want search instead of crawling, or you need something it does not extract at all. Different complaint, different answer - here are the five, honestly.",[11,882,883],{},"For the record, Firecrawl is good. Their pricing (verified July 2026): free 1,000 credits, Hobby $16/mo for 5,000 pages, Standard $83/mo for 100k, up to Scale at $599/mo for a million. Simple unit, fair prices. If it is doing its job for you, keep it, and skip to the last section for the one case where it genuinely cannot help.",[18,885,887],{"id":886},"_1-crawl4ai-the-open-source-answer","1. Crawl4AI - the open-source answer",[11,889,890,895],{},[28,891,894],{"href":892,"rel":893},"https://github.com/unclecode/crawl4ai",[32],"Crawl4AI"," is the most popular OSS route: a Python crawler built for LLM pipelines, outputting clean markdown, with an enthusiastic community and rapid development.",[52,897,898,903,908],{},[55,899,900,902],{},[25,901,59],{}," free forever, self-hosted, no per-page anxiety, full data control.",[55,904,905,907],{},[25,906,65],{}," you own the infrastructure - proxies, JS rendering, anti-bot upkeep, retries. The afternoon it saves in fees it can take back in maintenance.",[55,909,910,913],{},[25,911,912],{},"Pick it when:"," volume is high, budgets are tight, and you have the engineering appetite.",[18,915,917],{"id":916},"_2-jina-reader-the-simplest-possible-api","2. Jina Reader - the simplest possible API",[11,919,920,925,926,929],{},[28,921,924],{"href":922,"rel":923},"https://jina.ai/reader/",[32],"Jina Reader"," is the lowest-friction markdown-from-URL service that exists: prefix a URL with ",[155,927,928],{},"r.jina.ai/"," and get LLM-ready text, generous free tier, no signup for casual use.",[52,931,932,937,942],{},[55,933,934,936],{},[25,935,59],{}," zero setup, genuinely free for light use, great output for articles and docs.",[55,938,939,941],{},[25,940,65],{}," single-page reads, not site crawling; fewer knobs when a page fights back.",[55,943,944,946],{},[25,945,912],{}," your agent reads pages one at a time and you want the cheapest possible path.",[18,948,950],{"id":949},"_3-apify-when-scraping-is-an-application","3. Apify - when scraping is an application",[11,952,953,958,959,351],{},[28,954,957],{"href":955,"rel":956},"https://apify.com",[32],"Apify"," is a platform, not an endpoint: thousands of prebuilt scrapers (\"Actors\") for specific sites, scheduling, storage, and a marketplace. We compared it in depth in our ",[28,960,962],{"href":961},"/api/compare/apify-alternative","Apify alternative page",[52,964,965,970,975],{},[55,966,967,969],{},[25,968,59],{}," the prebuilt Actors cover sites that generic crawlers struggle with; real orchestration features.",[55,971,972,974],{},[25,973,65],{}," platform complexity and platform pricing. For \"give me this page as markdown\" it is a lot of machinery.",[55,976,977,979],{},[25,978,912],{}," scraping specific difficult sites on a schedule is a core workflow.",[18,981,983],{"id":982},"_4-tavily-search-instead-of-crawl","4. Tavily - search instead of crawl",[11,985,986,991],{},[28,987,990],{"href":988,"rel":989},"https://tavily.com",[32],"Tavily"," reframes the problem: instead of crawling sites, it gives agents a search API that returns answer-shaped, cited results.",[52,993,994,999,1004],{},[55,995,996,998],{},[25,997,59],{}," for research agents, search-shaped input beats crawl-shaped input - less context, more signal.",[55,1000,1001,1003],{},[25,1002,65],{}," it is not extraction. You cannot point it at a specific page and get its full content faithfully.",[55,1005,1006,1008],{},[25,1007,912],{}," the agent's question is \"what is true about X\" rather than \"what does this page say\".",[18,1010,1012],{"id":1011},"_5-miromiro-when-the-answer-isnt-text-at-all","5. MiroMiro - when the answer isn't text at all",[11,1014,1015,1016,1019],{},"Everything above ships text. If the reason you are searching for alternatives is that your agent builds ",[25,1017,1018],{},"UI"," - an app generator theming output to a user's brand, an onboarding flow that imports a company's look, a coding agent that needs real design context - then markdown was never the right output format, and that is the lane we occupy:",[148,1021,1023],{"className":150,"code":1022,"language":152,"meta":153,"style":153},"curl \"https://miromiro.app/api/v1/extract?url=stripe.com\" \\\n  -H \"Authorization: Bearer $MIROMIRO_API_KEY\"\n",[155,1024,1025,1038],{"__ignoreMap":153},[158,1026,1027,1029,1031,1034,1036],{"class":160,"line":161},[158,1028,165],{"class":164},[158,1030,169],{"class":168},[158,1032,1033],{"class":172},"https://miromiro.app/api/v1/extract?url=stripe.com",[158,1035,176],{"class":168},[158,1037,180],{"class":179},[158,1039,1040,1042,1044,1046,1048],{"class":160,"line":183},[158,1041,186],{"class":172},[158,1043,169],{"class":168},[158,1045,191],{"class":172},[158,1047,194],{"class":179},[158,1049,197],{"class":168},[11,1051,1052,1053,1055],{},"Design tokens (ranked colors, type scale, spacing, shadows, motion), brand data, SVGs, fonts, and section-level Tailwind/JSX/Vue via ",[28,1054,145],{"href":144},". MCP server included for Claude Code and Cursor. Free tier is 100 credits a month, no card; paid from €19/mo.",[52,1057,1058,1063,1068],{},[55,1059,1060,1062],{},[25,1061,59],{}," the only entry here that returns a design system. Complements Firecrawl rather than replacing it - content from them, design from us is a real pattern.",[55,1064,1065,1067],{},[25,1066,65],{}," it will not crawl a thousand documentation pages into markdown. Wrong tool for that; use the four above.",[55,1069,1070,1072],{},[25,1071,912],{}," the deliverable is on-brand UI, not text.",[18,1074,1076],{"id":1075},"the-five-sorted-by-complaint","The five, sorted by complaint",[227,1078,1079,1092],{},[230,1080,1081],{},[233,1082,1083,1086,1089],{},[236,1084,1085],{},"Your complaint with Firecrawl",[236,1087,1088],{},"Alternative",[236,1090,1091],{},"Why",[252,1093,1094,1104,1114,1124,1134],{},[233,1095,1096,1099,1101],{},[257,1097,1098],{},"Cost at volume",[257,1100,894],{},[257,1102,1103],{},"Self-hosted, no per-page fee",[233,1105,1106,1109,1111],{},[257,1107,1108],{},"Just want one page as markdown",[257,1110,924],{},[257,1112,1113],{},"URL prefix, done",[233,1115,1116,1119,1121],{},[257,1117,1118],{},"Difficult specific sites, scheduling",[257,1120,957],{},[257,1122,1123],{},"Prebuilt Actors + orchestration",[233,1125,1126,1129,1131],{},[257,1127,1128],{},"Agent needs answers, not pages",[257,1130,990],{},[257,1132,1133],{},"Search-shaped API",[233,1135,1136,1139,1142],{},[257,1137,1138],{},"Need design, not text",[257,1140,1141],{},"MiroMiro",[257,1143,1144],{},"Tokens, brand, assets, section code",[18,1146,338],{"id":337},[11,1148,1149,1150,1152,1153,351],{},"For text at scale, Crawl4AI or stay with Firecrawl - their pricing is honestly hard to beat below 100k pages. For agent research, Tavily. And if you landed here because no amount of markdown gets you a brand's colors, fonts, and components: that is not a Firecrawl weakness, it is a category boundary, and it is the one we built for. ",[28,1151,345],{"href":344},", or the full head-to-head is at ",[28,1154,1156],{"href":1155},"/api/compare/firecrawl-alternative","MiroMiro vs Firecrawl",[18,1158,355],{"id":354},[357,1160,1162],{"id":1161},"what-is-the-best-free-firecrawl-alternative","What is the best free Firecrawl alternative?",[11,1164,1165],{},"Crawl4AI self-hosted, or Jina Reader for zero-setup single pages.",[357,1167,1169],{"id":1168},"is-firecrawl-worth-it-vs-open-source","Is Firecrawl worth it vs open source?",[11,1171,1172],{},"Below serious volume, usually yes - $16/mo for 5,000 pages is cheaper than maintaining a crawler stack. OSS wins on volume and data control.",[357,1174,1176],{"id":1175},"what-cant-firecrawl-extract","What can't Firecrawl extract?",[11,1178,1179],{},"The design layer - tokens, brand, typography, assets, component code. Markdown strips it by design.",[357,1181,1183],{"id":1182},"which-alternative-is-best-for-ai-agents","Which alternative is best for AI agents?",[11,1185,1186],{},"Research agents: Tavily. Page-reading agents: Jina or Firecrawl. UI-building agents: MiroMiro.",[386,1188,388],{},{"title":153,"searchDepth":183,"depth":183,"links":1190},[1191,1192,1193,1194,1195,1196,1197,1198],{"id":886,"depth":183,"text":887},{"id":916,"depth":183,"text":917},{"id":949,"depth":183,"text":950},{"id":982,"depth":183,"text":983},{"id":1011,"depth":183,"text":1012},{"id":1075,"depth":183,"text":1076},{"id":337,"depth":183,"text":338},{"id":354,"depth":183,"text":355,"children":1199},[1200,1201,1202,1203],{"id":1161,"depth":400,"text":1162},{"id":1168,"depth":400,"text":1169},{"id":1175,"depth":400,"text":1176},{"id":1182,"depth":400,"text":1183},"Five real Firecrawl alternatives in 2026, matched to the job: cheap markdown, open source, site automation, agent search, or design context for AI.",[1206,1208,1211,1214],{"question":1162,"answer":1207},"Crawl4AI if you can self-host - it is open source, actively developed, and produces LLM-ready markdown with no per-page cost beyond your infrastructure. Jina Reader's free tier is the no-setup option: prefix any URL with r.jina.ai and get markdown back.",{"question":1209,"answer":1210},"Is Firecrawl worth it compared to open source scrapers?","If your time has a price, usually yes. Self-hosting a crawler means owning proxies, JS rendering, retries, and anti-bot upkeep. Firecrawl's Hobby tier at $16/mo for 5,000 pages is cheaper than the first afternoon of maintaining that stack. Open source wins on volume and data control, not convenience.",{"question":1212,"answer":1213},"What can't Firecrawl extract from a website?","The design. Firecrawl converts pages to markdown and structured text for LLMs - by design, that strips the visual layer. Brand colors, typography, spacing, design tokens, SVGs, and component code need a design-extraction tool; no volume of markdown credits gets you there.",{"question":1215,"answer":1216},"Which Firecrawl alternative is best for AI agents?","Depends on the loop. For research agents that answer questions, Tavily's search-shaped API fits better than crawling. For agents that read specific pages, Jina Reader or Firecrawl itself. For agents that build UI and need a site's design system as ground truth, a design-extraction API like MiroMiro.",{},"/api-blog/best-firecrawl-alternatives-2026",[865,1220,425],"best-brand-data-apis-2026",{"title":875,"description":1204},"api-blog/best-firecrawl-alternatives-2026",[1224,1225,1226,1227,434],"firecrawl","alternatives","web scraping","ai agents","IwAwF9vtdiqk_AlwZsEggBXVUHTcQNd0fz_Wwe13QZU",{"id":1230,"title":547,"author":6,"body":1231,"category":1925,"date":405,"dateModified":406,"description":1926,"extension":408,"faqs":1927,"image":406,"meta":1937,"navigation":421,"path":1938,"readingTime":1326,"relatedSlugs":1939,"seo":1941,"stem":1942,"tags":1943,"__hash__":1946},"apiBlog/api-blog/how-to-extract-design-tokens-from-any-website-in-python.md",{"type":8,"value":1232,"toc":1909},[1233,1240,1243,1247,1250,1276,1279,1477,1480,1488,1502,1506,1509,1548,1551,1555,1558,1596,1600,1603,1665,1669,1748,1754,1758,1761,1789,1819,1827,1831,1841,1843,1847,1850,1854,1866,1870,1873,1877,1880,1884,1906],[11,1234,1235,1236,1239],{},"The fastest way to extract design tokens from a website in Python is Playwright plus ",[155,1237,1238],{},"getComputedStyle()",": load the page in a real browser, collect the computed styles of every element, and count what repeats. The counting is the important part. A site's design system is whatever it uses everywhere, not every value that appears once in a forgotten footer.",[11,1241,1242],{},"Parsing CSS files without a browser is the approach most tutorials suggest, and it is the one that works worst on modern sites. More on that below.",[18,1244,1246],{"id":1245},"extract-colors-with-playwright","Extract colors with Playwright",[11,1248,1249],{},"First, install Playwright and a browser:",[148,1251,1253],{"className":150,"code":1252,"language":152,"meta":153,"style":153},"pip install playwright\nplaywright install chromium\n",[155,1254,1255,1266],{"__ignoreMap":153},[158,1256,1257,1260,1263],{"class":160,"line":161},[158,1258,1259],{"class":164},"pip",[158,1261,1262],{"class":172}," install",[158,1264,1265],{"class":172}," playwright\n",[158,1267,1268,1271,1273],{"class":160,"line":183},[158,1269,1270],{"class":164},"playwright",[158,1272,1262],{"class":172},[158,1274,1275],{"class":172}," chromium\n",[11,1277,1278],{},"Then collect styles from every element and count them:",[148,1280,1284],{"className":1281,"code":1282,"language":1283,"meta":153,"style":153},"language-python shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","from collections import Counter\nfrom playwright.sync_api import sync_playwright\n\nCOLLECT = \"\"\"\n() => {\n  const els = [...document.querySelectorAll('body *')].slice(0, 5000);\n  const out = { colors: [], fonts: [], sizes: [], radii: [], shadows: [] };\n  for (const el of els) {\n    const s = getComputedStyle(el);\n    out.colors.push(s.color, s.backgroundColor, s.borderTopColor);\n    out.fonts.push(s.fontFamily);\n    out.sizes.push(s.fontSize);\n    out.radii.push(s.borderTopLeftRadius);\n    out.shadows.push(s.boxShadow);\n  }\n  return out;\n}\n\"\"\"\n\ndef top(values, n=8, skip=(\"\", \"none\", \"normal\", \"auto\", \"0px\", \"rgba(0, 0, 0, 0)\")):\n    return Counter(v for v in values if v not in skip).most_common(n)\n\nwith sync_playwright() as p:\n    browser = p.chromium.launch()\n    page = browser.new_page(viewport={\"width\": 1440, \"height\": 900})\n    page.goto(\"https://stripe.com\", wait_until=\"networkidle\")\n    raw = page.evaluate(COLLECT)\n    browser.close()\n\nfor name in (\"colors\", \"fonts\", \"sizes\", \"radii\", \"shadows\"):\n    print(f\"\\n== {name} ==\")\n    for value, count in top(raw[name]):\n        print(f\"{count:>5}  {value}\")\n","python",[155,1285,1286,1291,1296,1301,1307,1313,1319,1324,1330,1336,1342,1348,1354,1360,1366,1372,1378,1384,1390,1395,1401,1407,1412,1418,1424,1430,1436,1442,1448,1453,1459,1465,1471],{"__ignoreMap":153},[158,1287,1288],{"class":160,"line":161},[158,1289,1290],{},"from collections import Counter\n",[158,1292,1293],{"class":160,"line":183},[158,1294,1295],{},"from playwright.sync_api import sync_playwright\n",[158,1297,1298],{"class":160,"line":400},[158,1299,1300],{"emptyLinePlaceholder":421},"\n",[158,1302,1304],{"class":160,"line":1303},4,[158,1305,1306],{},"COLLECT = \"\"\"\n",[158,1308,1310],{"class":160,"line":1309},5,[158,1311,1312],{},"() => {\n",[158,1314,1316],{"class":160,"line":1315},6,[158,1317,1318],{},"  const els = [...document.querySelectorAll('body *')].slice(0, 5000);\n",[158,1320,1321],{"class":160,"line":423},[158,1322,1323],{},"  const out = { colors: [], fonts: [], sizes: [], radii: [], shadows: [] };\n",[158,1325,1327],{"class":160,"line":1326},8,[158,1328,1329],{},"  for (const el of els) {\n",[158,1331,1333],{"class":160,"line":1332},9,[158,1334,1335],{},"    const s = getComputedStyle(el);\n",[158,1337,1339],{"class":160,"line":1338},10,[158,1340,1341],{},"    out.colors.push(s.color, s.backgroundColor, s.borderTopColor);\n",[158,1343,1345],{"class":160,"line":1344},11,[158,1346,1347],{},"    out.fonts.push(s.fontFamily);\n",[158,1349,1351],{"class":160,"line":1350},12,[158,1352,1353],{},"    out.sizes.push(s.fontSize);\n",[158,1355,1357],{"class":160,"line":1356},13,[158,1358,1359],{},"    out.radii.push(s.borderTopLeftRadius);\n",[158,1361,1363],{"class":160,"line":1362},14,[158,1364,1365],{},"    out.shadows.push(s.boxShadow);\n",[158,1367,1369],{"class":160,"line":1368},15,[158,1370,1371],{},"  }\n",[158,1373,1375],{"class":160,"line":1374},16,[158,1376,1377],{},"  return out;\n",[158,1379,1381],{"class":160,"line":1380},17,[158,1382,1383],{},"}\n",[158,1385,1387],{"class":160,"line":1386},18,[158,1388,1389],{},"\"\"\"\n",[158,1391,1393],{"class":160,"line":1392},19,[158,1394,1300],{"emptyLinePlaceholder":421},[158,1396,1398],{"class":160,"line":1397},20,[158,1399,1400],{},"def top(values, n=8, skip=(\"\", \"none\", \"normal\", \"auto\", \"0px\", \"rgba(0, 0, 0, 0)\")):\n",[158,1402,1404],{"class":160,"line":1403},21,[158,1405,1406],{},"    return Counter(v for v in values if v not in skip).most_common(n)\n",[158,1408,1410],{"class":160,"line":1409},22,[158,1411,1300],{"emptyLinePlaceholder":421},[158,1413,1415],{"class":160,"line":1414},23,[158,1416,1417],{},"with sync_playwright() as p:\n",[158,1419,1421],{"class":160,"line":1420},24,[158,1422,1423],{},"    browser = p.chromium.launch()\n",[158,1425,1427],{"class":160,"line":1426},25,[158,1428,1429],{},"    page = browser.new_page(viewport={\"width\": 1440, \"height\": 900})\n",[158,1431,1433],{"class":160,"line":1432},26,[158,1434,1435],{},"    page.goto(\"https://stripe.com\", wait_until=\"networkidle\")\n",[158,1437,1439],{"class":160,"line":1438},27,[158,1440,1441],{},"    raw = page.evaluate(COLLECT)\n",[158,1443,1445],{"class":160,"line":1444},28,[158,1446,1447],{},"    browser.close()\n",[158,1449,1451],{"class":160,"line":1450},29,[158,1452,1300],{"emptyLinePlaceholder":421},[158,1454,1456],{"class":160,"line":1455},30,[158,1457,1458],{},"for name in (\"colors\", \"fonts\", \"sizes\", \"radii\", \"shadows\"):\n",[158,1460,1462],{"class":160,"line":1461},31,[158,1463,1464],{},"    print(f\"\\n== {name} ==\")\n",[158,1466,1468],{"class":160,"line":1467},32,[158,1469,1470],{},"    for value, count in top(raw[name]):\n",[158,1472,1474],{"class":160,"line":1473},33,[158,1475,1476],{},"        print(f\"{count:>5}  {value}\")\n",[11,1478,1479],{},"Run it and you get something like:",[148,1481,1486],{"className":1482,"code":1484,"language":1485},[1483],"language-text","== colors ==\n 3021  rgb(255, 255, 255)\n 1204  rgb(26, 27, 37)\n  412  rgb(99, 91, 255)\n  118  rgb(66, 84, 102)\n","text",[155,1487,1484],{"__ignoreMap":153},[11,1489,1490,1491,1493,1494,1497,1498,1501],{},"That third line is the brand color, found by nothing smarter than counting. ",[155,1492,542],{}," has already done the hard work for you: it resolved every CSS variable chain, every ",[155,1495,1496],{},"var(--a, var(--b))"," fallback, every cascade conflict, and turned Tailwind utility soup into plain ",[155,1499,1500],{},"rgb()"," values.",[18,1503,1505],{"id":1504},"fonts-and-the-type-scale","Fonts and the type scale",[11,1507,1508],{},"The same collection already has them. Font families come back as full stacks, so take the first entry:",[148,1510,1512],{"className":1281,"code":1511,"language":1283,"meta":153,"style":153},"families = Counter(f.split(\",\")[0].strip('\"\\' ') for f in raw[\"fonts\"])\nprint(families.most_common(5))\n\nsizes = sorted(\n    {float(s.replace(\"px\", \"\")) for s, c in top(raw[\"sizes\"], n=20)},\n)\nprint(sizes)  # e.g. [12.0, 14.0, 16.0, 18.0, 20.0, 24.0, 36.0, 56.0]\n",[155,1513,1514,1519,1524,1528,1533,1538,1543],{"__ignoreMap":153},[158,1515,1516],{"class":160,"line":161},[158,1517,1518],{},"families = Counter(f.split(\",\")[0].strip('\"\\' ') for f in raw[\"fonts\"])\n",[158,1520,1521],{"class":160,"line":183},[158,1522,1523],{},"print(families.most_common(5))\n",[158,1525,1526],{"class":160,"line":400},[158,1527,1300],{"emptyLinePlaceholder":421},[158,1529,1530],{"class":160,"line":1303},[158,1531,1532],{},"sizes = sorted(\n",[158,1534,1535],{"class":160,"line":1309},[158,1536,1537],{},"    {float(s.replace(\"px\", \"\")) for s, c in top(raw[\"sizes\"], n=20)},\n",[158,1539,1540],{"class":160,"line":1315},[158,1541,1542],{},")\n",[158,1544,1545],{"class":160,"line":423},[158,1546,1547],{},"print(sizes)  # e.g. [12.0, 14.0, 16.0, 18.0, 20.0, 24.0, 36.0, 56.0]\n",[11,1549,1550],{},"That sorted list is the site's type scale. If it has fifteen entries instead of seven, you are looking at a site without a design system, which is also useful to know.",[18,1552,1554],{"id":1553},"from-raw-values-to-actual-tokens","From raw values to actual tokens",[11,1556,1557],{},"Raw counts are not tokens yet. Three cleanup steps matter:",[1559,1560,1561,1571,1583],"ol",{},[55,1562,1563,1566,1567,1570],{},[25,1564,1565],{},"Drop the defaults."," ",[155,1568,1569],{},"rgb(0, 0, 0)"," near the top does not mean the brand is black. Browser resets and inherited defaults pollute every element, so check whether a value actually appears on visible, styled elements before promoting it.",[55,1572,1573,1566,1576,34,1579,1582],{},[25,1574,1575],{},"Merge near-duplicates.",[155,1577,1578],{},"rgb(99, 91, 255)",[155,1580,1581],{},"rgb(99, 92, 255)"," are the same token with a rounding disagreement. Snap channels to a small tolerance before counting, or you will split one token's count across five entries.",[55,1584,1585,1588,1589,1592,1593,1595],{},[25,1586,1587],{},"Name by role, not by value."," The most frequent saturated color on buttons and links is ",[155,1590,1591],{},"primary",". The dominant text color is ",[155,1594,1485],{},". Frequency plus element context gets you there; k-means clustering is overkill for this and I would skip it.",[18,1597,1599],{"id":1598},"common-problems","Common problems",[11,1601,1602],{},"Real gotchas, in the order they will bite you:",[52,1604,1605,1615,1621,1638,1651],{},[55,1606,1607,1610,1611,1614],{},[25,1608,1609],{},"Your viewport is a filter."," Computed styles reflect the current viewport only. A ",[155,1612,1613],{},"@media (max-width: 640px)"," override is invisible at 1440px. Extract at two viewports (mobile and desktop) if you care about responsive tokens.",[55,1616,1617,1620],{},[25,1618,1619],{},"Cookie banners poison the palette."," Consent overlays and chat widgets bring their own colors and fonts, and they are often thousands of DOM nodes. Dismiss them or exclude their containers before collecting.",[55,1622,1623,1566,1626,1629,1630,1633,1634,1637],{},[25,1624,1625],{},"Fonts can lie.",[155,1627,1628],{},"font-family"," lists what CSS asked for, not what loaded. With ",[155,1631,1632],{},"font-display: swap"," the brand font may never arrive in a headless run. Await ",[155,1635,1636],{},"document.fonts.ready"," before collecting if exact loaded fonts matter.",[55,1639,1640,1646,1647,1650],{},[25,1641,1642,1643,351],{},"Gradients are not in ",[155,1644,1645],{},"backgroundColor"," They live in ",[155,1648,1649],{},"backgroundImage",". If a brand is gradient-heavy, collect that property too or you will report their hero as plain white.",[55,1652,1653,1656,1657,1660,1661,1664],{},[25,1654,1655],{},"Shadow DOM and iframes are invisible"," to ",[155,1658,1659],{},"querySelectorAll",". Web-component-heavy sites need you to walk ",[155,1662,1663],{},"shadowRoot","s explicitly.",[18,1666,1668],{"id":1667},"diy-vs-parsing-css-vs-an-api","DIY vs parsing CSS vs an API",[227,1670,1671,1693],{},[230,1672,1673],{},[233,1674,1675,1678,1681,1684,1687,1690],{},[236,1676,1677],{},"Approach",[236,1679,1680],{},"Tailwind / utility CSS",[236,1682,1683],{},"Runtime CSS-in-JS",[236,1685,1686],{},"Resolves var() and cascade",[236,1688,1689],{},"Media queries",[236,1691,1692],{},"Maintenance",[252,1694,1695,1712,1730],{},[233,1696,1697,1700,1702,1704,1706,1709],{},[257,1698,1699],{},"Playwright + computed styles (this guide)",[257,1701,315],{},[257,1703,315],{},[257,1705,315],{},[257,1707,1708],{},"Current viewport only",[257,1710,1711],{},"Browser infra is yours to run",[233,1713,1714,1717,1720,1722,1724,1727],{},[257,1715,1716],{},"Parse CSS files yourself (tinycss2, no browser)",[257,1718,1719],{},"Painful",[257,1721,689],{},[257,1723,689],{},[257,1725,1726],{},"Declared, but unused values included",[257,1728,1729],{},"Low, but wrong on modern sites",[233,1731,1732,1735,1737,1740,1742,1745],{},[257,1733,1734],{},"MiroMiro extract API",[257,1736,315],{},[257,1738,1739],{},"No (static HTML + CSS, no JS execution)",[257,1741,315],{},[257,1743,1744],{},"Yes, all declared breakpoints",[257,1746,1747],{},"None",[11,1749,1750,1751,1753],{},"Use the Playwright approach if you are extracting from a handful of sites, need runtime-injected styles, and want full control. Skip the hand-rolled CSS-parsing route: resolving the cascade, specificity, and nested ",[155,1752,203],{}," fallbacks yourself is a project, not a script.",[18,1755,1757],{"id":1756},"or-use-one-api-call","Or use one API call",[11,1759,1760],{},"The dedupe, the ranking, the var() chains, the resets, and every declared breakpoint - that is what our extract endpoint does for a living:",[148,1762,1763],{"className":150,"code":1022,"language":152,"meta":153,"style":153},[155,1764,1765,1777],{"__ignoreMap":153},[158,1766,1767,1769,1771,1773,1775],{"class":160,"line":161},[158,1768,165],{"class":164},[158,1770,169],{"class":168},[158,1772,1033],{"class":172},[158,1774,176],{"class":168},[158,1776,180],{"class":179},[158,1778,1779,1781,1783,1785,1787],{"class":160,"line":183},[158,1780,186],{"class":172},[158,1782,169],{"class":168},[158,1784,191],{"class":172},[158,1786,194],{"class":179},[158,1788,197],{"class":168},[11,1790,1791,1792,1795,1796,1795,1799,1795,1802,1795,1805,1795,1808,1795,1811,1814,1815,1818],{},"The JSON response has ",[155,1793,1794],{},"colors",", ",[155,1797,1798],{},"fontFamilies",[155,1800,1801],{},"fontSizes",[155,1803,1804],{},"fontWeights",[155,1806,1807],{},"spacing",[155,1809,1810],{},"borderRadiuses",[155,1812,1813],{},"boxShadows",", and more, already deduped and ranked. Trim it with ",[155,1816,1817],{},"?fields=colors,spacing"," if you only need part of it.",[11,1820,1821,1822,1824,1825,351],{},"If your script from this guide breaks on some site's cookie banner at 2am, that is roughly the moment an API earns its keep. You can ",[28,1823,775],{"href":344}," with 100 credits a month, no card, or try it without signing up in the ",[28,1826,350],{"href":349},[18,1828,1830],{"id":1829},"summary","Summary",[11,1832,1833,1834,1836,1837,1840],{},"Playwright plus ",[155,1835,542],{}," plus a ",[155,1838,1839],{},"Counter"," is the honest way to extract design tokens in Python, and the frequency counting matters more than any clever clustering. Parse-the-CSS approaches are not worth your time on modern sites. I hope this saved you a debugging evening.",[18,1842,355],{"id":354},[357,1844,1846],{"id":1845},"can-i-extract-design-tokens-without-a-headless-browser","Can I extract design tokens without a headless browser?",[11,1848,1849],{},"You can parse the site's CSS with a library like tinycss2, but on modern sites this works badly: CSS-in-JS generates styles at runtime, Tailwind buries the palette in utility classes, and you cannot tell which declared values are actually used. Computed styles from a real browser are the ground truth.",[357,1851,1853],{"id":1852},"how-do-i-extract-tokens-from-a-tailwind-site-where-everything-is-utility-classes","How do I extract tokens from a Tailwind site where everything is utility classes?",[11,1855,1856,1857,1859,1860,1656,1862,1865],{},"Ignore the class names entirely and read computed styles. ",[155,1858,542],{}," resolves ",[155,1861,817],{},[155,1863,1864],{},"rgb(79, 70, 229)"," like any other CSS, so nothing in this guide changes.",[357,1867,1869],{"id":1868},"why-do-my-extracted-colors-include-values-the-site-never-visibly-uses","Why do my extracted colors include values the site never visibly uses?",[11,1871,1872],{},"Three usual suspects: browser defaults on elements you collected, cookie banners and chat widgets injecting their own palette, and transparent or inherited values you forgot to filter.",[357,1874,1876],{"id":1875},"how-many-pages-should-i-sample","How many pages should I sample?",[11,1878,1879],{},"One landing page is usually enough for brand color and typography. Add one product or app page for functional colors (success, error, info). More than three pages rarely changes the top tokens.",[18,1881,1883],{"id":1882},"related-reading","Related reading",[52,1885,1886,1893,1899],{},[55,1887,1888,1892],{},[28,1889,1891],{"href":1890},"/api/design-tokens-api","Design tokens API"," - the endpoint this post's shortcut uses",[55,1894,1895,1898],{},[28,1896,1897],{"href":806},"Design tokens docs"," - full response shape and field list",[55,1900,1901,1905],{},[28,1902,1904],{"href":1903},"/api/use-cases/ai-agent-ground-truth","Ground truth for AI agents"," - why agents need real tokens instead of guessing from screenshots",[386,1907,1908],{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}",{"title":153,"searchDepth":183,"depth":183,"links":1910},[1911,1912,1913,1914,1915,1916,1917,1918,1924],{"id":1245,"depth":183,"text":1246},{"id":1504,"depth":183,"text":1505},{"id":1553,"depth":183,"text":1554},{"id":1598,"depth":183,"text":1599},{"id":1667,"depth":183,"text":1668},{"id":1756,"depth":183,"text":1757},{"id":1829,"depth":183,"text":1830},{"id":354,"depth":183,"text":355,"children":1919},[1920,1921,1922,1923],{"id":1845,"depth":400,"text":1846},{"id":1852,"depth":400,"text":1853},{"id":1868,"depth":400,"text":1869},{"id":1875,"depth":400,"text":1876},{"id":1882,"depth":183,"text":1883},"Tutorials","Extract colors, fonts, spacing, and shadows from any website with Playwright in Python - working code, the gotchas that bite, and the one-API-call shortcut.",[1928,1930,1932,1934],{"question":1846,"answer":1929},"You can parse the site's CSS files with a library like tinycss2, but on modern sites this works badly. CSS-in-JS generates styles at runtime, utility-class sites like Tailwind bury the palette in thousands of class rules, and you cannot tell which declared values are actually used. Computed styles from a real browser are the ground truth.",{"question":1853,"answer":1931},"Ignore the class names entirely and read computed styles. getComputedStyle resolves bg-indigo-600 to rgb(79, 70, 229) the same way it resolves any other CSS, so the frequency-counting approach in this guide works unchanged.",{"question":1869,"answer":1933},"Three usual suspects: browser default styles on elements you collected, cookie banners and chat widgets injecting their own palette, and transparent or inherited values you forgot to filter. Count frequency, filter defaults, and dismiss overlays before collecting.",{"question":1935,"answer":1936},"How many pages should I sample to get a reliable palette?","One page is usually enough for brand color and typography if it is the homepage or a landing page. Add one product or app page for the functional palette (success, error, info states). More than three pages rarely changes the top tokens.",{},"/api-blog/how-to-extract-design-tokens-from-any-website-in-python",[425,864,1940],"how-to-extract-website-color-palette-programmatically",{"title":547,"description":1926},"api-blog/how-to-extract-design-tokens-from-any-website-in-python",[869,1283,1270,1944,1945],"css","web extraction","L5qnHk0I6Xw2LZ4KpLx52C6CU18QlatcV45aNNbr8F0",1784751617363]