Google Maps Change Monitor 📍 Track listings, pay per change
Pricing
Pay per event
Google Maps Change Monitor 📍 Track listings, pay per change
✅ Watch Google Maps listings and get ONLY what moved — rating, reviews, phone, website, hours, closures — with the old value next to the new one. ✅ Unchanged places are not delivered and not charged. ✅ Also does one-off extraction of the full business record.
Pricing
Pay per event
Rating
0.0
(0)
Developer
Radosław Szal
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Share
Google Maps Change Monitor — track listings, pay per change
Unofficial. This Actor is not affiliated with, endorsed by, or sponsored by Google LLC. "Google Maps" is a trademark of its respective owner and is used here only to describe what this Actor reads. We are an independent developer and this tool is provided as-is.
Watch a list of businesses and get only what moved. Run it once to take a baseline, then on a schedule. Every later run delivers the places whose rating, review count, phone, website, opening hours or status changed — with the old value next to the new one. Unchanged places are not delivered and not charged, so watching 300 businesses daily costs what the movement costs, not 300 charges every morning.
| run on the same watch list | places checked | delivered & charged | unchanged — free |
|---|---|---|---|
| first run (takes the baseline) | 39 | 39 | — |
| a later run | 37 | 20 | 17 |
Measured on a live watch list of Denver dentists, 31 August 2026. The first run always delivers everything, because there is nothing yet to compare against.
A changed record tells you what moved:
{"name": "Warsaw Dental Center","changeType": "changed","changed": { "rating": { "from": 4.8, "to": 4.6 },"reviewCount": { "from": 312, "to": 340 } },"ratingChange": -0.2,"newReviews": 28,"phone": "+48 22 542 18 04","website": "https://warsawdentalcenter.pl/","googleMapsUrl": "https://www.google.com/maps/place/..."}
A business that closed is the loudest signal this list carries — it arrives as a change with
"closed": true, even if you asked to skip closed businesses, because "keep them off my list" and
"tell me when mine shuts down" are two different requests.
It also does plain one-off extraction. Leave onlyChanged off and you get the full business
record: name, category, address, phone, website, rating, review count, opening hours, coordinates,
placeId.
Three things this one does that the others do not
1. Every record tells you whether the list ran out
listComplete: false means you are not looking at the whole list — never that there were no
more businesses. The run status tells you which of the two reasons applied, because they are not
the same thing and the difference changes what you should do:
LIST NOT EXHAUSTED for: …— Google still had results we could not page through.TRUNCATED BY YOUR LIMIT for: …— we found the whole list and handed you part of it, becausemaxItemsPerTermormaxItemssaid so. Raising the limit gets the rest; there is nothing further to discover at Google.
This is not a detail. A market analysis built on 120 records is worth something if 120 is all there is, and worth nothing if it is where the budget ran out. Without this field the two look identical.
2. The same business is one record, not two
Google returns duplicates inside a single response — measured on 2026-08-11, forty result cards contained thirty-six distinct businesses. Across several searches the overlap is larger still.
We merge on the Google Place ID, never on the name: one city holds five places called Starbucks,
and merging by name would quietly delete four of them. A record we cannot identify is delivered
with deduplicated: false rather than merged into something it might not be.
3. Filters are free
Ask for open only, rated 4+, with a website and the price does not move. A filter is not an add-on — it is how you tell us what you want, and charging for it would penalise you for saving us work. You are billed for delivered businesses and nothing else: not for results a filter removed, not for merged duplicates, not for a run that found nothing.
Compare before you assume this is normal: the leading Google Maps Actor charges $0.001 per place per filter applied, so three filters raise the bill by 75% above its headline price.
Two fields that need a word of explanation
reviewCount is often null, and that never means "no reviews." Google shows the review
count next to the rating for some results in the search list and not for others — measured on
2026-08-14: one card in twenty-two carried it, and waiting longer did not change that. Opening
each business page would get it, at one extra page load per place; this Actor deliberately does
not do that, because it would multiply your cost and your run time for a field you may not need.
When the count is there, you get it. When it is not, the field is null — never 0.
isSponsored: true marks Google's paid placements. They come mixed in with ordinary results,
and the same business can appear twice: once as an advert and once normally. On the advert the
"website" is a Google click-tracking address rather than the company's own site, so we leave
website empty there rather than hand you a tracking link. Filter on this field if you want only
organic results.
Search terms: name the country
dentist in Warsaw returns dentists in Warsaw, Poland and in Warsaw, Indiana, mixed together —
we measured it. Google has no idea which one you meant and neither do we. Write
dentist in Warsaw, Poland, or put the area once in the Area field and let it apply to every
term.
Every record carries the searchTerm it came from, so wrong-city results are visible in the data
rather than hidden in an average.
Input
| field | meaning |
|---|---|
searchTerms | one or more searches, exactly as you would type them into Google Maps |
searchArea | appended to every term, so you write the city once |
maxItems | hard cap for the whole run — also your cost ceiling |
maxItemsPerTerm | keeps one broad search from eating the entire budget |
minRating | free filter; places with no rating are excluded when set |
skipClosedBusinesses | free filter; closed businesses do still appear in Google Maps |
onlyWithWebsite | free filter |
language | affects category names and how opening hours are worded |
includeContacts | on by default; off leaves phone and website out and skips the contact charge |
onlyChanged | watch mode: deliver and charge only what moved since your last run |
watchLabel | names the watch list, so two schedules do not overwrite each other's memory |
Give language a plain code (pl, de, es) and we pick the matching region for you. A full
code works too if it is a real one — pt-BR, en-GB, es-MX. A combination that does not exist,
like pl-US, is not passed through: the browser would silently fall back to US English and you
would be filtering categories you never asked for. We substitute the language's own region and say
so in the log.
Watch mode: pay for what moved, not for the same list again
This is the reason to put this Actor on a schedule, and the one thing the alternatives do not do.
Set onlyChanged: true and give the run a watchLabel. The first run hands you the full list and
remembers it. Every run after that compares what it finds against that memory and delivers only
the places that actually changed — with the previous value next to the new one, so you do not
have to keep your own history.
| you get | when |
|---|---|
changeType: "new" | a place we had never seen on this watch list |
changeType: "changed" + changed | rating, review count, phone, website, hours or status moved |
changeType: "missing" | a place that was on the list before and is not in the current results |
| nothing | the place is exactly as it was — not delivered, not charged |
Watching 300 restaurants daily therefore costs what the movement costs — usually a few percent of the list — instead of 300 charges every morning.
Three things we say out loud, because they decide whether you can trust the alert:
missingdoes not mean "closed". It means the place was not in the results we saw. Google reshuffles rankings. Everymissingrecord carries that caveat in the record itself.- If part of the list was not searched — a term timed out, hit a consent wall, or your
maxItemsran out — we do not report disappearances at all that run, and the run card says so. Absence of evidence is not evidence of absence. - A place removed by your own filters is not silently swallowed. If a watched place changed but
your
minRatingoronlyWithWebsitefilter removed it, the run card tells you how many.
Two schedules watching different lists need two different watchLabel values, otherwise they
overwrite each other's memory and everything looks new.
What it costs
Two charges, and you can switch the second one off.
| charged event | when | price on the free plan |
|---|---|---|
| Scraped place | every business actually delivered to your dataset | $0.005 |
| Contact included | on top, and only when that place really has a phone number or a website | $0.004 |
Both drop with your Apify plan — down to $0.0008 and $0.0007 on the Diamond tier.
If you do not need contacts, switch off includeContacts. The phone and website fields are
then left out of the record entirely and the second charge never happens: you pay $0.005 per
place, full stop.
Nothing is charged for results a filter removed, for duplicates merged into one record, for a run that found nothing, or for a business we handed you after failing to save the run state.
The whole-run ceiling is maxItems. With contacts on, maxItems: 500 cannot cost more than
500 × ($0.005 + $0.004) = $4.50 on the free plan — and less if some places have no phone or
website, because those are not charged the second event. With contacts off it cannot exceed
500 × $0.005 = $2.50. Set maxTotalChargeUsd on the run if you want a hard cap in dollars.
Limits, stated up front
- Reviews and reviewer names are out of scope. They are personal data and copyrighted text at the same time, and this Actor does not touch them.
- No email harvesting from business websites. The
websitefield is the address Google shows; we do not visit it. - We only use the paths Google's
robots.txtallows (/maps/search/,/maps/place/). The cheaper internal endpoint that other tools call sits underDisallow: /search, and we do not build that address. This costs us speed and we accept it. - A residential proxy is required. Google does not serve Maps to datacentre addresses. The default already selects one.
- No "scrape a whole city" mode, and there will not be one. This Actor runs your query.
- A business whose name looks like a street number can land in
address. When Google gives us neither a category nor a separate address line for a card — only the name — we decide which field it belongs to by shape.Topiel 11is an address;7-Elevenis not, and we get that right. But24/7 Fitnesshas the shape of a Polish house number (4/6) and will be read as an address. Every rule we tried that fixed this broke a real address somewhere else, so we are telling you instead of guessing better. It affects only cards where Google published nothing but the name. - Google's consent screen can stop a run, and we will say so. Outside the EU, Google sometimes
puts a cookie-consent wall in front of Maps. We click it through five different selectors, two of
which are language-independent, but we cannot promise all 23 supported languages. When the wall
is there and none of our selectors matched it, the run returns zero places, charges you
nothing, and the log says plainly that this is our bug — not "no such businesses". Retry with a
different proxy country (
proxyConfiguration.apifyProxyCountry) and tell us which language it was; that is the one thing we cannot test without hitting the wall ourselves.
If it worked for you
Ratings are the one thing we cannot build ourselves, and on Apify they feed the quality score that decides whether anyone finds this Actor at all. If it did the job, a rating takes a few seconds and genuinely changes what happens to it.
If it did not do the job, the issue tab is more useful to us than a low rating with no detail — tell us the search that failed and what you expected, and it becomes a test case in the next release.


