Google Maps Extractor Listing Completeness Audit
Pricing
from $5.99 / 1,000 results
Google Maps Extractor Listing Completeness Audit
Google Maps Extractor: Extract business listings with names, categories, ratings, reviews, addresses, phone numbers, websites, hours, and Google Maps URLs. Audit listing completeness to identify missing business information, optimize local profiles, and uncover data quality gaps.
Pricing
from $5.99 / 1,000 results
Rating
0.0
(0)
Developer
Scrapier
Maintained by CommunityActor stats
0
Bookmarked
9
Total users
0
Monthly active users
10 days ago
Last modified
Categories
Share
Google Maps Extractor — Score Business Listing Completeness
Google Maps Extractor — Listing Completeness Audit scrapes Google Maps business listings and scores how complete each Google Business Profile is: a profile_completeness_score from 0 to 100, a missing_fields gap list, and the evidence behind both. Every field the standard Google Maps Extractor returns — address, phone, hours, rating, place ID — rides on the same row. Results come back as structured JSON, ready to filter into a prospect list, pass to an LLM, or load into a spreadsheet. No Google account, API key, or Places API billing required.
🧭 What is Google Maps Extractor — Listing Completeness Audit?
Google Maps Extractor — Listing Completeness Audit searches Google Maps by business category and area, then audits every distinct listing it finds against six Google Business Profile completeness components — with a seventh, Street View, if you turn on the extra lookup. It runs on the same tile-sweep collection engine as the base Google Maps Extractor, so every row still carries the base extractor's address, rating, phone and category columns. What sets this variant apart is the audit layer: a 0-100 profile_completeness_score, a missing_fields gap list naming exactly what each listing lacks, and weak-listing filters that keep only the profiles worth working. No Google account, API key, or Google Places API billing is required — the Actor connects through Apify Proxy like any other web request.
- 📛 Business listing data — name, address, phone, website, category tags, coordinates and today's opening hours, identical to the base extractor
- 🩺 Completeness score and gap list —
profile_completeness_scoreplus amissing_fieldsarray naming which of the 6 (or 7) components are absent - 🕳️ Weak-listing filters —
maxCompletenessScoreandrequiredGapskeep only the listings worth pitching, so the filtering happens in the run instead of in a spreadsheet afterward - 🛣️ Optional Street View & owner lookup —
auditMediaDepthaddshas_street_view,street_view_thumbnailandowner_display_namefor one extra request per listing - 🗺️ Query controls —
locations+keywordsswept across a geocoded tile grid, orurlsto audit from a specific Google Maps link instead - 📐 Area confinement —
restrictToSearchAreadrops listings outside the requested bounding box, after first checking that the connection is honouring the requested coordinates at all
📦 What data can you get with Google Maps Extractor — Listing Completeness Audit?
Every audited listing returns three kinds of data on the same row: the base Google Maps listing fields, the completeness audit fields, and the evidence behind the score.
| Result Type | Extracted Fields | Primary Use Case |
|---|---|---|
| Business listing | name, full_address, street_address, city, state, zip, country_code, website, phone, avg_rating, tags, place_id, lat, long, hours, rowType | Standard NAP data and prospecting |
| Completeness audit | profile_completeness_score, missing_fields, present_field_count, scored_component_count, has_website, has_phone, has_hours, has_description, has_accessibility_info, has_booking_link, has_street_view | Scoring, sorting and filtering weak listings |
| Evidence | description, description_tagline, accessibility_features, neighborhood, thumbnail_url, street_view_thumbnail, owner_display_name | Proof behind the score, outreach personalization |
🩺 Listing completeness score and gap list
profile_completeness_score is a weighted percentage of the components that were actually evaluated for that listing — website (20), phone (20), today's opening hours (15), editorial description (15), accessibility info (10) and booking/ordering link (10), plus Street View (5) when the extra lookup is on. missing_fields lists exactly which of those failed, using the same values as the requiredGaps filter, so the two line up 1:1. With the Street View lookup off, that component is dropped from both sides of the ratio rather than counted as a gap — scored_component_count tells you whether a row was judged on 6 or 7 components. A photo/gallery-size component was deliberately not built: the place-detail lookup this Actor uses returns exactly one photo on every listing, so "has a photo" would be true 100% of the time and would only inflate every score by a fixed amount.
{"profile_completeness_score": 55,"missing_fields": ["description", "booking_link"],"present_field_count": 5,"scored_component_count": 7,"has_website": true,"has_phone": true,"has_hours": true,"has_description": false,"has_accessibility_info": true,"has_booking_link": false,"has_street_view": true}
📛 Business listing fields
The base row carried over from the standard Google Maps Extractor: full_address is Google's own formatted one-line address, not a concatenation of parts, and hours is a list of {day, hours, opens_at, closes_at} objects with "HH:MM" start/end times. place_id is Google's stable identifier, used internally to deduplicate listings across areas and categories. This is the data set most Google Maps scrapers stop at — here it rides on the same row as the audit fields above, so a lead list and a completeness score never need to be joined manually.
🆚 How does this differ from the official Google Places API?
The Google Places API (New) returns place fields you request by SKU tier, but it does not compute a completeness score or a gap list — that logic has to be built by whoever calls it. As of 2026-08-04, its published documentation (Place Details (New)) shows phone number, opening hours, price level, rating and website gated behind the "Enterprise" SKU, and reviews/accessibility/amenities behind "Enterprise + Atmosphere" — each billed per request against a Google Cloud project.
| Feature | Google Places API (New) | Google Maps Extractor — Listing Completeness Audit |
|---|---|---|
| Search by keyword + area | Yes, via Text Search / Nearby Search endpoints | Yes, via keywords + locations swept across a tile grid |
| Listing completeness score | Not computed — raw fields only | profile_completeness_score and missing_fields, computed automatically |
| Setup requirement | API key + billing-enabled Google Cloud project | An Apify account and a run — no API key |
| Pricing model | Per-field SKU tiers, billed per request | One pay-per-event charge per audited listing returned |
| Phone, hours, website | Gated behind the "Enterprise" SKU | Included on every row |
| Accessibility, booking link | Gated behind "Enterprise + Atmosphere" | Included on every row, no tier gating |
| Area-wide sweep with confinement check | Not applicable — per-query results, no bounding-box verification | Geo-preflight check confirms the connection honours the requested area before saving |
The official API is the right choice for a production app that needs a directly Google-operated endpoint and pays per field it actually uses. This Actor is the better fit for bulk prospecting runs across many areas and categories, where an automatic completeness score matters more than a direct Google support contract.
🔍 What is the difference between a Google Maps scraper and a Google Business Profile completeness audit?
A Google Maps scraper returns a list of places — name, address, phone, rating. A Google Business Profile completeness audit takes that same list and asks a second question for every row: what is this listing missing? The distinction matters because a raw place list treats every listing the same, while a local-SEO or lead-generation workflow only cares about the listings with a gap to sell against — a missing website, no booking link, no accessibility info.
Google Maps Extractor — Listing Completeness Audit returns both in one run: the plain listing data (the JSON object's full_address, phone, website, hours and related keys) and the audit data (profile_completeness_score, missing_fields, and the has_* booleans) on the same row, plus filters (maxCompletenessScore, requiredGaps) that turn the place list into a prospect list directly, without a separate scoring step afterward.
🛠️ How to scrape Google Maps business listings with Google Maps Extractor?
- Open Google Maps Extractor — Listing Completeness Audit on the Apify Store and click Try for free (or Run, if you already have it saved).
- Enter at least one business category in
keywords— this is the Actor's only required field, e.g.["dentists"]. - Add one or more areas in
locations(e.g.["Austin", "Brooklyn"]), or paste a Google Maps link intourlsinstead. - Set the real query controls:
maxCompletenessScoreandrequiredGapsto define what counts as a weak listing,auditMediaDepthto turn the Street View lookup on or off, andmaxResultsfor how many audited listings you want back. - Click Start, then download the results as JSON, CSV, Excel or the Apify API once the run finishes.
{"locations": ["Austin"],"keywords": ["dentists"],"maxCompletenessScore": 70,"requiredGaps": ["website"]}
📚 How to run multiple areas and categories in one job
locations and keywords are both arrays: every category is searched in every area, so two areas and three categories run as six searches in the same job, sharing one maxResults budget and deduplicating by Google place ID across all of them. urls runs alongside them as additional targets rather than replacing them. There is no separate concurrency setting to configure — the Actor manages its own tile-sweep parallelism internally.
⬇️ Input
Every field below comes straight from the Actor's input schema (.actor/actor.json) — same names, same types, same defaults.
| Parameter | Required | Type | Description | Example Value |
|---|---|---|---|---|
locations | No | array of strings | City, district or region names, e.g. Austin, Brooklyn, Manchester. One area per line — several areas run one after another. Default: ["New York"]. | ["Austin", "Brooklyn"] |
keywords | Yes | array of strings | What the listings should be, e.g. dentists, coffee shops, plumbers, hair salons. Each category is searched in every area above. Default: ["coffee shops"]. | ["dentists"] |
maxCompletenessScore | No | integer (0–100) | A listing is kept only when its profile_completeness_score is at or below this number. Lower values return fewer, more broken listings. Default: 100 (keep everything). | 60 |
requiredGaps | No | array (enum, multi-select) | A listing is kept only when it is missing every item ticked. Enum values: website, phone, hours, description, accessibility_info, booking_link, street_view. Default: []. | ["website"] |
auditMediaDepth | No | string (enum) | fetch = one extra lookup per listing, adding has_street_view, street_view_thumbnail and owner_display_name, scoring 7 components instead of 6. skip = listing payload only. Default: "fetch". | "fetch" |
maxResults | No | integer (1–10000) | Total unique listings saved across all areas, categories and links. Duplicates are merged by Google place ID. Default: 20. | 50 |
restrictToSearchArea | No | boolean | Drops every listing whose coordinates fall outside the geocoded bounding box of the requested area, after verifying the connection honours the requested coordinates. Default: true. | true |
urls | No | array of strings | Full Google Maps links, e.g. https://www.google.com/maps/search/dentists/@30.2672,-97.7431,13z — the search term and coordinates are both read from the link. Default: []. | ["https://www.google.com/maps/search/dentists/@30.2672,-97.7431,13z"] |
proxyConfiguration | No | object | Your proxy groups and country, passed through unchanged. Default: {"useApifyProxy": true}. | {"useApifyProxy": true} |
Example JSON input:
{"locations": ["Austin"],"keywords": ["dentists"],"maxCompletenessScore": 70,"requiredGaps": ["website"],"auditMediaDepth": "fetch","maxResults": 50,"restrictToSearchArea": true,"urls": [],"proxyConfiguration": { "useApifyProxy": true }}
⚠️ Pitfall: requiredGaps only accepts the seven enum values above — anything else is silently dropped rather than erroring. If you tick street_view in requiredGaps while auditMediaDepth is set to skip, the Actor turns the Street View lookup back on automatically for that run, because that gap cannot be judged without it. keywords is the only field the schema marks as required, but the run itself also needs at least one of locations or urls — an empty run with neither fails immediately rather than silently returning nothing.
⬆️ Output
Each run produces one dataset row per audited listing — typed, normalized JSON with a consistent schema across runs. Results can be downloaded as JSON, CSV, Excel, XML or HTML directly from the Apify Console, or pulled through the Apify API in the same formats. Three dataset views are provided on the Actor's page: Audit score & gaps (the default, 19 columns), Evidence behind the score, and All Google Maps place fields — all three read from the same underlying rows shown below.
📄 Scraped results
[{"rowType": "place","name": "Katz's Delicatessen","place_id": "ChIJCar0f49ZwokR6ozLV-dHNTE","street_address": "205 E Houston St","city": "New York","state": "NY","zip": "10002","country_code": "US","full_address": "205 E Houston St, New York, NY 10002","tags": ["Delicatessen", "Sandwich shop"],"website": "https://katzsdelicatessen.com/","phone": "(212) 254-2246","avg_rating": 4.6,"lat": 40.7223274,"long": -73.9873733,"hours": [{ "day": "Sunday", "hours": "8 AM-10:45 PM", "opens_at": "08:00", "closes_at": "22:45" }],"profile_completeness_score": 100,"missing_fields": [],"present_field_count": 7,"scored_component_count": 7,"has_website": true,"has_phone": true,"has_hours": true,"has_description": true,"has_accessibility_info": true,"has_booking_link": true,"has_street_view": true,"accessibility_features": ["Wheelchair accessible entrance", "Wheelchair accessible restroom"],"description": "Iconic Jewish deli slinging hand-carved pastrami since 1888.","description_tagline": "Legendary NYC deli","neighborhood": "Manhattan","thumbnail_url": "https://lh5.googleusercontent.com/p/example1=w152-h86","street_view_thumbnail": "https://streetviewpixels-pa.googleapis.com/v1/thumbnail?example1","owner_display_name": null},{"rowType": "place","name": "Sunrise Coffee Bar","place_id": "ChIJexampleplace002","street_address": "48 Nostrand Ave","city": "Brooklyn","state": "NY","zip": "11206","country_code": "US","full_address": "48 Nostrand Ave, Brooklyn, NY 11206","tags": ["Coffee shop"],"website": null,"phone": "(718) 555-0142","avg_rating": 4.1,"lat": 40.6987,"long": -73.9498,"hours": [{ "day": "Monday", "hours": "7 AM-4 PM", "opens_at": "07:00", "closes_at": "16:00" }],"profile_completeness_score": 55,"missing_fields": ["website", "booking_link"],"present_field_count": 5,"scored_component_count": 7,"has_website": false,"has_phone": true,"has_hours": true,"has_description": true,"has_accessibility_info": true,"has_booking_link": false,"has_street_view": true,"accessibility_features": ["Wheelchair accessible entrance"],"description": "Neighborhood coffee bar with in-house roasted beans.","description_tagline": null,"neighborhood": "Bedford-Stuyvesant","thumbnail_url": "https://lh5.googleusercontent.com/p/example2=w152-h86","street_view_thumbnail": "https://streetviewpixels-pa.googleapis.com/v1/thumbnail?example2","owner_display_name": "Sunrise Coffee Bar (Owner)"},{"rowType": "place","name": "QuickFix Plumbing Co","place_id": "ChIJexampleplace003","street_address": "900 Industrial Blvd","city": "Austin","state": "TX","zip": "78744","country_code": "US","full_address": "900 Industrial Blvd, Austin, TX 78744","tags": ["Plumber"],"website": null,"phone": null,"avg_rating": 3.4,"lat": 30.2015,"long": -97.7392,"hours": [],"profile_completeness_score": 17,"missing_fields": ["website", "phone", "hours", "description", "booking_link"],"present_field_count": 1,"scored_component_count": 6,"has_website": false,"has_phone": false,"has_hours": false,"has_description": false,"has_accessibility_info": true,"has_booking_link": false,"has_street_view": null,"accessibility_features": ["Wheelchair accessible entrance"],"description": null,"description_tagline": null,"neighborhood": null,"thumbnail_url": null,"street_view_thumbnail": null,"owner_display_name": null}]
⚠️ hours carries only the current day's opening hours — Google's map-search payload does not expose the full week on this surface, so a listing with published hours for every other day but not today still scores has_hours: false for that run. has_street_view, street_view_thumbnail and owner_display_name are null (not false) whenever the extra lookup was skipped or failed, so a null never gets counted as a scored gap.
💡 How can I use the data extracted with Google Maps Extractor — Listing Completeness Audit?
- 🏢 Local SEO agencies and GBP consultants: filter
requiredGapsto["website"]or["booking_link"]to build an outreach list of businesses with a specific, sellable gap, usingmissing_fieldsas the talking point in the first email. - 📞 Lead-generation and sales teams: run
maxCompletenessScoreat 50–60 across a metro area and category to surface the weakest profiles first, then usephoneandwebsiteto reach out directly. - 🤖 AI engineers and LLM developers: point an agent at this Actor's JSON output —
profile_completeness_scoreandmissing_fieldsgive a model grounded, structured evidence to generate an audit report or outreach draft without hallucinating what's missing. - 📊 Market researchers: aggregate
profile_completeness_scorebycityorneighborhoodacross a category to compare how well businesses in different areas maintain their Google Business Profile.
📈 How do you monitor listing completeness over time?
Listing completeness is not static — a business adds a website, fixes its hours, or lets its profile lapse, and profile_completeness_score moves accordingly between runs. The discipline is simple: run the same locations and keywords on a schedule, keep each run's dataset, and diff on place_id — the one field guaranteed to stay stable for the same physical business across runs.
The fields worth diffing are profile_completeness_score (did it go up or down), missing_fields (which specific gap opened or closed), and has_website / has_phone / has_booking_link individually if you only care about one component. A dropped website between two runs of the same place_id is a much stronger signal than a raw score change, because it names the exact thing that happened.
A practical workflow: schedule a weekly run across your target category and area, export both the current and previous run's datasets, join them on place_id, and alert only on rows where missing_fields gained an entry it didn't have last time — that is a business whose profile got worse, and therefore a fresher lead than one that has been broken for months.
This Actor has no built-in diff or alerting feature of its own — schedule repeated runs through the Apify Console's Schedules tab (a native Apify platform feature, not something this Actor implements itself) and do the comparison in whatever tool consumes the dataset afterward.
🔌 Integrate Google Maps Extractor — Listing Completeness Audit and automate your workflow
Google Maps Extractor — Listing Completeness Audit works with any language or tool that can send an HTTP request, through the Apify API and the apify-client SDKs.
🐍 REST API with Python
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("<store-username>/google-maps-extractor-listing-completeness-audit").call(run_input={"locations": ["Austin"],"keywords": ["dentists"],"maxCompletenessScore": 60,})for row in client.dataset(run["defaultDatasetId"]).iterate_items():print(row["name"], row["profile_completeness_score"], row["missing_fields"])
⏰ Scheduled monitoring and delivery
The Actor has no built-in webhook or delivery feature of its own, but it runs on the standard Apify platform: set up a recurring run under Schedules in the Apify Console, and attach an Apify webhook to the run to notify an external endpoint (Slack, a pipeline, your own API) once each run finishes, so a completeness sweep can run unattended on a cadence you choose.
⚖️ Is it legal to scrape Google Maps business listings?
Yes — this Actor collects only publicly visible Google Business Profile listing data: business name, address, phone, website, category, hours and similar fields that any visitor sees on Google Maps without logging in. This is business and public-record data, not personal data about a private individual, so GDPR and CCPA — which govern personal data — generally do not attach to it; the relevant framing instead is Google's own Terms of Service and database-rights law around bulk collection and reuse of a compiled dataset. In hiQ Labs, Inc. v. LinkedIn Corp. (9th Cir., 2019), the court held that scraping publicly accessible profile data does not, on its own, violate the U.S. Computer Fraud and Abuse Act — a precedent that has been widely applied to public-data scraping generally, though it does not override a platform's own Terms of Service. Scraping for internal monitoring or lead qualification carries a different risk profile than scraping at scale for AI training or resale. Consult your legal team for commercial use cases involving bulk data storage.
❓ Frequently asked questions
Can I audit listings outside the United States?
Yes. locations accepts any city, district or region name that OpenStreetMap's Nominatim geocoder can resolve — the Actor uses the resolved area's own country code to query Google in the matching region, so ["Manchester"] or ["Brooklyn"] both work without any separate country setting.
Can I control which listings get filtered out?
Yes, through two independent filters: maxCompletenessScore keeps only listings scoring at or below the number you set, and requiredGaps keeps only listings missing every gap you tick from the seven available components. Both default to keeping everything (100 and []).
How does this Actor handle Google's anti-bot measures?
It runs through Apify Proxy by default and escalates automatically: if a connection tier gets refused or blocked repeatedly, the Actor steps up from your configured proxy to a residential tier on its own. Before saving any results for an area, it also probes the requested coordinates and switches connection if the results come back from somewhere else entirely, rather than saving wrong-area rows.
Does this Actor compute the listing completeness score?
Yes — every row carries profile_completeness_score (0-100) and a missing_fields array. The score is a weighted percentage of the 6 listing-payload components (website, phone, today's hours, description, accessibility info, booking link) plus a 7th, Street View, when auditMediaDepth is set to fetch. scored_component_count on each row tells you whether it was judged on 6 or 7.
How many results does this Actor return per query?
Up to maxResults, which accepts 1–10,000 and defaults to 20. This is a total across every area, category and link in the run, deduplicated by Google place ID. ⚠️ When auditMediaDepth is fetch, the Street View/owner lookup is capped internally at max(100, 5 × maxResults) requests per run — once that budget is used up, remaining listings in that run are scored on the 6 listing components only, and a warning is logged.
How do I monitor a business category's completeness over time?
Schedule the same locations and keywords on a recurring cadence through the Apify Console's Schedules tab, keep each run's dataset, and join consecutive runs on place_id to see which listings' missing_fields grew or shrank between runs.
Does this Actor work with Claude, ChatGPT, and AI agent frameworks?
There is no dedicated MCP server for this Actor. It is callable as a standard HTTP endpoint through the Apify API by any agent framework that can issue an HTTP request, which lets an agent trigger a run, retrieve the resulting JSON, and ground its answer in the returned profile_completeness_score and missing_fields.
How does this Actor compare to other Google Maps scrapers?
Competing Google Maps scrapers' documented capabilities were not available for direct comparison at the time of writing. What this Actor's own source code confirms is that it returns the standard Google Maps listing row (name, address, phone, hours, rating) plus an automatically computed completeness score and gap list on the same row — a scoring layer most general-purpose Maps scrapers leave for the user to build themselves.
Can I use this Actor without managing proxies or Google credentials?
Yes. Apify Proxy is enabled by default (proxyConfiguration) and the Actor manages its own connection escalation. No Google account, API key or Google Places API billing is required — you only need an Apify account to run it.
💬 Your feedback
Found a bug, or a listing field that should be on the row but isn't? Open the Issues tab on this Actor's Apify Store page to report it. Bug reports and field requests are what keep this Actor's scoring accurate as Google's own listing payload changes.