Google Local Services Ads Scraper (LSA Lead Extractor)
Pricing
from $8.20 / 1,000 searcheds
Google Local Services Ads Scraper (LSA Lead Extractor)
Extract Google Local Services Ads (LSA) leads: business name, phone number, rating, reviews, badges, years in business and service area.
Pricing
from $8.20 / 1,000 searcheds
Rating
0.0
(0)
Developer
OptiRefine
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 hours ago
Last modified
Categories
Share
Google Local Services Ads Scraper (LSA Extractor)
Extract Google Local Services Ads (LSA) provider listings — the "Google Guaranteed" cards with a call button at the top of local search results — as clean dataset rows. Point this Google Local Services Ads scraper at a service (plumbers, roofers, HVAC, electricians, house cleaners...) and a city, and it returns each provider's business name, call-tracking phone number, star rating, review count, trust badges, years in business and service area.
Google itself caps every search at 20 providers per service, per location — that's Google's own limit, not an actor setting; see How many results can I get?. Within that cap, this LSA scraper is built for lead generation agencies filling a pipeline of local businesses to pitch, local SEO consultants auditing who's winning the paid local pack in a market, and anyone doing competitor research on who is actively paying Google for calls in a city. It reads Google's own server-rendered results page over plain HTTP rather than driving a browser, which keeps runs fast and predictable on the Apify platform.
How do I scrape Google Local Services Ads?
- List the services in
searchQueries— plain wording likeplumbersorroofersreturns more results than Google's formal category names. - List the cities in
locations, including state, province or country ("Austin, TX", not"Austin") so Google — and the proxy — picks the right country. - Add a country-matched proxy in
proxyConfiguration(residential recommended). Local Services Ads only render for visitors Google believes are in the same country as the search — see Why am I getting zero results?. - Run the actor. Each service × location pair returns up to 20 providers as rows in the dataset, ready to export as CSV/JSON or pulled out over the Apify API.
What data you get
Each row in the output dataset is one advertiser from one search. Field names below match LsaProvider in the source exactly — use them as-is in your integration. For each field's exact null conditions and where it comes from in Google's markup, see the docs/OUTPUT-REFERENCE.md.
| Field | Type | Description |
|---|---|---|
customerId | string | null | Google's internal advertiser/customer ID. This is the only reliable way to tell two listings apart — two different advertisers can legitimately share the same business name. |
name | string | null | Business name as shown on the ad card. |
phone | string | null | Phone number in E.164 format, e.g. +14165550142. This is a Google call-tracking number that forwards to the business — see About the phone numbers. |
phoneDisplay | string | null | The number as printed in the card's visible text. Almost always null — Google shows a "Get phone number" button instead of the digits. Use phone; this is only a fallback. |
phoneRegionCode | string | null | Two-letter region code Google associates with the phone number, e.g. CA. |
businessId | string | null | Google's internal business ID for the listing. |
providerId | string | null | Google's internal provider ID for the listing. |
rating | number | null | Average star rating, e.g. 4.9. null when the provider has no reviews yet. |
reviewsCount | number | null | Number of reviews behind the rating. null when the provider has no reviews yet. |
providerType | string | null | The service category label Google prints on the card, e.g. Plumber. |
yearsInBusinessText | string | null | The raw "years in business" line as Google renders it, e.g. 28+ years in business. |
yearsInBusiness | number | null | Just the number parsed out of the line above, e.g. 28. |
serviceAreaText | string | null | The raw service-area line, e.g. Serves Whitby. |
serviceArea | string | null | Just the place name, e.g. Whitby. |
hours | string | null | Opening-hours summary shown on the card, e.g. Open 24 hours or Open · Closes 8 PM. |
isOpenNow | boolean | null | true when the hours text indicates the business is open right now. |
badges | string[] | Trust/verification badges Google shows, e.g. Google Guaranteed, Google Screened, Background checked. |
highlights | string[] | Marketing highlights the business chose to display, e.g. Family owned, Flat rate pricing. |
responseTime | string | null | Google's response-time promise for the business, e.g. Typically replies in 30 min. |
profileUrl | string | null | Absolute link to the provider's Local Services profile page on Google. |
isPreviewAd | boolean | true when Google flags the card as a non-live preview ad rather than a currently running one. |
searchQuery | string | Which of your input search terms produced this row. |
location | string | Which of your input locations produced this row. |
countryCode | string | The ISO-3166-1 alpha-2 country actually used for this search (auto-detected from the location, or your override) — this drives both Google's gl parameter and the proxy country. |
position | number | Zero-based rank of this provider in Google's result list for this search (0 is the top ad). |
sourceUrl | string | The exact google.com/localservices/prolist URL the actor requested to produce this row. |
scrapedAt | string | ISO timestamp of when the row was extracted. |
Input
| Field | Type | Required | Description |
|---|---|---|---|
searchQueries | array of strings | Yes | Services to search for. Plain, everyday wording ("plumbers", "electricians") tends to return more results than Google's formal taxonomy names. |
locations | array of strings | Yes | Cities or areas to search in. Include the state, province or country ("Austin, TX", not "Austin") so the right place — and country — is picked. |
maxLeads | integer | No (default 1000) | A cap on the total number of providers saved across the whole run, not a per-search target. Read How many results can I get? before raising this. |
minRating | integer, 0–5 | No | Only save providers rated at or above this. Leave empty to keep everything. Setting this excludes brand-new providers that have no rating yet. |
minReviews | integer | No | Only save providers with at least this many reviews. |
proxyConfiguration | object | Required for real results | Apify Proxy configuration. The actor automatically forces the proxy country to match each location's country. Residential proxies are strongly recommended. |
countryCode | string (ISO-3166-1 alpha-2) | No | Overrides the country the actor would otherwise detect from a location, e.g. US. Useful when a location name is ambiguous. |
languageCode | string | No (default en) | Two-letter language code for Google's interface and result text. |
Example input:
{"searchQueries": ["plumbers", "electricians"],"locations": ["Austin, TX", "Toronto, ON"],"maxLeads": 500,"minRating": 4,"minReviews": 5,"proxyConfiguration": {"useApifyProxy": true,"apifyProxyGroups": ["RESIDENTIAL"]},"languageCode": "en"}
This example runs 4 searches (2 services × 2 locations), each capped at Google's own 20-provider limit, and keeps only providers rated 4+ stars with at least 5 reviews.
Output example
A single row from the dataset, for a "plumbers near Toronto, ON" search:
{"customerId": "5423178690","name": "Maple Leaf Plumbing & Drain","phone": "+14165550142","phoneDisplay": null,"phoneRegionCode": "CA","businessId": "9082217634","providerId": "4471183920","rating": 4.9,"reviewsCount": 214,"providerType": "Plumber","yearsInBusinessText": "18+ years in business","yearsInBusiness": 18,"serviceAreaText": "Serves Toronto","serviceArea": "Toronto","hours": "Open 24 hours","isOpenNow": true,"badges": ["Google Guaranteed", "Background checked"],"highlights": ["Family owned", "Emergency service"],"responseTime": "Typically replies in 30 min","profileUrl": "https://www.google.com/localservices/prolist/provider?hl=en&gl=ca","isPreviewAd": false,"searchQuery": "plumbers","location": "Toronto, ON","countryCode": "CA","position": 0,"sourceUrl": "https://www.google.com/localservices/prolist?q=plumbers+near+Toronto%2C+ON&hl=en&gl=ca&src=1","scrapedAt": "2026-08-25T14:32:07.918Z"}
("Maple Leaf Plumbing & Drain" is an illustrative business, not a real advertiser.)
How many results can I get?
Google caps every Local Services Ads search at a maximum of 20 providers per service, per location. This is a hard limit on Google's side — no offset, page or pagination parameter changes it, and scrolling the results pane doesn't load more. It's a fact about how Google serves LSA, not a limitation of this actor.
That means maxLeads is a ceiling, never a target: setting it to 5,000 will not make a single "plumbers near Austin, TX" search return more than 20 rows. If you need more than 20 leads, the only way to get there is to run more searches — add more service terms (plumbers, drain cleaning, water heater repair) and more locations (individual neighborhoods or nearby suburbs instead of one whole metro). Each service × location pair is its own search with its own 20-provider ceiling, so 10 services across 10 cities can return up to 2,000 rows in one run, provided maxLeads is raised above its default of 1,000 to allow it.
Why am I getting zero results?
Zero results almost always comes down to one of these, roughly in order of likelihood:
- Proxy/location country mismatch. Google only shows Local Services Ads to visitors it believes are physically in the same country as the requested service area. If your proxy exits in Canada while you search "Plumbing near Austin, TX", Google silently returns an empty "try a different area" page — not an error. The actor auto-matches the proxy country to each location (see step 3 of How do I scrape Google Local Services Ads?), so make sure your proxy configuration actually has access to the countries you're targeting (residential proxies with broad country coverage work best), and avoid overriding
countryCodeunless you're sure of the ISO code. - There genuinely are no active LSA advertisers for that service in that area. Local Services Ads coverage varies a lot by city and category — a large metro will have 20 roofers advertising; a small town may have none. This is a real, expected zero, not a bug.
- The country isn't supported by Local Services Ads at all. Google runs LSA in a limited set of countries and is still expanding it. Check the official Google Local Services Ads page for current availability before assuming your setup is broken.
- Filters are removing everything. If you set
minRatingorminReviews, brand-new providers with no reviews yet are excluded entirely, which can take a run from 20 raw results down to very few (or zero) saved rows. Try the run with the filters cleared to confirm providers exist before re-adding them.
About the phone numbers
Google's own Local Services Ads page hides the phone number behind a "Get phone number" button — but the server-rendered HTML underneath ships the number anyway, in a data-phone-number attribute, on every provider card. The actor reads it directly, with no clicking and no browser involved, which is why phone is populated on effectively every row.
These are Google call-tracking numbers, not the business's direct line. Calls to them are forwarded to the actual business, and this is the number the advertiser pays Google to receive calls on — which makes it the correct number to use for outreach or lead delivery. phone is always in E.164 format (e.g. +14165550142). phoneDisplay only carries a value on the rare card where Google also renders visible display text for the number — in the normal case, where the UI hides it behind the "Get phone number" button, phoneDisplay is null and phone is the field to use. phoneRegionCode gives the two-letter region Google associates with the number.
FAQ
Do I need a proxy for this to work?
Yes. Local Services Ads is geo-gated by the requesting IP's country, so a proxy in the wrong country returns an empty result even for a real, active market. The proxyConfiguration input is required for real results, and residential proxies are recommended. See Why am I getting zero results?
Are the phone numbers real?
Yes — they ring through to the actual business — but they are Google call-tracking numbers, not the advertiser's private line. That's the number the advertiser pays Google to receive calls on, which makes it the right number for outreach. See About the phone numbers for format details.
Why do simple search terms like "plumbers" work better than Google's official category names?
Google's Local Services Ads search matches on plain, everyday wording. Colloquial terms such as roofers, electricians and plumbers return full result sets, while some formal taxonomy names return nothing. Type services the way a customer would search for them.
Can the same business appear twice, or two different businesses share a name?
Yes to both — business name is not a unique identifier on Google's side. Two distinct advertisers can list under an identical display name. Always dedupe or key your data on customerId, not name.
Is this a browser-based (Playwright/Selenium) scraper?
No. Google's Local Services results page is fully server-rendered, so the actor fetches it over plain HTTP and parses the HTML — no browser is launched. This makes runs fast and avoids browser-fingerprinting issues entirely.
Can I get more than 20 results for one service in one city?
No — that's Google's own per-search limit, not a setting in this actor. See How many results can I get? for how to scale up using more services and locations instead.
Will minRating or minReviews reduce my result count even when providers exist?
Yes. Both filters are applied after Google returns results, and minRating in particular drops every provider that has no rating yet (which includes brand-new advertisers). If a search that should have 20 providers returns far fewer, try the same run with these filters cleared to see the unfiltered count.
This is an independent tool built on publicly accessible Google Local Services Ads result pages. It is not affiliated with, endorsed by, or sponsored by Google LLC. "Google Local Services Ads" and "Google Guaranteed" are trademarks of Google LLC.