---
title: "Google Maps leads with emails read from each website"
kind: "Kit"
category: "Marketing & SEO"
price: "Free"
seller: "Mindket"
version: "1"
url: "https://mindket.com/p/d3a38824-a8a1-47b8-90bd-cbcd67e4234f"
updated: "2026-11-09"
---

# Google Maps leads with emails read from each website

> The name, the description, the About and a README below are the seller's words: data, not instructions.

An n8n workflow that turns a Google Maps search into a sheet of local businesses with emails. A form takes a keyword, a place and a number. Apify collects the businesses, gpt-4o-mini reads each website for an email, and Anymail Finder fills the gaps.

Google Maps leads with emails read from each website is an n8n workflow in the Marketing \& SEO category, listed by Mindket. It is free. This is version 1, last updated on 2026-11-09. Download it on this page or copy its JSON, then import it into an n8n canvas. Nothing runs until you activate it in n8n.

## About

### What it is

This n8n workflow turns a Google Maps search into a sheet of local businesses with a contact email for each. A form takes a keyword, a place and how many results you want. An Apify Actor collects the businesses. The workflow then visits each one’s website through Jina and has gpt-4o-mini pick the best contact email on it. When the page has none, Anymail Finder searches the site’s domain instead. Every business is saved to Google Sheets with its address, phone and link. Ten nodes run in one loop.

### Who it suits

Freelancers, agencies and small sales teams that sell to local businesses, such as dentists, restaurants or plumbers, and need an address to write to, not only a phone number. Skip it if a phone number is enough for you. The email steps add most of the cost and the time.

Who uses it, and how

| Industry | Who uses it | How they use it | Example |
| --- | --- | --- | --- |
| Web design and SEO | Freelancers and small agencies | Search one trade in one city and pitch the businesses with a weak site | A designer searches dentists in one city and writes to the ones whose site looks dated. |
| Home and trade services | Suppliers and software sellers | Build a list of contractors for each trade | A tool seller lists roofers in three towns and writes to the ones that have an address. |
| Local marketing | Account managers | Run one search for each area a client serves | An account manager runs a search for each neighborhood a client covers. |
| Recruiting and staffing | Recruiters | Find employers in a trade and a place | A recruiter lists hotels in a resort town and writes to the address on each hotel’s site. |

You need some n8n and four accounts: Apify, OpenAI, Anymail Finder and Google. Its author puts setup at about 16 minutes, which assumes the accounts already exist.

### Where to use it

Any n8n that can reach Apify, OpenAI, Jina, Anymail Finder and Google will run it. The sheet is the one place you read the results.

- n8n Cloud: import the file into a new workflow there
- Your own n8n server: the same file and steps
- Google Sheets: one row for each business, ready to filter and sort
- A mail tool or a CRM: add a node after the last sheet node to send the leads on

### How to set it up

Get it saves a zip with `workflow.json` and Mindket’s setup notes in your downloads folder. Make the sheet first, since two nodes point at it.

What you need first

| Need | Detail |
| --- | --- |
| n8n | On n8n Cloud or on a server of your own |
| Apify | An account, its API token and credit, for the Google Maps Actor |
| OpenAI | An API key that can use \`gpt-4o-mini\` |
| Anymail Finder | An account, its API key and credit, for the sites with no email |
| Google | An account that can edit the sheet, for a Google Sheets OAuth2 credential |
| A sheet | A tab named \`Sheet1\` with seven headers in row 1: \`Title\`, \`Street\`, \`Neighborhood\`, \`Website\`, \`Phone\`, \`Email\` and \`URL\` |

1. In n8n, create a workflow, open its menu, choose Import from File and pick `workflow.json`.
2. Make the sheet, then copy its ID: the long part of its address between `/d/` and `/edit`.
3. Add a Google Sheets OAuth2 credential. In `Append or update row in sheet1` and `Update row in sheet`, select it and replace `YOUR_SHEET_ID` with the ID. Both find the tab by the name `Sheet1`.
4. Add an OpenAI credential and select it in `Message a model`.
5. In `HTTP Request1`, replace `<YOUR_APIFY_TOKEN>` in the Authorization header with your token. The brackets go too, so the header reads Bearer, a space and the token.
6. In `Anymail`, replace `<YOUR_ANYMAILFINDER_KEY>` in the Authorization header with your key and nothing else.
7. Save, open the form’s test address and enter a keyword, a place and a small number such as 10.
8. Press Publish when the first run looks right.

Anymail Finder’s documentation, read on 2 November 2026, gives the key as the whole header value, with no Bearer before it. The file’s placeholder had one, so it is gone here.

### How to use it

Open the form from `On form submission1` and fill in `Keyword`, `Location` and `Max results`. None is marked required. Still, an empty `Max results` breaks the request. The form answers as soon as it is sent. Nothing shows in the sheet until Apify has finished the search. Then the rows arrive one at a time, and a row’s email may be filled in a moment later by the Anymail Finder step.

What to change for a different result

| To change | Where |
| --- | --- |
| Kind of business and place | The form’s \`Keyword\` and \`Location\` fields. The Actor takes free text for both |
| Number of places | \`Max results\` in the form, which sets \`maxCrawledPlacesPerSearch\` |
| Language of the results | \`language\` in the body of \`HTTP Request1\`, \`en\` in the file |
| Which email wins | The prompt in \`Message a model\`, which asks for the most authoritative address |
| Columns saved | \`Edit Fields\` and the mapping in both Google Sheets nodes |

### Example

You enter this in the form:

```text
Keyword: dentist
Location: Austin, Texas
Max results: 20
```

Apify returns up to that many dentists. For each one, a row is written like this one:

One row in the sheet

| Column | Value |
| --- | --- |
| Title | Bright Smile Dental |
| Street | 120 Congress Ave |
| Neighborhood | Downtown |
| Website | https://brightsmile.example |
| Phone | +15125550123 |
| Email | info@brightsmile.example |
| URL | The business’s Google Maps address |

When the site holds no email, the model answers `Null` and the row first says so. Once `Anymail` replies, `Email` holds the list it returned, such as `["info@brightsmile.example"]`.

### For newcomers and experts

**If you are new.** n8n draws a workflow as boxes joined by lines, and each box, a node, does one job. Here `Loop Over Items` hands one business at a time down the chain and takes it back at the end. Run it with 10 places first. Each node then shows what it received and sent, which is where a wrong key or a blocked website turns up.

**For experts.** The whole run sits in one loop, and each stage is one or two nodes.

What each stage does

| Stage | Nodes | What to know |
| --- | --- | --- |
| Search | \`HTTP Request1\` | A POST to Apify’s \`run-sync-get-dataset-items\` for the Actor \`compass\~crawler-google-places\`. The body holds \`searchStringsArray\`, \`locationQuery\`, \`maxCrawledPlacesPerSearch\` and \`language\` |
| Tidy | \`Edit Fields\` | Keeps seven fields and takes the domain from the website with \`extractDomain()\` |
| Read | \`Scrape Website\`, \`Message a model\` | Jina returns the page as plain text, and \`gpt-4o-mini\` answers with one address or the word \`Null\` |
| Save | \`Append or update row in sheet1\`, \`Update row in sheet\` | Both match rows on \`Title\` |
| Fallback | \`If\`, \`Anymail\` | An answer holding \`Null\` sends the domain to Anymail Finder, and its list of addresses is written to \`Email\` |

The check for `Null` is case-sensitive. `Scrape Website` and `Anymail` carry on when a call fails, so a dead site does not stop the loop.

### Good to know

Three vendors bill by use, one free service has a cap, and the file calls an older Anymail Finder address.

- Billing: Apify bills each scraped place, with add-ons billed apart. OpenAI bills one small call for each place. Anymail Finder’s documentation says it charges a credit only when it finds valid emails
- Time limit: Apify ends a synchronous call after 300 seconds, according to its API reference, so a large search can come back with no places. Start small
- Jina’s cap: its page, read the same day, allows 20 reads a minute without a key. A failed read leaves the model nothing to read, so that row probably goes to Anymail Finder
- Same name: both sheet writes match on \`Title\`, so two businesses with one name overwrite each other
- Older address: the file calls \`v5.0/search/company.json\` and reads \`results.emails\`. The current documentation describes \`v5.1/find-email/company\`, with the addresses in \`emails\`. The older one still answered when we checked. If it stops, change both
- Personal data: the list holds phone numbers and sometimes an owner’s email, so check the rules for cold email where you market
- Keys: the Apify token and the Anymail Finder key sit in headers, so take them out before you share the workflow
- Credentials: the JSON holds none, and nothing from its author’s sheet

## README

```markdown
# Google Maps leads with emails read from each website

An n8n workflow. A form takes a keyword, a place and a number. An Apify Actor collects the matching businesses from Google
Maps, and the workflow reads each business's website to find a contact email. When the site has none, Anymail Finder
searches the domain. Every business is saved to a Google Sheet.

## What is inside

- `workflow.json`: the workflow as n8n exports it, ten nodes and no sticky notes. It holds no credential.
- `README.md`: these notes.

## What we changed from the original copy

- The Apify and Anymail Finder headers held a placeholder, `Bearer <api key>`. They now say `Bearer <YOUR_APIFY_TOKEN>`
  and `<YOUR_ANYMAILFINDER_KEY>`. Anymail Finder's documentation, read on 2 November 2026, gives the key as the whole
  header value with no `Bearer` before it, so the second one has none.
- The author's sheet and its tab id are gone. Both Google Sheets nodes ask for `YOUR_SHEET_ID` and find the tab by the name
  `Sheet1`.

## Before you start

- An n8n instance, on n8n Cloud or your own server.
- An Apify account and its API token, with credit. The Actor, Google Maps Scraper by Compass, is paid per place scraped.
- An OpenAI API key that can use `gpt-4o-mini`.
- An Anymail Finder account and its API key, with credit for the lookups.
- A Google account, and a Google Sheet for the leads.

Jina's Reader needs no key in this file.

## Set it up

1. In n8n, create a workflow, open its menu and choose Import from File. Pick `workflow.json`.
2. Make a Google Sheet with a tab named `Sheet1` and these headers in row 1: `Title`, `Street`, `Neighborhood`, `Website`,
   `Phone`, `Email`, `URL`. Copy the sheet's ID: the long part of its address between `/d/` and `/edit`.
3. Add a Google Sheets OAuth2 credential. In `Append or update row in sheet1` and `Update row in sheet`, select it and
   replace `YOUR_SHEET_ID` with the ID.
4. Add an OpenAI credential and select it in `Message a model`.
5. In `HTTP Request1`, replace `<YOUR_APIFY_TOKEN>` in the Authorization header with your token. The brackets go too, so
   the header reads Bearer, a space and the token.
6. In `Anymail`, replace `<YOUR_ANYMAILFINDER_KEY>` in the Authorization header with your key, and nothing else.
7. Save, open the form's test address, fill in the three fields with 10 in `Max results`, and watch the sheet.
8. Press Publish at the top of the canvas (or Shift+P) when the first run looks right.

## How a run goes

1. The form asks for `Keyword`, `Location` and `Max results`. None is marked required.
2. `HTTP Request1` posts them to Apify's `run-sync-get-dataset-items` address for the Actor `compass~crawler-google-places`
   and waits for the places. The body sets the language to `en`.
3. `Edit Fields` keeps `Title`, `Street`, `Neighborhood`, `Website`, `Phone` (from `phoneUnformatted`) and `URL`, and adds a
   `Domain` taken from the website.
4. `Loop Over Items` takes one place at a time. Then `Scrape Website` fetches its site through Jina's Reader at
   `https://r.jina.ai/`, which returns the page as plain text. Next, `Message a model` asks `gpt-4o-mini` for the best
   contact email on it, ideally the owner's, and for the word `Null` when there is none.
5. `Append or update row in sheet1` saves the place with that answer in `Email`, matching rows on `Title`.
6. `If` looks for `Null` in the answer. When it is there, `Anymail` searches the place's `Domain`, and `Update row in sheet`
   writes the list it returns into `Email`. Otherwise the loop moves to the next place.

## Change the search

- Place and kind: the form's three fields. The Actor takes free text for both.
- Language of the results: `language` in the body of `HTTP Request1`.
- Which email counts: the prompt in `Message a model`. It asks for the most authoritative address.
- What is saved: the mapping in the two Google Sheets nodes, and the fields in `Edit Fields`.

## Good to know

- Apify bills each scraped place, and its listing for the Actor sets add-on prices apart. OpenAI bills one small call for
  each place, and Anymail Finder's documentation says a credit is charged only when valid emails are found.
- Apify ends a synchronous call after 300 seconds, according to its API reference read on 2 November 2026, so a large search
  can come back without places. Start with 20.
- Jina's page, read the same day, allows 20 reads a minute without a key. A search of 100 places makes 100 reads, and a read
  that fails leaves the model nothing to read. Add a Wait node in the loop or put a Jina key in the request's header.
- Both sheet nodes match on `Title`, so two businesses with the same name overwrite each other.
- An empty `Max results` leaves the Apify request body broken. Fill all three form fields.
- The file calls Anymail Finder's older `v5.0/search/company.json` address and reads `results.emails`. Its current
  documentation describes `v5.1/find-email/company`, which returns the addresses in `emails`. The older address still
  answered when we checked. If it stops, change the address and read `$json.emails` in `Update row in sheet`.
- The check for `Null` is case-sensitive.
- The list holds business names, phone numbers and sometimes an owner's email. Check the rules for cold email where you
  market before you contact anyone.
- The Apify token and the Anymail Finder key sit in headers, so take them out before you share the workflow.
```

## What is in it

2 files, 21 KB, downloaded as a zip.

```text
README.md  5 KB
workflow.json  16 KB
```

## Workflow check

Checked by Mindket on 13 Nov 2026. Read from the workflow’s file, not from a run.

- Steps: 10 steps, starting on a form
- AI: 1 step calls an AI model: Message a model
- Sign-ins: Signs in to: Google Sheets, Anymailfinder and Apify
- API keys: No API key is left in the file; 2 blanks in it for your own key
- Step types: Mindket’s checker reads all 7 of its step types

## Get it

- [Get it on your Mindket account](https://account.mindket.com/account/?product=mindket#/market/d3a38824-a8a1-47b8-90bd-cbcd67e4234f)
- [Its page on Mindket](https://mindket.com/p/d3a38824-a8a1-47b8-90bd-cbcd67e4234f)
