Every few weeks someone asks me to scrape Google search results with n8n and shows me their first attempt. It is always the same shape: an HTTP Request node pointed at google.com/search, a regex over the HTML, and a Google Sheets node. It works for about two days.
The version that survives production looks nothing like that. It is a queue of queries, a licensed SERP API, a normalisation step, a dedupe key, a cache, and a database. I have shipped this shape inside larger crawling systems, including a distributed scraping platform running 100K+ jobs a day. Here is the whole pattern, in n8n.
Is it legal to scrape Google search results?
Scraping public search result pages is not usually a criminal matter, but pointing a bot at google.com/search breaches Google's Terms of Service and ignores its published crawl directives. Google's robots.txt file contains an explicit Disallow: /search rule for general crawlers, with narrow exceptions such as /search/about and /search/howsearchworks.
That distinction matters commercially more than legally. If you are building this for a client, a workflow that knowingly violates a platform's terms is a liability you signed for. If you are building it for yourself, it is an operational risk that surfaces at the worst possible moment, usually the day a campaign launches.
The clean answer is to buy the data from a provider whose entire business is acquiring it under its own terms and infrastructure. You get an invoice, a support contact, and a stable JSON contract. You do not get a CAPTCHA at 3am.
"If your scraping strategy depends on not being noticed, it is not a strategy. It is a countdown."
Why a licensed SERP API beats fighting anti-bot systems
A SERP API wins because the cost of maintaining an evasion stack is unbounded and the cost of an API call is a line item. Rotating residential proxies, headless Chrome fingerprint patching, CAPTCHA solving and HTML selector repair are all recurring engineering work with no ceiling.
What you actually pay for when you self-scrape Google, beyond the proxy bill:
- Selector maintenance every time the results markup changes, which is not on your schedule.
- Silent data corruption when a layout shift makes your parser return empty arrays instead of errors.
- Geolocation and language drift, because results differ by location and device and you now have to simulate both.
- CAPTCHA and soft-block handling, which turns a stateless workflow into a stateful retry system.
- Legal review time on every client project, which is the most expensive hour in the list.
n8n is a good host for this precisely because it does not care where the JSON came from. The HTTP Request node handles auth, pagination and batching, and everything downstream is provider-agnostic. If you are new to the tool, start with the n8n automation tutorial for beginners and come back.
Which data source should you point n8n at?
There are four realistic options, and only two of them belong in a client deliverable. The deciding factors are licensing posture, result fidelity, and who absorbs the maintenance.
SERP data sources compared for an n8n workflow:
| Approach | How it gets results | Posture | Where it breaks |
|---|---|---|---|
| Commercial SERP API (SerpApi, Bright Data, Serper, Oxylabs) | Vendor infrastructure returns parsed JSON per query | Vendor carries acquisition risk; you buy a data service | Per-query cost at high volume; feature parity varies by vendor |
| Google Custom Search JSON API | Google's own programmable search endpoint | Fully sanctioned, but a different index than google.com | Google's docs state it is closed to new customers and retires 1 January 2027 |
| Apify or similar actor marketplace | Hosted scrapers you invoke as an API | Managed, but you are still consuming scraped SERP HTML | Run duration and concurrency limits; cold starts on burst traffic |
| DIY headless browser plus proxies | You render google.com/search yourself | Breaches robots.txt and Terms of Service | Blocks, CAPTCHAs, parser rot, and no vendor to escalate to |
One nuance people miss: Google's Custom Search JSON API is not the same corpus as a live SERP. It queries a Programmable Search Engine configuration, so a competitor-tracking or rank-tracking use case will produce numbers that do not match what a user sees. Google's own overview page documents the free daily allowance, the per-thousand paid rate above it, the daily ceiling, and the retirement date. Check that page before you build on it.
How to scrape Google search results with n8n: the architecture
Build it as a pipeline with a queue at the front and a database at the back, never as a single linear flow triggered by hand. Seven stages, each of which can fail and retry independently.
The seven stages of a production SERP workflow in n8n:
- 1Trigger. A Schedule Trigger for recurring runs, or a Webhook when another system requests a query on demand.
- 2Query queue. Read pending queries from Postgres, Supabase or a sheet, filtered to rows whose last_fetched_at is older than your cache window.
- 3Rate gate. Loop Over Items with a batch size and a Wait node, so you never exceed the provider's concurrency ceiling.
- 4SERP call. HTTP Request node with the provider endpoint, credentials stored as an n8n credential, and query parameters bound from the item.
- 5Parse and normalise. A Code node that flattens organic results into one row per result with a stable schema.
- 6Dedupe. Hash the canonical URL plus query, and drop anything already stored.
- 7Enrich and store. Optional LLM classification or metadata lookup, then an upsert into your warehouse and a write-back of last_fetched_at.
Why the queue table is non-negotiable
Without a queue table you have no idempotency. A workflow that dies on query 340 of 500 has to start over, and you pay the provider twice for the first 339. With a queue, each row carries its own state and a rerun only picks up what is genuinely pending.
This is the same discipline I apply to any batch job in a data engineering build. The unit of work is a row, not a run.
Building the workflow node by node
The whole thing is roughly nine nodes. The parsing Code node is where most of the judgement lives, because raw SERP JSON is nested, inconsistent between result types, and full of tracking parameters you do not want in your dedupe key.
// n8n Code node, run once for all items
const seen = new Set();
const out = [];
for (const item of $input.all()) {
const query = item.json.search_parameters?.q;
const results = item.json.organic_results || [];
for (const r of results) {
let host;
let clean;
try {
const u = new URL(r.link);
host = u.hostname.replace(/^www\./, "");
clean = u.origin + u.pathname;
} catch {
continue;
}
const key = query + "|" + clean;
if (seen.has(key)) continue;
seen.add(key);
out.push({
json: {
dedupe_key: key,
query,
position: r.position ?? null,
title: r.title ?? null,
url: clean,
domain: host,
snippet: r.snippet ?? null,
fetched_at: new Date().toISOString(),
},
});
}
}
return out;Stripping the query string before hashing is the single highest-value line in that file. Providers and Google both append tracking parameters that change between runs, and if you hash the raw link every rerun looks like fresh data.
For cross-run deduplication, n8n's Remove Duplicates node has a mode that discards items it has already seen in previous executions, keyed on a field you choose. It is convenient for small workflows. For anything you plan to audit later, do the dedupe in the database with a unique constraint on dedupe_key and an upsert, so the truth lives in one place.
How do you handle rate limits and caching?
Handle rate limits with batching plus waits inside n8n, and handle cost with a cache keyed on the query. The HTTP Request node exposes batching options for items per batch and a batch interval in milliseconds, which is usually enough to stay under a provider's concurrency limit without extra nodes.
The four controls that keep a SERP workflow inside its limits:
- Batch size and batch interval on the HTTP Request node, tuned to the provider's documented concurrency.
- Retry on fail with exponential backoff at the node level, so a single 429 does not kill the execution.
- A last_fetched_at column checked in the queue query, which is the cache, and the cheapest one you will ever build.
- A hard daily budget: a counter row that the workflow reads first and refuses to exceed.
Sensible cache windows by use case, based on how fast the underlying results actually move:
| Use case | Refresh cadence | Why |
|---|---|---|
| Rank tracking for a core keyword set | Daily | Positions move, and trend lines need consistent intervals |
| Competitor content discovery | Weekly | New URLs appear on publishing cycles, not hourly |
| Lead or prospect list building | Monthly or once | The set of companies matching a query is fairly stable |
| Brand or reputation monitoring | Daily or on alert | Negative results need short detection windows |
| One-off research for a proposal | Never refresh | Snapshot the JSON, store it, move on |
If you run this at volume, self-host. The execution counts add up fast on managed plans, and long-running loops are exactly the workload that makes the self-hosting trade-off worth doing properly.
What does it cost to run?
Cost is dominated by SERP API calls, not by n8n. The formula is queries multiplied by pages per query multiplied by refresh frequency, and every one of those three is a decision you control.
SERP vendors price in credits or searches per month, usually with tiered rates that fall as volume rises, and some charge extra for JavaScript-rendered or location-specific results. Google's Custom Search JSON API prices differently again, with a small free daily allowance and a per-thousand rate above it up to a daily ceiling. Pricing changes constantly, so read the vendor's official pricing page rather than a blog post, including this one.
The controllable half is the multiplier. Pulling three pages when page one answers the question triples your bill. Refreshing a stable prospect list daily instead of monthly multiplies it by thirty. In practice I see caching and page-depth discipline cut spend more than any vendor negotiation does.
When this workflow is the wrong tool
If you need to scrape Google search results at tens of thousands of queries an hour, with complex retry semantics and per-item observability, n8n is the wrong host. At that point you want a real job queue and workers, not a visual workflow engine holding execution state.
Signals that you have outgrown the n8n version:
- Executions regularly run longer than your instance timeout, and you are splitting flows to work around it.
- You need per-query cost attribution and SLA tracking across multiple providers.
- The enrichment step is a multi-stage LLM pipeline rather than a single call.
- You are storing more than a few million rows and need partitioning and backfills.
Below those thresholds, n8n is genuinely the fastest path from idea to running system. The same skeleton powers most of the lead generation workflows I build, and it is the backbone of the search-and-enrich layer in ProLeads. If you want it built and handed over rather than assembled from tutorials, that is what my n8n integration work and broader AI automation services cover.
Key takeaways
- Google's robots.txt disallows /search, so direct scraping breaches its crawl directives and Terms of Service.
- A licensed SERP API called from n8n's HTTP Request node moves the anti-bot problem to a vendor with a support contract.
- Structure the workflow as a queue with per-row state, not a linear run, so failures resume instead of restarting.
- Strip query parameters before hashing URLs, or every rerun will look like new data.
- Caching by last_fetched_at and limiting page depth cut cost more than switching vendors does.
- Google's Custom Search JSON API is closed to new customers and retires on 1 January 2027, so do not architect around it.
Frequently asked questions
- Can I scrape Google search results with n8n without an API?
- Technically yes, using an HTTP Request node and HTML parsing, but it breaches Google's Terms of Service and its robots.txt Disallow: /search directive. It also fails quickly against CAPTCHAs and markup changes. Use a licensed SERP API instead so a vendor carries the acquisition risk and you get stable JSON.
- How much does it cost to scrape Google search results with n8n?
- The n8n side is near zero if you self-host. Cost is driven by the SERP provider and follows queries times pages per query times refresh frequency. Vendors sell credits or monthly search bundles with volume tiers, and extras for rendered or geo-targeted results. Check the vendor's official pricing page for current rates.
- Which SERP API works best with n8n?
- Any provider returning JSON over HTTPS works, because n8n's HTTP Request node is provider-agnostic. SerpApi, Bright Data, Serper and Oxylabs all fit that pattern. Choose on result fidelity for your locale, documented concurrency limits, and pricing structure rather than on whether a dedicated n8n node exists.
- What is the difference between a SERP API and the Google Custom Search JSON API?
- A SERP API returns what a user would see on google.com for a given location and device. The Custom Search JSON API queries a Programmable Search Engine configuration, which is a different corpus, so rankings will not match live results. Google's documentation also states the API is closed to new customers and retires on 1 January 2027.
- How do I avoid rate limits in an n8n scraping workflow?
- Use the HTTP Request node's batching options to set items per batch and a batch interval in milliseconds, enable retry on fail so a single 429 does not end the execution, and gate the run with a queue query that skips anything fetched inside your cache window. Add a daily budget counter for hard safety.
- Is it worth building this in n8n instead of writing Python?
- It is worth it below roughly a few thousand queries per hour, where visual retries, credential management and scheduling save real engineering time. Above that, or when you need per-item observability and partitioned storage, move to a job queue with workers. n8n can still orchestrate the trigger and reporting layer.
- How do I deduplicate search results across multiple n8n runs?
- Hash the query plus the canonical URL with query parameters stripped, and store it as a unique dedupe key. Upsert into Postgres or Supabase on that constraint. n8n's Remove Duplicates node can also discard items seen in previous executions, but database-level constraints are auditable and survive workflow edits.
- Can I enrich Google search results with an LLM inside n8n?
- Yes. After parsing, pass each result to an OpenAI or Anthropic Claude node to classify intent, extract entities or score relevance, then store the structured output alongside the row. Batch the calls and cache by URL, because enrichment cost scales with tokens per result multiplied by result volume.
Sources
Written by Syed Husnain Haider Bukhari
AI engineer, data scientist, and founder of Revolutionary Technologies LLC. Ships production AI agents, automations, and data platforms for teams in the US, UK, and UAE — including AgentFlow, AI Walay, and ProLeads.
Get in touch →Related pages
Want this built instead of researched?
Book a 30-minute scoping call. You get a one-page plan and a fixed-scope quote within 48 hours.
Start a conversation