{
  "data": {
    "id": "duuYoKAJjgqw8gZcV",
    "actId": "DyqwW70LMciEDk5Aq",
    "userId": "IYgBDiXtHOijAaUel",
    "startedAt": "2026-10-24T15:53:48.995Z",
    "finishedAt": "2026-10-24T15:54:20.493Z",
    "status": "SUCCEEDED",
    "meta": {
      "origin": "CLI"
    },
    "stats": {
      "durationMillis": 31405,
      "runTimeSecs": 31.405,
      "computeUnits": 0.03489444444444444,
      "imageSizeBytes": 3108545536
    },
    "options": {
      "useCache": true,
      "betaPackages": false,
      "memoryMbytes": 4096,
      "diskMbytes": 8192
    },
    "createdByOrganizationMemberUserId": "QYo53EZkJk0prePWY",
    "exitCode": 0,
    "inputSchema": "{\n  \"title\": \"Google Maps Place Data & Popular Times (When Available)\",\n  \"description\": \"Scrape Google Maps place data (name, address, category, phone, website, rating, open status, coordinates, local time) and, when Google serves it to an anonymous page, Popular Times (hourly busy hours for every day) with live busyness vs the usual level. Google often serves signed-out sessions a limited view without Popular Times; those places are still returned as basic records (dataStatus=limited_view). No API key or login needed.\",\n  \"type\": \"object\",\n  \"schemaVersion\": 1,\n  \"properties\": {\n    \"placeUrls\": {\n      \"title\": \"Place URLs\",\n      \"type\": \"array\",\n      \"description\": \"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.\",\n      \"editor\": \"stringList\",\n      \"prefill\": [\n        \"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\"\n      ],\n      \"items\": {\n        \"type\": \"string\"\n      },\n      \"minItems\": 1,\n      \"maxItems\": 100000\n    },\n    \"placeIds\": {\n      \"title\": \"Google Place IDs\",\n      \"type\": \"array\",\n      \"description\": \"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.\",\n      \"editor\": \"stringList\",\n      \"items\": {\n        \"type\": \"string\"\n      },\n      \"minItems\": 1,\n      \"maxItems\": 100000\n    },\n    \"language\": {\n      \"title\": \"Google Maps language\",\n      \"type\": \"string\",\n      \"description\": \"Language of the Google Maps pages; text fields such as the live label and open status are returned in this language.\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"en\",\n        \"es\",\n        \"fr\",\n        \"de\",\n        \"it\",\n        \"pt\",\n        \"ja\",\n        \"ko\",\n        \"zh\",\n        \"ar\",\n        \"ru\"\n      ],\n      \"enumTitles\": [\n        \"English\",\n        \"Spanish\",\n        \"French\",\n        \"German\",\n        \"Italian\",\n        \"Portuguese\",\n        \"Japanese\",\n        \"Korean\",\n        \"Chinese\",\n        \"Arabic\",\n        \"Russian\"\n      ],\n      \"default\": \"en\",\n      \"prefill\": \"en\"\n    },\n    \"maxConcurrency\": {\n      \"title\": \"Places scraped in parallel\",\n      \"type\": \"integer\",\n      \"description\": \"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).\",\n      \"default\": 3,\n      \"prefill\": 3,\n      \"minimum\": 1,\n      \"maximum\": 8,\n      \"sectionCaption\": \"Speed, retries and failures\",\n      \"sectionDescription\": \"Control throughput and how much effort is spent on places Google does not return on the first try.\"\n    },\n    \"maxAttemptsPerPlace\": {\n      \"title\": \"Max attempts per place\",\n      \"type\": \"integer\",\n      \"description\": \"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.\",\n      \"default\": 8,\n      \"prefill\": 8,\n      \"minimum\": 1,\n      \"maximum\": 12\n    },\n    \"placeTimeoutSecs\": {\n      \"title\": \"Time limit per place\",\n      \"type\": \"integer\",\n      \"unit\": \"seconds\",\n      \"description\": \"Hard time limit for one place across all of its attempts.\",\n      \"default\": 240,\n      \"prefill\": 240,\n      \"minimum\": 30,\n      \"maximum\": 600\n    },\n    \"includeFailedPlaces\": {\n      \"title\": \"Include unavailable places in the output\",\n      \"type\": \"boolean\",\n      \"description\": \"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.\",\n      \"default\": false,\n      \"prefill\": false\n    },\n    \"includeLatestReviews\": {\n      \"title\": \"Include newest reviews and closure mentions\",\n      \"type\": \"boolean\",\n      \"description\": \"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.\",\n      \"default\": false,\n      \"prefill\": false,\n      \"sectionCaption\": \"Closure monitoring\",\n      \"sectionDescription\": \"Extra signals for tracking places that may have closed or are losing customers. Run the actor on a schedule with the same monitoring key to compare every reading with earlier ones.\"\n    },\n    \"latestReviewsCount\": {\n      \"title\": \"Newest reviews per place\",\n      \"type\": \"integer\",\n      \"description\": \"How many of the newest reviews to return and check for closure mentions (used when newest reviews are included).\",\n      \"default\": 10,\n      \"prefill\": 10,\n      \"minimum\": 1,\n      \"maximum\": 60\n    },\n    \"monitoringKey\": {\n      \"title\": \"Monitoring key\",\n      \"type\": \"string\",\n      \"description\": \"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.\",\n      \"editor\": \"textfield\"\n    },\n    \"lowActivityRatio\": {\n      \"title\": \"Low activity threshold (live / usual)\",\n      \"type\": \"number\",\n      \"description\": \"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.\",\n      \"default\": 0.25,\n      \"prefill\": 0.25,\n      \"minimum\": 0.05,\n      \"maximum\": 1\n    },\n    \"minUsualBusyness\": {\n      \"title\": \"Busy-hour threshold (usual busyness %)\",\n      \"type\": \"integer\",\n      \"description\": \"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.\",\n      \"default\": 30,\n      \"prefill\": 30,\n      \"minimum\": 5,\n      \"maximum\": 100\n    },\n    \"proxyConfiguration\": {\n      \"title\": \"Proxy configuration\",\n      \"type\": \"object\",\n      \"description\": \"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.\",\n      \"editor\": \"proxy\",\n      \"sectionCaption\": \"Proxy fallback\",\n      \"sectionDescription\": \"Proxies are only used as a last resort for places that direct access could not retrieve.\"\n    }\n  },\n  \"required\": []\n}",
    "readme": "# Google Maps Place Data & Popular Times (When Available)\r\n\r\nGet reliable **Google Maps place data** — name, address, category, phone, website, rating, open/closed status, coordinates and local time — and, **when Google serves it to an anonymous page**, the hourly **Popular Times** chart and **live busyness** reading. Google often serves signed-out sessions a **limited view** that omits Popular Times; the actor then returns an honest basic record (`dataStatus: \"limited_view\"`, `popularTimesAvailable: false`) instead of failing or inventing busyness. Works with Google Maps place URLs, search links or Google Place IDs, in any country, with no API key and no login.\r\n\r\n## At a glance\r\n\r\n| | |\r\n|---|---|\r\n| **What you get** | Basic place data for every resolved place: stable place ID, name, address, coordinates, local time, category, phone, website, rating, review count, open-now line and listing status. When Google serves a full render: hourly busyness (0–100%) for each day, live busyness vs the usual level, and Google's live label. Optional newest reviews with closure mentions and a run-to-run monitoring summary |\r\n| **Limited view** | Google's signed-out limited view omits Popular Times. Those places are still emitted as normal basic records with `dataStatus: \"limited_view\"`, `popularTimesAvailable: false`, `limitedViewReason: \"google_signin_required\"` and `popularTimesHasData: false`; no busyness is estimated |\r\n| **Input** | Google Maps place URLs, search links (`/maps/search/?api=1&query=…`), short links or Google Place IDs (`ChIJ…`) |\r\n| **Output** | JSON, CSV, Excel, XML or HTML via the Apify dataset; ready-made \"Place data & Popular Times\", \"Live monitoring\" and \"Closure signals\" table views |\r\n| **Coverage** | Any country Google Maps serves; Google Maps UI in 11 languages. Popular Times depends on Google's anonymous rendering and is not guaranteed |\r\n| **Requirements** | No Google API key, no Google account, no cookies |\r\n| **Scale** | Up to 8 places in parallel; about 370 places per hour at 6 in parallel (measured October 2026) |\r\n| **Automation** | Run from the Apify Console, the API, Python/JavaScript clients, schedules, webhooks and integrations |\r\n\r\n## What is Google Maps Popular Times?\r\n\r\n**Popular Times** is the bar chart Google Maps shows on a place's page to indicate how busy it usually is at each hour of each day. Google builds it from aggregated, anonymised location data and expresses each hour as a percentage of that place's typical peak (100 = as busy as it gets). While a place is open, Google often adds a **live** reading that compares how busy it is right now with how busy it usually is at this hour.\r\n\r\nGoogle withholds the chart from the **limited view** it serves to signed-out sessions (the same view that removes reviews, photos, price range, nearby places and Q&A). This actor does not bypass that gate: it returns the place's basic data with an explicit `limited_view` status, and only emits Popular Times when Google actually renders them.\r\n\r\n## What does this scraper extract?\r\n\r\n- **Basic place data for every resolved place** — name, stable identity, address, coordinates, local time, category, phone, website, rating, review count and open/closed status, even when Google serves its limited view\r\n- **Per-day hourly busyness** (0–100%) for every day Google charts — a full week in one request, when a full render is available\r\n- **Live vs usual** (when Google publishes them) — Google's live percentage (`currentBusyness`) next to its usual percentage for the same hour (`usualBusyness`), plus the chart day and hour the reading belongs to\r\n- **Live label** (when Google publishes it) — Google's wording such as *\"Not too busy\"*, *\"Less busy than usual\"* or *\"As busy as it gets\"*\r\n- **Open / closed status** — whether the listing is operating, temporarily closed or permanently closed, plus Google's open-now line (e.g. *\"Open · Closes 11 PM\"*)\r\n- **Typical time spent** when Google shows it (e.g. *\"People typically spend 30 min to 1 hour here\"*)\r\n- **Business name and a stable place identity** — `featureId` / `cid` (and the canonical `ChIJ…` `placeId` when Google shows it) for every place, including places given as search links or short links, so readings from different runs can be joined\r\n- **Listing details** — category, address, latitude/longitude, phone, website, rating and review count\r\n- **Local time of each reading** — the place's time zone, the local date and hour of the scrape, and Google's usual value for that hour from the chart (also when there is no live reading)\r\n- **Live vs usual, ready to compare** — `liveToUsualRatio` and `liveMinusUsual`, plus `liveReadingStatus` explaining why a live reading is missing (closed now, open but no live data, permanently closed…)\r\n- **Newest reviews and closure mentions** (optional) — the newest Google reviews with exact dates, flagged when they say the place is closing or closed (\"final weekend\", \"it was closed\", \"permanently closed\", in 11 languages)\r\n- **Run-to-run monitoring** (optional) — with a monitoring key, each record compares the reading with the place's earlier readings: low-activity streaks, recent vs earlier live/usual ratio, listing status changes, Popular Times removed or changed, review-count change and new closure mentions. Limited-view readings are stored as basic readings and are not reported as a removed chart\r\n- **Every input accounted for** — each place is returned, or (when enabled) reported as an unavailable-place record with the reason; inputs that turn out to be the same place as an earlier input are returned once, and every outcome (including such duplicates) is counted in a run summary\r\n\r\n## Use cases\r\n\r\n- **Place enrichment and lead lists** — get name, address, category, phone, website, rating and open status for a list of Google Maps places, regardless of whether Popular Times render\r\n- **Foot-traffic monitoring** — when Google serves Popular Times, track live busyness against the usual level across a fixed list of restaurants or stores\r\n- **Closure detection and early warning** — find restaurants that have stopped operating while Google still lists them as open: closure mentions in the newest reviews, live readings that stay far below usual or are missing during listed opening hours, Popular Times that disappear, and listings that turn \"Temporarily closed\" / \"Permanently closed\"\r\n- **Site selection and competitor research** — compare busy hours of competing locations when the chart is available\r\n- **Staffing and operations** — plan shifts, deliveries and field visits around quiet and peak hours\r\n- **Travel and \"when to go\" apps** — recommend the best time to visit restaurants and attractions\r\n- **Research and dashboards** — build time series of busyness by city, category or chain\r\n\r\n## How to scrape Google Maps place data and Popular Times\r\n\r\n1. **Collect your places** — copy place URLs from Google Maps or use Google Place IDs (`ChIJ…`).\r\n2. **Paste them** into *Place URLs* or *Google Place IDs* and pick the Google Maps language.\r\n3. **Set speed and retries** (optional) — places in parallel, attempts per place, time limit per place, and whether to output unavailable places.\r\n4. **Turn on closure monitoring** (optional) — include the newest reviews and set a monitoring key.\r\n5. **Run** and download the results as JSON, CSV or Excel, or open the *Live monitoring* or *Closure signals* view. Use a schedule with the same monitoring key to repeat the list and build a time series.\r\n\r\n## Input\r\n\r\n| Field | Type | Default | Description |\r\n|---|---|---|---|\r\n| `placeUrls` | Array of strings | – | Google Maps place URLs; short links, copied punctuation and tracking parameters are normalized. One of `placeUrls`/`placeIds` is required |\r\n| `placeIds` | Array of strings | – | Canonical Google Place IDs beginning with `ChIJ`. One of `placeUrls`/`placeIds` is required |\r\n| `language` | String | `en` | Google Maps language for labels and parsing: `en`, `es`, `fr`, `de`, `it`, `pt`, `ja`, `ko`, `zh`, `ar`, `ru` |\r\n| `maxConcurrency` | Integer | 3 | Places scraped at the same time (1–8). Needs about 1 GB of run memory per parallel place; lowered automatically if the run has less memory |\r\n| `maxAttemptsPerPlace` | Integer | 8 | Maximum attempts for one place before it is reported as unavailable (1–12) |\r\n| `placeTimeoutSecs` | Integer | 240 | Time limit for one place across all of its attempts, in seconds (30–600) |\r\n| `includeFailedPlaces` | Boolean | `false` | Also output one record per place that could not be retrieved, with the reason |\r\n| `includeLatestReviews` | Boolean | `false` | Also return each place's newest reviews and flag closure mentions |\r\n| `latestReviewsCount` | Integer | 10 | Newest reviews per place (1–60) |\r\n| `monitoringKey` | String | – | Name of a monitoring list; readings are kept in your account between runs and each record gets a `monitoring` summary. Use the same key on every scheduled run |\r\n| `lowActivityRatio` | Number | 0.25 | A live reading counts as low when live ÷ usual is at most this value (0.05–1) |\r\n| `minUsualBusyness` | Integer | 30 | Busy-hour threshold: readings count toward the monitoring streaks and medians only when Google's usual level for that hour is at least this value (5–100) |\r\n| `proxyConfiguration` | Object | – | 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). Choose \"No proxy\" to never use a proxy, or your own proxy for those fallback attempts |\r\n\r\n### Input examples\r\n\r\n**One place by URL**\r\n\r\n```json\r\n{\r\n  \"placeUrls\": [\r\n    \"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\"\r\n  ]\r\n}\r\n```\r\n\r\n**Places by Google Place ID**\r\n\r\n```json\r\n{\r\n  \"placeIds\": [\"ChIJaXQRs6lZwokRY6EFpJnhNNE\", \"ChIJabtoT7hlwokRLECK0SW3_8I\"]\r\n}\r\n```\r\n\r\n**Live monitoring list (large, recurring)** — run with 8 GB of memory:\r\n\r\n```json\r\n{\r\n  \"placeIds\": [\"ChIJaXQRs6lZwokRY6EFpJnhNNE\", \"ChIJabtoT7hlwokRLECK0SW3_8I\"],\r\n  \"maxConcurrency\": 6,\r\n  \"maxAttemptsPerPlace\": 6,\r\n  \"includeFailedPlaces\": true\r\n}\r\n```\r\n\r\n**Closure monitoring (scheduled several times a week)**\r\n\r\n```json\r\n{\r\n  \"placeIds\": [\"ChIJaXQRs6lZwokRY6EFpJnhNNE\", \"ChIJabtoT7hlwokRLECK0SW3_8I\"],\r\n  \"includeLatestReviews\": true,\r\n  \"latestReviewsCount\": 10,\r\n  \"monitoringKey\": \"vancouver-restaurants\",\r\n  \"includeFailedPlaces\": true\r\n}\r\n```\r\n\r\n**Localized labels**\r\n\r\n```json\r\n{\r\n  \"placeIds\": [\"ChIJaXQRs6lZwokRY6EFpJnhNNE\"],\r\n  \"language\": \"es\"\r\n}\r\n```\r\n\r\n## Output\r\n\r\nOne record per place. A real record for an open place with a live reading (with `includeLatestReviews`; chart and review lists shortened):\r\n\r\n```json\r\n{\r\n  \"recordType\": \"popularTimes\",\r\n  \"businessName\": \"Café de Flore\",\r\n  \"featureId\": \"0x47e671d781fb9dab:0x18bba6dd45e173ff\",\r\n  \"cid\": \"1782201546845549567\",\r\n  \"googleMapsUrl\": \"https://www.google.com/maps?cid=1782201546845549567\",\r\n  \"placeUrl\": \"https://www.google.com/maps/search/?api=1&query=Cafe+de+Flore+Paris\",\r\n  \"category\": \"Coffee shop\",\r\n  \"address\": \"172 Bd Saint-Germain, 75006 Paris, France\",\r\n  \"latitude\": 48.8541588,\r\n  \"longitude\": 2.3326046,\r\n  \"timezone\": \"Europe/Paris\",\r\n  \"phone\": \"+33145485526\",\r\n  \"website\": \"https://cafedeflore.fr/\",\r\n  \"rating\": 3.9,\r\n  \"reviewCount\": 14535,\r\n  \"businessStatus\": \"OPERATIONAL\",\r\n  \"openStatusText\": \"Open · Closes 1:30 AM\",\r\n  \"isOpenNow\": true,\r\n  \"liveReadingStatus\": \"live\",\r\n  \"currentBusyness\": 18,\r\n  \"usualBusyness\": 21,\r\n  \"liveToUsualRatio\": 0.86,\r\n  \"liveMinusUsual\": -3,\r\n  \"currentBusynessLevel\": \"Not busy\",\r\n  \"currentBusynessText\": \"Currently 18% busy, usually 21% busy.\",\r\n  \"currentBusynessDay\": \"friday\",\r\n  \"currentBusynessHour\": 8,\r\n  \"observedAtLocal\": \"2026-10-09T08:06:10+02:00\",\r\n  \"observedLocalDay\": \"friday\",\r\n  \"observedLocalHour\": 8,\r\n  \"usualBusynessAtObservedHour\": 21,\r\n  \"popularTimesHasData\": true,\r\n  \"popularTimesAvailable\": true,\r\n  \"dataStatus\": \"full\",\r\n  \"popularTimesSignature\": \"fe878c8c86fc16e5\",\r\n  \"popularTimes\": {\r\n    \"friday\": [\r\n      {\r\n        \"hour\": 6,\r\n        \"busyness\": 0\r\n      },\r\n      {\r\n        \"hour\": 7,\r\n        \"busyness\": 13\r\n      },\r\n      {\r\n        \"hour\": 8,\r\n        \"busyness\": 21\r\n      },\r\n      {\r\n        \"hour\": 9,\r\n        \"busyness\": 31\r\n      },\r\n      {\r\n        \"hour\": 10,\r\n        \"busyness\": 40\r\n      },\r\n      \"...\"\r\n    ],\r\n    \"saturday\": [\r\n      \"...\"\r\n    ]\r\n  },\r\n  \"closureMentionCount\": 0,\r\n  \"latestReviewAt\": \"2026-10-09T03:58:59+00:00\",\r\n  \"daysSinceLatestReview\": 0,\r\n  \"latestReviews\": [\r\n    {\r\n      \"publishedAt\": \"2026-10-08T22:56:12+00:00\",\r\n      \"publishedAtText\": \"7 hours ago\",\r\n      \"rating\": 5,\r\n      \"text\": \"Ironic place with very good service and food.\",\r\n      \"originalText\": \"Lugar irónico con muy buen servicio y comida.\"\r\n    },\r\n    \"...\"\r\n  ],\r\n  \"sourceUrl\": \"https://www.google.com/maps/search/?api=1&query=Cafe+de+Flore+Paris\",\r\n  \"scrapedAt\": \"2026-10-09T06:06:09.536970+00:00\"\r\n}\r\n```\r\n\r\nFields Google does not show for a place are omitted — no `null` values appear in the dataset.\r\n\r\n### Limited view (Google sign-in required)\r\n\r\nWhen Google serves its anonymous limited view, the place is still returned as a normal basic record. Only fields Google actually rendered are included; Popular Times are absent rather than estimated:\r\n\r\n```json\r\n{\r\n  \"recordType\": \"popularTimes\",\r\n  \"businessName\": \"McDonald's\",\r\n  \"featureId\": \"0x89c2597777397641:0x4387a82ee10d3e3b\",\r\n  \"placeUrl\": \"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\",\r\n  \"category\": \"Fast food restaurant\",\r\n  \"address\": \"1560 Broadway, New York, NY 10036, United States\",\r\n  \"latitude\": 40.7577297,\r\n  \"longitude\": -73.9853627,\r\n  \"timezone\": \"America/New_York\",\r\n  \"phone\": \"+1 212-555-0100\",\r\n  \"website\": \"https://www.mcdonalds.com/us/en-us.html\",\r\n  \"rating\": 4.2,\r\n  \"reviewCount\": 34567,\r\n  \"businessStatus\": \"OPERATIONAL\",\r\n  \"openStatusText\": \"Open · Closes 11 PM\",\r\n  \"isOpenNow\": true,\r\n  \"observedAtLocal\": \"2026-10-24T09:15:00-04:00\",\r\n  \"observedLocalDay\": \"saturday\",\r\n  \"observedLocalHour\": 9,\r\n  \"popularTimesHasData\": false,\r\n  \"popularTimesAvailable\": false,\r\n  \"dataStatus\": \"limited_view\",\r\n  \"limitedViewReason\": \"google_signin_required\",\r\n  \"liveReadingStatus\": \"limitedView\",\r\n  \"sourceUrl\": \"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\",\r\n  \"scrapedAt\": \"2026-10-24T13:15:00+00:00\"\r\n}\r\n```\r\n\r\n`dataStatus` tells you which path produced the record:\r\n\r\n| `dataStatus` | Meaning |\r\n|---|---|\r\n| `full` | Google rendered Popular Times; `popularTimesAvailable` is `true` |\r\n| `no_popular_times` | A full render showed no chart for this place; `popularTimesAvailable` is `false` |\r\n| `limited_view` | Google served its signed-out limited view; basic place data is returned, Popular Times are withheld, and `limitedViewReason` explains why |\r\n\r\n### Unavailable places\r\n\r\nA limited view that still resolves to a place is **not** an unavailable place: it is emitted as a normal basic record (see above). With `includeFailedPlaces` enabled, only places for which **no place data could be resolved** produce a `failed` record like this. It carries the Place ID or feature ID from your input when the input contains one, and has no `attempts` when the place was never started:\r\n\r\n```json\r\n{\r\n  \"recordType\": \"failed\",\r\n  \"placeId\": \"ChIJaXQRs6lZwokRY6EFpJnhNNE\",\r\n  \"placeUrl\": \"https://www.google.com/maps/search/?api=1&query=ChIJaXQRs6lZwokRY6EFpJnhNNE&query_place_id=ChIJaXQRs6lZwokRY6EFpJnhNNE\",\r\n  \"failureReason\": \"notResolved\",\r\n  \"attempts\": 2,\r\n  \"scrapedAt\": \"2026-10-07T13:25:40+00:00\"\r\n}\r\n```\r\n\r\n| `failureReason` | Meaning |\r\n|---|---|\r\n| `timeout` | The time limit was reached |\r\n| `network` | The page could not be loaded |\r\n| `unconfirmedEmpty` | The place showed no popular times once, but repeated attempts could not confirm it |\r\n| `notResolved` | The input did not lead to a single matching Google Maps place, so no place data could be returned |\r\n| `notStarted` | The run's time limit was reached before this place could be started — raise the run timeout or split the list |\r\n| `error` | An unexpected error occurred |\r\n\r\n### Output fields\r\n\r\n| Field | Description |\r\n|---|---|\r\n| `recordType` | `popularTimes` for a place record (full or basic), `failed` for an input with no place data |\r\n| `businessName` | Place name as shown on Google Maps |\r\n| `placeId` / `featureId` | Canonical `ChIJ…` Place ID or legacy `0x…:0x…` token (see below) |\r\n| `cid` / `googleMapsUrl` | Google's numeric place ID and a stable link to the place |\r\n| `category`, `address`, `phone`, `website` | Listing details as shown on Google Maps (omitted when the limited view does not render them) |\r\n| `latitude` / `longitude` | The place's pin (or, where Google shows no pin, as in South Korea, the centre of the place's Plus Code) |\r\n| `rating` / `reviewCount` | Star rating and number of reviews, when Google shows them |\r\n| `placeUrl` / `sourceUrl` | The input URL, normalized |\r\n| `popularTimesHasData` | Whether Google rendered a Popular Times chart for this record |\r\n| `popularTimesAvailable` | Whether an accepted, complete-or-place-appropriate chart is present |\r\n| `dataStatus` | `full`, `no_popular_times` or `limited_view` |\r\n| `limitedViewReason` | On a limited view: `google_signin_required` |\r\n| `popularTimes` | Hourly busyness per day: `{day: [{hour, busyness}]}`; absent on a limited view |\r\n| `currentBusyness` | Google's live reading at the moment of the scrape, exactly as displayed (0–100) |\r\n| `usualBusyness` | Google's usual level for the same hour, as displayed beside the live reading |\r\n| `currentBusynessLevel` | Google's live label, e.g. \"Not too busy\", \"Less busy than usual\", \"As busy as it gets\" |\r\n| `currentBusynessDay` / `currentBusynessHour` | The chart day and hour the live reading belongs to (the place's local time) |\r\n| `currentBusynessText` | Google's full live text, e.g. \"Currently 52% busy, usually 34% busy.\" |\r\n| `liveToUsualRatio` / `liveMinusUsual` | Live ÷ usual (e.g. 0.08) and live − usual in points (e.g. −22), when Google shows both |\r\n| `liveReadingStatus` | `live`, `limitedView` (Google withheld the module), `closedNow` (outside listed hours), `openNoLiveData` (listing says open, no live reading), `noPopularTimes`, `temporarilyClosed`, `permanentlyClosed` or `noLiveData` |\r\n| `timezone`, `observedAtLocal`, `observedLocalDay`, `observedLocalHour` | The place's time zone and the local time of the scrape |\r\n| `usualBusynessAtObservedHour` | Google's usual value for that local hour, read from the chart (also when there is no live reading). Just after the hour turns, Google can still show the previous hour's live reading; `currentBusynessDay` / `currentBusynessHour` name the hour a live value belongs to, and `usualBusyness` is the usual value for that same hour |\r\n| `popularTimesSignature` | Fingerprint of the weekly profile; it changes when Google updates the usual values |\r\n| `businessStatus` | `OPERATIONAL`, `CLOSED_TEMPORARILY` or `CLOSED_PERMANENTLY`, as shown on the listing |\r\n| `openStatusText` / `isOpenNow` | Google's open-status line (e.g. \"Closed · Opens 8 AM\") and whether it says the place is open now |\r\n| `typicalTimeSpent` | Google's visit-duration text, when shown |\r\n| `latestReviews` | With `includeLatestReviews`: newest reviews with `publishedAt`, `publishedAtText`, `rating`, `text` (in the chosen language), `originalText` (when translated) and `closurePhrase` (when the review mentions a closure) |\r\n| `latestReviewAt` / `daysSinceLatestReview` | Date of the newest review and days since |\r\n| `closureMentionCount` / `latestClosureMentionAt` | Newest reviews mentioning a closure, and the date of the latest one |\r\n| `monitoring` | With `monitoringKey`: run-to-run summary (see [Closure monitoring](#closure-monitoring)) |\r\n| `failureReason` / `attempts` | Only on `failed` records: the reason and the number of attempts used |\r\n| `scrapedAt` | Time of the scrape (UTC, ISO 8601) |\r\n\r\n### Hourly busyness format\r\n\r\nEach day in `popularTimes` is an array of `{hour, busyness}` pairs: `hour` is 0–23 in the place's local time and `busyness` is 0–100 relative to that place's peak. Each day follows Google's chart, which runs from early morning through the small hours of the next day (for example 4 AM to 3 AM), so late-night hours appear at the end of the day they belong to. Hours with no data are omitted, and days for which Google shows no data (usually days the place is closed) are omitted.\r\n\r\nThe chart slot for the current hour always holds Google's **usual** value; the live reading is only in `currentBusyness`. In the example above, the Friday 8 AM slot holds `21` (the usual level) while `currentBusyness` is `18`.\r\n\r\n### Place identity\r\n\r\nA canonical `ChIJ…` token is reported as `placeId` and a legacy `0x…:0x…` token as `featureId`; a legacy token is never relabelled as a Place ID. Google exposes a canonical Place ID for some places and only the legacy token (or neither) for others, so `placeId` is legitimately absent on many place records — the actor never invents or back-fills it. Records for unavailable places carry the identity contained in your own input.\r\n\r\n### Run summary\r\n\r\nEvery run stores a `RUN_SUMMARY` record in its key-value store with: places requested, records produced, places without popular times, duplicates, failures by reason, attempts, attempts that used a proxy, places not started because of the time limit, parallelism and run duration (plus places whose newest reviews could not be read, and the monitoring store name, when those options are on).\r\n\r\n## Closure monitoring\r\n\r\nGoogle can keep a restaurant listed as open for a while after it stops trading, and diners often notice first, writing reviews such as *\"It was closed, looked permanently.\"* or *\"Went on final weekend\"*. This actor collects those signals, together with changes in live busyness and listing status, so you can review the places that need a closer look.\r\n\r\n**Recommended setup**\r\n\r\n1. Use stable inputs: Place IDs or place URLs (search links also work; every record carries a stable `featureId` / `cid`).\r\n2. Turn on `includeLatestReviews` and set a `monitoringKey` (one key per list).\r\n3. Schedule the actor several times a week at the same local hours, including each place's usual busy hours (see `popularTimes`) — a quiet reading at a quiet hour says little.\r\n4. Enable `includeFailedPlaces` so every place appears in every run.\r\n5. Review the *Closure signals* view, or filter on `monitoring.signals`.\r\n\r\n**Monitoring summary (`monitoring`)**\r\n\r\n| Field | Meaning |\r\n|---|---|\r\n| `readingsCount`, `firstReadingAt`, `previousReadingAt` | How many readings are stored for the place and when |\r\n| `liveReadingsCount` | Readings that had a live value |\r\n| `busyHourReadingsCount` / `busyHourLiveReadingsCount` | Readings taken at busy hours (usual level ≥ `minUsualBusyness`), and how many of them had a live value |\r\n| `lowActivityStreak` | Latest consecutive busy-hour live readings at or below `lowActivityRatio` × usual |\r\n| `openNoLiveDataStreak` | Latest consecutive busy-hour readings where the listing said open but Google showed no live reading |\r\n| `recentMedianRatio` / `baselineMedianRatio` | Median live ÷ usual of the last 5 busy-hour live readings vs the 20 before them (needs 3+ readings each) |\r\n| `statusChange` | Listing status change since the previous reading, e.g. `OPERATIONAL` → `CLOSED_PERMANENTLY` |\r\n| `popularTimesRemoved` / `popularTimesChanged` | The weekly chart disappeared, or its usual values changed |\r\n| `reviewCountChange` | New reviews since the previous reading |\r\n| `newClosureMentions` | Closure-mentioning reviews not seen in earlier runs |\r\n| `signals` | Plain flags: `statusChanged`, `closedOnGoogle`, `popularTimesRemoved`, `popularTimesChanged`, `newClosureMentions`, `lowActivityStreak` (3+), `openWithoutLiveDataStreak` (3+), `belowBaseline` (recent median ≤ 70% of baseline) |\r\n\r\n**Busy hours only.** A low or missing reading at an hour the place is usually quiet says little (2% live when the usual level is 10% is noise; 2% when it is usually 79% is not). Streaks and medians therefore use only readings taken when Google's usual level for that hour is at least `minUsualBusyness` (default 30%). Readings at quiet hours are kept in the history but neither extend nor break a streak.\r\n\r\n**Reading the signals**\r\n\r\n- *Sudden collapse*: `lowActivityStreak` or `openWithoutLiveDataStreak` at the place's usual busy hours, often together with closure mentions.\r\n- *Gradual decline*: `belowBaseline` over several weeks of readings at consistent hours, with a slowing `reviewCountChange`.\r\n- *Confirmed by Google*: `statusChanged` / `closedOnGoogle`, usually with `popularTimesRemoved` (Google drops the chart from closed listings).\r\n\r\nThese are indicators to investigate, not proof: Popular Times comes from Google's aggregated location data, not visitor counts, single readings swing widely, and closure mentions are matched by phrase (each flagged review keeps the matched `closurePhrase` and its text so you can check it).\r\n\r\nThe history is kept in a key-value store named `popular-times-monitor-<your key>` in your Apify account (up to 500 readings per place). Avoid running two runs with the same key at the same time.\r\n\r\n## Speed at scale\r\n\r\nMeasured in October 2026 on 100 restaurants in 20 cities without proxies:\r\n\r\n| Places in parallel (memory) | Places per hour | Time per 1,000 places |\r\n|---|---|---|\r\n| 1 (2 GB) | about 95–100 | about 10.5 hours |\r\n| 3 (4 GB, default) | about 220 | about 4.5 hours |\r\n| 6 (8 GB) | about 370 | about 2.7 hours |\r\n\r\nEach place also waits for Google to settle its place link (for a stable ID) and reads the listing details, which adds to the time per place above. `includeLatestReviews` adds one small request per place after the place is scraped; it never makes a place fail. These requests are paced (at most one every 2 seconds) and, if Google ever limits them, paused for two minutes rather than retried; `RUN_SUMMARY` counts places whose reviews could not be read (`latestReviewsUnavailable`) and such pauses (`latestReviewsBlocked`). `monitoringKey` adds two key-value store operations per place.\r\n\r\n## FAQ\r\n\r\n### What is the difference between `currentBusyness` and `usualBusyness`?\r\n`currentBusyness` is Google's live reading at the moment of the scrape; `usualBusyness` is Google's usual level for the same hour, shown beside it. Both are read verbatim from Google — the actor never estimates or interpolates.\r\n\r\n### Why is Popular Times missing from my record?\r\nGoogle serves its **limited view of Maps** to signed-out sessions (a sign-in gate). That view keeps the place heading and basic listing facts but removes Popular Times, reviews, photos, price range, nearby places and Q&A. The actor does not sign in or bypass this gate. A resolved place is returned as a normal basic record with `dataStatus: \"limited_view\"`, `popularTimesAvailable: false`, `limitedViewReason: \"google_signin_required\"` and `popularTimesHasData: false`; no busyness is invented. Run again later or from a different network if you need to catch a full render. A limited view is not counted as a failed place.\r\n\r\n### Why is `currentBusyness` sometimes missing?\r\nGoogle only shows live data while the place is open and has enough recent visits, and places without a Popular Times chart never have one. `liveReadingStatus` tells you which case applies; `limitedView` means Google withheld the module from an anonymous session.\r\n\r\n### What happens to live data when a business is closed?\r\nWhen the listing shows the place as closed (outside listed hours, temporarily or permanently closed), Google normally shows no live reading and the field is omitted. `isOpenNow`, `openStatusText` and `businessStatus` tell you what the listing says.\r\n\r\n### Why can a closed business still show a small live percentage?\r\nGoogle states that live busyness comes from aggregated, anonymised location data and does not publish its model. Staff, neighbouring businesses in the same building, deliveries or passers-by can plausibly produce small readings, especially in dense areas. Treat low single-digit readings as \"near the floor\", not as proof of customers.\r\n\r\n### How do I detect a drop in activity at a location?\r\nSet a `monitoringKey` and run the same list on a schedule at consistent local hours. Each record then reports `lowActivityStreak`, `openNoLiveDataStreak` and the recent vs earlier median of `liveToUsualRatio`, with plain `signals` when they cross their thresholds. Sustained low ratios, or live readings that are repeatedly missing during listed opening hours, are stronger signals than any single value. Google's usual profile is a multi-month average, so it lags real change.\r\n\r\n### Can it find restaurants that closed but are still listed as open?\r\nIt surfaces the evidence: newest reviews that mention a closure (`closureMentionCount`, `closurePhrase`), missing or very low live readings during listed opening hours, Popular Times that disappear, and status changes between runs. Treat these as reasons to check a place, not as proof.\r\n\r\n### Why did a place's Popular Times disappear?\r\nCheck `dataStatus` first. `limited_view` means Google withheld the module from that anonymous session, not that the place has no Popular Times; the chart may return on another run. A full render (`dataStatus: \"full\"`) can genuinely lose its chart when Google marks the listing temporarily or permanently closed or when the place has too little recent visit data. With a `monitoringKey`, the summary reports `popularTimesRemoved` only for a full render that no longer has a chart, not for a limited view.\r\n\r\n### Which phrases count as a closure mention?\r\nSpecific phrases that state a closure, such as \"permanently closed\", \"it was closed\", \"out of business\", \"final weekend\", \"shame you're closing\" or \"will miss this place\", in all 11 supported languages; Google's own translation is checked too. A bare \"closed\" (as in \"closed on Mondays\") does not count. Each flagged review keeps `closurePhrase` and its text.\r\n\r\n### Where is the monitoring history stored?\r\nIn your own Apify account, in a key-value store named `popular-times-monitor-<your key>` (the key is lowercased, other characters become hyphens, and the full name is cut to 63 characters). Delete the store to start the history again.\r\n\r\n### How stable is the usual profile between runs?\r\nThe weekly profile is Google's long-run average, so it normally stays the same between runs and only shifts when Google updates it; `popularTimesSignature` changes when that happens. The live reading, by contrast, can move a lot from hour to hour.\r\n\r\n### Which places have Popular Times data?\r\nRestaurants, cafés, bars, retail stores, gyms, grocery stores and major attractions can have them, but availability now depends on what Google serves to the anonymous session as well as on the place itself. Small businesses, services without foot traffic and very new listings often have no chart. A `limited_view` record is not evidence either way; only `dataStatus: \"no_popular_times\"` from a full render is.\r\n\r\n### Which input should I use for reliable monitoring?\r\nUse Place IDs (`placeIds`) or the full place URL copied from Google Maps. Search links (`/maps/search/?api=1&query=…`) work too, and the record then carries the place's stable `featureId` and `cid` for joining runs. A query with the name and street address opens the place directly. When a query matches several places, Google shows a list: the actor opens the listed place whose full name appears in your query (e.g. \"ICHIRAN Shibuya\" for \"Ichiran Shibuya Tokyo\"; for duplicate listings at one address, the one with the most reviews), and reports branches of a chain at different addresses as unavailable (`notResolved`) rather than guessing — add the street address to such queries. A short name-plus-map-position URL can be ambiguous when several places share a name, and Google leaves permanently closed places out of its search results, so such places can only be reached by their Place ID or full place URL. An input that cannot be matched to exactly one place is reported as unavailable (`notResolved`) rather than guessed.\r\n\r\n### Can it handle thousands of places on a schedule?\r\nYes. Raise `maxConcurrency` (6 with 8 GB of memory is recommended for large lists) and set a run timeout long enough for your list; see [Speed at scale](#speed-at-scale). The actor stops starting new places shortly before the run's time limit, counts them in `RUN_SUMMARY` and, with `includeFailedPlaces`, outputs a `notStarted` record for each. Split very large lists into several runs and schedule them at consistent local times.\r\n\r\n### What if none of my places can be retrieved?\r\nIf a run produces no place records and at least one place failed, the run is marked as failed with a status message saying whether the inputs could not be matched to a place or no place data could be retrieved. A limited view that resolves to a place is a normal basic record, so a run made only of limited-view places still succeeds. With `includeFailedPlaces` on, the `failed` records are still in the dataset.\r\n\r\n### Can I limit retries for places that fail?\r\nYes. `maxAttemptsPerPlace` and `placeTimeoutSecs` cap the effort per place, \"No proxy\" avoids all proxy usage, and inputs that do not resolve to a place stop after two tries. Enable `includeFailedPlaces` to get a record for every unavailable place.\r\n\r\n### Do I need a proxy, cookies or a Google API key?\r\nNo. Places are fetched directly first; by default only the last two attempts for a hard-to-reach place use Apify residential proxies. No cookies, Google account or API key are needed. Because the actor stays signed out, Google may serve the limited view; basic place data is still returned and Popular Times are emitted only when Google actually renders them.\r\n\r\n### Is a live label without a percentage still captured?\r\nYes. When Google states the live level only in words (e.g. \"Currently as busy as it gets\"), you get the wording in `currentBusynessText` and `currentBusyness` is omitted rather than guessed.\r\n\r\n### Why is `typicalTimeSpent` often missing?\r\nGoogle shows visit duration only for some places, and rarely for restaurants. The actor only outputs the text Google displays.\r\n\r\n### Which languages are supported?\r\nEnglish, Spanish, French, German, Italian, Portuguese, Japanese, Korean, Chinese, Arabic and Russian. Labels are accepted only when their localized meaning is recognized; otherwise the field is omitted.\r\n\r\n### Does this use the Google Places API?\r\nNo. It reads the same public Google Maps page you see in your browser, so no API key, billing account or quota is needed.\r\n\r\n## Data source\r\n\r\nPublic Google Maps web pages (`google.com/maps`). You are responsible for using the extracted data lawfully and in line with Google's terms.\r\n",
    "actorDefinition": {
      "actorSpecification": 1,
      "name": "google-maps-popular-times-and-live-busyness",
      "title": "Google Maps Place Data & Popular Times (When Available)",
      "description": "Scrape Google Maps place data — name, address, category, phone, website, rating, open status, coordinates and local time — and, when Google serves it to an anonymous page, hourly Popular Times with live busyness. Google often serves signed-out sessions a limited view without Popular Times; those places are still returned as honest basic records. Place URLs or Place IDs, any country, no API key or login.",
      "version": "1.0",
      "buildTag": "latest",
      "dockerfile": "../Dockerfile",
      "readme": "# Google Maps Place Data & Popular Times (When Available)\r\n\r\nGet reliable **Google Maps place data** — name, address, category, phone, website, rating, open/closed status, coordinates and local time — and, **when Google serves it to an anonymous page**, the hourly **Popular Times** chart and **live busyness** reading. Google often serves signed-out sessions a **limited view** that omits Popular Times; the actor then returns an honest basic record (`dataStatus: \"limited_view\"`, `popularTimesAvailable: false`) instead of failing or inventing busyness. Works with Google Maps place URLs, search links or Google Place IDs, in any country, with no API key and no login.\r\n\r\n## At a glance\r\n\r\n| | |\r\n|---|---|\r\n| **What you get** | Basic place data for every resolved place: stable place ID, name, address, coordinates, local time, category, phone, website, rating, review count, open-now line and listing status. When Google serves a full render: hourly busyness (0–100%) for each day, live busyness vs the usual level, and Google's live label. Optional newest reviews with closure mentions and a run-to-run monitoring summary |\r\n| **Limited view** | Google's signed-out limited view omits Popular Times. Those places are still emitted as normal basic records with `dataStatus: \"limited_view\"`, `popularTimesAvailable: false`, `limitedViewReason: \"google_signin_required\"` and `popularTimesHasData: false`; no busyness is estimated |\r\n| **Input** | Google Maps place URLs, search links (`/maps/search/?api=1&query=…`), short links or Google Place IDs (`ChIJ…`) |\r\n| **Output** | JSON, CSV, Excel, XML or HTML via the Apify dataset; ready-made \"Place data & Popular Times\", \"Live monitoring\" and \"Closure signals\" table views |\r\n| **Coverage** | Any country Google Maps serves; Google Maps UI in 11 languages. Popular Times depends on Google's anonymous rendering and is not guaranteed |\r\n| **Requirements** | No Google API key, no Google account, no cookies |\r\n| **Scale** | Up to 8 places in parallel; about 370 places per hour at 6 in parallel (measured October 2026) |\r\n| **Automation** | Run from the Apify Console, the API, Python/JavaScript clients, schedules, webhooks and integrations |\r\n\r\n## What is Google Maps Popular Times?\r\n\r\n**Popular Times** is the bar chart Google Maps shows on a place's page to indicate how busy it usually is at each hour of each day. Google builds it from aggregated, anonymised location data and expresses each hour as a percentage of that place's typical peak (100 = as busy as it gets). While a place is open, Google often adds a **live** reading that compares how busy it is right now with how busy it usually is at this hour.\r\n\r\nGoogle withholds the chart from the **limited view** it serves to signed-out sessions (the same view that removes reviews, photos, price range, nearby places and Q&A). This actor does not bypass that gate: it returns the place's basic data with an explicit `limited_view` status, and only emits Popular Times when Google actually renders them.\r\n\r\n## What does this scraper extract?\r\n\r\n- **Basic place data for every resolved place** — name, stable identity, address, coordinates, local time, category, phone, website, rating, review count and open/closed status, even when Google serves its limited view\r\n- **Per-day hourly busyness** (0–100%) for every day Google charts — a full week in one request, when a full render is available\r\n- **Live vs usual** (when Google publishes them) — Google's live percentage (`currentBusyness`) next to its usual percentage for the same hour (`usualBusyness`), plus the chart day and hour the reading belongs to\r\n- **Live label** (when Google publishes it) — Google's wording such as *\"Not too busy\"*, *\"Less busy than usual\"* or *\"As busy as it gets\"*\r\n- **Open / closed status** — whether the listing is operating, temporarily closed or permanently closed, plus Google's open-now line (e.g. *\"Open · Closes 11 PM\"*)\r\n- **Typical time spent** when Google shows it (e.g. *\"People typically spend 30 min to 1 hour here\"*)\r\n- **Business name and a stable place identity** — `featureId` / `cid` (and the canonical `ChIJ…` `placeId` when Google shows it) for every place, including places given as search links or short links, so readings from different runs can be joined\r\n- **Listing details** — category, address, latitude/longitude, phone, website, rating and review count\r\n- **Local time of each reading** — the place's time zone, the local date and hour of the scrape, and Google's usual value for that hour from the chart (also when there is no live reading)\r\n- **Live vs usual, ready to compare** — `liveToUsualRatio` and `liveMinusUsual`, plus `liveReadingStatus` explaining why a live reading is missing (closed now, open but no live data, permanently closed…)\r\n- **Newest reviews and closure mentions** (optional) — the newest Google reviews with exact dates, flagged when they say the place is closing or closed (\"final weekend\", \"it was closed\", \"permanently closed\", in 11 languages)\r\n- **Run-to-run monitoring** (optional) — with a monitoring key, each record compares the reading with the place's earlier readings: low-activity streaks, recent vs earlier live/usual ratio, listing status changes, Popular Times removed or changed, review-count change and new closure mentions. Limited-view readings are stored as basic readings and are not reported as a removed chart\r\n- **Every input accounted for** — each place is returned, or (when enabled) reported as an unavailable-place record with the reason; inputs that turn out to be the same place as an earlier input are returned once, and every outcome (including such duplicates) is counted in a run summary\r\n\r\n## Use cases\r\n\r\n- **Place enrichment and lead lists** — get name, address, category, phone, website, rating and open status for a list of Google Maps places, regardless of whether Popular Times render\r\n- **Foot-traffic monitoring** — when Google serves Popular Times, track live busyness against the usual level across a fixed list of restaurants or stores\r\n- **Closure detection and early warning** — find restaurants that have stopped operating while Google still lists them as open: closure mentions in the newest reviews, live readings that stay far below usual or are missing during listed opening hours, Popular Times that disappear, and listings that turn \"Temporarily closed\" / \"Permanently closed\"\r\n- **Site selection and competitor research** — compare busy hours of competing locations when the chart is available\r\n- **Staffing and operations** — plan shifts, deliveries and field visits around quiet and peak hours\r\n- **Travel and \"when to go\" apps** — recommend the best time to visit restaurants and attractions\r\n- **Research and dashboards** — build time series of busyness by city, category or chain\r\n\r\n## How to scrape Google Maps place data and Popular Times\r\n\r\n1. **Collect your places** — copy place URLs from Google Maps or use Google Place IDs (`ChIJ…`).\r\n2. **Paste them** into *Place URLs* or *Google Place IDs* and pick the Google Maps language.\r\n3. **Set speed and retries** (optional) — places in parallel, attempts per place, time limit per place, and whether to output unavailable places.\r\n4. **Turn on closure monitoring** (optional) — include the newest reviews and set a monitoring key.\r\n5. **Run** and download the results as JSON, CSV or Excel, or open the *Live monitoring* or *Closure signals* view. Use a schedule with the same monitoring key to repeat the list and build a time series.\r\n\r\n## Input\r\n\r\n| Field | Type | Default | Description |\r\n|---|---|---|---|\r\n| `placeUrls` | Array of strings | – | Google Maps place URLs; short links, copied punctuation and tracking parameters are normalized. One of `placeUrls`/`placeIds` is required |\r\n| `placeIds` | Array of strings | – | Canonical Google Place IDs beginning with `ChIJ`. One of `placeUrls`/`placeIds` is required |\r\n| `language` | String | `en` | Google Maps language for labels and parsing: `en`, `es`, `fr`, `de`, `it`, `pt`, `ja`, `ko`, `zh`, `ar`, `ru` |\r\n| `maxConcurrency` | Integer | 3 | Places scraped at the same time (1–8). Needs about 1 GB of run memory per parallel place; lowered automatically if the run has less memory |\r\n| `maxAttemptsPerPlace` | Integer | 8 | Maximum attempts for one place before it is reported as unavailable (1–12) |\r\n| `placeTimeoutSecs` | Integer | 240 | Time limit for one place across all of its attempts, in seconds (30–600) |\r\n| `includeFailedPlaces` | Boolean | `false` | Also output one record per place that could not be retrieved, with the reason |\r\n| `includeLatestReviews` | Boolean | `false` | Also return each place's newest reviews and flag closure mentions |\r\n| `latestReviewsCount` | Integer | 10 | Newest reviews per place (1–60) |\r\n| `monitoringKey` | String | – | Name of a monitoring list; readings are kept in your account between runs and each record gets a `monitoring` summary. Use the same key on every scheduled run |\r\n| `lowActivityRatio` | Number | 0.25 | A live reading counts as low when live ÷ usual is at most this value (0.05–1) |\r\n| `minUsualBusyness` | Integer | 30 | Busy-hour threshold: readings count toward the monitoring streaks and medians only when Google's usual level for that hour is at least this value (5–100) |\r\n| `proxyConfiguration` | Object | – | 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). Choose \"No proxy\" to never use a proxy, or your own proxy for those fallback attempts |\r\n\r\n### Input examples\r\n\r\n**One place by URL**\r\n\r\n```json\r\n{\r\n  \"placeUrls\": [\r\n    \"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\"\r\n  ]\r\n}\r\n```\r\n\r\n**Places by Google Place ID**\r\n\r\n```json\r\n{\r\n  \"placeIds\": [\"ChIJaXQRs6lZwokRY6EFpJnhNNE\", \"ChIJabtoT7hlwokRLECK0SW3_8I\"]\r\n}\r\n```\r\n\r\n**Live monitoring list (large, recurring)** — run with 8 GB of memory:\r\n\r\n```json\r\n{\r\n  \"placeIds\": [\"ChIJaXQRs6lZwokRY6EFpJnhNNE\", \"ChIJabtoT7hlwokRLECK0SW3_8I\"],\r\n  \"maxConcurrency\": 6,\r\n  \"maxAttemptsPerPlace\": 6,\r\n  \"includeFailedPlaces\": true\r\n}\r\n```\r\n\r\n**Closure monitoring (scheduled several times a week)**\r\n\r\n```json\r\n{\r\n  \"placeIds\": [\"ChIJaXQRs6lZwokRY6EFpJnhNNE\", \"ChIJabtoT7hlwokRLECK0SW3_8I\"],\r\n  \"includeLatestReviews\": true,\r\n  \"latestReviewsCount\": 10,\r\n  \"monitoringKey\": \"vancouver-restaurants\",\r\n  \"includeFailedPlaces\": true\r\n}\r\n```\r\n\r\n**Localized labels**\r\n\r\n```json\r\n{\r\n  \"placeIds\": [\"ChIJaXQRs6lZwokRY6EFpJnhNNE\"],\r\n  \"language\": \"es\"\r\n}\r\n```\r\n\r\n## Output\r\n\r\nOne record per place. A real record for an open place with a live reading (with `includeLatestReviews`; chart and review lists shortened):\r\n\r\n```json\r\n{\r\n  \"recordType\": \"popularTimes\",\r\n  \"businessName\": \"Café de Flore\",\r\n  \"featureId\": \"0x47e671d781fb9dab:0x18bba6dd45e173ff\",\r\n  \"cid\": \"1782201546845549567\",\r\n  \"googleMapsUrl\": \"https://www.google.com/maps?cid=1782201546845549567\",\r\n  \"placeUrl\": \"https://www.google.com/maps/search/?api=1&query=Cafe+de+Flore+Paris\",\r\n  \"category\": \"Coffee shop\",\r\n  \"address\": \"172 Bd Saint-Germain, 75006 Paris, France\",\r\n  \"latitude\": 48.8541588,\r\n  \"longitude\": 2.3326046,\r\n  \"timezone\": \"Europe/Paris\",\r\n  \"phone\": \"+33145485526\",\r\n  \"website\": \"https://cafedeflore.fr/\",\r\n  \"rating\": 3.9,\r\n  \"reviewCount\": 14535,\r\n  \"businessStatus\": \"OPERATIONAL\",\r\n  \"openStatusText\": \"Open · Closes 1:30 AM\",\r\n  \"isOpenNow\": true,\r\n  \"liveReadingStatus\": \"live\",\r\n  \"currentBusyness\": 18,\r\n  \"usualBusyness\": 21,\r\n  \"liveToUsualRatio\": 0.86,\r\n  \"liveMinusUsual\": -3,\r\n  \"currentBusynessLevel\": \"Not busy\",\r\n  \"currentBusynessText\": \"Currently 18% busy, usually 21% busy.\",\r\n  \"currentBusynessDay\": \"friday\",\r\n  \"currentBusynessHour\": 8,\r\n  \"observedAtLocal\": \"2026-10-09T08:06:10+02:00\",\r\n  \"observedLocalDay\": \"friday\",\r\n  \"observedLocalHour\": 8,\r\n  \"usualBusynessAtObservedHour\": 21,\r\n  \"popularTimesHasData\": true,\r\n  \"popularTimesAvailable\": true,\r\n  \"dataStatus\": \"full\",\r\n  \"popularTimesSignature\": \"fe878c8c86fc16e5\",\r\n  \"popularTimes\": {\r\n    \"friday\": [\r\n      {\r\n        \"hour\": 6,\r\n        \"busyness\": 0\r\n      },\r\n      {\r\n        \"hour\": 7,\r\n        \"busyness\": 13\r\n      },\r\n      {\r\n        \"hour\": 8,\r\n        \"busyness\": 21\r\n      },\r\n      {\r\n        \"hour\": 9,\r\n        \"busyness\": 31\r\n      },\r\n      {\r\n        \"hour\": 10,\r\n        \"busyness\": 40\r\n      },\r\n      \"...\"\r\n    ],\r\n    \"saturday\": [\r\n      \"...\"\r\n    ]\r\n  },\r\n  \"closureMentionCount\": 0,\r\n  \"latestReviewAt\": \"2026-10-09T03:58:59+00:00\",\r\n  \"daysSinceLatestReview\": 0,\r\n  \"latestReviews\": [\r\n    {\r\n      \"publishedAt\": \"2026-10-08T22:56:12+00:00\",\r\n      \"publishedAtText\": \"7 hours ago\",\r\n      \"rating\": 5,\r\n      \"text\": \"Ironic place with very good service and food.\",\r\n      \"originalText\": \"Lugar irónico con muy buen servicio y comida.\"\r\n    },\r\n    \"...\"\r\n  ],\r\n  \"sourceUrl\": \"https://www.google.com/maps/search/?api=1&query=Cafe+de+Flore+Paris\",\r\n  \"scrapedAt\": \"2026-10-09T06:06:09.536970+00:00\"\r\n}\r\n```\r\n\r\nFields Google does not show for a place are omitted — no `null` values appear in the dataset.\r\n\r\n### Limited view (Google sign-in required)\r\n\r\nWhen Google serves its anonymous limited view, the place is still returned as a normal basic record. Only fields Google actually rendered are included; Popular Times are absent rather than estimated:\r\n\r\n```json\r\n{\r\n  \"recordType\": \"popularTimes\",\r\n  \"businessName\": \"McDonald's\",\r\n  \"featureId\": \"0x89c2597777397641:0x4387a82ee10d3e3b\",\r\n  \"placeUrl\": \"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\",\r\n  \"category\": \"Fast food restaurant\",\r\n  \"address\": \"1560 Broadway, New York, NY 10036, United States\",\r\n  \"latitude\": 40.7577297,\r\n  \"longitude\": -73.9853627,\r\n  \"timezone\": \"America/New_York\",\r\n  \"phone\": \"+1 212-555-0100\",\r\n  \"website\": \"https://www.mcdonalds.com/us/en-us.html\",\r\n  \"rating\": 4.2,\r\n  \"reviewCount\": 34567,\r\n  \"businessStatus\": \"OPERATIONAL\",\r\n  \"openStatusText\": \"Open · Closes 11 PM\",\r\n  \"isOpenNow\": true,\r\n  \"observedAtLocal\": \"2026-10-24T09:15:00-04:00\",\r\n  \"observedLocalDay\": \"saturday\",\r\n  \"observedLocalHour\": 9,\r\n  \"popularTimesHasData\": false,\r\n  \"popularTimesAvailable\": false,\r\n  \"dataStatus\": \"limited_view\",\r\n  \"limitedViewReason\": \"google_signin_required\",\r\n  \"liveReadingStatus\": \"limitedView\",\r\n  \"sourceUrl\": \"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\",\r\n  \"scrapedAt\": \"2026-10-24T13:15:00+00:00\"\r\n}\r\n```\r\n\r\n`dataStatus` tells you which path produced the record:\r\n\r\n| `dataStatus` | Meaning |\r\n|---|---|\r\n| `full` | Google rendered Popular Times; `popularTimesAvailable` is `true` |\r\n| `no_popular_times` | A full render showed no chart for this place; `popularTimesAvailable` is `false` |\r\n| `limited_view` | Google served its signed-out limited view; basic place data is returned, Popular Times are withheld, and `limitedViewReason` explains why |\r\n\r\n### Unavailable places\r\n\r\nA limited view that still resolves to a place is **not** an unavailable place: it is emitted as a normal basic record (see above). With `includeFailedPlaces` enabled, only places for which **no place data could be resolved** produce a `failed` record like this. It carries the Place ID or feature ID from your input when the input contains one, and has no `attempts` when the place was never started:\r\n\r\n```json\r\n{\r\n  \"recordType\": \"failed\",\r\n  \"placeId\": \"ChIJaXQRs6lZwokRY6EFpJnhNNE\",\r\n  \"placeUrl\": \"https://www.google.com/maps/search/?api=1&query=ChIJaXQRs6lZwokRY6EFpJnhNNE&query_place_id=ChIJaXQRs6lZwokRY6EFpJnhNNE\",\r\n  \"failureReason\": \"notResolved\",\r\n  \"attempts\": 2,\r\n  \"scrapedAt\": \"2026-10-07T13:25:40+00:00\"\r\n}\r\n```\r\n\r\n| `failureReason` | Meaning |\r\n|---|---|\r\n| `timeout` | The time limit was reached |\r\n| `network` | The page could not be loaded |\r\n| `unconfirmedEmpty` | The place showed no popular times once, but repeated attempts could not confirm it |\r\n| `notResolved` | The input did not lead to a single matching Google Maps place, so no place data could be returned |\r\n| `notStarted` | The run's time limit was reached before this place could be started — raise the run timeout or split the list |\r\n| `error` | An unexpected error occurred |\r\n\r\n### Output fields\r\n\r\n| Field | Description |\r\n|---|---|\r\n| `recordType` | `popularTimes` for a place record (full or basic), `failed` for an input with no place data |\r\n| `businessName` | Place name as shown on Google Maps |\r\n| `placeId` / `featureId` | Canonical `ChIJ…` Place ID or legacy `0x…:0x…` token (see below) |\r\n| `cid` / `googleMapsUrl` | Google's numeric place ID and a stable link to the place |\r\n| `category`, `address`, `phone`, `website` | Listing details as shown on Google Maps (omitted when the limited view does not render them) |\r\n| `latitude` / `longitude` | The place's pin (or, where Google shows no pin, as in South Korea, the centre of the place's Plus Code) |\r\n| `rating` / `reviewCount` | Star rating and number of reviews, when Google shows them |\r\n| `placeUrl` / `sourceUrl` | The input URL, normalized |\r\n| `popularTimesHasData` | Whether Google rendered a Popular Times chart for this record |\r\n| `popularTimesAvailable` | Whether an accepted, complete-or-place-appropriate chart is present |\r\n| `dataStatus` | `full`, `no_popular_times` or `limited_view` |\r\n| `limitedViewReason` | On a limited view: `google_signin_required` |\r\n| `popularTimes` | Hourly busyness per day: `{day: [{hour, busyness}]}`; absent on a limited view |\r\n| `currentBusyness` | Google's live reading at the moment of the scrape, exactly as displayed (0–100) |\r\n| `usualBusyness` | Google's usual level for the same hour, as displayed beside the live reading |\r\n| `currentBusynessLevel` | Google's live label, e.g. \"Not too busy\", \"Less busy than usual\", \"As busy as it gets\" |\r\n| `currentBusynessDay` / `currentBusynessHour` | The chart day and hour the live reading belongs to (the place's local time) |\r\n| `currentBusynessText` | Google's full live text, e.g. \"Currently 52% busy, usually 34% busy.\" |\r\n| `liveToUsualRatio` / `liveMinusUsual` | Live ÷ usual (e.g. 0.08) and live − usual in points (e.g. −22), when Google shows both |\r\n| `liveReadingStatus` | `live`, `limitedView` (Google withheld the module), `closedNow` (outside listed hours), `openNoLiveData` (listing says open, no live reading), `noPopularTimes`, `temporarilyClosed`, `permanentlyClosed` or `noLiveData` |\r\n| `timezone`, `observedAtLocal`, `observedLocalDay`, `observedLocalHour` | The place's time zone and the local time of the scrape |\r\n| `usualBusynessAtObservedHour` | Google's usual value for that local hour, read from the chart (also when there is no live reading). Just after the hour turns, Google can still show the previous hour's live reading; `currentBusynessDay` / `currentBusynessHour` name the hour a live value belongs to, and `usualBusyness` is the usual value for that same hour |\r\n| `popularTimesSignature` | Fingerprint of the weekly profile; it changes when Google updates the usual values |\r\n| `businessStatus` | `OPERATIONAL`, `CLOSED_TEMPORARILY` or `CLOSED_PERMANENTLY`, as shown on the listing |\r\n| `openStatusText` / `isOpenNow` | Google's open-status line (e.g. \"Closed · Opens 8 AM\") and whether it says the place is open now |\r\n| `typicalTimeSpent` | Google's visit-duration text, when shown |\r\n| `latestReviews` | With `includeLatestReviews`: newest reviews with `publishedAt`, `publishedAtText`, `rating`, `text` (in the chosen language), `originalText` (when translated) and `closurePhrase` (when the review mentions a closure) |\r\n| `latestReviewAt` / `daysSinceLatestReview` | Date of the newest review and days since |\r\n| `closureMentionCount` / `latestClosureMentionAt` | Newest reviews mentioning a closure, and the date of the latest one |\r\n| `monitoring` | With `monitoringKey`: run-to-run summary (see [Closure monitoring](#closure-monitoring)) |\r\n| `failureReason` / `attempts` | Only on `failed` records: the reason and the number of attempts used |\r\n| `scrapedAt` | Time of the scrape (UTC, ISO 8601) |\r\n\r\n### Hourly busyness format\r\n\r\nEach day in `popularTimes` is an array of `{hour, busyness}` pairs: `hour` is 0–23 in the place's local time and `busyness` is 0–100 relative to that place's peak. Each day follows Google's chart, which runs from early morning through the small hours of the next day (for example 4 AM to 3 AM), so late-night hours appear at the end of the day they belong to. Hours with no data are omitted, and days for which Google shows no data (usually days the place is closed) are omitted.\r\n\r\nThe chart slot for the current hour always holds Google's **usual** value; the live reading is only in `currentBusyness`. In the example above, the Friday 8 AM slot holds `21` (the usual level) while `currentBusyness` is `18`.\r\n\r\n### Place identity\r\n\r\nA canonical `ChIJ…` token is reported as `placeId` and a legacy `0x…:0x…` token as `featureId`; a legacy token is never relabelled as a Place ID. Google exposes a canonical Place ID for some places and only the legacy token (or neither) for others, so `placeId` is legitimately absent on many place records — the actor never invents or back-fills it. Records for unavailable places carry the identity contained in your own input.\r\n\r\n### Run summary\r\n\r\nEvery run stores a `RUN_SUMMARY` record in its key-value store with: places requested, records produced, places without popular times, duplicates, failures by reason, attempts, attempts that used a proxy, places not started because of the time limit, parallelism and run duration (plus places whose newest reviews could not be read, and the monitoring store name, when those options are on).\r\n\r\n## Closure monitoring\r\n\r\nGoogle can keep a restaurant listed as open for a while after it stops trading, and diners often notice first, writing reviews such as *\"It was closed, looked permanently.\"* or *\"Went on final weekend\"*. This actor collects those signals, together with changes in live busyness and listing status, so you can review the places that need a closer look.\r\n\r\n**Recommended setup**\r\n\r\n1. Use stable inputs: Place IDs or place URLs (search links also work; every record carries a stable `featureId` / `cid`).\r\n2. Turn on `includeLatestReviews` and set a `monitoringKey` (one key per list).\r\n3. Schedule the actor several times a week at the same local hours, including each place's usual busy hours (see `popularTimes`) — a quiet reading at a quiet hour says little.\r\n4. Enable `includeFailedPlaces` so every place appears in every run.\r\n5. Review the *Closure signals* view, or filter on `monitoring.signals`.\r\n\r\n**Monitoring summary (`monitoring`)**\r\n\r\n| Field | Meaning |\r\n|---|---|\r\n| `readingsCount`, `firstReadingAt`, `previousReadingAt` | How many readings are stored for the place and when |\r\n| `liveReadingsCount` | Readings that had a live value |\r\n| `busyHourReadingsCount` / `busyHourLiveReadingsCount` | Readings taken at busy hours (usual level ≥ `minUsualBusyness`), and how many of them had a live value |\r\n| `lowActivityStreak` | Latest consecutive busy-hour live readings at or below `lowActivityRatio` × usual |\r\n| `openNoLiveDataStreak` | Latest consecutive busy-hour readings where the listing said open but Google showed no live reading |\r\n| `recentMedianRatio` / `baselineMedianRatio` | Median live ÷ usual of the last 5 busy-hour live readings vs the 20 before them (needs 3+ readings each) |\r\n| `statusChange` | Listing status change since the previous reading, e.g. `OPERATIONAL` → `CLOSED_PERMANENTLY` |\r\n| `popularTimesRemoved` / `popularTimesChanged` | The weekly chart disappeared, or its usual values changed |\r\n| `reviewCountChange` | New reviews since the previous reading |\r\n| `newClosureMentions` | Closure-mentioning reviews not seen in earlier runs |\r\n| `signals` | Plain flags: `statusChanged`, `closedOnGoogle`, `popularTimesRemoved`, `popularTimesChanged`, `newClosureMentions`, `lowActivityStreak` (3+), `openWithoutLiveDataStreak` (3+), `belowBaseline` (recent median ≤ 70% of baseline) |\r\n\r\n**Busy hours only.** A low or missing reading at an hour the place is usually quiet says little (2% live when the usual level is 10% is noise; 2% when it is usually 79% is not). Streaks and medians therefore use only readings taken when Google's usual level for that hour is at least `minUsualBusyness` (default 30%). Readings at quiet hours are kept in the history but neither extend nor break a streak.\r\n\r\n**Reading the signals**\r\n\r\n- *Sudden collapse*: `lowActivityStreak` or `openWithoutLiveDataStreak` at the place's usual busy hours, often together with closure mentions.\r\n- *Gradual decline*: `belowBaseline` over several weeks of readings at consistent hours, with a slowing `reviewCountChange`.\r\n- *Confirmed by Google*: `statusChanged` / `closedOnGoogle`, usually with `popularTimesRemoved` (Google drops the chart from closed listings).\r\n\r\nThese are indicators to investigate, not proof: Popular Times comes from Google's aggregated location data, not visitor counts, single readings swing widely, and closure mentions are matched by phrase (each flagged review keeps the matched `closurePhrase` and its text so you can check it).\r\n\r\nThe history is kept in a key-value store named `popular-times-monitor-<your key>` in your Apify account (up to 500 readings per place). Avoid running two runs with the same key at the same time.\r\n\r\n## Speed at scale\r\n\r\nMeasured in October 2026 on 100 restaurants in 20 cities without proxies:\r\n\r\n| Places in parallel (memory) | Places per hour | Time per 1,000 places |\r\n|---|---|---|\r\n| 1 (2 GB) | about 95–100 | about 10.5 hours |\r\n| 3 (4 GB, default) | about 220 | about 4.5 hours |\r\n| 6 (8 GB) | about 370 | about 2.7 hours |\r\n\r\nEach place also waits for Google to settle its place link (for a stable ID) and reads the listing details, which adds to the time per place above. `includeLatestReviews` adds one small request per place after the place is scraped; it never makes a place fail. These requests are paced (at most one every 2 seconds) and, if Google ever limits them, paused for two minutes rather than retried; `RUN_SUMMARY` counts places whose reviews could not be read (`latestReviewsUnavailable`) and such pauses (`latestReviewsBlocked`). `monitoringKey` adds two key-value store operations per place.\r\n\r\n## FAQ\r\n\r\n### What is the difference between `currentBusyness` and `usualBusyness`?\r\n`currentBusyness` is Google's live reading at the moment of the scrape; `usualBusyness` is Google's usual level for the same hour, shown beside it. Both are read verbatim from Google — the actor never estimates or interpolates.\r\n\r\n### Why is Popular Times missing from my record?\r\nGoogle serves its **limited view of Maps** to signed-out sessions (a sign-in gate). That view keeps the place heading and basic listing facts but removes Popular Times, reviews, photos, price range, nearby places and Q&A. The actor does not sign in or bypass this gate. A resolved place is returned as a normal basic record with `dataStatus: \"limited_view\"`, `popularTimesAvailable: false`, `limitedViewReason: \"google_signin_required\"` and `popularTimesHasData: false`; no busyness is invented. Run again later or from a different network if you need to catch a full render. A limited view is not counted as a failed place.\r\n\r\n### Why is `currentBusyness` sometimes missing?\r\nGoogle only shows live data while the place is open and has enough recent visits, and places without a Popular Times chart never have one. `liveReadingStatus` tells you which case applies; `limitedView` means Google withheld the module from an anonymous session.\r\n\r\n### What happens to live data when a business is closed?\r\nWhen the listing shows the place as closed (outside listed hours, temporarily or permanently closed), Google normally shows no live reading and the field is omitted. `isOpenNow`, `openStatusText` and `businessStatus` tell you what the listing says.\r\n\r\n### Why can a closed business still show a small live percentage?\r\nGoogle states that live busyness comes from aggregated, anonymised location data and does not publish its model. Staff, neighbouring businesses in the same building, deliveries or passers-by can plausibly produce small readings, especially in dense areas. Treat low single-digit readings as \"near the floor\", not as proof of customers.\r\n\r\n### How do I detect a drop in activity at a location?\r\nSet a `monitoringKey` and run the same list on a schedule at consistent local hours. Each record then reports `lowActivityStreak`, `openNoLiveDataStreak` and the recent vs earlier median of `liveToUsualRatio`, with plain `signals` when they cross their thresholds. Sustained low ratios, or live readings that are repeatedly missing during listed opening hours, are stronger signals than any single value. Google's usual profile is a multi-month average, so it lags real change.\r\n\r\n### Can it find restaurants that closed but are still listed as open?\r\nIt surfaces the evidence: newest reviews that mention a closure (`closureMentionCount`, `closurePhrase`), missing or very low live readings during listed opening hours, Popular Times that disappear, and status changes between runs. Treat these as reasons to check a place, not as proof.\r\n\r\n### Why did a place's Popular Times disappear?\r\nCheck `dataStatus` first. `limited_view` means Google withheld the module from that anonymous session, not that the place has no Popular Times; the chart may return on another run. A full render (`dataStatus: \"full\"`) can genuinely lose its chart when Google marks the listing temporarily or permanently closed or when the place has too little recent visit data. With a `monitoringKey`, the summary reports `popularTimesRemoved` only for a full render that no longer has a chart, not for a limited view.\r\n\r\n### Which phrases count as a closure mention?\r\nSpecific phrases that state a closure, such as \"permanently closed\", \"it was closed\", \"out of business\", \"final weekend\", \"shame you're closing\" or \"will miss this place\", in all 11 supported languages; Google's own translation is checked too. A bare \"closed\" (as in \"closed on Mondays\") does not count. Each flagged review keeps `closurePhrase` and its text.\r\n\r\n### Where is the monitoring history stored?\r\nIn your own Apify account, in a key-value store named `popular-times-monitor-<your key>` (the key is lowercased, other characters become hyphens, and the full name is cut to 63 characters). Delete the store to start the history again.\r\n\r\n### How stable is the usual profile between runs?\r\nThe weekly profile is Google's long-run average, so it normally stays the same between runs and only shifts when Google updates it; `popularTimesSignature` changes when that happens. The live reading, by contrast, can move a lot from hour to hour.\r\n\r\n### Which places have Popular Times data?\r\nRestaurants, cafés, bars, retail stores, gyms, grocery stores and major attractions can have them, but availability now depends on what Google serves to the anonymous session as well as on the place itself. Small businesses, services without foot traffic and very new listings often have no chart. A `limited_view` record is not evidence either way; only `dataStatus: \"no_popular_times\"` from a full render is.\r\n\r\n### Which input should I use for reliable monitoring?\r\nUse Place IDs (`placeIds`) or the full place URL copied from Google Maps. Search links (`/maps/search/?api=1&query=…`) work too, and the record then carries the place's stable `featureId` and `cid` for joining runs. A query with the name and street address opens the place directly. When a query matches several places, Google shows a list: the actor opens the listed place whose full name appears in your query (e.g. \"ICHIRAN Shibuya\" for \"Ichiran Shibuya Tokyo\"; for duplicate listings at one address, the one with the most reviews), and reports branches of a chain at different addresses as unavailable (`notResolved`) rather than guessing — add the street address to such queries. A short name-plus-map-position URL can be ambiguous when several places share a name, and Google leaves permanently closed places out of its search results, so such places can only be reached by their Place ID or full place URL. An input that cannot be matched to exactly one place is reported as unavailable (`notResolved`) rather than guessed.\r\n\r\n### Can it handle thousands of places on a schedule?\r\nYes. Raise `maxConcurrency` (6 with 8 GB of memory is recommended for large lists) and set a run timeout long enough for your list; see [Speed at scale](#speed-at-scale). The actor stops starting new places shortly before the run's time limit, counts them in `RUN_SUMMARY` and, with `includeFailedPlaces`, outputs a `notStarted` record for each. Split very large lists into several runs and schedule them at consistent local times.\r\n\r\n### What if none of my places can be retrieved?\r\nIf a run produces no place records and at least one place failed, the run is marked as failed with a status message saying whether the inputs could not be matched to a place or no place data could be retrieved. A limited view that resolves to a place is a normal basic record, so a run made only of limited-view places still succeeds. With `includeFailedPlaces` on, the `failed` records are still in the dataset.\r\n\r\n### Can I limit retries for places that fail?\r\nYes. `maxAttemptsPerPlace` and `placeTimeoutSecs` cap the effort per place, \"No proxy\" avoids all proxy usage, and inputs that do not resolve to a place stop after two tries. Enable `includeFailedPlaces` to get a record for every unavailable place.\r\n\r\n### Do I need a proxy, cookies or a Google API key?\r\nNo. Places are fetched directly first; by default only the last two attempts for a hard-to-reach place use Apify residential proxies. No cookies, Google account or API key are needed. Because the actor stays signed out, Google may serve the limited view; basic place data is still returned and Popular Times are emitted only when Google actually renders them.\r\n\r\n### Is a live label without a percentage still captured?\r\nYes. When Google states the live level only in words (e.g. \"Currently as busy as it gets\"), you get the wording in `currentBusynessText` and `currentBusyness` is omitted rather than guessed.\r\n\r\n### Why is `typicalTimeSpent` often missing?\r\nGoogle shows visit duration only for some places, and rarely for restaurants. The actor only outputs the text Google displays.\r\n\r\n### Which languages are supported?\r\nEnglish, Spanish, French, German, Italian, Portuguese, Japanese, Korean, Chinese, Arabic and Russian. Labels are accepted only when their localized meaning is recognized; otherwise the field is omitted.\r\n\r\n### Does this use the Google Places API?\r\nNo. It reads the same public Google Maps page you see in your browser, so no API key, billing account or quota is needed.\r\n\r\n## Data source\r\n\r\nPublic Google Maps web pages (`google.com/maps`). You are responsible for using the extracted data lawfully and in line with Google's terms.\r\n",
      "input": {
        "title": "Google Maps Place Data & Popular Times (When Available)",
        "description": "Scrape Google Maps place data (name, address, category, phone, website, rating, open status, coordinates, local time) and, when Google serves it to an anonymous page, Popular Times (hourly busy hours for every day) with live busyness vs the usual level. Google often serves signed-out sessions a limited view without Popular Times; those places are still returned as basic records (dataStatus=limited_view). No API key or login needed.",
        "type": "object",
        "schemaVersion": 1,
        "properties": {
          "placeUrls": {
            "title": "Place URLs",
            "type": "array",
            "description": "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.",
            "editor": "stringList",
            "prefill": [
              "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"
            ],
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "maxItems": 100000
          },
          "placeIds": {
            "title": "Google Place IDs",
            "type": "array",
            "description": "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.",
            "editor": "stringList",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "maxItems": 100000
          },
          "language": {
            "title": "Google Maps language",
            "type": "string",
            "description": "Language of the Google Maps pages; text fields such as the live label and open status are returned in this language.",
            "editor": "select",
            "enum": [
              "en",
              "es",
              "fr",
              "de",
              "it",
              "pt",
              "ja",
              "ko",
              "zh",
              "ar",
              "ru"
            ],
            "enumTitles": [
              "English",
              "Spanish",
              "French",
              "German",
              "Italian",
              "Portuguese",
              "Japanese",
              "Korean",
              "Chinese",
              "Arabic",
              "Russian"
            ],
            "default": "en",
            "prefill": "en"
          },
          "maxConcurrency": {
            "title": "Places scraped in parallel",
            "type": "integer",
            "description": "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).",
            "default": 3,
            "prefill": 3,
            "minimum": 1,
            "maximum": 8,
            "sectionCaption": "Speed, retries and failures",
            "sectionDescription": "Control throughput and how much effort is spent on places Google does not return on the first try."
          },
          "maxAttemptsPerPlace": {
            "title": "Max attempts per place",
            "type": "integer",
            "description": "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.",
            "default": 8,
            "prefill": 8,
            "minimum": 1,
            "maximum": 12
          },
          "placeTimeoutSecs": {
            "title": "Time limit per place",
            "type": "integer",
            "unit": "seconds",
            "description": "Hard time limit for one place across all of its attempts.",
            "default": 240,
            "prefill": 240,
            "minimum": 30,
            "maximum": 600
          },
          "includeFailedPlaces": {
            "title": "Include unavailable places in the output",
            "type": "boolean",
            "description": "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.",
            "default": false,
            "prefill": false
          },
          "includeLatestReviews": {
            "title": "Include newest reviews and closure mentions",
            "type": "boolean",
            "description": "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.",
            "default": false,
            "prefill": false,
            "sectionCaption": "Closure monitoring",
            "sectionDescription": "Extra signals for tracking places that may have closed or are losing customers. Run the actor on a schedule with the same monitoring key to compare every reading with earlier ones."
          },
          "latestReviewsCount": {
            "title": "Newest reviews per place",
            "type": "integer",
            "description": "How many of the newest reviews to return and check for closure mentions (used when newest reviews are included).",
            "default": 10,
            "prefill": 10,
            "minimum": 1,
            "maximum": 60
          },
          "monitoringKey": {
            "title": "Monitoring key",
            "type": "string",
            "description": "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.",
            "editor": "textfield"
          },
          "lowActivityRatio": {
            "title": "Low activity threshold (live / usual)",
            "type": "number",
            "description": "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.",
            "default": 0.25,
            "prefill": 0.25,
            "minimum": 0.05,
            "maximum": 1
          },
          "minUsualBusyness": {
            "title": "Busy-hour threshold (usual busyness %)",
            "type": "integer",
            "description": "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.",
            "default": 30,
            "prefill": 30,
            "minimum": 5,
            "maximum": 100
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "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.",
            "editor": "proxy",
            "sectionCaption": "Proxy fallback",
            "sectionDescription": "Proxies are only used as a last resort for places that direct access could not retrieve."
          }
        },
        "required": []
      },
      "output": {
        "actorOutputSchemaVersion": 1,
        "title": "Google Maps Place Data & Popular Times (When Available) Output",
        "description": "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.",
        "properties": {
          "popularTimes": {
            "type": "string",
            "title": "Place data and Popular Times records",
            "description": "All records: place identity, listing details, open status, coordinates and local time; hourly busyness per day and live/usual busyness when available; and an explicit dataStatus/limitedViewReason when Google serves its limited view.",
            "template": "{{links.apiDefaultDatasetUrl}}/items"
          },
          "liveMonitoring": {
            "type": "string",
            "title": "Live monitoring view",
            "description": "Compact table for monitoring: live busyness vs the usual level, live label, open status, listing status and the reason for any unavailable place.",
            "template": "{{links.apiDefaultDatasetUrl}}/items?view=liveMonitoring"
          },
          "closureSignals": {
            "type": "string",
            "title": "Closure signals view",
            "description": "Per place: listing status, live reading status and live/usual ratio, review recency, closure mentions in the newest reviews and run-to-run monitoring signals.",
            "template": "{{links.apiDefaultDatasetUrl}}/items?view=closureSignals"
          }
        }
      },
      "defaultRunOptions": {
        "timeoutSecs": 3600,
        "memoryMbytes": 4096
      },
      "defaultMemoryMbytes": 4096,
      "minMemoryMbytes": 2048,
      "maxMemoryMbytes": 8192,
      "storages": {
        "dataset": {
          "actorSpecification": 1,
          "views": {
            "overview": {
              "title": "Place data & Popular Times",
              "transformation": {
                "fields": [
                  "recordType",
                  "businessName",
                  "placeId",
                  "featureId",
                  "cid",
                  "category",
                  "address",
                  "latitude",
                  "longitude",
                  "timezone",
                  "phone",
                  "website",
                  "profileImageUrl",
                  "rating",
                  "reviewCount",
                  "businessStatus",
                  "isOpenNow",
                  "openStatusText",
                  "popularTimesHasData",
                  "popularTimesAvailable",
                  "dataStatus",
                  "limitedViewReason",
                  "liveReadingStatus",
                  "currentBusyness",
                  "usualBusyness",
                  "liveToUsualRatio",
                  "currentBusynessLevel",
                  "currentBusynessDay",
                  "currentBusynessHour",
                  "currentBusynessText",
                  "typicalTimeSpent",
                  "popularTimes",
                  "closureMentionCount",
                  "latestReviewAt",
                  "googleMapsUrl",
                  "failureReason",
                  "attempts",
                  "sourceUrl",
                  "scrapedAt"
                ]
              },
              "display": {
                "component": "table",
                "properties": {
                  "recordType": {
                    "label": "Record type"
                  },
                  "businessName": {
                    "label": "Business name"
                  },
                  "placeId": {
                    "label": "Place ID"
                  },
                  "featureId": {
                    "label": "Feature ID"
                  },
                  "cid": {
                    "label": "CID"
                  },
                  "category": {
                    "label": "Category"
                  },
                  "address": {
                    "label": "Address"
                  },
                  "latitude": {
                    "label": "Latitude"
                  },
                  "longitude": {
                    "label": "Longitude"
                  },
                  "timezone": {
                    "label": "Time zone"
                  },
                  "phone": {
                    "label": "Phone"
                  },
                  "website": {
                    "label": "Website",
                    "format": "link"
                  },
                  "profileImageUrl": {
                    "label": "Photo",
                    "format": "image"
                  },
                  "rating": {
                    "label": "Rating"
                  },
                  "reviewCount": {
                    "label": "Reviews"
                  },
                  "businessStatus": {
                    "label": "Listing status"
                  },
                  "isOpenNow": {
                    "label": "Open now"
                  },
                  "openStatusText": {
                    "label": "Open status"
                  },
                  "popularTimesHasData": {
                    "label": "Has popular times"
                  },
                  "popularTimesAvailable": {
                    "label": "Popular times available"
                  },
                  "dataStatus": {
                    "label": "Data status"
                  },
                  "limitedViewReason": {
                    "label": "Limited-view reason"
                  },
                  "liveReadingStatus": {
                    "label": "Live reading status"
                  },
                  "currentBusyness": {
                    "label": "Live busyness (%)"
                  },
                  "usualBusyness": {
                    "label": "Usual busyness (%)"
                  },
                  "liveToUsualRatio": {
                    "label": "Live / usual"
                  },
                  "currentBusynessLevel": {
                    "label": "Live label"
                  },
                  "currentBusynessDay": {
                    "label": "Live reading day"
                  },
                  "currentBusynessHour": {
                    "label": "Live reading hour"
                  },
                  "currentBusynessText": {
                    "label": "Live text"
                  },
                  "typicalTimeSpent": {
                    "label": "Typical time spent"
                  },
                  "popularTimes": {
                    "label": "Popular times (hourly)",
                    "format": "object"
                  },
                  "closureMentionCount": {
                    "label": "Closure mentions"
                  },
                  "latestReviewAt": {
                    "label": "Latest review",
                    "format": "date"
                  },
                  "googleMapsUrl": {
                    "label": "Google Maps link",
                    "format": "link"
                  },
                  "failureReason": {
                    "label": "Failure reason"
                  },
                  "attempts": {
                    "label": "Attempts"
                  },
                  "sourceUrl": {
                    "label": "Source URL",
                    "format": "link"
                  },
                  "scrapedAt": {
                    "label": "Scraped at",
                    "format": "date"
                  }
                }
              }
            },
            "liveMonitoring": {
              "title": "Live monitoring",
              "transformation": {
                "fields": [
                  "recordType",
                  "businessName",
                  "placeId",
                  "featureId",
                  "placeUrl",
                  "businessStatus",
                  "isOpenNow",
                  "openStatusText",
                  "dataStatus",
                  "limitedViewReason",
                  "liveReadingStatus",
                  "currentBusyness",
                  "usualBusyness",
                  "liveToUsualRatio",
                  "liveMinusUsual",
                  "usualBusynessAtObservedHour",
                  "currentBusynessLevel",
                  "currentBusynessDay",
                  "currentBusynessHour",
                  "observedAtLocal",
                  "timezone",
                  "failureReason",
                  "scrapedAt"
                ]
              },
              "display": {
                "component": "table",
                "properties": {
                  "recordType": {
                    "label": "Record type"
                  },
                  "businessName": {
                    "label": "Business name"
                  },
                  "placeId": {
                    "label": "Place ID"
                  },
                  "featureId": {
                    "label": "Feature ID"
                  },
                  "placeUrl": {
                    "label": "Place URL",
                    "format": "link"
                  },
                  "businessStatus": {
                    "label": "Listing status"
                  },
                  "isOpenNow": {
                    "label": "Open now"
                  },
                  "openStatusText": {
                    "label": "Open status"
                  },
                  "dataStatus": {
                    "label": "Data status"
                  },
                  "limitedViewReason": {
                    "label": "Limited-view reason"
                  },
                  "liveReadingStatus": {
                    "label": "Live reading status"
                  },
                  "currentBusyness": {
                    "label": "Live busyness (%)"
                  },
                  "usualBusyness": {
                    "label": "Usual busyness (%)"
                  },
                  "liveToUsualRatio": {
                    "label": "Live / usual"
                  },
                  "liveMinusUsual": {
                    "label": "Live − usual (points)"
                  },
                  "usualBusynessAtObservedHour": {
                    "label": "Usual at observed hour (%)"
                  },
                  "currentBusynessLevel": {
                    "label": "Live label"
                  },
                  "currentBusynessDay": {
                    "label": "Live reading day"
                  },
                  "currentBusynessHour": {
                    "label": "Live reading hour"
                  },
                  "observedAtLocal": {
                    "label": "Observed at (local time)"
                  },
                  "timezone": {
                    "label": "Time zone"
                  },
                  "failureReason": {
                    "label": "Failure reason"
                  },
                  "scrapedAt": {
                    "label": "Scraped at",
                    "format": "date"
                  }
                }
              }
            },
            "closureSignals": {
              "title": "Closure signals",
              "transformation": {
                "fields": [
                  "businessName",
                  "placeId",
                  "featureId",
                  "address",
                  "businessStatus",
                  "isOpenNow",
                  "liveReadingStatus",
                  "liveToUsualRatio",
                  "rating",
                  "reviewCount",
                  "latestReviewAt",
                  "daysSinceLatestReview",
                  "closureMentionCount",
                  "latestClosureMentionAt",
                  "monitoring",
                  "googleMapsUrl",
                  "scrapedAt"
                ]
              },
              "display": {
                "component": "table",
                "properties": {
                  "businessName": {
                    "label": "Business name"
                  },
                  "placeId": {
                    "label": "Place ID"
                  },
                  "featureId": {
                    "label": "Feature ID"
                  },
                  "address": {
                    "label": "Address"
                  },
                  "businessStatus": {
                    "label": "Listing status"
                  },
                  "isOpenNow": {
                    "label": "Open now"
                  },
                  "liveReadingStatus": {
                    "label": "Live reading status"
                  },
                  "liveToUsualRatio": {
                    "label": "Live / usual"
                  },
                  "rating": {
                    "label": "Rating"
                  },
                  "reviewCount": {
                    "label": "Reviews"
                  },
                  "latestReviewAt": {
                    "label": "Latest review",
                    "format": "date"
                  },
                  "daysSinceLatestReview": {
                    "label": "Days since latest review"
                  },
                  "closureMentionCount": {
                    "label": "Closure mentions"
                  },
                  "latestClosureMentionAt": {
                    "label": "Latest closure mention",
                    "format": "date"
                  },
                  "monitoring": {
                    "label": "Monitoring history",
                    "format": "object"
                  },
                  "googleMapsUrl": {
                    "label": "Google Maps link",
                    "format": "link"
                  },
                  "scrapedAt": {
                    "label": "Scraped at",
                    "format": "date"
                  }
                }
              }
            }
          }
        }
      },
      "environmentVariables": {}
    },
    "buildNumber": "1.0.2",
    "imageDigest": "e3b6e24eae1f984c6be1e5d964a14b06415a644a14897fd5e62f6166988daf79",
    "actVersion": {
      "sourceType": "SOURCE_FILES",
      "buildTag": "latest",
      "versionNumber": "1.0"
    },
    "usage": {
      "ACTOR_COMPUTE_UNITS": 0.03489444444444444
    }
  }
}