{
  "openapi": "3.0.1",
  "info": {
    "title": "Google Maps Email Extractor & Lead Scraper",
    "description": "Google Maps email scraper with built-in MX/SPF/DMARC validation + catch-all detection. 50-70% email hit rate (vs 0-15% English-only). Multilingual crawl (10+ langs: kapcsolat/kontakt/contacto/contatti/...). Lead scoring 0-100, delta mode ($0 dupes). $0.007 per delivered lead + $0.06 run start.",
    "version": "1.4",
    "x-build-id": "Jh0gg69a1sy1icKxn"
  },
  "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: flat $0.007 per delivered lead (all enrichment included) + a $0.015/GB run-start fee ($0.06 on the 4 GB default) that covers browser startup. Example: 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. Apify Proxy is recommended."
          },
          "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 $0.007, 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, \"maxResults\" wins."
          },
          "scrapeContacts": {
            "title": "Extract emails (compass alias)",
            "type": "boolean",
            "description": "Alias for \"Extract emails from websites\". If both are set, \"scrapeEmails\" wins."
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}