DEV Community

Cover image for How to scrape Google Maps leads with n8n (free workflow)
Scraper Finder
Scraper Finder

Posted on

How to scrape Google Maps leads with n8n (free workflow)

Last updated: 6 November 2026 (n8n 2.46)

Short answer: import a free six-node workflow into n8n, add your Apify API token as a Query Auth credential, type a search like "restaurants in New York, NY", and click Execute. You get one row per business (name, address, phone, website, email, rating, Google placeId), deduped and ready to append to Google Sheets. A 20-place test costs about $0.45 on Apify's free plan.

Disclosure: I maintain the free workflow repo used here. The scraping step runs a paid Apify Actor on your own Apify account (it has a free monthly credit), so the real costs have their own section. I wrote this with AI help for the wording; the steps, settings and numbers come from my own runs.

What does the workflow return?

One row per business with these fields: name, googleBusinessCategories, street, city, state, zip, phoneNumber, url (the business website), email, reviewScore, reviewsNumber and placeId. The clean-up node adds _source and _scrapedAt. Social profile links, googleMapsUrl and coordinates are in the full output when the Actor finds them.

In a 20-place test for "restaurants in New York, NY", the run took about 10 seconds and 13 of the 20 places came back with an email.

The six nodes:

Daily trigger → Configure input → Run Apify Actor → Normalize + dedupe → Rows ready → Google Sheets (optional)

The Google Maps leads workflow in n8n: Daily trigger, Configure input, Run Apify Actor, Normalize + dedupe, Rows ready, Google Sheets

How do I set it up? (5 steps)

1. Import the workflow

In n8n, open a new workflow, click ⋯ → Import from URL and paste the raw file link:

https://raw.githubusercontent.com/bolvein-firex/scraping-n8n-workflows/main/workflows/google-maps-business-lead-and-email-finder.json
Enter fullscreen mode Exit fullscreen mode

The file has no tokens, credentials or sheet IDs in it, so nothing runs until you do steps 2 and 5.

2. Add your Apify token as a Query Auth credential

Run Apify Actor is a plain HTTP Request node, not a community node, so it works on n8n Cloud and self-hosted.

  1. In the Apify Console, copy your API token (Settings → API & Integrations).
  2. In n8n, open Run Apify Actor → Credential → create a Query Auth credential.
  3. Query parameter name: token. Value: your Apify token. Name the credential anything, for example "Apify API Token".

Apify reads the token from the ?token= query parameter, which is what Query Auth adds. In a credential it never ends up in an exported workflow or a screenshot.

3. Edit the search in "Configure input"

Configure input is a Code node that returns the Actor's input:

The Configure input Code node with the starter Google Maps search

  • searchQueries: one phrase per search, with the place in the phrase ("plumbers in Leeds", "coffee shops in Austin TX"). Several phrases per run are fine.
  • max_results: 20 for the first run (why: see the timeout question below).
  • extractEmails: true: reads each business's own website for contact emails. This fills the email column.
  • onlySaveResults: "onlyWithContacts": drops places with no email or phone.

The starter input is validated against the Actor's input schema. When you add fields, copy the names from the Actor's Input tab: an unknown field is silently ignored, which is a confusing way to lose a filter.

4. Run it and check "Rows ready"

Click Execute workflow. Rows ready is a No Operation node that lets you look at the cleaned rows before anything is written.

5. Turn on Google Sheets

The Google Sheets (optional) node ships disabled, so a test can't write to a real sheet by accident.

  1. Enable it and add a Google Sheets OAuth2 credential.
  2. Replace YOUR_GOOGLE_SHEET_ID with the ID from your sheet's URL, and set the sheet name (the file uses Rows).
  3. It uses Append with Map Automatically, so the field names become the columns.

For a daily schedule, switch to Append or Update and match on placeId. That stops yesterday's places from being appended again. The Daily trigger fires at 08:00 in your instance's timezone.

Why does the workflow dedupe on placeId and not email?

Because chains share emails. My first version deduped on email and lost real rows: five branches of one franchise, with five addresses, phones and ratings, collapsed into one row because they shared info@. placeId is Google's own ID for a place and stays the same between runs.

Dedupe key Keeps every branch? Stable between runs? Use it for
placeId Yes Yes The places sheet (this workflow)
email No, chains collapse Mostly The send step, so one inbox gets one message
phoneNumber No, call centres collapse Mostly Rarely useful
Business name No, "Starbucks" collapses No Don't

If you're emailing these leads, dedupe on the lowercased email in the outreach step, right before sending. A reader on Reddit also pointed out that crawled info@ addresses bounce a lot, so put an email verifier right before the send step too. Not before the sheet: that way you only pay to verify the rows you actually contact.

Why does the run time out, and how big can a run be?

The node calls Apify's run-sync-get-dataset-items endpoint. It starts the Actor and returns the rows in the same HTTP response, so there's no polling loop. Apify ends a synchronous request after 300 seconds, so the node timeout is set to 300000 ms to wait exactly that long.

With extractEmails on, the Actor visits every business website, so large pulls take minutes. Keep sync runs at 20 to 50 places. For hundreds of places, switch to the async pattern: POST /v2/acts/{actor}/runs, wait for it to finish, then GET /v2/datasets/{datasetId}/items.

Also, Google returns a ranked window of roughly 150 to 220 businesses per search phrase, so asking one phrase for 1,000 results won't get you 1,000. Split by neighbourhood or category instead.

What happens when the Apify run fails?

Apify answers with an object like {"error": {"type": "...", "message": "..."}}. Depending on the failure and on the HTTP node's response settings, that object can reach the next node as an ordinary item, and you find one junk row in your sheet a week later. The clean-up node checks for it first and fails the execution with Apify's message:

const rows = $input.all().flatMap((item) => (Array.isArray(item.json) ? item.json : [item.json]));
const failed = rows.find((row) => row && row.error && typeof row.error === 'object' && Object.keys(row).length === 1);
if (failed) throw new Error(`Apify: ${failed.error.type || 'error'} ${failed.error.message || ''}`.trim());
Enter fullscreen mode Exit fullscreen mode

After that, it trims strings, drops null fields and keeps one row per placeId.

How much does it cost to scrape Google Maps with n8n?

n8n is free self-hosted (n8n Cloud has its own plans). The scraping is billed by Apify, pay-per-event, to your account. On Apify's Free plan ($5 of credit a month):

Item Price
Run start $0.10 per GB of run memory (4 GB default = $0.40 per run)
Each place returned about $0.001
Platform compute a few cents
20-place test about $0.45
Daily run, 30 days about $13 a month on the Free plan, mostly start fees

So the free credit covers about ten test runs. Paid Apify plans are cheaper per event. Check the Actor's Pricing tab before you schedule anything, and keep max_results small until you know what a run returns.

FAQ

Do I need to know JavaScript?
No. You only edit the JSON object in "Configure input". The two Code nodes work as shipped.

Does it work on n8n Cloud?
Yes. It uses only core nodes (Schedule Trigger, Code, HTTP Request, No Operation, Google Sheets).

Can I search outside the US?
Yes. Put the place in the phrase ("dentists in Lyon, France"), or set country and locationQuery in the input.

Is scraping Google Maps legal?
These are public business listings, but a business email can still be personal data (GDPR in the EU and UK, similar laws elsewhere). Check what you're allowed to do with it, where you and the recipients are, before you contact anyone.

Can I use it without Google Sheets?
Yes. Leave the Sheets node disabled and connect anything after Rows ready: Airtable, Postgres, a CRM node or a webhook.

Is there a version for Claude Code or other AI agents?
Yes. The same Actor is wrapped as an agent skill (a SKILL.md with the real input and output fields): google-maps-business-lead-and-email-finder skill.

More free workflows like this

The same six-node shape exists for other public data: Amazon and Shopify prices, Zillow listings, Indeed jobs, TikTok and Reddit search, Google Trends. Each workflow has a docs page with the Actor's real input and output fields: bolvein-firex/scraping-n8n-workflows. The next articles in this series take one source each. Short demos are on YouTube @ScraperFinder.

If something breaks on your n8n version, or you want a source that isn't there, leave a comment here or open an issue on the repo.

Top comments (0)