# Google Maps Leads & Email Finder (with Website Audit) (`optirefine/google-maps-leads-email-finder`) Actor

Find local businesses on Google Maps and turn them into outreach-ready leads: emails and social profiles from each website, a website audit (HTTPS, mobile, analytics, booking), and filters for rating, reviews, no-website prospects and more.

- **URL**: https://apify.com/optirefine/google-maps-leads-email-finder.md
- **Developed by:** [OptiRefine](https://apify.com/optirefine) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 website enricheds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Google Maps Leads & Email Finder (with Website Audit)

Turn a Google Maps search into an **outreach-ready lead list** in one run. This Google Maps scraper finds local businesses ("roofers in Houston, TX"), visits each business's own website to find **emails, extra phone numbers and social profiles**, **audits the website** (HTTPS, mobile layout, analytics, online booking, contact form, stale copyright), and keeps only the leads that match your filters — including the classic agency list: **businesses with no website at all**.

It is built for lead-generation and web-design agencies, local SEO consultants, and anyone who sells to local businesses and needs to know *who to contact* and *what to pitch*.

### What makes it different

- **Emails you can actually use.** Addresses come from `mailto:` links, visible text, Cloudflare-protected emails and structured data — and the junk every other scraper returns is removed: Wix error-tracking addresses, Squarespace's `user@domain.com` placeholder, image filenames like `logo@2x.png`, website vendors' addresses stamped on hundreds of sites, and the web designer's credit in the footer. Each email is classified (**company domain / freemail / other**, **role / personal**), **MX-checked**, and ranked, with the best one in the `email` column.
- **A website audit on every lead.** `websiteIssues` lists what each site is missing — the pitch your agency sells. Every claim is conservative: a site that blocked the crawler gets no "no analytics" finding, and "no contact form" is only claimed after a contact page was actually read.
- **"No website" prospecting.** One setting returns businesses with no website — or only a Facebook/Instagram page, link-in-bio or directory listing.
- **Deep coverage.** A single Google Maps search stops somewhere between 120 and 260 businesses. Deep mode splits the area into a grid and zooms into dense parts — in a live test for roofers in Houston it found **800 businesses** (where it hit the run's cap) versus 244 from a standard search.
- **You pay for leads, not for waste.** The run asks Google and business websites for only as much as your lead count needs: asking for 10 leads with emails never crawls 100 websites.

### How to use it

1. **What businesses** — `searchQueries`, the way a customer searches: `roofers`, `dentists`, `Italian restaurants`.
2. **Where** — `locations`, with state/province/country: `Houston, TX`, `Whitby, ON`, `Manchester, UK`.
3. **How many** — `maxLeads`. The run stops once that many leads have passed your filters.
4. **Filters** (optional) — rating, reviews, website/no website, email required, required social profiles, website issues.
5. **Start.** Export the dataset as CSV, Excel or JSON, or pull it through the [Apify API](https://docs.apify.com/api/v2).

#### Example: cold-email list of established roofers

```json
{
  "searchQueries": ["roofers"],
  "locations": ["Houston, TX", "Katy, TX", "Sugar Land, TX"],
  "maxLeads": 200,
  "minRating": 4,
  "minReviews": 20,
  "emailRequirement": "companyEmail",
  "onePerWebsite": true
}
```

#### Example: web-design prospects — businesses without a website

```json
{
  "searchQueries": ["handyman", "house cleaning"],
  "locations": ["Oshawa, ON"],
  "maxLeads": 100,
  "websiteFilter": "withoutWebsite",
  "scrapePlaceDetails": false
}
```

#### Example: sites that need a rebuild

```json
{
  "searchQueries": ["dentists"],
  "locations": ["Dallas, TX"],
  "maxLeads": 50,
  "requiredWebsiteIssues": ["NO_MOBILE_VIEWPORT", "NO_HTTPS", "OUTDATED_COPYRIGHT"]
}
```

### Input

| Field | Default | What it does |
|---|---|---|
| `searchQueries` | required | Kinds of business to find. |
| `locations` | required | Places to search. Include the state/province/country. |
| `maxLeads` | `100` | Stop after this many leads pass your filters. |
| `searchMode` | `standard` | `deep` grids the location and zooms into dense areas to find more businesses. |
| `maxPlacesPerSearch` | `200` | Businesses to examine per query × location, before filters — the main cost control. Raise it when strict filters leave you short. |
| `enrichWebsites` | `true` | Visit websites for emails, phones, socials and the audit. |
| `maxPagesPerWebsite` | `4` | Homepage plus contact/about/team pages. |
| `checkEmailMx` | `true` | DNS check that each email domain can receive mail. |
| `scrapePlaceDetails` | `true` | Review counts, full week of hours, description (one extra Google request per business). |
| `minRating` / `minReviews` / `maxReviews` | — | Listing filters. `maxReviews` finds small or new businesses. |
| `websiteFilter` | `any` | `withWebsite`, or `withoutWebsite` (none, or only a social/directory page). |
| `skipClosed` | `true` | Skip permanently closed businesses. |
| `requirePhone` | `false` | Skip listings without a phone. |
| `includeCategories` / `excludeCategories` | — | Keep/drop by Google category words, e.g. exclude `supplier`. |
| `onePerWebsite` | `false` | One lead per website domain — chains list the same site and email on every branch. |
| `emailRequirement` | `none` | `anyEmail`, or `companyEmail` (on the business's own domain, MX-deliverable). |
| `requiredSocials` | — | e.g. `["facebook", "instagram"]`. |
| `requiredWebsiteIssues` | — | Keep leads with at least one of these issues (see below). |
| `proxyConfiguration` | Apify residential | For Google. Exits in the US unless you pick a country. |
| `websiteProxyConfiguration` | none | Business websites are fetched directly by default. |
| `language`, `countryCode`, `maxConcurrency` | `en`, —, `20` | Advanced. |

Filters on the Google listing run **before** a website is visited, so businesses they remove cost nothing to enrich.

### What you get

One row per business. The main columns:

| Group | Fields |
|---|---|
| Business | `name`, `primaryCategory`, `categories`, `rating`, `reviewsCount`, `businessStatus`, `openingHours`, `description`, `googleMapsUrl`, `placeId`, `cid` |
| Contact | `phone` (E.164), `phoneDisplay`, **`email`**, `emails`, `emailDetails`, `websitePhones` |
| Social | `facebook`, `instagram`, `linkedin`, `twitter`, `youtube`, `tiktok`, `pinterest`, `yelp` |
| Location | `address`, `street`, `neighborhood`, `city`, `state`, `postalCode`, `countryCode`, `latitude`, `longitude`, `timeZone` |
| Website audit | `website`, `websiteStatus`, **`websiteIssues`**, `websitePlatform`, `hasHttps`, `hasValidSsl`, `hasMobileViewport`, `hasContactForm`, `analyticsTools`, `adPixels`, `bookingTools`, `chatTools`, `copyrightYear`, `websiteResponseTimeMs` |
| Provenance | `searchQuery`, `location`, `searchMode`, `searchRank`, `searchUrl`, `scrapedAt`, `pagesCrawled` |

Every field, its type and exactly when it is empty: **[output reference](docs/OUTPUT-REFERENCE.md)**. Console shows four ready-made views of the dataset: Leads, Website audit, Emails, Locations.

#### Example row

(An illustrative business, showing a subset of the fields — field names and value formats are exact.)

```json
{
  "name": "Maple Ridge Roofing",
  "primaryCategory": "Roofing contractor",
  "phone": "+17135550142",
  "email": "info@mapleridgeroofing.com",
  "emails": ["info@mapleridgeroofing.com", "mapleridgeroofing@gmail.com"],
  "emailDetails": [
    { "email": "info@mapleridgeroofing.com", "type": "role", "domainKind": "company", "source": "mailto", "foundOn": ["https://mapleridgeroofing.com/contact"], "hasMxRecord": true },
    { "email": "mapleridgeroofing@gmail.com", "type": "personal", "domainKind": "freemail", "source": "text", "foundOn": ["https://mapleridgeroofing.com/"], "hasMxRecord": true }
  ],
  "rating": 4.8,
  "reviewsCount": 214,
  "website": "https://mapleridgeroofing.com/",
  "websiteStatus": "OK",
  "websitePlatform": "WordPress",
  "websiteIssues": ["NO_ANALYTICS", "NO_ONLINE_BOOKING", "OUTDATED_COPYRIGHT"],
  "hasHttps": true,
  "hasMobileViewport": true,
  "facebook": "https://www.facebook.com/mapleridgeroofing",
  "instagram": null,
  "city": "Houston",
  "state": "Texas",
  "googleMapsUrl": "https://www.google.com/maps?cid=1234567890123456789",
  "searchQuery": "roofers",
  "location": "Houston, TX",
  "searchRank": 7
}
```

### Website issues

| Code | Means |
|---|---|
| `NO_WEBSITE` | The listing has no website. |
| `NO_OWN_WEBSITE` | The "website" is a Facebook/Instagram profile, a link-in-bio or a directory listing. |
| `FREE_SUBDOMAIN` | Hosted on a builder's subdomain (`acme.wixsite.com`, `acme.square.site`…). |
| `WEBSITE_UNREACHABLE` | Domain doesn't resolve, connection refused, timeout, redirect loop. |
| `WEBSITE_HTTP_ERROR` | The homepage returns an error page. |
| `PARKED_DOMAIN` | A registrar parking or "domain for sale" page. |
| `NO_HTTPS` | The site is served over plain HTTP. |
| `INVALID_SSL_CERTIFICATE` | Expired or mismatched certificate — visitors see a warning. |
| `NO_MOBILE_VIEWPORT` | No mobile viewport tag: the site doesn't scale to phones. |
| `NO_ANALYTICS` | No analytics tag found (Google Analytics, Tag Manager, Clarity, Hotjar, builder analytics…). An ads-only tag doesn't count. |
| `NO_CONTACT_FORM` | A contact page was read and has no form (including JavaScript-embedded ones). |
| `NO_ONLINE_BOOKING` | No booking tool, booking page or "Book now"-style button found. |
| `OUTDATED_COPYRIGHT` | The copyright notice is two or more years old. |
| `SLOW_HOMEPAGE` | The homepage took 5 seconds or more to download. |

A website the crawler couldn't read (bot protection, not HTML) gets **no** audit findings — the actor never reports something it didn't see.

### How many results can I get?

- **Standard mode:** Google usually stops returning results for one query in one place somewhere between **120 and 260 businesses** — and the tail is padded with loosely related businesses (in a live test, only 79 of the 123 businesses returned for `roofers in Whitby, ON` had roofing as their main category).
- **Deep mode:** the location's area is searched as a grid, and cells that are still dense are split into four. Live, for `roofers` in `Houston, TX`: **800 businesses (the run's cap) versus 244** in standard mode — 752 of the 800 with a roofing category — in 52 seconds.
- Deep mode searches the area Google frames for the location — the city **and its surroundings** (Houston's frame includes Katy, Sugar Land and Pasadena). Businesses Google pads in from outside that area are skipped. Use the `city` column to narrow further.
- Your filters decide the final count. If a run comes back short, the run log and the **Run summary** say exactly how many businesses each filter removed; raise `maxPlacesPerSearch`, add locations, or use deep mode.

### Pricing

Pay per event: a small charge per run start, a charge **per lead saved** to the dataset, and a charge **per business website crawled** for enrichment — including a website that turns out to be down or blocked, because the request was made and that finding is part of the result. Social profiles and directory pages listed as a "website" are never fetched and never charged. Businesses removed by listing filters (rating, reviews, website presence, category…) are never crawled and cost nothing to enrich. Businesses removed *after* the crawl (for example "must have an email" when the site has none) were crawled, so the website charge applies to them. The actual prices are shown on the Store page.

Tips to spend less:

- Put your cheapest filters (rating, reviews, no-website) in the listing filters — they run first.
- Turn off `scrapePlaceDetails` if you don't need review counts or full opening hours.
- Turn off `enrichWebsites` for Google Maps data only.
- Keep `maxPagesPerWebsite` at 4; more pages rarely find more emails.

### FAQ

#### Why is `reviewsCount` sometimes empty?

Google randomly serves about half of its responses in a "limited view" without review counts. With `scrapePlaceDetails` on (the default) the actor re-asks Google up to four times per business until it gets the full response; a handful may still end up without a count. With details off, expect about half the rows to have no review count.

#### Why didn't it find an email for every business?

Many small businesses publish no email at all — only a phone number and a contact form. On a live run of Dallas dentists, 22 of 40 websites published one. `emailRequirement` keeps only the ones that do.

#### Are the emails verified?

They are **MX-checked**: the email's domain is confirmed to receive mail. That is a DNS check, not a mailbox test — no email is sent and no SMTP probing is done.

#### Does it collect personal data?

It collects what businesses publish for their customers: listing data from Google Maps and contact details from the business's own website. It reads only what a visitor can read, click or find in structured business data. Data embedded in page scripts — including reviewers' details that some review widgets leak into page code — is deliberately ignored. You are responsible for using the data lawfully (e.g. CAN-SPAM, GDPR, CASL) for your outreach.

#### Do I need a proxy?

Yes for anything beyond a small test — Google rate-limits a single IP. The default (Apify residential, US exits) is right for almost every run and cheap here: a page of 20 businesses is about 24 KB. Results depend on the searched location, not the proxy's country.

#### Why are two rows for the same company?

Chains and multi-location businesses have one Google listing per branch, often with the same website and email. Tick `onePerWebsite` to keep one lead per website domain.

#### Is this a browser-based scraper?

No. Google Maps results are fetched as JSON over plain HTTP and websites are fetched directly. There is no browser, which keeps runs fast and cheap. The flip side: a website that renders its content only with JavaScript can show fewer emails.

#### What happens when Google changes something?

Every Google response is classified as results, end of results, blocked, or unrecognised — never silently treated as "no results". Blocked requests retry on a new IP. If Google changes its request format, the actor reads the new format from Google's own page and switches automatically; if the data layout itself changes, the run log says so loudly.

***

This is an independent tool built on publicly accessible Google Maps pages and businesses' own public websites. It is not affiliated with, endorsed by, or sponsored by Google LLC. "Google Maps" is a trademark of Google LLC.

# Actor input Schema

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

Kinds of business, the way a customer would search Google Maps: 'roofers', 'dentists', 'Italian restaurants'. Each one is searched in every location.

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

Cities, neighbourhoods or regions. Include the state, province or country so Google knows which one you mean: 'Houston, TX', 'Whitby, ON', 'Manchester, UK'.

## `maxLeads` (type: `integer`):

The run stops once this many leads have been saved — after all your filters. Only businesses that pass every filter count.

## `searchMode` (type: `string`):

Standard runs one Google Maps search per query and location; Google usually stops returning results somewhere between 120 and 260 businesses. Deep splits the location into a grid and searches each cell, zooming into dense areas, to find far more (several times more in a big city). Deep mode costs more Google requests but no more per lead.

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

How many businesses to look at for each query × location, before filters. This is your main cost control: raise it when strict filters (for example 'must have an email') leave you short of leads.

## `enrichWebsites` (type: `boolean`):

Visit each business's website (homepage plus its contact, about and team pages) to find emails, extra phone numbers and social profiles, and to audit the site. Charged per website visited. Turn off for Google Maps data only.

## `maxPagesPerWebsite` (type: `integer`):

Homepage included. 4 covers the homepage, contact page and about/team pages on almost every small-business site; more pages rarely find more emails.

## `checkEmailMx` (type: `boolean`):

Looks up each email domain's MX records. An address whose domain cannot receive mail is never chosen as the lead's main email. This is a DNS check, not a mailbox verification.

## `scrapePlaceDetails` (type: `boolean`):

One extra Google request per business. Google leaves review counts out of about half of its search results, so without this many leads will have no review count. Required for the review-count filters.

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

Keep businesses rated at least this (decimals allowed, e.g. 4.5). Leave empty to keep everyone. Any value — even 0 — removes businesses nobody has rated yet.

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

Keep businesses with at least this many reviews. Leave empty to keep everyone.

## `maxReviews` (type: `integer`):

Keep businesses with at most this many reviews — useful for finding small or new businesses that need marketing help. Leave empty for no limit.

## `websiteFilter` (type: `string`):

'Without a website' keeps businesses whose listing has no website or only a Facebook/Instagram page, link-in-bio or directory listing — the classic prospect list for web designers.

## `skipClosed` (type: `boolean`):

Google marks businesses that have closed for good. They are skipped unless you untick this.

## `requirePhone` (type: `boolean`):

Skip listings that show no phone number.

## `includeCategories` (type: `array`):

Keep a business only if one of its Google categories contains one of these words (case-insensitive). 'roof' matches 'Roofing contractor'. Leave empty to keep all.

## `excludeCategories` (type: `array`):

Drop a business if any of its Google categories contains one of these words, e.g. 'supplier' to skip roofing-supply shops in a roofers search.

## `onePerWebsite` (type: `boolean`):

Chains and multi-location businesses list the same website (and email) on every branch. Tick this to keep only the first branch found per website domain. Duplicates are dropped before their website is visited, so they cost nothing.

## `emailRequirement` (type: `string`):

'Must have an email' keeps only businesses where an email was found. 'Must have a company-domain email' also requires it to be on the business's own domain (info@acmeroofing.com, not acmeroofing@gmail.com). Needs website enrichment.

## `requiredSocials` (type: `array`):

Keep only businesses whose website links to every profile selected here.

## `requiredWebsiteIssues` (type: `array`):

Keep only businesses whose website has at least one of the selected problems — the ones your service fixes. For example, pick 'No mobile layout' and 'No HTTPS' to build a list of sites that need a rebuild.

## `proxyConfiguration` (type: `object`):

Google Maps rate-limits a single IP quickly, so residential proxies are recommended — and cheap here: a search page of 20 businesses is about 24 KB. Google requests go out through US exits unless you pick a country: results depend on the searched location, not the proxy country, and US exits avoid the consent wall Google shows EU visitors.

## `websiteProxyConfiguration` (type: `object`):

Business websites are fetched directly by default, which is fast and adds no proxy cost. Enable a proxy only if many sites block the crawler; residential proxy traffic is billed per GB.

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

Language code for Google's result text, e.g. 'en', 'de', 'es', 'pt-BR'.

## `countryCode` (type: `string`):

Two-letter country code (US, GB, CA…) that tells Google how to format addresses. Results do not depend on it: Google Maps is searched by location, not by your IP's country. Leave empty.

## `maxConcurrency` (type: `integer`):

Websites visited in parallel. Google requests are always capped at 8 in parallel regardless.

## Actor input object example

```json
{
  "searchQueries": [
    "roofers",
    "plumbers",
    "dentists"
  ],
  "locations": [
    "Houston, TX",
    "Austin, TX"
  ],
  "maxLeads": 20,
  "searchMode": "standard",
  "maxPlacesPerSearch": 200,
  "enrichWebsites": true,
  "maxPagesPerWebsite": 4,
  "checkEmailMx": true,
  "scrapePlaceDetails": true,
  "minRating": 4,
  "minReviews": 10,
  "maxReviews": 50,
  "websiteFilter": "any",
  "skipClosed": true,
  "requirePhone": false,
  "includeCategories": [
    "roofing contractor"
  ],
  "excludeCategories": [
    "supplier",
    "store"
  ],
  "onePerWebsite": false,
  "emailRequirement": "none",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "websiteProxyConfiguration": {
    "useApifyProxy": false
  },
  "language": "en",
  "countryCode": "US",
  "maxConcurrency": 20
}
```

# Actor output Schema

## `leads` (type: `string`):

Every saved lead. Console shows it with the dataset's saved views (Leads, Website audit, Emails, Locations); use Export for CSV, Excel or JSON.

## `summary` (type: `string`):

What the run did: businesses examined, why any were filtered out, website outcomes, blocked requests and charges.

## `runInConsole` (type: `string`):

The run's page in Apify Console, including the log.

# 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": [
        "roofers"
    ],
    "locations": [
        "Houston, TX"
    ],
    "maxLeads": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("optirefine/google-maps-leads-email-finder").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": ["roofers"],
    "locations": ["Houston, TX"],
    "maxLeads": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("optirefine/google-maps-leads-email-finder").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": [
    "roofers"
  ],
  "locations": [
    "Houston, TX"
  ],
  "maxLeads": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call optirefine/google-maps-leads-email-finder --silent --output-dataset

```

## MCP server setup

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

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/3II4Hgj0agZmSIIj1/builds/u9HURvEWa2n7drpVn/openapi.json
