{
  "openapi": "3.0.1",
  "info": {
    "title": "Google Maps Email Extractor & Lead Scraper",
    "description": "Extract business emails and leads from Google Maps. Finds the contact page under its native name - impressum, kapcsolat, contatti and 44 more across ten languages - then grades every address with MX, SPF, DMARC and catch-all detection. Measured: 71% of rows returned an email.",
    "version": "1.4",
    "x-build-id": "gcmpGdRzT0mpQqhf1"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/highbrow_fame~google-maps-email-extractor/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-highbrow_fame-google-maps-email-extractor",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/highbrow_fame~google-maps-email-extractor/runs": {
      "post": {
        "operationId": "runs-sync-highbrow_fame-google-maps-email-extractor",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/highbrow_fame~google-maps-email-extractor/run-sync": {
      "post": {
        "operationId": "run-sync-highbrow_fame-google-maps-email-extractor",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "properties": {
          "searchQueries": {
            "title": "Search Queries",
            "type": "array",
            "description": "REQUIRED unless you set startUrls: the run needs at least one of the two, and it will stop immediately if both are empty. List of search queries to use on Google Maps (e.g., 'restaurants in Budapest', 'dentists in London'). Each query will produce a separate search.",
            "items": {
              "type": "string"
            }
          },
          "startUrls": {
            "title": "Google Maps URLs",
            "type": "array",
            "description": "An alternative to searchQueries: supply one and leave the other empty. Direct Google Maps search result URLs. Use this if you already have specific Google Maps URLs to scrape.",
            "items": {
              "type": "object",
              "required": [
                "url"
              ],
              "properties": {
                "url": {
                  "type": "string",
                  "title": "URL of a web page",
                  "format": "uri"
                }
              }
            }
          },
          "maxResults": {
            "title": "Maximum Results Per Query",
            "minimum": 0,
            "maximum": 1000,
            "type": "integer",
            "description": "Maximum number of business listings to extract per search query. Set to 0 for unlimited. If you are calling this Actor programmatically or from an AI agent, pass this value explicitly: the form is prefilled with 5 for a fast first look, while the value applied when the field is omitted is 25. Default is 25 — enough to judge output quality on a real market; that run takes about 4–5 minutes (longer when third-party sites are slow). Runtime is roughly 70s + 7.5s per lead, so no run returns within a 30–45s tool-call window; expect to poll the run and then read the dataset. For production runs, bump to 100–1000. 💸 Billing: $0.007 per delivered lead on the Free plan, scaling down with your Apify plan to $0.004 on Platinum and Diamond (all enrichment included at every tier) + a $0.015/GB run-start fee ($0.06 on the 4 GB default, the same on every plan) that covers browser startup. Example on the Free plan: 100 leads ≈ $0.76, 1000 leads ≈ $7.06 — the start fee amortises away on larger runs, so bigger runs are cheaper per lead. ⚠️ The 4-hour default timeout tops out at about 891 leads. Beyond that, raise the run timeout (Start new run modal → ⚙ Options → Timeout): 1000 leads needs at least 18000s. At ~7.5s/lead plus ~70s startup, 500 leads ≈ 65 min. The scraper emits a runtime estimate and a preflight check at startup that refuses to start (0 events billed) if your settings wouldn't fit the timeout.",
            "default": 25
          },
          "scrapeEmails": {
            "title": "Scrape Emails from Websites",
            "type": "boolean",
            "description": "Visit each business website to extract email addresses. Disabling this speeds up the scraper significantly.",
            "default": true
          },
          "scrapeSocials": {
            "title": "Scrape Social Media Links",
            "type": "boolean",
            "description": "Extract social media profile links (Facebook, Instagram, LinkedIn, Twitter) from business websites.",
            "default": true
          },
          "maxConcurrency": {
            "title": "Max Concurrency",
            "minimum": 1,
            "maximum": 20,
            "type": "integer",
            "description": "Maximum number of pages processed in parallel. Lower values reduce the chance of being blocked.",
            "default": 5
          },
          "proxyConfiguration": {
            "title": "Proxy Configuration",
            "type": "object",
            "description": "Proxy configuration for the scraper. The default (Apify datacenter proxy) was measured on four markets in paired runs against RESIDENTIAL: same rows delivered, same email hit rate, ~78% cheaper. Switch to the RESIDENTIAL group only if your runs hit Google's consent wall or return nothing — that is Google throttling datacenter IPs, and RESIDENTIAL gets past it at $8/GB."
          },
          "language": {
            "title": "Language",
            "enum": [
              "en",
              "de",
              "fr",
              "es",
              "it",
              "pt",
              "nl",
              "hu",
              "pl",
              "cs",
              "sk",
              "ro",
              "bg",
              "hr",
              "sl",
              "sr",
              "bs",
              "mk",
              "sq",
              "el",
              "tr",
              "ar",
              "he",
              "ja",
              "ko",
              "zh",
              "th",
              "vi",
              "id",
              "ms",
              "fil",
              "hi",
              "bn",
              "ta",
              "te",
              "ml",
              "kn",
              "mr",
              "gu",
              "pa",
              "ur",
              "fa",
              "ru",
              "uk",
              "sv",
              "no",
              "da",
              "fi"
            ],
            "type": "string",
            "description": "Language code for Google Maps results (e.g., 'en', 'de', 'hu').",
            "default": "en"
          },
          "maxEmailScrapeConcurrency": {
            "title": "Email Scrape Concurrency",
            "minimum": 1,
            "maximum": 10,
            "type": "integer",
            "description": "Maximum concurrent requests when scraping business websites for emails. Keep low to avoid blocks.",
            "default": 3
          },
          "sinceDatasetId": {
            "title": "Delta Mode — Skip places already in this dataset",
            "type": "string",
            "description": "Optional, and it requires state: you have to remember the datasetId that a previous run returned and pass it back here. Leave it empty on a first run. If you provide a dataset ID from a previous run, the actor will skip any Google Maps place already present there (matched by placeId). Perfect for daily/weekly scheduled runs that only want NEW leads — you save on every duplicate. Example: '0selLasyFyBlq5xRq' from a previous run."
          },
          "enrichMetaAds": {
            "title": "Enrich with Meta Ad Library lookup URL",
            "type": "boolean",
            "description": "When enabled, the scraper fetches each business's Facebook page to extract the numeric page ID, then builds a targeted Meta Ad Library URL (active ads only). Adds ~1 request per business with a Facebook URL. Great for identifying actively-advertising leads (high purchase intent).",
            "default": false
          },
          "validateEmails": {
            "title": "Validate emails (MX / SPF / DMARC / SMTP)",
            "type": "boolean",
            "description": "When enabled, the actor grades every primaryEmail before delivery: checks MX records, SPF & DMARC DNS entries, and attempts an SMTP RCPT TO probe to detect catch-all domains (high bounce risk). Fills the `emailValidation` field with deliverability 'high'/'medium'/'low'. Critical for cold-outreach teams protecting sender reputation.",
            "default": true
          },
          "extractWebSignals": {
            "title": "Extract web quality signals (lite Lighthouse)",
            "type": "boolean",
            "description": "When enabled, the actor extracts lightweight web quality signals from every homepage it already fetches: HTTPS-only, mobile-responsive, page size, favicon, Open Graph tags, structured data. Fills `webSignals` + `webQuality` ('modern'/'dated'/'poor'). Free (uses HTML already in memory). Perfect for web-agency outreach targeting.",
            "default": true
          },
          "autoExtend": {
            "title": "Auto-extend run on timeout shortage (zero-touch UX)",
            "type": "boolean",
            "description": "⭐ Recommended. If your run's timeout is too short for the requested maxResults, the actor automatically starts a fresh run with a sufficient timeout instead of refusing. You never have to adjust the timeout manually. Note for programmatic callers: when this fires, the run you started finishes early and your results live in a SECOND run with a different runId, named in the first run's status message. Follow that pointer rather than reading the first run's empty dataset. Billing is unchanged — PAY_PER_EVENT only charges for leads actually delivered, regardless of which run delivered them. The original run exits cleanly with a pointer to the new run's dataset. Set to false only if you want the preflight to refuse with a detailed error instead.",
            "default": true
          },
          "geoGridTiles": {
            "title": "Geo-grid tiles — bypass Google's 120-result cap",
            "minimum": 1,
            "maximum": 10,
            "type": "integer",
            "description": "🎯 Power feature. Google Maps caps a single search result list at ~120 places. If you need comprehensive coverage of a large city (say all 800+ restaurants in Manhattan), set this to N and the actor splits the search area into an N×N geographic grid, issuing the same query against each tile's map viewport. Tile results are de-duplicated by placeId so you get a single clean dataset. Leave at 1 (default) for small cities or when the 120-cap isn't a concern. Try 3 (→9 tiles) for medium cities, 5 (→25 tiles) for big cities, up to 10 (→100 tiles) for NYC/Tokyo-scale coverage. Only works when your query contains a recognizable location (e.g. 'restaurants in Manhattan', 'dentists near Berlin') — geocoded free via OpenStreetMap/Nominatim. ⚠️ Billing impact: each extra lead still costs one lead at your plan rate ($0.007 Free, $0.004 Platinum/Diamond), and the run-start fee is charged once regardless of tile count — so 5× tiles doesn't mean 5× cost, it means up to 5× unique leads discovered.",
            "default": 1
          },
          "searchStringsArray": {
            "title": "Search terms (compass alias)",
            "type": "array",
            "description": "Alias for \"Search queries\", accepted so an input written for compass/crawler-google-places runs here unchanged. If both are set, \"searchQueries\" wins.",
            "items": {
              "type": "string"
            }
          },
          "maxCrawledPlacesPerSearch": {
            "title": "Max results per search (compass alias)",
            "minimum": 0,
            "type": "integer",
            "description": "Alias for \"Max results\". If both are set, the alias wins: the platform writes schema defaults into every input, so the native field is always present and the explicitly supplied alias is the stronger signal of intent."
          },
          "scrapeContacts": {
            "title": "Extract emails (compass alias)",
            "type": "boolean",
            "description": "Alias for \"Extract emails from websites\". If both are set, the alias wins (see \"Max results\" alias for why)."
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}