# Changelog of Google Maps Scraper with Emails (`al_mansouri/verified-maps-harvester`) Actor

- **URL**: https://apify.com/al\_mansouri/verified-maps-harvester/changelog.md
- **Full Actor documentation**: https://apify.com/al\_mansouri/verified-maps-harvester.md

## Changelog

### 0.1.0 — unreleased

First private build.

#### Added

- Place harvesting for a named location or a customer-supplied GeoJSON area (`Polygon`,
  `MultiPolygon`, or `Point` with `radiusKm`).
- Areas resolved through OpenStreetMap, so a search follows a real administrative outline rather
  than a bounding square.
- Adaptive subdivision. A map view that returns at Google's ~120-result ceiling is treated as
  truncated and split into quadrants, rather than accepted as complete.
- A `COVERAGE` record written once per run, stating whether the requested area was read
  exhaustively and, when it was not, why.
- Per-place output carrying all four Google identifiers — `placeId`, `cid`, `fid`, `kgmid` — plus
  category, address, coordinates, rating, review count, price band, description, opening status,
  and service options.
- Pay-per-event charging on `place-scraped`. Failed rows are never charged.
- Optional dedicated worker, configured through Actor environment variables
  (`MAPS_GATEWAY_URL`, `MAPS_GATEWAY_TOKEN`) and never through customer input. The Actor
  preflights it and runs the work in its own container when it is unavailable or is running a
  different DOM revision, so output is identical either way and an outage costs margin rather
  than a run. `COVERAGE.worker` records which runtime served the run.

#### Added in this version

- `scrapePlaceDetails` opens each place's own page for `website`, `phone`, `phoneUnformatted`,
  address components, `plusCode`, `categories`, opening hours, `reviewsDistribution` and
  `reviewsTags`. None of these appear in Google's results list.

- `enrichContacts` reads each website for `emails` and `socials`, using the same extractor the
  contact-finder Actor runs.

- `fieldSources` records whether each value came from the results list, the place's page, or the
  website.

- Two further charge tiers, `place-detailed` and `place-enriched`, billed at what a row actually
  carries rather than what was requested. `place-enriched` needs an email address or a social
  profile: a website that publishes only its own company name is billed as `place-detailed`, even
  though reading it cost the same.

- `WORKER_UNAVAILABLE`, for the one failure that is entirely ours: harvesting capacity was
  configured and could not be reached. The run fails, publishes nothing and charges nothing,
  rather than falling back to a runtime that cannot reach Google from this platform and returning
  an empty dataset on a successful-looking run. `RAN_LOCALLY` is gone from `COVERAGE` with it —
  the fallback it described no longer exists.

#### Notes

- Prices are set from measured platform cost: $0.000283 per place at the base tier over 113
  places, $0.001375 enriched over 40. Measured at a realistic place count on purpose -- a 10-place
  run reports three times the marginal rate, because the fixed container start dominates it.
- Reviews are out of scope. The reviews panel renders inconsistently and the direct endpoint
  returns bot detection, and reviewer identity is the one part of Google Maps that is squarely
  personal data. `reviewsDistribution` and `reviewsTags` give the aggregate signal without it.
- Photos are not collected. Image requests are aborted to keep a run near 284 KB per place, and
  loading them purely to harvest URLs would multiply the largest cost in the run.
- Only today's opening hours are available; the weekly table sits behind a control that does not
  expand for an automated click.
