Use Google Maps Popular Times & Live Busyness Scraper with Python
Scrape Google Maps Popular Times: hourly busy hours, live busyness vs usual, open/closed status, newest reviews with closure mentions and run-to-run monitoring signals. Place URLs or Place IDs, any country, no API key or login.
1. Choose the data you need
Review the published README for supported collection modes, examples, and limits. The recipe below uses the current published input definition.
2. Prepare a source-based input
This JSON contains published prefills and required-field defaults. Review every value for your task before running it; it is not a promise of successful collection.
{
"includeFailedPlaces": false,
"includeLatestReviews": false,
"language": "en",
"latestReviewsCount": 10,
"lowActivityRatio": 0.25,
"maxAttemptsPerPlace": 8,
"maxConcurrency": 3,
"minUsualBusyness": 30,
"placeTimeoutSecs": 240,
"placeUrls": [
"https://www.google.com/maps/place/McDonald%27s/@40.7577297,-73.9853627,17z/data=!3m1!4b1!4m6!3m5!1s0x89c2597777397641:0x4387a82ee10d3e3b!8m2!3d40.7577297!4d-73.9853627!16s%2Fg%2F11fld77pvs"
]
}
Download input.example.json and save your reviewed copy as input.json.
| Field | Type | Required | Description |
|---|---|---|---|
placeUrls | array | optional | Google Maps place URLs — copy the full URL from the address bar while viewing a place (short maps.app.goo.gl links also work). Full place URLs are the most reliable; for places with the same name nearby, prefer Place IDs. |
placeIds | array | optional | Google Place IDs beginning with ChIJ (for example ChIJaXQRs6lZwokRY6EFpJnhNNE). Recommended for monitoring fixed lists: each ID always points to the same place. IDs that do not match a place are reported as unavailable, never guessed. |
language | string | optional | Language of the Google Maps pages; text fields such as the live label and open status are returned in this language. |
maxConcurrency | integer | optional | How many places are scraped at the same time. Higher values finish large lists faster and need more run memory (about 1 GB per parallel place; the actor lowers this automatically if the run has less memory). |
maxAttemptsPerPlace | integer | optional | Maximum number of fresh attempts for one place before it is reported as unavailable. Lower values cap time and cost for hard-to-reach places; higher values maximise coverage. |
placeTimeoutSecs | integer | optional | Hard time limit for one place across all of its attempts. |
includeFailedPlaces | boolean | optional | Also output one record per place for which no place data could be resolved, with the reason and number of attempts. A limited view that still resolves to a place is a normal basic record, not a failure. Recommended for monitoring lists so every input appears in the results. |
includeLatestReviews | boolean | optional | Also return each place's newest Google reviews (exact date, rating, text) and flag reviews that mention the place closing, such as "final weekend", "it was closed" or "permanently closed". Diners often report a closure in reviews before Google updates the listing. |
latestReviewsCount | integer | optional | How many of the newest reviews to return and check for closure mentions (used when newest reviews are included). |
monitoringKey | string | optional | Name for a monitoring list, for example "vancouver-restaurants". When set, each place's readings are kept in your account between runs and every record gets a monitoring summary: readings so far, low-activity and open-without-live-data streaks, recent vs earlier live/usual ratio, listing status changes, Popular Times removed or changed, new closure mentions. Use the same key on every scheduled run. |
lowActivityRatio | number | optional | A live reading counts as low when it is at most this share of the usual level (0.25 = a quarter of usual). Used for the low-activity streak in the monitoring summary. |
minUsualBusyness | integer | optional | Readings count toward the monitoring streaks and medians only when Google's usual level for that hour is at least this value, so quiet hours (where a low reading means little) are ignored. |
proxyConfiguration | object | optional | Places are fetched directly first. If omitted, the last two attempts for a hard-to-reach place use Apify residential proxies (United States, then Canada). Set 'No proxy' to never use a proxy, or choose your own proxy to use it for those fallback attempts. |
3. Start an Actor run
Set APIFY_TOKEN in your environment. Python 3.10 or newer is sufficient; this recipe uses no third-party packages.
Execution may incur charges. Review current pricing on Apify. The request asks for a 120-second timeout and a charge limit; these settings are subject to Apify’s pricing and do not guarantee an all-inclusive spending cap.
import json
import os
import urllib.request
# Save the schema-derived example as input.json; review and edit it first.
with open("input.json", encoding="utf-8") as stream:
actor_input = json.load(stream)
token = os.environ["APIFY_TOKEN"]
request = urllib.request.Request(
"https://api.apify.com/v2/acts/DyqwW70LMciEDk5Aq/runs?timeout=120&maxTotalChargeUsd=0.50",
data=json.dumps(actor_input).encode("utf-8"),
headers={"Authorization": "Bearer " + token, "Content-Type": "application/json"},
method="POST",
)
# This starts a potentially billable run. Do not automatically retry this POST.
with urllib.request.urlopen(request, timeout=40) as response:
run = json.load(response)["data"]
print("Run ID:", run["id"])
print("Status:", run["status"])
# Inspect and download results in Apify Console once the run succeeds.
4. Inspect the actual results
Open the run in Apify Console and wait for a successful completion. Use the published output schema to locate results and the dataset schema to understand declared views. Missing or optional record fields must not be treated as guaranteed values.
One record per Google Maps place: place identity and listing details, open/closed status, coordinates and local time, hourly Popular Times and live busyness when Google serves them, the newest reviews with closure mentions, run-to-run monitoring signals and, when enabled, records for places that could not be retrieved. Google often serves signed-out sessions a limited view without Popular Times; those places are returned as basic records with dataStatus=limited_view, popularTimesAvailable=false and limitedViewReason=google_signin_required, never with invented busyness.
Questions before you run
Which inputs are required?
No top-level fields are marked required in the published schema. Conditional requirements can still apply; check the README.
What does this guide verify?
The fields, prefills, and schema links are rendered from the published build. This is a usage recipe, not a paid live extraction test. Source availability and collection results can vary.
What if the run request times out?
Check Apify Console before retrying. The first request may already have created a run. Do not automatically repeat a run-creation POST.
Generated from source build duuYoKAJjgqw8gZcV and its README and schemas. Source changes regenerate this guide; no third-party editorial claims are inferred.