{
  "openapi": "3.0.1",
  "info": {
    "title": "Google Maps Scraper — Leads, Emails, Reviews & Local SEO",
    "description": "Turn Google Maps searches into business leads with phones, websites, public emails, social profiles, reviews and owner replies. Choose Fast or Full, explore results on a map and measure local search rankings.",
    "version": "2.0",
    "x-build-id": "DEGWyLy9bcnVit6O4"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/shadowextractor~google-maps-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-shadowextractor-google-maps-scraper",
        "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/shadowextractor~google-maps-scraper/runs": {
      "post": {
        "operationId": "runs-sync-shadowextractor-google-maps-scraper",
        "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/shadowextractor~google-maps-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-shadowextractor-google-maps-scraper",
        "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": {
          "queries": {
            "title": "Businesses, Maps URLs or place IDs",
            "minItems": 1,
            "maxItems": 10000,
            "type": "array",
            "description": "One search phrase, Google Maps search/place URL, place ID, or 0x...:0x... data ID per entry. Use separate entries for different searches. Existing searchStringsArray and startUrls API inputs are also accepted.",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 2000
            }
          },
          "locationQuery": {
            "title": "City or area (optional)",
            "maxLength": 200,
            "type": "string",
            "description": "Optional city, district, address, postal code or country added only to text searches. Leave blank when each search already includes a location."
          },
          "locations": {
            "title": "Multiple cities or neighborhoods (optional)",
            "maxItems": 100,
            "type": "array",
            "description": "Run each text search in every listed location. Overrides locationQuery when populated. Direct Maps URLs and known place IDs are not repeated. maxResults still caps the whole run.",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "mode": {
            "title": "Scraping mode",
            "enum": [
              "fast",
              "full",
              "contacts"
            ],
            "type": "string",
            "description": "Fast collects the place card. Full prioritizes richer public data, deeper website checks and review pagination; it can take longer.",
            "default": "fast"
          },
          "includeContacts": {
            "title": "Find public website emails & socials (Full)",
            "type": "boolean",
            "description": "Read public business website and contact pages in Full mode. The website event applies once per saved business whose crawl read at least one page; no website or wholly failed crawls do not trigger it. Emails include source pages and are not deliverability-verified.",
            "default": true
          },
          "includeReviews": {
            "title": "Collect review text (Full)",
            "type": "boolean",
            "description": "Save public reviews and owner replies in Full mode. Each unique review successfully written to the separate review table is billed once; the attached sample is not billed again.",
            "default": true
          },
          "maxReviews": {
            "title": "Reviews per place",
            "minimum": 0,
            "maximum": 100000,
            "type": "integer",
            "description": "Maximum delivered reviews per business, up to 100,000. Reviews are priced individually; the run budget can stop review pagination earlier. Use 0 to skip review collection.",
            "default": 1000
          },
          "reviewsSort": {
            "title": "Review order",
            "enum": [
              "relevant",
              "newest",
              "highest",
              "lowest"
            ],
            "type": "string",
            "description": "Choose which reviews are collected first in Full mode.",
            "default": "relevant"
          },
          "maxImages": {
            "title": "Photos per place",
            "minimum": 0,
            "maximum": 500,
            "type": "integer",
            "description": "Maximum available place photo URLs retained from Google place responses. Actual availability depends on the source.",
            "default": 100
          },
          "includeEvConnectors": {
            "title": "EV charging connectors (Full)",
            "type": "boolean",
            "description": "Collect published connector types, power and counts for EV stations. HTTP data is used first; the optional browser fallback can still receive a limited Google view.",
            "default": true
          },
          "includePopularTimes": {
            "title": "Popular times and live busyness (Full)",
            "type": "boolean",
            "description": "Collect published day/hour busyness percentages and live busyness when available. These are relative indices, not visitor counts.",
            "default": true
          },
          "maxCrawledPlacesPerSearch": {
            "title": "Maximum places per search",
            "minimum": 1,
            "maximum": 5000,
            "type": "integer",
            "description": "Saved matching unique businesses per search. Filtered places and duplicates do not consume this limit. Pagination is also bounded by maxPagesPerSearch.",
            "default": 50
          },
          "maxResults": {
            "title": "Total businesses per run",
            "minimum": 1,
            "maximum": 100000,
            "type": "integer",
            "description": "Global cap on saved unique businesses across all searches and direct places.",
            "default": 10000
          },
          "maxPagesPerSearch": {
            "title": "Search pages to examine",
            "minimum": 1,
            "maximum": 250,
            "type": "integer",
            "description": "Safety cap on pages fetched for each search, including pages that contain only duplicates or filtered places. If the cap is hit, OUTPUT reports max_pages instead of claiming the source was exhausted.",
            "default": 10
          },
          "categoryFilterWords": {
            "title": "Category contains",
            "maxItems": 50,
            "type": "array",
            "description": "Optional category words. A place is kept when at least one word matches its Google category.",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100,
              "pattern": "\\S"
            },
            "default": []
          },
          "categoryIds": {
            "title": "Canonical Google category IDs",
            "maxItems": 100,
            "type": "array",
            "description": "Examples: restaurant, coffee_shop, dentist. Exact IDs and underscore-delimited subtypes match independent of localized category labels. With no search terms, IDs become search phrases.",
            "items": {
              "type": "string"
            }
          },
          "placeMinimumStars": {
            "title": "Minimum Google rating",
            "minimum": 0,
            "maximum": 5,
            "type": "number",
            "description": "Keep places at or above this rating. Use 0 to disable the filter.",
            "default": 0
          },
          "placeMaximumStars": {
            "title": "Maximum rating",
            "minimum": 0,
            "maximum": 5,
            "type": "number",
            "description": "Keep only places rated at or below this. Pair it with the minimum to target a band, or use it alone to find businesses whose rating needs work."
          },
          "minReviewsCount": {
            "title": "Minimum reviews",
            "minimum": 0,
            "type": "integer",
            "description": "Skip places with fewer reviews than this. A business with three reviews is usually too small to be worth contacting."
          },
          "maxReviewsCount": {
            "title": "Maximum reviews",
            "minimum": 0,
            "type": "integer",
            "description": "Skip places with more reviews than this, which is how you avoid chains and landmarks when you want independent businesses."
          },
          "requirePhone": {
            "title": "Only places with a phone number",
            "type": "boolean",
            "description": "Drop places Google publishes no phone number for. Checked before anything is fetched for them, so they cost nothing.",
            "default": false
          },
          "requireEmail": {
            "title": "Only places with an email address",
            "type": "boolean",
            "description": "Drop places whose website yields no email address. This one can only be judged after the website has been read, so those places are fetched and then discarded; the run summary reports how many.",
            "default": false
          },
          "website": {
            "title": "Website availability",
            "enum": [
              "allPlaces",
              "withWebsite",
              "withoutWebsite"
            ],
            "type": "string",
            "description": "Keep all places, only places with a website, or only places without one.",
            "default": "allPlaces"
          },
          "skipClosedPlaces": {
            "title": "Skip permanently closed places",
            "type": "boolean",
            "description": "Exclude businesses Google marks as permanently closed.",
            "default": false
          },
          "skipTemporarilyClosedPlaces": {
            "title": "Skip temporarily closed places",
            "type": "boolean",
            "description": "Separate from skipClosedPlaces, which preserves its existing permanent-closure behavior.",
            "default": false
          },
          "skipPlacesNotMatchingSearch": {
            "title": "Drop clearly unrelated search results",
            "type": "boolean",
            "description": "Conservative matching for recognized business types using category IDs. Unknown or ambiguous terms remain marked not_judged and are kept.",
            "default": false
          },
          "excludePlaceIds": {
            "title": "Place IDs to skip",
            "type": "array",
            "description": "Place IDs you already have. They are dropped before anything is fetched for them, so re-running a search costs nothing for businesses you have already exported.",
            "items": {
              "type": "string"
            }
          },
          "minPricePerPerson": {
            "title": "Minimum price per person",
            "minimum": 0,
            "maximum": 100000000,
            "type": "integer",
            "description": "Native Google Maps numeric price-per-person filter. Whole amounts in the search area currency, unless priceCurrency is set. Boundaries overlap published price ranges; unknown direct-place prices are excluded."
          },
          "maxPricePerPerson": {
            "title": "Maximum price per person",
            "minimum": 0,
            "maximum": 100000000,
            "type": "integer",
            "description": "Native Google Maps numeric price-per-person filter. Whole amounts in the search area currency, unless priceCurrency is set. Boundaries overlap published price ranges; unknown direct-place prices are excluded."
          },
          "priceCurrency": {
            "title": "Price currency (optional)",
            "pattern": "^[A-Za-z]{3}$",
            "type": "string",
            "description": "Optional three-letter code, for example USD or EUR. Omit to let Google interpret the filter in the search context. This does not convert prices."
          },
          "language": {
            "title": "Result language",
            "pattern": "^[A-Za-z]{2,3}(?:-[A-Za-z]{2})?$",
            "type": "string",
            "description": "Google language code such as en, de, fr or ru.",
            "default": "en"
          },
          "countryCode": {
            "title": "Country code",
            "pattern": "^[A-Za-z]{2}$",
            "type": "string",
            "description": "Two-letter country code such as US, GB, DE or IN.",
            "default": "US"
          },
          "languages": {
            "title": "Additional search languages",
            "maxItems": 6,
            "type": "array",
            "description": "Search the same term and area in each selected language. Saved businesses are deduplicated; the per-search result cap is shared across passes.",
            "items": {
              "type": "string"
            }
          },
          "customGeolocation": {
            "title": "Custom area — radius or GeoJSON",
            "type": "object",
            "description": "Point with [longitude, latitude] and radiusKm, Polygon, MultiPolygon, Feature or FeatureCollection. Polygons support holes. Overrides named location suffixes for text searches."
          },
          "geoStrictMatch": {
            "title": "Keep places inside the custom area",
            "type": "boolean",
            "description": "Requires customGeolocation. Coordinate membership is checked before enrichment and billing; named locations alone do not define an exact boundary.",
            "default": false
          },
          "keepUnverifiedLocations": {
            "title": "Keep places without usable coordinates",
            "type": "boolean",
            "description": "With strict geographic filtering, retain unknown coordinate locations and mark locationUnverified. Confirmed outside points are still excluded.",
            "default": false
          },
          "searchCellSizeKm": {
            "title": "Search cell width (km)",
            "minimum": 0.1,
            "maximum": 100,
            "type": "number",
            "description": "The bounding area is searched in cells of approximately this size. Smaller cells can reveal additional places and require more searches.",
            "default": 5
          },
          "maxSearchCells": {
            "title": "Maximum geographic search cells",
            "minimum": 1,
            "maximum": 1000,
            "type": "integer",
            "description": "A larger plan is rejected before network work rather than silently truncated. Raise the cap or increase cell width for a larger area.",
            "default": 100
          },
          "reviewsStartDate": {
            "title": "Review date — from",
            "type": "string",
            "description": "Inclusive ISO date or timestamp, interpreted as UTC when no timezone is supplied. Undated reviews are excluded when a date filter is active."
          },
          "reviewsEndDate": {
            "title": "Review date — through",
            "type": "string",
            "description": "Inclusive ISO date or timestamp. A date-only value includes that whole UTC day. Filtering does not assume the source obeys its requested sort order."
          },
          "reviewsWithTextOnly": {
            "title": "Keep reviews with written text",
            "type": "boolean",
            "description": "Exclude rating-only reviews. maxReviews counts retained matching reviews; diagnostics report examined and filtered records.",
            "default": false
          },
          "rankGrid": {
            "title": "Local rank grid",
            "type": "boolean",
            "description": "Check the business position for one keyword from multiple nearby coordinates. This is a ranking snapshot, not a guarantee of every customer’s personalized results. Failed points are marked and not charged.",
            "default": false
          },
          "rankGridKeyword": {
            "title": "Rank grid keyword",
            "type": "string",
            "description": "Customer search phrase to measure. Leave blank to use the business category."
          },
          "rankGridSize": {
            "title": "Grid size",
            "minimum": 2,
            "maximum": 9,
            "type": "integer",
            "description": "Points per side. 3 gives 9 searches per business, 5 gives 25, 7 gives 49. Bigger grids draw a finer map and cost proportionally more.",
            "default": 3
          },
          "rankGridRadiusKm": {
            "title": "Grid radius (km)",
            "minimum": 0.1,
            "maximum": 50,
            "type": "number",
            "description": "How far from the business the grid reaches. Two kilometres suits a city neighbourhood; widen it for a business whose customers drive to it.",
            "default": 2
          },
          "rankGridMaxResults": {
            "title": "How deep to look at each point",
            "minimum": 3,
            "maximum": 60,
            "type": "integer",
            "description": "Maximum positions checked at each grid point, including additional result pages when needed. Each point reports resultsChecked.",
            "default": 20
          },
          "includeResultsMap": {
            "title": "Create a results map and GeoJSON",
            "type": "boolean",
            "description": "Write the interactive MAP record and complete RESULTS.geojson from saved businesses with valid coordinates. No separate Actor event charge.",
            "default": true
          },
          "mapMaxPlaces": {
            "title": "Map preview places",
            "minimum": 1,
            "maximum": 20000,
            "type": "integer",
            "description": "Maximum markers in the interactive preview. GeoJSON retains all saved places with coordinates; the map legend reports omitted markers.",
            "default": 5000
          },
          "includeRawPlace": {
            "title": "Include raw place payload",
            "type": "boolean",
            "description": "Attach the full decoded Google Maps place array (rawPlace) to every record — every last source field, before mapping. Large output; for power users.",
            "default": false
          },
          "maxConcurrency": {
            "title": "Businesses processed in parallel",
            "minimum": 1,
            "maximum": 24,
            "type": "integer",
            "description": "Businesses processed in parallel. The Full default favors coverage and fewer simultaneous website requests.",
            "default": 6
          },
          "maxContactPages": {
            "title": "Website pages per business",
            "minimum": 1,
            "maximum": 100,
            "type": "integer",
            "description": "Maximum distinct public pages visited for contacts. Failed pages are retried separately. Discovery follows contact, about, team, support and legal links.",
            "default": 10
          },
          "contactRequestTimeoutSeconds": {
            "title": "Website request timeout",
            "minimum": 5,
            "maximum": 120,
            "type": "integer",
            "description": "Seconds allowed for each website request. A slow request may be retried; this is not a limit for the whole business.",
            "default": 30
          },
          "contactMaxRetries": {
            "title": "Retries per failed website page",
            "minimum": 0,
            "maximum": 5,
            "type": "integer",
            "description": "Retry transient failures after checking other discovered pages. Permanent missing pages are recorded without repeated requests.",
            "default": 2
          },
          "contactDeadlineSeconds": {
            "title": "Overall website deadline (0 = no cutoff)",
            "minimum": 0,
            "maximum": 3600,
            "type": "integer",
            "description": "Optional overall seconds per business website. Default 0 removes the former short stage cutoff; per-request limits and the run timeout still apply.",
            "default": 0
          },
          "reviewDeadlineSeconds": {
            "title": "Overall review deadline (0 = no cutoff)",
            "minimum": 0,
            "maximum": 3600,
            "type": "integer",
            "description": "Optional seconds for review pagination. Default 0 allows pagination to continue to maxReviews or source exhaustion.",
            "default": 0
          },
          "browserFallback": {
            "title": "Additional EV / popular-times lookup ($0.025 per attempt)",
            "type": "boolean",
            "description": "Optional additional lookup for missing EV connectors or popular-times fields in Full. Off by default. Costs $0.025 per completed lookup, including limited-view or unavailable outcomes; ordinary source-provided values have no lookup fee.",
            "default": false
          },
          "browserTimeoutSeconds": {
            "title": "Browser request timeout",
            "minimum": 10,
            "maximum": 180,
            "type": "integer",
            "description": "Seconds per browser navigation or expected-page wait. Does not impose a batch completion target.",
            "default": 60
          },
          "browserRetries": {
            "title": "Browser retries after a source error",
            "minimum": 0,
            "maximum": 3,
            "type": "integer",
            "description": "Retry network/runtime failures. A Google limited_view response is recorded directly and is not treated as an empty successful extraction.",
            "default": 1
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Use the default connection settings or your existing Apify proxy configuration. The legacy proxy API field is also accepted.",
            "default": {
              "useApifyProxy": true,
              "apifyProxyGroups": [
                "RESIDENTIAL"
              ],
              "apifyProxyCountry": "US"
            }
          }
        }
      },
      "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
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "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
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}