How to Scrape Google Maps with n8n (and Send Results to Google Sheets)

A working n8n workflow that pulls Google Maps business data into a Google Sheet on demand or on a schedule. No code, no browser automation, no proxy configuration. The template is free, the actor bills about a dollar per thousand places, and the whole thing sets up in under ten minutes.

Difficulty: Beginner
Time: 10 minutes
Cost: ~$1 per 1,000 places (free Apify tier covers ~5,000/month)
Tools: n8n, Apify, Google Sheets
Download the n8n template ↓ Open the actor on Apify

In this tutorial

  1. What you will build
  2. Prerequisites
  3. Step 1: Get your Apify API token
  4. Step 2: Import the n8n template
  5. Step 3: Paste your token and search query
  6. Step 4: Connect Google Sheets
  7. Step 5: Run it
  8. Schedule daily runs
  9. Add reviews, popular times, or contact emails
  10. Skip places you have already scraped
  11. Handling large runs
  12. What it costs
  13. FAQ

What you will build

A four-node n8n workflow. Click Run, and about ten seconds later a fresh batch of businesses lands in your Google Sheet with 30-plus fields per row: business name, category, full address with parsed city and postal code, phone, website, GPS coordinates, rating, review count, opening hours, price range, photos, and more.

The workflow calls the NanoScrape Google Maps Scraper under the hood. That actor is a lightweight Go binary running on Apify, roughly 80 MB in size, uses datacenter proxies, and returns results in seconds. All the field extraction, geocoding, and pagination is handled for you.

Prerequisites

STEP 1

Get your Apify API token

  1. Open the Google Maps Scraper and click Try for free.
  2. Sign up with Google or email. It takes about a minute.
  3. Once signed in, click your avatar (top right), open Settings, then Integrations.
  4. Copy the Personal API token. Keep the tab open, you will paste it in a moment.
Tip: the free tier is more than enough to complete this tutorial. You only pay if you exceed $5 in usage in a given month.
STEP 2

Import the n8n template

  1. Download the workflow: scrape-google-maps-to-google-sheets.json
  2. In n8n, open the workflows list. Click the three-dot menu at the top right and choose Import from File.
  3. Select the JSON you just downloaded.

You will see four nodes wired left to right:

  1. Manual Trigger starts the run when you click a button.
  2. Set Search Params holds your Apify token, search query, and options.
  3. Run Google Maps Scraper calls the Apify sync endpoint and gets results back in the same request.
  4. Append to Google Sheet writes one row per business.
STEP 3

Paste your Apify token and search query

Open the Set Search Params node and fill in the four fields:

Save the node.

Why include the location in the query? Google Maps ranks results by relevance to the whole search string. plumber Berlin returns better results than plumber alone with a separate location filter.
STEP 4

Create a Google Sheet and connect it

  1. Go to Google Sheets and create a new blank spreadsheet. Leave the first row empty. The n8n node handles headers automatically.
  2. Copy the spreadsheet ID from the URL. It is the long string between /d/ and /edit.
  3. In n8n, open the Append to Google Sheet node.
  4. Paste the spreadsheet ID into the Document ID field.
  5. Leave the sheet name as Sheet1 if that is what your tab is called, otherwise update it.
  6. Click the Credential dropdown at the top of the node. Pick an existing Google Sheets credential or click Create New to walk through the Google OAuth flow.
  7. Save the node.
Tip for self-hosted n8n: if you have not set up Google credentials before, follow n8n's OAuth setup guide. It takes about five minutes.
STEP 5

Run it

Click Test Workflow at the bottom left. You should see each node light up green as it runs. Within about ten seconds, open your Google Sheet. You will find one row per business with columns for name, address, phone, website, rating, review count, opening hours, GPS coordinates, and roughly 25 other fields.

If nothing shows up, check the output of the Run Google Maps Scraper node:

Schedule daily runs

Replace the Manual Trigger with a Schedule Trigger node. Set the interval to once a day, once a week, or a cron expression of your choice. Every morning your sheet will grow with fresh data for the search terms you configured.

To keep the sheet clean, either clear it at the start of each run (add a Google Sheets "Clear" node before the Append), or skip already-scraped places (see the next section).

Add reviews, popular times, or contact emails

The Google Maps Scraper has three optional enrichments that stack on top of the basic scrape. Enable them by adding fields to the JSON body of the Run Google Maps Scraper node.

Featured reviews

Add "includeReviews": true and each place gets a user_reviews array with author name, star rating, publication date, and review text. Adds about 300 ms per place.

{
  "searchStrings": ["restaurants in Paris"],
  "maxResultsPerQuery": 20,
  "includeReviews": true,
  "maxReviewsPerPlace": 10,
  "reviewsSort": "newest"
}

Sort options: most_relevant (default), newest, highest_rating, lowest_rating. To only pull reviews from the last month, add "reviewsNewerThan": "2026-06-14".

Popular times histogram

Add "includePopularTimes": true and each place gets a popular_times object with visitor-traffic scores by weekday and hour (0 to 100). Great for finding low-traffic time slots. Adds about 1.5 seconds per place.

Contact email extraction

Add "enableContactExtraction": true and "geminiApiKey": "your-gemini-key". After the Maps scrape completes, an AI-powered add-on visits every business website found in the results and extracts team member names, emails, phone numbers, and departments. Great for turning a lead list into a contact list in one step. Get a free Gemini API key at Google AI Studio.

How the add-ons are billed: the base Google Maps scrape stays at $1 per 1,000 places regardless of which enrichments you enable. Contact extraction is billed separately by the Website Contact Extractor. Reviews and popular times are free.

Skip places you have already scraped

Every place on Google Maps has a stable identifier called a CID. It does not change even if the business renames or moves. To avoid re-collecting places on scheduled runs, pass an array of CIDs in the excludeCids parameter.

{
  "searchStrings": ["cafes in Zurich"],
  "maxResultsPerQuery": 100,
  "excludeCids": ["12345678901234567", "98765432109876543"]
}

A common pattern in n8n: read the CID column from your existing sheet with a Google Sheets "Read" node, feed it into a Set node that builds the array, then reference that array in the HTTP Request body.

Handling large runs

The template uses Apify's synchronous endpoint, which returns results in the same HTTP response. That endpoint has a 5-minute timeout, which is plenty for a few hundred places. For larger jobs, switch to the async pattern:

  1. Change the URL to /runs (drop -sync-get-dataset-items) to start the run without waiting.
  2. Add a Wait node that polls /runs/{runId} every 30 seconds until the status is SUCCEEDED.
  3. Fetch results from /datasets/{defaultDatasetId}/items once the run finishes.

The Apify API docs cover the full endpoint list.

What it costs

A daily workflow that pulls 100 new places every morning runs at about $3 per month. A weekly workflow that pulls 1,000 places every Monday runs at $4 per month.

FAQ

Do I need a paid Apify plan to run this?

No. The free tier includes $5 of usage credit every month, enough for around 5,000 places from this actor. You only pay if you go over.

Does the template work with n8n Cloud, self-hosted, and Desktop?

Yes, all three. The template uses only core n8n nodes (Manual Trigger, Set, HTTP Request, Google Sheets), so there is nothing to install and no community node dependency.

Can I send results to Airtable, PostgreSQL, or Notion instead?

Yes. Replace the Google Sheets node at the end of the workflow with whatever destination you prefer. All incoming fields are auto-mapped, so you just need to point the new node at your target and pick which fields to keep.

How do I search multiple queries in one run?

Two options. Simple approach: add more strings to the searchStrings array in the HTTP Request body. Advanced approach: use the structured queries parameter, which lets you attach your own company_id per query and separate the search term from the location and country code. The actor README has examples.

Can I collect email addresses too?

Yes. Set enableContactExtraction to true and provide a Gemini API key. The scraper visits every business website found in the results and extracts team member emails, names, positions, and phone numbers using AI.

What if I want to scrape more than 500 places in one query?

Google Maps returns at most about 120 results per single query. For broader coverage, split the search by neighborhood, category, or sub-region and run each as a separate search string. For example, instead of "restaurants in London", try "restaurants in Shoreditch", "restaurants in Camden", "restaurants in Notting Hill".

How fresh is the data?

Every scrape hits Google Maps live. There is no cached data. Whatever Google shows at the moment of the run is what you get in your sheet.

Is scraping Google Maps legal?

Scraping publicly available data is generally permitted in most jurisdictions, but the specifics depend on where you and your users are located and what you do with the data. The hiQ Labs v. LinkedIn ruling in the US established that scraping public data is not a violation of the Computer Fraud and Abuse Act. GDPR still applies to any personal data you collect. Consult a lawyer if you have specific compliance questions.

Related resources

Download the template ↓ Open the actor on Apify