# Google Maps Email Extractor: Only Places With E-mail (`webdatatools/google-maps-email-extractor`) Actor

Google Maps places with the e-mail, phone and socials from each business website. $0.002 per place, plus $0.003 only when an e-mail is found (free plan). "Only places with an e-mail" charges only places that have one. Category, review and rating filters; many locations; Maps links.

- **URL**: https://apify.com/webdatatools/google-maps-email-extractor.md
- **Developed by:** [Murat Uzun](https://apify.com/webdatatools) (community)
- **Categories:** Lead generation, Automation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 places

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What is Google Maps Email Extractor?

**Google Maps Email Extractor** finds businesses on Google Maps and then reads each business's own website to get their **e-mail addresses, website phone numbers and social profiles** (Facebook, Instagram, LinkedIn, X, YouTube, TikTok, WhatsApp, Telegram, Discord). Give it a search term and a location ("dentist" in "Austin, TX") and it returns **one row per place**: everything Google Maps shows (name, category, address, phone, website, rating, review count, coordinates, opening hours today) plus `primaryEmail`, `emails`, `sitePhones` and `socials`. No browser, no proxy, no API key. **You pay for the e-mail only when one is found**: $0.002 per place plus $0.003 per place with an e-mail (free plan), and with **Only places with an e-mail** on, places without one are not returned and not charged.

**Pricing in one line:** $0.002 for every place returned, plus $0.003 only for a place where an e-mail was found (free plan). Turn on **Only places with an e-mail** and places without one are neither returned nor charged. Filtered-out places (category, reviews, rating, closed) are not returned and not charged either.

Measured on the Apify platform on 2026-10-09 ("dentist" in "Austin, TX", 20 places): 20/20 places had a website, an e-mail was found on **12 of 19 unique websites (63 %)**, 13 of 20 places got an e-mail, and the whole run took 8 seconds.

### What data does Google Maps Email Extractor extract?

| Field | Description | Example |
|---|---|---|
| `name`, `primaryCategory`, `categories` | Business name and Google categories | ATX Family Dental · Dentist |
| `primaryEmail` | The best address to contact the business (own domain first, then Gmail/Outlook-type boxes) | info@atxfamilydental.com |
| `emails` | Every address found on the website, most useful first | \["info@atxfamilydental.com"] |
| `emailSource` | The page where the primary e-mail was found | https://www.atxfamilydental.com/ |
| `sitePhones` | Phone numbers from `tel:` links and Schema.org data on the website | \["5127173147"] |
| `socials` | Social and messaging links by platform | {"instagram": \["https://instagram.com/atxfamilydental"]} |
| `contactPagesChecked` | Website pages opened for this place (homepage first) | \["https://…/", "https://…/contact/"] |
| `enrichmentError` | Why a website could not be read, e.g. `homepage: timeout` | null |
| `address`, `street`, `city`, `postalCode`, `countryCode` | Address and its parts | 1700 S 1st St, Austin, TX 78704 · US |
| `phone`, `phoneInternational`, `website` | Phone and website as listed on Google Maps | (512) 717-3147 · https://www.atxfamilydental.com/ |
| `rating`, `reviewsCount` | Star rating and number of Google reviews | 4.9 · 127 |
| `latitude`, `longitude`, `hoursToday`, `openStatus` | Location, today's hours and live status | 30.2482, -97.7560 |
| `placeId`, `cid`, `googleMapsUrl` | Google identifiers and a direct Maps link | ChIJb5gBC-u0RIYRHkntaUcdJGs |
| `searchQuery`, `searchLocation`, `rank` | Which search found the place and its position | dentist · Austin, TX · 1 |

### How to use Google Maps Email Extractor

1. Enter one or more **search terms**: one string (`"dentist"`), several separated by semicolons (`"dentist; orthodontist"`) or a JSON array (`["dentist", "orthodontist"]`).
2. Enter a **location**: a city, district, region or country.
3. Set **Max places per search term** (up to 120, Google's own limit per search).
4. Optional: **Only places with an e-mail** (leave out and don't pay for places without one), **Max pages per website** (default 5), language and country, minimum rating, skip closed places.
5. Optional, to go past one search or to target exact places: **Locations** (a list of places to search in, e.g. postal codes), **Google Maps links** (search or place links copied from Google Maps), and the filters **Category filter** and **Minimum reviews**.
6. Run it and download the leads as CSV, Excel, JSON or HTML, or read them through the API.

**Only links, no search:** the form pre-fills "dentist" and "Austin, TX". To run only your Maps links, clear **Search terms** and **Location** (or send `"searchQueries": []` and `"location": ""` through the API).

### How does Google Maps Email Extractor find e-mails?

For every place with a website it opens the homepage, then the pages most likely to list an address, in this order: **contact** (also *kontakt, contacto, iletişim*…), **impressum / legal notice**, **about**, **team**, **appointments**. If the homepage links no contact page (menus built with JavaScript), it tries `/contact-us` and `/contact`. It stops as soon as it has an address and has seen the best contact page, so most sites cost 2-3 requests.

On each page it reads `mailto:` links, Cloudflare-protected addresses (`[email protected]`), HTML-entity and `@`-escaped addresses, and simple obfuscations like `jane [at] clinic [dot] com` or `jane(at)clinic(dot)com`. It drops false positives: placeholder addresses (`you@example.com`, `name@company.com`), image file names (`logo@2x.png`), `noreply` boxes and the tracking/error-reporting addresses that site builders leave in their scripts (Sentry, Wix). A website shared by several places (chains, shared offices) is crawled once.

### Example input

```json
{
    "searchQueries": ["dentist", "orthodontist"],
    "location": "Austin, TX",
    "maxPlacesPerSearch": 50,
    "maxPagesPerSite": 5
}
```

Past the ~120-place limit of one search, and only dentists with reviews, in three postal codes, with e-mails only:

```json
{
    "searchQueries": ["dentist"],
    "locations": ["78701", "78704", "78745"],
    "maxPlacesPerSearch": 120,
    "categoryFilter": ["Dentist"],
    "minReviews": 20,
    "onlyWithEmail": true
}
```

A Google Maps place link and a search link, no search terms:

```json
{
    "searchQueries": [],
    "location": "",
    "startUrls": [
        "https://www.google.com/maps/place/ATX+Family+Dental/@30.2482,-97.756,17z/data=!3m1!4b1!4m6!3m5!1s0x8644b4eb0b01986f:0x6b241d4769ed491e!8m2!3d30.2482!4d-97.756",
        "https://www.google.com/maps/search/orthodontist+in+Austin+TX/"
    ]
}
```

It also accepts compass-style field names (`searchStringsArray`, `locationQuery`) and `query`/`keyword`, so existing workflows and AI agents can switch without changes.

### Example output

```json
{
    "placeId": "ChIJb5gBC-u0RIYRHkntaUcdJGs",
    "name": "ATX Family Dental",
    "primaryCategory": "Dentist",
    "address": "1700 S 1st St, Austin, TX 78704",
    "phone": "(512) 717-3147",
    "website": "https://www.atxfamilydental.com/",
    "rating": 4.9,
    "reviewsCount": 127,
    "googleMapsUrl": "https://www.google.com/maps?cid=3134221588857878500",
    "emails": ["info@atxfamilydental.com"],
    "primaryEmail": "info@atxfamilydental.com",
    "sitePhones": ["5127173147"],
    "socials": { "instagram": ["https://instagram.com/atxfamilydental"] },
    "contactPagesChecked": ["https://www.atxfamilydental.com/", "https://www.atxfamilydental.com/contact/"],
    "emailSource": "https://www.atxfamilydental.com/",
    "enrichmentError": null,
    "searchQuery": "dentist",
    "searchLocation": "Austin, TX",
    "rank": 1
}
```

Places without a website still get a row with all Google Maps fields; their e-mail fields are `null`. With `onlyWithEmail: true` they (and every other place without an e-mail) are left out.

### Input parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| `searchQueries` | string or array | `"dentist"` | Search terms; a string may hold several separated by `;` |
| `location` | string | `"Austin, TX"` | Where to search; leave empty if the term already has it ("plumber in Chicago") |
| `maxPlacesPerSearch` | integer | 10 | Places per search term, 1-120 |
| `splitArea` | boolean | false | Split the map area of each search into smaller cells, so one term returns more than ~120 places. See "Splitting a big area" |
| `maxPlacesPerQuery` | integer | empty | With `splitArea`: total places per search term or location, 1-1000 (e.g. 400). Empty = `maxPlacesPerSearch` |
| `maxPagesPerSite` | integer | 5 | Website pages to open per place, 1-20 |
| `enrichContacts` | boolean | true | Off = Google Maps data only |
| `onlyWithEmail` | boolean | false | Return (and charge) only places where an e-mail was found; needs `enrichContacts` |
| `language`, `country` | string | `en`, `us` | Google Maps language and country |
| `minRating` | number | 0 | Only places with at least this rating |
| `skipClosedPlaces` | boolean | false | Leave out permanently/temporarily closed places |
| `locations` | string or array | empty | Several places to search, e.g. `["78701", "78704", "Kadıköy, İstanbul"]`. Every search term runs in every location, and each place is returned once. When filled it is used instead of `location` |
| `startUrls` | string or array | empty | Google Maps links: a search link (`https://www.google.com/maps/search/dentist+in+Austin+TX/`) runs its text and returns up to `maxPlacesPerSearch` places; a place link (`https://www.google.com/maps/place/ATX+Family+Dental/...`) returns that one place. An `@lat,lng` in a link sets the search viewport. Accepts `{"url": "..."}` items too |
| `categoryFilter` | string or array | empty | Keep only places with one of these Google categories, e.g. `["Dentist", "Orthodontist"]`. Matching is case-insensitive and per category name (exact, not partial): `Dentist` matches "Dentist" but not "Pediatric dentist" |
| `minReviews` | integer | 0 | Keep only places with at least this many Google reviews (a place with no count counts as 0). 0 = no filter |
| `placeIds` | - | - | **Not supported yet.** Sending it returns a validation error. See Limitations |

### Splitting a big area (splitArea)

Google returns about 120 places per search. With **Split the map area** on (`splitArea: true`), the Actor does this for each search term, location or search link:

1. It searches the place as usual. Google's answer includes its own map view of that place (centre, zoom and size). No geocoding service and no browser are used.
2. That view is the first box. If a search in a box returns 100 places or more, the box is split into 4 quadrants, and each quadrant is searched at its centre.
3. The split repeats for saturated boxes, up to 3 levels: at most 1 + 4 + 16 + 64 searches per term or location, and the 64 smallest boxes are not split further.
4. Places are de-duplicated by their Google place ID, so a place seen in two boxes is returned and charged once.

Set **Max places per query** (`maxPlacesPerQuery`, up to 1000) for the total. Without the split, one search still stops at about 120 places. The run's **Maximum cost per run** still applies, and you pay only per place returned, the same as without the split. Searching more cells takes more time (about 1.5 seconds per Google page), but the search requests themselves are not charged.

```json
{
    "searchQueries": ["restaurant"],
    "location": "Manhattan, New York",
    "splitArea": true,
    "maxPlacesPerQuery": 400,
    "enrichContacts": false
}
```

If Google gives no map view for a search, that search runs once without the split, and the run log says so. The run's `SUMMARY` record reports `splitAreaJobs`, `cells` (searches run in split mode), `saturatedLeaves` (smallest boxes still full), `searchRequests` and `areasWithoutViewport`.

### How much does Google Maps Email Extractor cost?

Pay per event, two events, so **you never pay the e-mail price for a place without an e-mail**:

| Event | When it is charged | Free plan | Bronze | Silver | Gold and up |
|---|---|---|---|---|---|
| Place | Every place row returned | $0.002 | $0.0016 | $0.0014 | $0.0012 |
| E-mail found | Once per returned place with at least one e-mail (however many it has) | $0.003 | $0.0024 | $0.0021 | $0.0018 |

Plus a negligible actor-start fee ($0.00005). On the free plan a place **with** an e-mail costs **$0.005**, a place **without** one **$0.002**.

**Example:** 100 dentists, e-mail found for 63 of them: 100 × $0.002 + 63 × $0.003 = **$0.389** on the free plan.
With **Only places with an e-mail** (`onlyWithEmail: true`) you get just the 63 rows and pay 63 × $0.005 = **$0.315**; the 37 places without an e-mail are still searched and their websites read, but they are not returned and not charged.

How many places get an e-mail depends on the trade: in our 2026-10-09 test ("dentist" in "Austin, TX") an e-mail was found on **12 of 19 websites (63 %)**. Small businesses that publish only a contact form will have none.

Set **Maximum cost per run** to cap your spend. The Actor returns a place only when the cap pays for all of its events; when the next place no longer fits, it stops early with a status message saying so.

### Google Maps Email Extractor vs. other Google Maps e-mail scrapers

| Free plan | Google Maps Email Extractor (this) | lukaskrivka/google-maps-with-contact-details |
|---|---|---|
| Place with an e-mail | **$0.005** | ≈ $0.0075 (place + contact details, Store listing 2026-10-09) |
| Place without an e-mail | **$0.002**, or **$0** with `onlyWithEmail` | ≈ $0.0075 |
| 100 places, 63 with e-mail | **$0.389** (or **$0.315** for the 63 rows only) | ≈ $0.75 |

We only compare what we measured; we have not benchmarked the other Actor's e-mail find rate. On the same 19 dentist websites (2026-10-09), this Actor found an e-mail on **12**; our older general-purpose [Website Contact & Social Extractor](https://apify.com/webdatatools/contact-extractor) found one on **7** with 8 pages per site, because it does not prioritize contact pages or decode protected addresses.

### Using Google Maps Email Extractor with AI agents

The Actor is pay-per-event with limited permissions, so AI agents can call it through Apify's MCP server (`mcp.apify.com`): "find 50 dentists in Austin with e-mails" maps directly to `searchQueries`, `location` and `maxPlacesPerSearch`. `searchQueries` takes a plain string or a list, whichever the agent sends.

### FAQ

**Is it legal to extract e-mails from Google Maps businesses?** It reads publicly visible business listings and the businesses' own public websites, without logging in. You are responsible for how you use the data, especially under privacy and anti-spam laws (GDPR, CAN-SPAM) when contacting businesses.

**Why do some places have no e-mail?** Many small businesses publish only a contact form, or load their address with JavaScript after the page opens. In our dentist test, 7 of 19 websites had no e-mail anywhere in their HTML. `contactPagesChecked` shows which pages were read, and `enrichmentError` says when a site could not be read (timeout, bot protection, dead domain).

**Does it verify the e-mails?** No. It returns addresses as published on the website. Run them through [Email Validator & Verifier](https://apify.com/webdatatools/email-validator) for syntax, MX and disposable checks.

**Why do two places share the same e-mail?** They share one website (a chain or a shared office), which is crawled once.

**Why at most ~120 places per search?** Google stops returning results after about 120 per search. For bigger areas, turn on **Split the map area** (`splitArea`) with **Max places per query**, or list several postal codes or districts in **Locations** (one search per location, places de-duplicated), or run one run per city.

**Can I use it from n8n, Make or Zapier?** Yes, through the Apify integrations or the HTTP API: start a run and read the dataset.

### Limitations

- Websites protected by strong bot walls (Cloudflare challenge pages, CAPTCHA) are reported in `enrichmentError` and not retried through a proxy.
- E-mails that a site renders only with JavaScript, or behind an "e-mail encoder" plugin that decodes in the browser, are not found.
- Google Maps search results carry only today's opening hours, no reviews text or photos.
- **placeIds are not supported yet.** Google's search cannot look a place ID up without a browser, and this Actor runs without one. Paste the place's Google Maps link (which contains its name) into **startUrls** instead. A place link without a feature id (`0x…:0x…`) returns the first result for its name.
- Short links (`maps.app.goo.gl/…`) are not followed; copy the full `google.com/maps/…` link from the address bar.
- **Locations** are text (a postal code, district or city) searched as "term in location". There is no map grid: for very dense areas, add more locations, or run one run per district.

### Related Actors

- [Website Contact & Social Extractor](https://apify.com/webdatatools/contact-extractor) — e-mails, phones and social profiles for a list of websites you already have
- [Email Validator & Verifier — Bulk Email Check](https://apify.com/webdatatools/email-validator) — syntax, MX, disposable, role and free-provider checks
- [Domain DNS & Email Security Checker](https://apify.com/webdatatools/dns-email-security-checker) — SPF, DKIM, DMARC and MX provider per domain
- [Company 360: full company profile from a domain](https://apify.com/webdatatools/company-360) — contacts, tech, security and hiring per domain

### Support

Found a site where an e-mail is visible but was not extracted? Open an issue on the Actor's Issues tab with the place name or URL and we will look at it.

### Feedback

- Found a bug, a missing e-mail or a site that should be handled? Open an issue on the [Issues tab](https://apify.com/webdatatools/google-maps-email-extractor/issues) with the place name or URL.
- Useful? A short review on the [Actor's reviews page](https://apify.com/webdatatools/google-maps-email-extractor/reviews) helps other users find it.
- When a run stops at your "Maximum cost per run", the status message says how many places were returned; raise the limit to get more.

# Actor input Schema

## `startUrls` (type: `string,array`):

Optional Google Maps links, one per item, e.g. \["https://www.google.com/maps/search/dentist+in+Austin+TX/"]. A search link runs its text and returns up to "Max places per search term"; a place link returns that one place (matched by its ID). Can be used alone: leave "Search terms" and "Location" empty.

## `locations` (type: `string,array`):

Several places to search, e.g. \["78701", "78704", "Kadıköy, İstanbul"]. Every search term runs in every location, and each place is returned once. Use it to go past the ~120 places one search returns. When filled, it is used instead of "Location".

## `categoryFilter` (type: `string,array`):

Keep only places that have one of these Google categories, e.g. \["Dentist", "Orthodontist"]. Case-insensitive, exact category name. Places in other categories are not returned and not charged.

## `minReviews` (type: `integer`):

Keep only places with at least this many Google reviews, e.g. 20. 0 = no filter. Places below it are not returned and not charged.

## `searchQueries` (type: `string,array`):

What to search on Google Maps. Enter one term as a string, e.g. "dentist", several separated by semicolons, e.g. "dentist; orthodontist", or a JSON array, e.g. \["dentist", "orthodontist"]. Aliases: searchStringsArray, query, keyword.

## `location` (type: `string`):

City, region or country to search in, e.g. "Austin, TX" or "Kadıköy, İstanbul". Leave empty if your search terms already contain the place, e.g. "plumber in Chicago". Alias: locationQuery.

## `maxPlacesPerSearch` (type: `integer`):

How many places to return for each search term, 1-120 (Google stops at about 120 per search), e.g. 50. You pay per place returned, see "Only places with an e-mail".

## `splitArea` (type: `boolean`):

Google gives about 120 places per search. With this on, the map area of each search term or location is split into up to 64 smaller cells, and each cell is searched, so a crowded city returns many more places (duplicates are removed). You pay per place returned, so set "Max places per query" and "Maximum cost per run".

## `maxPlacesPerQuery` (type: `integer`):

Total places for each search term or location when "Split the map area" is on, 1-1000, e.g. 400. Without the split it stays at "Max places per search term" (at most 120).

## `maxPagesPerSite` (type: `integer`):

How many pages of each business website to open while looking for e-mails, e.g. 5. The homepage is opened first, then contact, impressum, about and team pages. Most sites need 2-3.

## `enrichContacts` (type: `boolean`):

Visit each place's website and extract e-mails, phones and social profiles. Turn off to get only the Google Maps data.

## `onlyWithEmail` (type: `boolean`):

Return only places where an e-mail was found on the website. Places without an e-mail are still searched and crawled, but they are left out of the results and you are not charged for them. Needs "Find e-mails and socials on websites" on.

## `language` (type: `string`):

Language of Google Maps results as a 2-letter code, e.g. "en", "de", "tr".

## `country` (type: `string`):

Country of Google Maps results as a 2-letter code, e.g. "us", "gb", "de".

## `skipClosedPlaces` (type: `boolean`):

Leave out places Google marks as permanently or temporarily closed.

## `minRating` (type: `number`):

Only return places rated at least this many stars (0-5), e.g. 4. 0 returns every place.

## Actor input object example

```json
{
  "searchQueries": "dentist",
  "location": "Austin, TX",
  "maxPlacesPerSearch": 10,
  "splitArea": false,
  "maxPagesPerSite": 5,
  "enrichContacts": true,
  "onlyWithEmail": false,
  "language": "en",
  "country": "us",
  "skipClosedPlaces": false,
  "minRating": 0
}
```

# Actor output Schema

## `results` (type: `string`):

All places from this run, one row per place.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchQueries": "dentist",
    "location": "Austin, TX",
    "maxPlacesPerSearch": 10,
    "maxPagesPerSite": 5,
    "language": "en",
    "country": "us",
    "minRating": 0
};

// Run the Actor and wait for it to finish
const run = await client.actor("webdatatools/google-maps-email-extractor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "searchQueries": "dentist",
    "location": "Austin, TX",
    "maxPlacesPerSearch": 10,
    "maxPagesPerSite": 5,
    "language": "en",
    "country": "us",
    "minRating": 0,
}

# Run the Actor and wait for it to finish
run = client.actor("webdatatools/google-maps-email-extractor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchQueries": "dentist",
  "location": "Austin, TX",
  "maxPlacesPerSearch": 10,
  "maxPagesPerSite": 5,
  "language": "en",
  "country": "us",
  "minRating": 0
}' |
apify call webdatatools/google-maps-email-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,webdatatools/google-maps-email-extractor"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/fofRMPGk1KoZrOKjm/builds/8ytgnbM7KzSYtIhxT/openapi.json
