Google Search Results Scraper with Local Businesses
Pricing
$19.99/month + usage
Google Search Results Scraper with Local Businesses
🔎 Google Search Results Scraper extracts live SERP data—titles, snippets, URLs, rankings, ads & featured snippets—by location, language and device. ⚙️ Built for SEO, keyword research, competitor analysis & content planning. 🚀 Fast, scalable, proxy-ready.
Pricing
$19.99/month + usage
Rating
0.0
(0)
Developer
ScraperForge
Maintained by CommunityActor stats
0
Bookmarked
16
Total users
3
Monthly active users
a day ago
Last modified
Categories
Share
Scrape Google Search results and extract the local/map "Places" business pack — name, rating, category, address, phone, website, hours, booking and directions links — directly from the same search results page. This Google SERP scraper is built for local SEO, local lead generation, and "near me" keyword research: run any keyword ("plumber in austin tx", "coffee shop chicago", "dentist near me") and get both the organic/paid Google search results and a structured list of the local businesses Google surfaces for that query, in one Apify dataset.
No Google Maps API key or Google Places API billing required — this actor parses the local pack straight off the public Google Search results page (google.com/search), the same block you see under the map when you search a "near me" style query in a browser.
What this Google local pack scraper does
- Runs one or many search queries (plain keywords or full Google Search URLs) through Google Search, page by page, the same way
apify/google-search-scraperand other SERP scraper actors do. - Detects when a query triggers Google's local/map business pack and extracts every business entry: title, star rating, review count text, category, price range, address, years in business, open/closed status, phone number, website, booking link, and directions link.
- Optionally expands past the default 3-entry teaser into Google's fuller local business list ("More places",
udm=1) for up to 100 businesses per query, with sponsored/ad entries flagged. - Filters keyword lists down to only the ones with a local pack, or to only businesses above a minimum star rating — useful for local-SEO auditing and lead-list triage.
- Still returns everything the base Google Search Results Scraper returns — organic results, paid ads/products, People Also Ask, related queries, AI Overview (with a SerpApi key) — so it's a drop-in replacement for the base actor plus local business data.
Why use the local business pack extraction
Most Google SERP scraper actors on Apify (including the highest-usage one in this category) scrape organic results, ads, and People Also Ask, but skip the local/map pack entirely — even though it's the single most commercially relevant block for "near me" and service-area searches. This actor targets exactly that gap:
- Local SEO rank tracking — see which businesses Google's local pack shows for a given keyword + location, and where a specific business ranks.
- Local lead generation — pull business name, phone, website, and address for every business ranking in a niche/location without touching a paid Google Places API.
- Competitor and market research — check ratings, review volume, price range, and "open now" status across all local competitors for a search term.
- Local-SEO keyword triage — run a big keyword list and keep only the ones that actually surface a local pack (
onlyQueriesWithLocalPack), so you know which keywords are worth local-SEO effort.
Input
The actor accepts the base Google Search Results Scraper's full input (30 fields, grouped into the same accordion sections), plus 4 new local-pack fields grouped under their own section.
📍 Local Business Pack (new in this variant)
| Field | Type | Default | Description |
|---|---|---|---|
includeLocalPack | boolean | true | Extracts the local/map business pack for local-intent queries into localResults. Automatically removes the base actor's default Web-only restriction so the local pack can appear. When false, behavior is identical to the base actor (no local pack extracted). |
maxLocalResults | integer (0–100) | 20 | Caps businesses returned per query. 3 or fewer only reads the inline pack (no extra request); a higher value also fetches Google's paginated "More places" finder page. 0 = unlimited. |
onlyQueriesWithLocalPack | boolean | false | Drops a query's row entirely (not pushed, not charged) when no local pack was found — for triaging a keyword list to only local-pack-triggering terms. |
minLocalRating | number (0–5) | 0 | Drops local businesses whose parsed star rating is below this threshold. Businesses with no rating found are always kept. 0 = no filtering. |
🔍 Search configuration
| Field | Type | Description |
|---|---|---|
queries (required) | string (textarea) | One search term or full Google Search URL per line. Supports operators like site:, OR, AI site:twitter.com. |
resultsPerPage | integer (1–100) | Requested results per page (Google's own filtering may return fewer). |
maxPagesPerQuery | integer | Max pages per query (~10 results per page). |
🌍 Location and language
countryCode, searchLanguage, languageCode, locationUule — country/domain, results language, interface language, and an exact-location UULE code for local search emulation.
🔎 Advanced search filters
forceExactMatch, site, relatedToSite, wordsInTitle, wordsInText, wordsInUrl, quickDateRange, beforeDate/afterDate (absolute or relative datepicker), fileTypes.
⚙️ Add-ons and additional settings
aiMode (Google AI Mode), serpApiKey (for AI Overview via SerpApi), perplexitySearch, chatGptSearch, maximumLeadsEnrichmentRecords, leadsEnrichmentDepartments, focusOnPaidAds, mobileResults, includeUnfilteredResults, saveHtml, saveHtmlToKeyValueStore, includeIcons, proxyConfiguration (proxy defaults to Apify's GOOGLE_SERP group).
Input example
{"queries": "plumber in austin tx\ncoffee shop chicago\npython","includeLocalPack": true,"maxLocalResults": 20,"onlyQueriesWithLocalPack": false,"minLocalRating": 4,"maxPagesPerQuery": 1,"countryCode": "us","languageCode": "en"}
Output
Every dataset item is one search query result page, carrying the full base actor output plus the new local-pack fields.
New local-pack fields
| Field | Type | Description |
|---|---|---|
hasLocalPack | boolean | Whether a local business pack was found for this query. |
localPackHeading | string | null | The pack's own heading text (e.g. "Places", "Businesses"). |
localSearchLocation | string | null | The location line Google shows above the pack (e.g. "Results for Austin, TX"). |
localFinderUrl | string | null | Link to Google's fuller "More places" list for this query. |
localResultsCount | number | Count of businesses in localResults after minLocalRating filtering. |
localResults | array | The business records — see below. |
Each entry in localResults[]:
| Sub-field | Type | Description |
|---|---|---|
position | number | Rank within the returned list (re-numbered after filtering/dedup). |
isAd | boolean | Whether the entry is labeled "Ad"/"Sponsored". |
title | string | Business name. |
rating | number | null | Parsed star rating (0–5), when present. |
reviewsText | string | null | Review count as printed by Google (e.g. "1.2K") — abbreviated text, not an exact integer. |
reviewsAriaLabel | string | null | Raw accessibility label the rating was parsed from. |
category | string | null | Business category/type. |
priceRange | string | null | Price tier (e.g. $, $$) when shown. |
address | string | null | Street address, when it could be separated from other text on the page. |
cityState | string | null | City/state line, when detected separately from address. |
yearsInBusiness | string | null | "X years in business" text, when shown. |
openStatus | string | null | "Open" / "Closed", when detectable. |
openDetail | string | null | Full open/closed text (e.g. "Closes 9 PM"). |
phone | string | null | Phone number, when shown. |
website | string | null | Business website link. |
scheduleUrl | string | null | Booking/ordering/reservation/menu link, when present. |
directionsUrl | string | null | Google Maps directions link. |
mapsFeatureId | string | null | Google's internal place/CID identifier, when extractable from the page. |
attributes | array of strings | Leftover short text snippets from the entry that didn't match a known field (amenities, hours snippets, etc.) — a catch-all so nothing visible is silently dropped. |
reviewSnippet | string | null | A quoted customer review fragment, when Google shows one. |
source | string | "pack" (inline 3-entry box) or "finder" (the paginated "More places" list). |
Base fields (unchanged, still present)
searchQuery (term, url, device, page, type, domain, countryCode, languageCode, locationUule, resultsPerPage), searchQueryTerm, url, hasNextPage, serpProviderCode, resultsTotal, relatedQueries[], paidResults[], paidProducts[], aiOverview (populated only with a serpApiKey and AI Mode enabled), organicResults[], suggestedResults[], peopleAlsoAsk[], customData (echoes the perplexitySearch/chatGptSearch/leads-enrichment input config), htmlSnapshotUrl (when saveHtmlToKeyValueStore is on), html (when saveHtml is on).
Output example
{"searchQueryTerm": "coffee shop chicago","hasLocalPack": true,"localPackHeading": "Places","localSearchLocation": "Results for Chicago, IL","localResultsCount": 2,"localResults": [{"position": 1,"isAd": false,"title": "Example Coffee Roasters","rating": 4.7,"reviewsText": "1.1K","category": "Coffee shop","priceRange": "$$","address": null,"cityState": "Chicago, IL","openStatus": "Open","openDetail": "Closes 6 PM","phone": "(312) 555-0100","website": "https://example-coffee.com","directionsUrl": "https://www.google.com/maps/dir//...","mapsFeatureId": "12345678901234567890","attributes": ["Dine-in", "Takeout"],"reviewSnippet": "Great espresso and a cozy spot to work.","source": "pack"}],"resultsTotal": 214000,"organicResults": ["..."],"peopleAlsoAsk": []}
Honest limitations (read before relying on a field)
- The local pack only appears for local-intent queries. Google shows it for "near me"/service+location searches, not for informational or product searches —
hasLocalPack: falseon a non-local query is expected behavior, not a bug. - Address parsing is heuristic and partial. Google's HTML doesn't label "address" explicitly; it is split from surrounding text using pattern matching, so
address/cityStateare sometimesnulleven when the information is visible — in that case it usually still shows up inside the catch-allattributesarray instead of being fabricated. - Review counts are abbreviated strings (e.g. "35K"), not exact integers — there is no exact review-count filter for this reason, only
minLocalRating(star ratings are printed as exact values, e.g. "4.9"). - Website / booking / directions links are matched by English link text ("Website", "Directions", "Book", …). Under a non-default
languageCode, some of these links may not be detected. resultsTotalis parsed from Google's own "About N results" text and can be affected by locale-specific number formatting — treat it as an estimate, not an exact count.peopleAlsoAskand the local pack share the same requirement (not being restricted to the Web-only results tab); withincludeLocalPackoff and default settings,peopleAlsoAskmay return empty on many queries.perplexitySearch/chatGptSearch/ leads-enrichment fields are pass-through configuration inherited from the base actor's schema — the values you set are echoed back incustomDatafor now; they do not currently trigger an external AI or lead-enrichment call.- Google occasionally serves a blocking page for a given query/IP combination, which can result in zero rows for that specific query. This is a transport-level limitation of scraping Google directly (shared with the base actor) rather than a local-pack-specific issue — retrying the query or adjusting the proxy configuration usually resolves it.
Use cases
- Local SEO rank tracking and local-pack keyword auditing
- Local business lead generation (name, phone, website, address, rating) without a Google Places API key
- Competitor benchmarking on ratings, review volume, price range, and open hours
- "Near me" / service-area keyword research at scale
- General Google SERP scraping (organic, paid ads, People Also Ask, related queries, AI Overview) alongside the local data
Frequently asked questions
Does this need a Google Places API key or Google Maps API billing?
No. localResults is parsed directly from the public Google Search results page, not from the Google Places/Maps API.
Will I still get organic and paid results, or only the local pack? Both. This actor is a full superset of the base Google Search Results Scraper — every base input and output field still works exactly as before; the local-pack fields are additive.
Why is localResults empty for my query?
The query most likely has no local intent (Google didn't show a local pack for it), or includeLocalPack is set to false. Try a "near me" or "[service] in [city]" style query with includeLocalPack: true.
Can I get more than 3 local businesses per query?
Yes — set maxLocalResults above 3 (default 20) to trigger the paginated "More places" fetch, up to 100 per query.
How do I keep only keywords that have a local pack?
Set onlyQueriesWithLocalPack to true; rows without a local pack are dropped from the dataset and not charged.
Compliance
Data is collected only from publicly available Google Search result pages. You are responsible for complying with Google's Terms of Service, robots.txt, and applicable laws (including privacy and data protection regulations) in your jurisdiction and use case.