[{"data":1,"prerenderedAt":1600},["ShallowReactive",2],{"api-blog-n8n-website-scraping":3,"api-blog-related-n8n-website-scraping":508},{"id":4,"title":5,"author":6,"body":7,"category":469,"date":470,"dateModified":471,"description":472,"extension":473,"faqs":474,"image":471,"meta":490,"navigation":491,"path":492,"readingTime":493,"relatedSlugs":494,"seo":499,"seoTitle":471,"stem":500,"tags":501,"__hash__":507},"apiBlog/api-blog/n8n-website-scraping.md","n8n Website Scraping: Text, Code, Brand Kits and Images","Soraia",{"type":8,"value":9,"toc":458},"minimark",[10,23,26,31,37,65,70,132,144,147,151,154,157,161,164,167,250,253,294,313,317,378,382,388,405,411,421,427,431,451,455],[11,12,13,14,18,19,22],"p",{},"To scrape a website with n8n, chain an ",[15,16,17],"strong",{},"HTTP Request"," node (download the page) and an ",[15,20,21],{},"HTML"," node (pull values out with CSS selectors). That handles static pages in two minutes. It breaks on JavaScript-built sites, and it only ever gives you text. If what you want is the page's design (code, an Elementor template, brand colors, the images), use a node that reads the page in a real browser and returns that directly.",[11,24,25],{},"Here are the three setups, when each one is right, and the problems you will hit.",[27,28,30],"h2",{"id":29},"scrape-text-with-http-request-html","Scrape text with HTTP Request + HTML",[11,32,33,34,36],{},"First, an ",[15,35,17],{}," node:",[38,39,40,48,54],"ul",{},[41,42,43,44],"li",{},"Method: ",[45,46,47],"code",{},"GET",[41,49,50,51],{},"URL: ",[45,52,53],{},"https://example.com/pricing",[41,55,56,57,60,61,64],{},"Response format: ",[45,58,59],{},"String"," (put the body in a field called ",[45,62,63],{},"data",")",[11,66,67,68,36],{},"Then an ",[15,69,21],{},[38,71,72,78,87],{},[41,73,74,75],{},"Operation: ",[15,76,77],{},"Extract HTML Content",[41,79,80,81,84,85],{},"Source data: ",[45,82,83],{},"JSON",", property ",[45,86,63],{},[41,88,89,90],{},"Extraction values, one row per value:\n",[38,91,92,106,117],{},[41,93,94,95,98,99,102,103],{},"Key ",[45,96,97],{},"title",", CSS selector ",[45,100,101],{},"h1",", return value ",[45,104,105],{},"Text",[41,107,94,108,98,111,102,114,116],{},[45,109,110],{},"plans",[45,112,113],{},".plan-name",[45,115,105],{},", Return array on",[41,118,94,119,98,122,102,125,128,129],{},[45,120,121],{},"image",[45,123,124],{},"meta[property=\"og:image\"]",[45,126,127],{},"Attribute",", attribute ",[45,130,131],{},"content",[11,133,134,135,137,138,140,141,143],{},"Run it and you get one item with ",[45,136,97],{},", ",[45,139,110],{}," and ",[45,142,121],{},".",[11,145,146],{},"This is the right tool for prices, headlines, links and anything else that is text in the HTML. It is free and it is fast. I would start here every time the page is server-rendered.",[27,148,150],{"id":149},"scrape-javascript-websites-with-a-browser-node","Scrape JavaScript websites with a browser node",[11,152,153],{},"Open the page with View Source. If the text you want is not in it, the HTTP Request node will not see it either: the site builds its content in the browser. Most React, Next.js, Framer and Webflow sites behave like this.",[11,155,156],{},"You need something that runs a real browser and gives the result back to n8n. Firecrawl and Apify both have n8n nodes; Firecrawl returns the page as Markdown, Apify runs whatever scraper you pick from its store. For text from JavaScript sites, either is a good choice.",[27,158,160],{"id":159},"scrape-the-design-code-elementor-brand-and-images","Scrape the design: code, Elementor, brand and images",[11,162,163],{},"Text scrapers return text. If you are rebuilding a site, moving it to WordPress or Shopify, or collecting a brand, you want the design itself, and HTML-plus-selectors gets you nowhere near it.",[11,165,166],{},"That is what the MiroMiro node does. It loads the page in a real browser and returns:",[168,169,170,186],"table",{},[171,172,173],"thead",{},[174,175,176,180,183],"tr",{},[177,178,179],"th",{},"Operation",[177,181,182],{},"What you get",[177,184,185],{},"Credits",[187,188,189,208,218,228,239],"tbody",{},[174,190,191,195,205],{},[192,193,194],"td",{},"Extract Code",[192,196,197,198,201,202],{},"A section (hero, pricing, footer...) as Tailwind, HTML + CSS, React, Vue, an ",[15,199,200],{},"Elementor template"," or a ",[15,203,204],{},"Shopify section",[192,206,207],{},"10",[174,209,210,213,216],{},[192,211,212],{},"Extract Brand",[192,214,215],{},"Logo, brand colors with roles, fonts, and whether each was declared by the site or inferred",[192,217,207],{},[174,219,220,223,226],{},[192,221,222],{},"Extract Design Tokens",[192,224,225],{},"Every color, font size, spacing and radius with usage counts, or a W3C tokens file",[192,227,207],{},[174,229,230,233,236],{},[192,231,232],{},"Extract Images",[192,234,235],{},"Every image URL: img tags, srcset, CSS backgrounds, favicons, og:image",[192,237,238],{},"1",[174,240,241,244,247],{},[192,242,243],{},"Extract SVGs, Fonts, Videos, Audio, Lottie",[192,245,246],{},"The files of that type",[192,248,249],{},"1 to 5",[11,251,252],{},"To try it:",[254,255,256,267,275],"ol",{},[41,257,258,259,262,263,266],{},"Install the node. On self-hosted n8n: ",[15,260,261],{},"Settings > Community nodes > Install",", package ",[45,264,265],{},"n8n-nodes-miromiro",". It is verified by n8n and arrives in n8n Cloud's nodes panel with their next release.",[41,268,269,270,143],{},"Add a MiroMiro node, create the credential with a ",[271,272,274],"a",{"href":273},"/api/onboarding","free API key",[41,276,277,278,280,281,284,285,140,288,284,291,143],{},"Pick ",[15,279,194],{},", paste a URL, set ",[15,282,283],{},"Section"," to ",[45,286,287],{},"Pricing",[15,289,290],{},"Output",[45,292,293],{},"Elementor Template",[11,295,296,297,299,300,303,304,307,308,312],{},"The ",[45,298,45],{}," field is the complete template. Send it through a ",[15,301,302],{},"Convert to File"," node and import the ",[45,305,306],{},".json"," in WordPress. Every result also lists the page's other sections with a ready selector, so a Split + second MiroMiro node can rebuild the whole page. The ",[271,309,311],{"href":310},"/api/n8n","ready-made templates"," do exactly that.",[27,314,316],{"id":315},"which-one-to-use","Which one to use",[168,318,319,335],{},[171,320,321],{},[174,322,323,326,329,332],{},[177,324,325],{},"You want",[177,327,328],{},"Use",[177,330,331],{},"Handles JavaScript sites",[177,333,334],{},"Cost",[187,336,337,351,365],{},[174,338,339,342,345,348],{},[192,340,341],{},"Text from static pages (prices, titles, links)",[192,343,344],{},"HTTP Request + HTML",[192,346,347],{},"No",[192,349,350],{},"Free",[174,352,353,356,359,362],{},[192,354,355],{},"Text or Markdown from JavaScript pages",[192,357,358],{},"Firecrawl or Apify node",[192,360,361],{},"Yes",[192,363,364],{},"Per page",[174,366,367,370,373,375],{},[192,368,369],{},"Code, Elementor, Shopify, brand kit, images",[192,371,372],{},"MiroMiro node",[192,374,361],{},[192,376,377],{},"1 to 10 credits per call",[27,379,381],{"id":380},"common-problems","Common problems",[11,383,384,387],{},[15,385,386],{},"The HTML node returns empty values."," The content is built by JavaScript. Check View Source; if it is missing there, switch to a browser node.",[11,389,390,396,397,400,401,404],{},[15,391,392,395],{},[45,393,394],{},"URL is not defined"," in an expression."," n8n's expression sandbox has no ",[45,398,399],{},"URL"," constructor. To get the domain of a link, use ",[45,402,403],{},"{{ $json.url.split('/')[2] }}"," instead.",[11,406,407,410],{},[15,408,409],{},"The site returns 403."," Bot protection. Browser nodes get through most of it. When a site refuses even a real browser, no scraper is going to work on it, and MiroMiro says so instead of returning an empty result (and does not charge the call).",[11,412,413,416,417,420],{},[15,414,415],{},"Images only appear when you scroll."," Lazy loading. On the MiroMiro images operation, add the ",[15,418,419],{},"Render"," option: the page is scrolled in a browser before the images are collected.",[11,422,423,426],{},[15,424,425],{},"One run, hundreds of URLs."," Read the list from a Google Sheet or a Code node; n8n runs each following node once per item. Same page, same settings within 24 hours costs nothing on MiroMiro, so re-running a failed batch only pays for what actually re-extracts.",[27,428,430],{"id":429},"or-start-from-a-template","Or start from a template",[11,432,433,434,137,438,137,442,137,446,450],{},"Every setup above exists as a free n8n template you import in one click: ",[271,435,437],{"href":436},"/api/n8n/download-every-image","download every image from a website",[271,439,441],{"href":440},"/api/n8n/rebuild-whole-page-as-code","rebuild a whole page as code",[271,443,445],{"href":444},"/api/n8n/rebuild-whole-page-in-elementor","a page in Elementor",[271,447,449],{"href":448},"/api/n8n/brand-kit-files","brand kits"," and more. The MiroMiro API includes 300 free credits a month, no card. You can start for free.",[27,452,454],{"id":453},"summary","Summary",[11,456,457],{},"For text on static pages, HTTP Request + HTML is all you need. For text on JavaScript pages, add a browser node. For anything you want to build with, the design itself, skip the selectors and use a node that returns code, templates and brand data directly.",{"title":459,"searchDepth":460,"depth":460,"links":461},"",2,[462,463,464,465,466,467,468],{"id":29,"depth":460,"text":30},{"id":149,"depth":460,"text":150},{"id":159,"depth":460,"text":160},{"id":315,"depth":460,"text":316},{"id":380,"depth":460,"text":381},{"id":429,"depth":460,"text":430},{"id":453,"depth":460,"text":454},"Tutorials","2026-10-26",null,"How to scrape a website with n8n: the HTTP Request + HTML node for text, a scraping node for JavaScript sites, and the MiroMiro node when you need code, Elementor, brand colors or images.","md",[475,478,481,484,487],{"question":476,"answer":477},"How do I scrape a website in n8n?","Add an HTTP Request node with the page URL, then an HTML node with the Extract HTML Content operation and a CSS selector for each value you want. That covers static pages. For pages that build themselves with JavaScript, use a node that runs a real browser, such as Firecrawl, Apify or MiroMiro.",{"question":479,"answer":480},"Can n8n scrape JavaScript websites?","Not with the HTTP Request node alone: it downloads the HTML before any JavaScript runs, so React, Next.js, Framer and Webflow pages often come back nearly empty. Use a node that loads the page in a real browser first.",{"question":482,"answer":483},"Can n8n turn a website into code or an Elementor template?","Yes, with the MiroMiro node. Its Extract Code operation returns a section of any page as Tailwind, HTML + CSS, React, Vue, an Elementor template (.json) or a Shopify section (.liquid), styled like the original. One section costs 10 credits.",{"question":485,"answer":486},"Is scraping with n8n free?","Self-hosted n8n and the HTTP Request and HTML nodes are free. Browser-based scraping services charge per page or per credit; MiroMiro includes 300 free credits a month with no card, which is about 30 sections as code or 300 image lists.",{"question":488,"answer":489},"How do I scrape many pages in one n8n run?","Put the URLs in a list (a Code node, a Google Sheet or a Read From File node), and n8n runs every node after it once per item. Add a Wait node if a site rate-limits you.",{},true,"/api-blog/n8n-website-scraping",7,[495,496,497,498],"free-n8n-templates-for-websites","rebuild-website-in-wordpress-with-n8n-and-elementor","how-to-extract-brand-assets-in-bulk","how-to-extract-website-color-palette-programmatically",{"title":5,"description":472},"api-blog/n8n-website-scraping",[502,503,504,505,506],"n8n","web scraping","automation","no-code","workflows","GN7_4Y-0YFN1A1j-mZ20AwQNfYnzvYIx6shjoWjWwXE",[509,832,1100],{"id":510,"title":511,"author":6,"body":512,"category":469,"date":470,"dateModified":471,"description":806,"extension":473,"faqs":807,"image":471,"meta":820,"navigation":491,"path":821,"readingTime":822,"relatedSlugs":823,"seo":826,"seoTitle":471,"stem":827,"tags":828,"__hash__":831},"apiBlog/api-blog/free-n8n-templates-for-websites.md","Free n8n Templates for Websites: 14 Workflow Examples",{"type":8,"value":513,"toc":795},[514,521,533,537,545,549,557,566,575,579,587,599,603,616,625,629,645,654,667,671,680,684,693,697,750,753,757,788],[11,515,516,517,520],{},"The n8n template library is full of social media posters, lead scrapers and support bots. Templates that work on the ",[15,518,519],{},"design"," of a website (its code, its sections, its brand, its images) are rare. These 14 are free, each one runs on a real website end to end, and each has its own page with the workflow and an import link.",[11,522,523,524,526,527,530,531,143],{},"All of them use the MiroMiro node. Get a ",[271,525,274],{"href":273}," (300 credits a month, no card) and install the node from ",[15,528,529],{},"Settings > Community nodes"," with the package name ",[45,532,265],{},[27,534,536],{"id":535},"images-and-files","Images and files",[11,538,539,544],{},[15,540,541,143],{},[271,542,543],{"href":436},"Download every image from a website"," MiroMiro lists every image on the page (img tags, srcset, CSS backgrounds, favicons, og:image), n8n downloads each one and zips them. 1 credit per page, however many images. Turn on Render for images that only load when you scroll.",[27,546,548],{"id":547},"website-to-code","Website to code",[11,550,551,556],{},[15,552,553,143],{},[271,554,555],{"href":440},"Rebuild a whole page as code"," Every section of a page as Tailwind, React, HTML or Vue, one file per section in a zip, plus a link to the whole page assembled with a Download HTML button. This is the template I would start with if you build websites.",[11,558,559,565],{},[15,560,561,143],{},[271,562,564],{"href":563},"/api/n8n/rebuild-any-website-form","Rebuild any website from a form"," Same job behind an n8n form: paste a URL, pick the output, and the browser opens the rebuilt page. Good as an internal tool for a team that does not use n8n.",[11,567,568,574],{},[15,569,570,143],{},[271,571,573],{"href":572},"/api/n8n/migrate-site-to-nextjs","Migrate a site to Next.js"," List the pages of a WordPress, Elementor, Shopify or Webflow site with the route each should become; get a Next.js + Tailwind project as a zip. Menus, sliders and forms arrive as static markup, so plan an afternoon to wire them up.",[27,576,578],{"id":577},"wordpress-and-elementor","WordPress and Elementor",[11,580,581,586],{},[15,582,583,143],{},[271,584,585],{"href":444},"Rebuild a whole page in Elementor"," Every section of a page joined, in order, into one Elementor page template you import into WordPress. Each section arrives as an Elementor container with its styled HTML inside, so it looks like the original as soon as you import it.",[11,588,589,595,596,598],{},[15,590,591,143],{},[271,592,594],{"href":593},"/api/n8n/section-to-elementor","Turn website sections into Elementor templates"," One section, or a list of pages and sections in one run, each as its own importable ",[45,597,306],{},". The bulk version is the one agencies use to build a library of section templates.",[27,600,602],{"id":601},"shopify","Shopify",[11,604,605,611,612,615],{},[15,606,607,143],{},[271,608,610],{"href":609},"/api/n8n/rebuild-whole-page-as-shopify-sections","Rebuild a whole page as Shopify sections"," Every section as an Online Store 2.0 section (",[45,613,614],{},".liquid","), zipped for Edit code > sections.",[11,617,618,624],{},[15,619,620,143],{},[271,621,623],{"href":622},"/api/n8n/rebuild-section-in-shopify","Upload a section to your Shopify theme"," Extracts one section and pushes it straight into your theme through the Shopify Admin API. Test it on an unpublished theme copy first.",[27,626,628],{"id":627},"brand-and-design-research","Brand and design research",[11,630,631,636,637,640,641,644],{},[15,632,633,143],{},[271,634,635],{"href":448},"Get any website's brand kit as files"," A zip with the logo, ",[45,638,639],{},"brand.css"," (colors and fonts as CSS variables), ",[45,642,643],{},"tokens.json"," (W3C Design Tokens for Figma or Style Dictionary) and a readable summary. 20 credits per site.",[11,646,647,653],{},[15,648,649,143],{},[271,650,652],{"href":651},"/api/n8n/compare-brands-csv","Compare the brands of many websites"," A list of websites in, one CSV out: primary and accent colors, fonts, logo and confidence per site. Useful for competitor research and agency pitches.",[11,655,656,662,663,666],{},[15,657,658,143],{},[271,659,661],{"href":660},"/api/n8n/brand-board","Brand board from any website"," Open your webhook with ",[45,664,665],{},"?url=stripe.com"," and get a designed brand board in the browser. The fastest one to show to a client.",[27,668,670],{"id":669},"ai-agents","AI agents",[11,672,673,679],{},[15,674,675,143],{},[271,676,678],{"href":677},"/api/n8n/ai-agent-rebuild-websites","An AI agent that rebuilds websites"," A chat agent with MiroMiro as its tools: \"turn the hero of linear.app into a React component\", \"what are airbnb.com's brand colors?\". Works with Claude, OpenAI, Gemini or any chat model with tool calling.",[27,681,683],{"id":682},"all-of-them-at-once","All of them at once",[11,685,686,692],{},[15,687,688,143],{},[271,689,691],{"href":690},"/api/n8n/miromiro-showcase","The starter workflow"," Four of the above on one canvas (images, a section in Elementor, a whole page as code, the agent) to see what the node does before picking a focused template.",[27,694,696],{"id":695},"what-they-cost","What they cost",[168,698,699,708],{},[171,700,701],{},[174,702,703,706],{},[177,704,705],{},"Template",[177,707,185],{},[187,709,710,718,726,734,742],{},[174,711,712,715],{},[192,713,714],{},"Download every image",[192,716,717],{},"1 per page",[174,719,720,723],{},[192,721,722],{},"A section as code, Elementor or Shopify",[192,724,725],{},"10 per section",[174,727,728,731],{},[192,729,730],{},"A whole page (6 to 12 sections)",[192,732,733],{},"60 to 120",[174,735,736,739],{},[192,737,738],{},"Brand kit as files",[192,740,741],{},"20 per site",[174,743,744,747],{},[192,745,746],{},"Compare brands, brand board",[192,748,749],{},"10 per site",[11,751,752],{},"The same page with the same settings within 24 hours is free, so re-running a template while you adjust it costs nothing.",[27,754,756],{"id":755},"how-to-import-one","How to import one",[254,758,759,765,775,778],{},[41,760,761,762,143],{},"Open the template's page and click ",[15,763,764],{},"Copy link",[41,766,767,768,771,772,143],{},"In n8n, open the ",[15,769,770],{},"⋯"," menu at the top right of a workflow and choose ",[15,773,774],{},"Import from URL",[41,776,777],{},"Open any MiroMiro node, create the credential with your API key.",[41,779,780,781,784,785,143],{},"Change the website in ",[15,782,783],{},"Settings"," and click ",[15,786,787],{},"Execute workflow",[11,789,790,791,794],{},"Browse all of them, with the workflow drawn and the result shown, at ",[271,792,793],{"href":310},"miromiro.app/api/n8n",". You can start for free.",{"title":459,"searchDepth":460,"depth":460,"links":796},[797,798,799,800,801,802,803,804,805],{"id":535,"depth":460,"text":536},{"id":547,"depth":460,"text":548},{"id":577,"depth":460,"text":578},{"id":601,"depth":460,"text":602},{"id":627,"depth":460,"text":628},{"id":669,"depth":460,"text":670},{"id":682,"depth":460,"text":683},{"id":695,"depth":460,"text":696},{"id":755,"depth":460,"text":756},"14 free n8n workflow templates for designers, agencies and developers: download every image, rebuild a page in Elementor or Shopify, get a brand kit, and an AI agent that rebuilds websites.",[808,811,814,817],{"question":809,"answer":810},"Where can I find free n8n templates for websites?","MiroMiro publishes 14 free n8n workflows at miromiro.app/api/n8n: image downloads, whole pages as code, Elementor and Shopify rebuilds, brand kits, competitor brand comparisons, a migration to Next.js and an AI agent. The source is on GitHub.",{"question":812,"answer":813},"How do I import an n8n template?","Copy the template's link, then in n8n open the ⋯ menu at the top right of a workflow and choose Import from URL. You can also download the .json file and use Import from File.",{"question":815,"answer":816},"Do these templates work on n8n Cloud?","They use the MiroMiro node, which n8n has verified. On self-hosted n8n you install it today from Settings > Community nodes (package n8n-nodes-miromiro); on n8n Cloud it arrives in the nodes panel with n8n's next release.",{"question":818,"answer":819},"What do the templates cost to run?","The templates are free. They call the MiroMiro API, which includes 300 free credits a month with no card: a section as code or Elementor is 10 credits, a brand kit 10, an image list 1. A whole page of 6 to 12 sections is 60 to 120 credits.",{},"/api-blog/free-n8n-templates-for-websites",6,[824,496,825,497],"n8n-website-scraping","convert-html-to-elementor-json-template",{"title":511,"description":806},"api-blog/free-n8n-templates-for-websites",[502,829,504,830,601],"n8n templates","elementor","-jA3PhK3byzARjE-ayIiUy6L94nvBqjzZphwTW8tlBs",{"id":833,"title":834,"author":6,"body":835,"category":469,"date":470,"dateModified":471,"description":1073,"extension":473,"faqs":1074,"image":471,"meta":1090,"navigation":491,"path":1091,"readingTime":822,"relatedSlugs":1092,"seo":1094,"seoTitle":471,"stem":1095,"tags":1096,"__hash__":1099},"apiBlog/api-blog/rebuild-website-in-wordpress-with-n8n-and-elementor.md","n8n + WordPress: Rebuild Any Website in Elementor Automatically",{"type":8,"value":836,"toc":1064},[837,840,843,847,869,873,920,927,934,938,945,987,994,998,1009,1012,1016,1019,1045,1049,1055,1057],[11,838,839],{},"You can rebuild any live website in WordPress with n8n: the MiroMiro node turns each section of a page into an Elementor template, and n8n joins them into one page template you import. One section takes a minute to set up. A whole page is the same workflow plus a loop. A list of pages is the same loop again.",[11,841,842],{},"This is the setup agencies use to move clients off Webflow, Framer, Wix or a custom site, and to start a WordPress page from a design a client points at.",[27,844,846],{"id":845},"what-you-need","What you need",[38,848,849,852,859,866],{},[41,850,851],{},"n8n (self-hosted today; n8n Cloud gets the node with n8n's next release, it is already verified)",[41,853,854,855,262,857],{},"The MiroMiro node: ",[15,856,261],{},[45,858,265],{},[41,860,861,862,865],{},"A ",[271,863,864],{"href":273},"free MiroMiro API key",": 300 credits a month, no card",[41,867,868],{},"WordPress with Elementor (the free plugin is enough)",[27,870,872],{"id":871},"one-section-in-elementor","One section in Elementor",[254,874,875,886,903,917],{},[41,876,877,878,881,882,885],{},"Add a ",[15,879,880],{},"Manual Trigger",", then a ",[15,883,884],{},"MiroMiro"," node.",[41,887,888,889,891,892,895,896,899,900,143],{},"In the MiroMiro node: Operation ",[15,890,194],{},", URL ",[45,893,894],{},"https://www.allbirds.com",", Section ",[15,897,898],{},"Hero",", Output ",[15,901,902],{},"Elementor Template (WordPress)",[41,904,877,905,907,908,911,912,914,915,143],{},[15,906,302],{}," node: Operation ",[15,909,910],{},"Convert to Text File",", source property ",[45,913,45],{},", file name ending in ",[45,916,306],{},[41,918,919],{},"Execute, download the file.",[11,921,922,923,926],{},"In WordPress: ",[15,924,925],{},"Templates > Saved Templates > Import Templates",", pick the file, then insert it into any page with the folder icon in the Elementor editor.",[11,928,929,930,933],{},"That is the whole thing. The ready-made version is the ",[271,931,932],{"href":593},"section to Elementor template",", which also has a variant that takes a list of pages and sections and returns one template each.",[27,935,937],{"id":936},"a-whole-page-in-one-template","A whole page in one template",[11,939,940,941,944],{},"A page is a list of sections. MiroMiro gives you that list: every Extract Code result has a ",[45,942,943],{},"sections"," field with each section's label and a ready CSS selector.",[254,946,947,954,963,977,982],{},[41,948,949,951,952,143],{},[15,950,884],{}," (Extract Code, Elementor output) on the page. Besides the hero, it returns ",[45,953,943],{},[41,955,861,956,959,960,962],{},[15,957,958],{},"Code"," node that splits ",[45,961,943],{}," into one item per section (skipping the hero you already have).",[41,964,965,966,968,969,972,973,976],{},"A second ",[15,967,884],{}," node with ",[15,970,971],{},"Selector"," set to ",[45,974,975],{},"{{ $json.selector }}",", so each item becomes one Elementor section.",[41,978,861,979,981],{},[15,980,958],{}," node that joins the hero and every section, in page order, into one page template.",[41,983,984,986],{},[15,985,302],{},", then import as above.",[11,988,989,990,993],{},"Skip building it: the ",[271,991,992],{"href":444},"whole page in Elementor template"," is exactly these five nodes, tested end to end.",[27,995,997],{"id":996},"what-comes-out-in-elementor","What comes out in Elementor",[11,999,1000,1001,1004,1005,1008],{},"Each section arrives as one Elementor ",[15,1002,1003],{},"container"," holding an ",[15,1006,1007],{},"HTML widget"," with the section's markup and styles: the colors, fonts and spacing the page shows in a real browser, not a screenshot guess. It looks like the original the moment you import it.",[11,1010,1011],{},"You edit the text, links and images inside that HTML widget. If you want every heading, paragraph and button as its own native Elementor widget instead, the MiroMiro Chrome extension exports that (Download > Elementor template with Editable widgets on), one section or a whole page at a time.",[27,1013,1015],{"id":1014},"what-it-does-not-do","What it does not do",[11,1017,1018],{},"Be clear with clients about this part:",[38,1020,1021,1027,1033,1039],{},[41,1022,1023,1026],{},[15,1024,1025],{},"Content is the source site's."," Text and images belong to whoever owns the original. Replace them unless it is your client's own site.",[41,1028,1029,1032],{},[15,1030,1031],{},"Interactive parts arrive static."," Menus, sliders, tabs and forms come back in their first visible state. Rebuild them with Elementor's own widgets or a form plugin.",[41,1034,1035,1038],{},[15,1036,1037],{},"One page at a time."," It does not crawl a whole site by itself; you list the pages.",[41,1040,1041,1044],{},[15,1042,1043],{},"Fonts."," If the site uses a custom font, add it in Elementor > Custom Fonts (or Google Fonts if it is one) so the headings match.",[27,1046,1048],{"id":1047},"deliver-it-automatically","Deliver it automatically",[11,1050,1051,1052,1054],{},"Since it is n8n, the last step does not have to be a download. Swap ",[15,1053,302],{}," for a Google Drive or Dropbox node to drop the templates into a client folder, or an email node to send them. Put the page list in a Google Sheet and the whole migration runs when someone adds a row.",[27,1056,454],{"id":453},[11,1058,1059,1060,1063],{},"For one section, the MiroMiro node plus Convert to File is enough. For whole pages and site moves, start from the ",[271,1061,1062],{"href":444},"whole page in Elementor"," template and change only the website. Either way, every section lands in WordPress looking like the original, ready to edit. You can start for free with 300 credits a month.",{"title":459,"searchDepth":460,"depth":460,"links":1065},[1066,1067,1068,1069,1070,1071,1072],{"id":845,"depth":460,"text":846},{"id":871,"depth":460,"text":872},{"id":936,"depth":460,"text":937},{"id":996,"depth":460,"text":997},{"id":1014,"depth":460,"text":1015},{"id":1047,"depth":460,"text":1048},{"id":453,"depth":460,"text":454},"Use n8n to turn any live website into Elementor templates for WordPress: one section, a whole page, or a list of pages in one run. Step by step, with a free template.",[1075,1078,1081,1084,1087],{"question":1076,"answer":1077},"Can n8n create Elementor templates?","Yes. The MiroMiro node's Extract Code operation with the output set to Elementor Template returns a complete Elementor template (.json) for any section of a live website. A Convert to File node turns it into a file you import under Templates > Saved Templates > Import Templates.",{"question":1079,"answer":1080},"Are the imported sections editable in Elementor?","Yes. Each section is a container with an HTML widget holding its markup and styles; you edit the text, links and images there. The MiroMiro Chrome extension can instead export every heading, text, button and image as its own native Elementor widget.",{"question":1082,"answer":1083},"Do I need Elementor Pro?","No. The templates use a container and the HTML widget, both part of free Elementor.",{"question":1085,"answer":1086},"Can I move a whole site from Webflow, Framer or Wix to WordPress with n8n?","Page by page, yes: list the pages, rebuild each one as an Elementor page template, then import them. Navigation menus, forms, sliders and anything that needs a backend still have to be set up in WordPress.",{"question":1088,"answer":1089},"How much does it cost?","Each section is 10 MiroMiro credits. A page of 6 to 12 sections is 60 to 120 credits, and the free plan includes 300 credits a month with no card. Re-running the same page within 24 hours is free.",{},"/api-blog/rebuild-website-in-wordpress-with-n8n-and-elementor",[825,495,824,1093],"make-ai-agent-match-a-real-website-design",{"title":834,"description":1073},"api-blog/rebuild-website-in-wordpress-with-n8n-and-elementor",[502,1097,830,1098,504],"wordpress","website migration","BcUfraMl3oSHucyFD_ltxX1yiwYd3wRv4KLpVY-kzsk",{"id":1101,"title":1102,"author":6,"body":1103,"category":469,"date":1572,"dateModified":471,"description":1573,"extension":473,"faqs":1574,"image":471,"meta":1586,"navigation":491,"path":1587,"readingTime":493,"relatedSlugs":1588,"seo":1593,"seoTitle":471,"stem":1594,"tags":1595,"__hash__":1599},"apiBlog/api-blog/how-to-extract-brand-assets-in-bulk.md","How to Extract Brand Assets from 1,000 URLs in Bulk (Python)",{"type":8,"value":1104,"toc":1559},[1105,1108,1112,1123,1127,1151,1403,1414,1418,1438,1444,1454,1458,1507,1510,1512,1519,1523,1528,1531,1535,1538,1542,1545,1549,1555],[11,1106,1107],{},"The person with 1,000 URLs is never the person who wants to babysit 1,000 browser tabs. Bulk brand extraction in Python is an asyncio problem wearing a design-data hat: a semaphore for rate limits, retries for the 10% of URLs that misbehave, and checkpointing so a crash at URL 900 does not cost you the first 899. Here is the working script, then the failure math.",[27,1109,1111],{"id":1110},"why-not-1000-playwright-launches","Why not 1,000 Playwright launches",[11,1113,296,1114,1118,1119,1122],{},[271,1115,1117],{"href":1116},"/api/blog/how-to-extract-design-tokens-from-any-website-in-python","single-site Playwright approach"," does not scale linearly. A thousand headless Chromium sessions means gigabytes of RAM, cookie banners in six languages, and a long tail of sites that hang ",[45,1120,1121],{},"networkidle"," forever. It is buildable - a browser pool, per-site timeouts, crash recovery - but at that point you are maintaining scraping infrastructure as a hobby. For bulk, put the browser problem on someone else's side of the API.",[27,1124,1126],{"id":1125},"the-script","The script",[1128,1129,1133],"pre",{"className":1130,"code":1131,"language":1132,"meta":459,"style":459},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pip install httpx\n","bash",[45,1134,1135],{"__ignoreMap":459},[1136,1137,1140,1144,1148],"span",{"class":1138,"line":1139},"line",1,[1136,1141,1143],{"class":1142},"sBMFI","pip",[1136,1145,1147],{"class":1146},"sfazB"," install",[1136,1149,1150],{"class":1146}," httpx\n",[1128,1152,1156],{"className":1153,"code":1154,"language":1155,"meta":459,"style":459},"language-python shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import asyncio, csv, json\nimport httpx\n\nAPI = \"https://miromiro.app/api/v1/brand\"\nKEY = \"mm_live_your_key\"\nCONCURRENCY = 5          # stay under your plan's req/min cap\nRETRIES = 3\n\nasync def extract(client, sem, url):\n    async with sem:\n        for attempt in range(RETRIES):\n            try:\n                r = await client.get(\n                    API,\n                    params={\"url\": url, \"fields\": \"logo,palette\"},\n                    headers={\"Authorization\": f\"Bearer {KEY}\"},\n                    timeout=60,\n                )\n                if r.status_code == 429:            # rate limited: back off\n                    await asyncio.sleep(2 ** attempt * 5)\n                    continue\n                if r.status_code == 200:\n                    return {\"url\": url, \"ok\": True, \"data\": r.json()}\n                return {\"url\": url, \"ok\": False, \"error\": f\"HTTP {r.status_code}\"}\n            except httpx.HTTPError as e:\n                if attempt == RETRIES - 1:\n                    return {\"url\": url, \"ok\": False, \"error\": str(e)}\n                await asyncio.sleep(2 ** attempt)\n\nasync def main(urls):\n    sem = asyncio.Semaphore(CONCURRENCY)\n    async with httpx.AsyncClient() as client:\n        results = await asyncio.gather(*(extract(client, sem, u) for u in urls))\n    with open(\"brands.jsonl\", \"w\") as f:\n        for row in results:\n            f.write(json.dumps(row) + \"\\n\")\n    failed = [r for r in results if not r[\"ok\"]]\n    print(f\"{len(results) - len(failed)} ok, {len(failed)} failed\")\n\nif __name__ == \"__main__\":\n    urls = [row[0] for row in csv.reader(open(\"domains.csv\"))]\n    asyncio.run(main(urls))\n","python",[45,1157,1158,1163,1168,1174,1180,1186,1191,1196,1201,1207,1213,1219,1225,1231,1237,1243,1249,1255,1261,1267,1273,1279,1285,1291,1297,1303,1309,1315,1321,1326,1332,1338,1344,1350,1356,1362,1368,1374,1380,1385,1391,1397],{"__ignoreMap":459},[1136,1159,1160],{"class":1138,"line":1139},[1136,1161,1162],{},"import asyncio, csv, json\n",[1136,1164,1165],{"class":1138,"line":460},[1136,1166,1167],{},"import httpx\n",[1136,1169,1171],{"class":1138,"line":1170},3,[1136,1172,1173],{"emptyLinePlaceholder":491},"\n",[1136,1175,1177],{"class":1138,"line":1176},4,[1136,1178,1179],{},"API = \"https://miromiro.app/api/v1/brand\"\n",[1136,1181,1183],{"class":1138,"line":1182},5,[1136,1184,1185],{},"KEY = \"mm_live_your_key\"\n",[1136,1187,1188],{"class":1138,"line":822},[1136,1189,1190],{},"CONCURRENCY = 5          # stay under your plan's req/min cap\n",[1136,1192,1193],{"class":1138,"line":493},[1136,1194,1195],{},"RETRIES = 3\n",[1136,1197,1199],{"class":1138,"line":1198},8,[1136,1200,1173],{"emptyLinePlaceholder":491},[1136,1202,1204],{"class":1138,"line":1203},9,[1136,1205,1206],{},"async def extract(client, sem, url):\n",[1136,1208,1210],{"class":1138,"line":1209},10,[1136,1211,1212],{},"    async with sem:\n",[1136,1214,1216],{"class":1138,"line":1215},11,[1136,1217,1218],{},"        for attempt in range(RETRIES):\n",[1136,1220,1222],{"class":1138,"line":1221},12,[1136,1223,1224],{},"            try:\n",[1136,1226,1228],{"class":1138,"line":1227},13,[1136,1229,1230],{},"                r = await client.get(\n",[1136,1232,1234],{"class":1138,"line":1233},14,[1136,1235,1236],{},"                    API,\n",[1136,1238,1240],{"class":1138,"line":1239},15,[1136,1241,1242],{},"                    params={\"url\": url, \"fields\": \"logo,palette\"},\n",[1136,1244,1246],{"class":1138,"line":1245},16,[1136,1247,1248],{},"                    headers={\"Authorization\": f\"Bearer {KEY}\"},\n",[1136,1250,1252],{"class":1138,"line":1251},17,[1136,1253,1254],{},"                    timeout=60,\n",[1136,1256,1258],{"class":1138,"line":1257},18,[1136,1259,1260],{},"                )\n",[1136,1262,1264],{"class":1138,"line":1263},19,[1136,1265,1266],{},"                if r.status_code == 429:            # rate limited: back off\n",[1136,1268,1270],{"class":1138,"line":1269},20,[1136,1271,1272],{},"                    await asyncio.sleep(2 ** attempt * 5)\n",[1136,1274,1276],{"class":1138,"line":1275},21,[1136,1277,1278],{},"                    continue\n",[1136,1280,1282],{"class":1138,"line":1281},22,[1136,1283,1284],{},"                if r.status_code == 200:\n",[1136,1286,1288],{"class":1138,"line":1287},23,[1136,1289,1290],{},"                    return {\"url\": url, \"ok\": True, \"data\": r.json()}\n",[1136,1292,1294],{"class":1138,"line":1293},24,[1136,1295,1296],{},"                return {\"url\": url, \"ok\": False, \"error\": f\"HTTP {r.status_code}\"}\n",[1136,1298,1300],{"class":1138,"line":1299},25,[1136,1301,1302],{},"            except httpx.HTTPError as e:\n",[1136,1304,1306],{"class":1138,"line":1305},26,[1136,1307,1308],{},"                if attempt == RETRIES - 1:\n",[1136,1310,1312],{"class":1138,"line":1311},27,[1136,1313,1314],{},"                    return {\"url\": url, \"ok\": False, \"error\": str(e)}\n",[1136,1316,1318],{"class":1138,"line":1317},28,[1136,1319,1320],{},"                await asyncio.sleep(2 ** attempt)\n",[1136,1322,1324],{"class":1138,"line":1323},29,[1136,1325,1173],{"emptyLinePlaceholder":491},[1136,1327,1329],{"class":1138,"line":1328},30,[1136,1330,1331],{},"async def main(urls):\n",[1136,1333,1335],{"class":1138,"line":1334},31,[1136,1336,1337],{},"    sem = asyncio.Semaphore(CONCURRENCY)\n",[1136,1339,1341],{"class":1138,"line":1340},32,[1136,1342,1343],{},"    async with httpx.AsyncClient() as client:\n",[1136,1345,1347],{"class":1138,"line":1346},33,[1136,1348,1349],{},"        results = await asyncio.gather(*(extract(client, sem, u) for u in urls))\n",[1136,1351,1353],{"class":1138,"line":1352},34,[1136,1354,1355],{},"    with open(\"brands.jsonl\", \"w\") as f:\n",[1136,1357,1359],{"class":1138,"line":1358},35,[1136,1360,1361],{},"        for row in results:\n",[1136,1363,1365],{"class":1138,"line":1364},36,[1136,1366,1367],{},"            f.write(json.dumps(row) + \"\\n\")\n",[1136,1369,1371],{"class":1138,"line":1370},37,[1136,1372,1373],{},"    failed = [r for r in results if not r[\"ok\"]]\n",[1136,1375,1377],{"class":1138,"line":1376},38,[1136,1378,1379],{},"    print(f\"{len(results) - len(failed)} ok, {len(failed)} failed\")\n",[1136,1381,1383],{"class":1138,"line":1382},39,[1136,1384,1173],{"emptyLinePlaceholder":491},[1136,1386,1388],{"class":1138,"line":1387},40,[1136,1389,1390],{},"if __name__ == \"__main__\":\n",[1136,1392,1394],{"class":1138,"line":1393},41,[1136,1395,1396],{},"    urls = [row[0] for row in csv.reader(open(\"domains.csv\"))]\n",[1136,1398,1400],{"class":1138,"line":1399},42,[1136,1401,1402],{},"    asyncio.run(main(urls))\n",[11,1404,1405,1406,1409,1410,1413],{},"Swap the endpoint for ",[45,1407,1408],{},"/v1/extract"," if you want full token sets instead of brand data, and adjust ",[45,1411,1412],{},"fields="," to trim the response to what you store - it does not change the credit cost, but it makes the output files dramatically smaller.",[27,1415,1417],{"id":1416},"the-three-things-that-make-bulk-runs-survive","The three things that make bulk runs survive",[11,1419,1420,1423,1424,1428,1429,1432,1433,1437],{},[15,1421,1422],{},"1. The semaphore is the contract."," Your plan has a requests-per-minute cap (the ladder is in the ",[271,1425,1427],{"href":1426},"/api/docs/rate-limits","rate limits docs","). Five concurrent with backoff on 429 stays comfortably inside the entry tiers; raise it as your plan allows. Blasting unbounded ",[45,1430,1431],{},"gather"," at any API gets you rate-limited into taking ",[1434,1435,1436],"em",{},"longer"," than the polite version.",[11,1439,1440,1443],{},[15,1441,1442],{},"2. Expect 5-15% failures and capture them."," On a real 1,000-domain list some are dead, parked, or behind bot walls. The script writes per-URL errors instead of dying, so the run always finishes and the failures are a re-runnable list, not a mystery.",[11,1445,1446,1449,1450,1453],{},[15,1447,1448],{},"3. Re-runs are cheap because of caching."," Responses are cached for 24 hours and a cache hit costs 0 credits (",[45,1451,1452],{},"\"cached\": true"," in the usage object). Re-running today's failed batch only pays for URLs that actually re-extract - so retry freely.",[27,1455,1457],{"id":1456},"budgeting-a-1000-url-run","Budgeting a 1,000-URL run",[168,1459,1460,1472],{},[171,1461,1462],{},[174,1463,1464,1466,1469],{},[177,1465],{},[177,1467,1468],{},"Brand data (15 cr/URL)",[177,1470,1471],{},"Design tokens (10 cr/URL)",[187,1473,1474,1485,1496],{},[174,1475,1476,1479,1482],{},[192,1477,1478],{},"100 URLs",[192,1480,1481],{},"1,500 credits",[192,1483,1484],{},"1,000 credits",[174,1486,1487,1490,1493],{},[192,1488,1489],{},"1,000 URLs",[192,1491,1492],{},"15,000 credits",[192,1494,1495],{},"10,000 credits",[174,1497,1498,1501,1504],{},[192,1499,1500],{},"Fits in",[192,1502,1503],{},"Growth (€79/mo, 30k)",[192,1505,1506],{},"Growth, or 2× Developer months",[11,1508,1509],{},"The free 300 credits cover a 20-30 URL pilot - do that first, on your ugliest URLs, before committing a plan to the full list. Wall-clock: the rate limiter sets the pace, not the extraction; expect tens of minutes for 1,000 URLs, not hours.",[27,1511,454],{"id":453},[11,1513,1514,1515,1518],{},"Bulk extraction is a queue-discipline problem: bounded concurrency, backoff on 429, per-URL error capture, and a re-run list. The 24-hour cache turns retries from a cost into a free operation. Pilot on 10 URLs with a ",[271,1516,1517],{"href":273},"free key",", then size the plan to the list.",[27,1520,1522],{"id":1521},"frequently-asked-questions","Frequently asked questions",[1524,1525,1527],"h3",{"id":1526},"how-do-i-scrape-brand-colors-from-a-list-of-websites-in-python","How do I scrape brand colors from a list of websites in Python?",[11,1529,1530],{},"For a few sites, Playwright and computed styles. For hundreds or thousands, the async httpx script above against an extraction API.",[1524,1532,1534],{"id":1533},"how-long-does-1000-urls-take","How long does 1,000 URLs take?",[11,1536,1537],{},"Tens of minutes - your requests-per-minute cap is the bottleneck, not the extraction itself.",[1524,1539,1541],{"id":1540},"what-failure-rate-should-i-expect","What failure rate should I expect?",[11,1543,1544],{},"5-15% on real-world lists: dead domains, parked pages, bot walls. Capture and re-run rather than aiming for zero.",[1524,1546,1548],{"id":1547},"do-repeated-extractions-cost-credits-again","Do repeated extractions cost credits again?",[11,1550,1551,1552,143],{},"Not within 24 hours - cache hits cost 0 credits and report ",[45,1553,1554],{},"cached: true",[1556,1557,1558],"style",{},"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);}",{"title":459,"searchDepth":460,"depth":460,"links":1560},[1561,1562,1563,1564,1565,1566],{"id":1110,"depth":460,"text":1111},{"id":1125,"depth":460,"text":1126},{"id":1416,"depth":460,"text":1417},{"id":1456,"depth":460,"text":1457},{"id":453,"depth":460,"text":454},{"id":1521,"depth":460,"text":1522,"children":1567},[1568,1569,1570,1571],{"id":1526,"depth":1170,"text":1527},{"id":1533,"depth":1170,"text":1534},{"id":1540,"depth":1170,"text":1541},{"id":1547,"depth":1170,"text":1548},"2026-07-18","Bulk-extract brand data and design tokens from thousands of domains in Python - async code with rate limiting and retries that survives a real URL list.",[1575,1577,1580,1583],{"question":1527,"answer":1576},"For a handful of sites, a Playwright script reading computed styles works. Past a few hundred URLs, run the extraction through an API with asyncio and httpx: a semaphore to respect rate limits, retries with backoff for the URLs that fail, and checkpointing so a crash does not restart the whole run.",{"question":1578,"answer":1579},"How long does it take to extract data from 1,000 URLs?","With an API at a typical plan rate limit, roughly 20-60 minutes for 1,000 URLs depending on your requests-per-minute cap - the limiter, not the extraction, sets the pace. A self-hosted browser farm is usually slower per URL once retries and crashes are counted.",{"question":1581,"answer":1582},"What percentage of URLs fail in a bulk extraction run?","Plan for 5-15% on a real-world list: dead domains, redirects to parked pages, bot walls, timeouts. This is why retries and per-URL error capture matter more than raw speed - a bulk script that stops on the first 404 never finishes.",{"question":1584,"answer":1585},"Do repeated extractions of the same URL cost credits again?","On MiroMiro, responses are cached for 24 hours and a cache hit costs 0 credits - the usage object reports cached: true. Re-running a failed batch the same day only pays for the URLs that actually re-extract.",{},"/api-blog/how-to-extract-brand-assets-in-bulk",[1589,1590,1591,1592],"clearbit-logo-api-alternatives","best-brand-data-apis-2026","how-to-extract-design-tokens-from-any-website-in-python","add-design-extraction-to-claude-code-mcp",{"title":1102,"description":1573},"api-blog/how-to-extract-brand-assets-in-bulk",[1596,1155,1597,1598,504],"bulk extraction","async","brand data","yMBiXQ6hQjp4IiwEhjdFHas6tXlXi77EkepkhsiE62I",1793050643520]