To scrape a website with n8n, chain an HTTP Request node (download the page) and an 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.
Here are the three setups, when each one is right, and the problems you will hit.
Scrape text with HTTP Request + HTML
First, an HTTP Request node:
- Method:
GET - URL:
https://example.com/pricing - Response format:
String(put the body in a field calleddata)
Then an HTML node:
- Operation: Extract HTML Content
- Source data:
JSON, propertydata - Extraction values, one row per value:
- Key
title, CSS selectorh1, return valueText - Key
plans, CSS selector.plan-name, return valueText, Return array on - Key
image, CSS selectormeta[property="og:image"], return valueAttribute, attributecontent
- Key
Run it and you get one item with title, plans and image.
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.
Scrape JavaScript websites with a browser node
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.
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.
Scrape the design: code, Elementor, brand and images
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.
That is what the MiroMiro node does. It loads the page in a real browser and returns:
| Operation | What you get | Credits |
|---|---|---|
| Extract Code | A section (hero, pricing, footer...) as Tailwind, HTML + CSS, React, Vue, an Elementor template or a Shopify section | 10 |
| Extract Brand | Logo, brand colors with roles, fonts, and whether each was declared by the site or inferred | 10 |
| Extract Design Tokens | Every color, font size, spacing and radius with usage counts, or a W3C tokens file | 10 |
| Extract Images | Every image URL: img tags, srcset, CSS backgrounds, favicons, og:image | 1 |
| Extract SVGs, Fonts, Videos, Audio, Lottie | The files of that type | 1 to 5 |
To try it:
- Install the node. On self-hosted n8n: Settings > Community nodes > Install, package
n8n-nodes-miromiro. It is verified by n8n and arrives in n8n Cloud's nodes panel with their next release. - Add a MiroMiro node, create the credential with a free API key.
- Pick Extract Code, paste a URL, set Section to
Pricingand Output toElementor Template.
The code field is the complete template. Send it through a Convert to File node and import the .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 ready-made templates do exactly that.
Which one to use
| You want | Use | Handles JavaScript sites | Cost |
|---|---|---|---|
| Text from static pages (prices, titles, links) | HTTP Request + HTML | No | Free |
| Text or Markdown from JavaScript pages | Firecrawl or Apify node | Yes | Per page |
| Code, Elementor, Shopify, brand kit, images | MiroMiro node | Yes | 1 to 10 credits per call |
Common problems
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.
URL is not defined in an expression. n8n's expression sandbox has no URL constructor. To get the domain of a link, use {{ $json.url.split('/')[2] }} instead.
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).
Images only appear when you scroll. Lazy loading. On the MiroMiro images operation, add the Render option: the page is scrolled in a browser before the images are collected.
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.
Or start from a template
Every setup above exists as a free n8n template you import in one click: download every image from a website, rebuild a whole page as code, a page in Elementor, brand kits and more. The MiroMiro API includes 300 free credits a month, no card. You can start for free.
Summary
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.
Skip the maintenance - one API call
Design tokens, brand data, fonts, SVGs, images, and section code from any URL. 300 free credits a month, no card.
Soraia · Founder, MiroMiro
Building MiroMiro: a browser extension and API that extract design tokens, assets, and production-ready code from any live website. The gotchas in these posts come from the extraction engine's own commit history.
Follow on X