Guides · 8 min read
Local rank tracking API: track Google local rankings by city with code
Build a local rank tracker with an API: find a business's position in Google's local results for any city, handle chains, and log the history. Python.
Places API Text Search returns places that match a text query. If you need the local results and local pack Google shows a searcher in a city, with ratings and review counts, CrawlerData returns them as JSON.
Last checked against Google Places API's public pages. Sources
Google's Text Search documentation says the API "orders the results based on their perceived relevance" and that the list "is not guaranteed to be consistent for identical requests." It does not say how that order relates to Google Maps or Google Search results.
Places API (New) Text Search takes a text query and returns up to 20 places per page, 60 across pages, ordered by what Google calls perceived relevance (or by distance with rankPreference). You choose the fields with a field mask, and the field tier sets the price: rating, review count, phone and website are in the Enterprise tier.
If you need to know what a searcher in a city actually sees, such as where a business sits in the local results, request the results page itself. CrawlerData's Google Local endpoint returns the local results for a query and city (title, rating, review count, type, address, phone, hours, website), and the Google Search endpoint returns the local pack alongside organic results, AI Overview and People Also Ask, in any of 31 countries.
They do different jobs. Places API is Google's place database, queried by text; CrawlerData returns the search results Google lists, so it does not return place IDs or Places-style detail records.
| CrawlerData | Google Places API | |
|---|---|---|
| Pricing model | Prepaid credit packs, no subscription. Credits valid 6 months | Pay per billable event, with a free monthly usage cap per SKU |
| Cost per 1,000 at entry | $1.00 per 1,000 requests (Starter, $50 for 50k credits) | Text Search Pro $32.00 per 1,000; Enterprise (adds rating, review count, phone, website) $35.00 per 1,000 |
| Cost per 1,000 at volume | $0.30 per 1,000 requests (Ultimate, $3,750 for 12.5M credits) | Those are first-tier prices (up to 100,000 billable events a month); higher tiers are on Google's pricing page |
| Free tier | 50 free credits with a verified work email, valid 30 days | Each month: Essentials (IDs only) unlimited, Pro 5,000, Enterprise 1,000 |
| Google Shopping sellers | Yes. Every seller for a product in one request, 1 credit per 10 sellers returned (rounded up, minimum 1) | Not offered. Place data, not Shopping sellers |
| Async and webhooks | Live (synchronous), plus Fast and Regular queues with polling or a webhook (postbackUrl). Same price on every queue | Synchronous POST to places.googleapis.com/v1/places:searchText with a field mask |
| MCP server | Yes. Remote server at api.crawlerdata.com/mcp, 8 tools, same API key | Not covered on this page |
| Failed requests | Not charged. A failed job costs 0 credits | Not covered on this page |
| Rate limit | 100 requests per minute and 20 per second per API key | Not covered on this page |
| What you get | Google's local results and local pack for your query and city: title, rating, review count, type, address, phone, hours, website | Place records for a text query; rating, review count, phone and website need the Enterprise field tier |
| Ordering | The order Google returns for your query, country and city, with a position field | Perceived relevance (or distance with rankPreference); not guaranteed consistent for identical requests |
| Results per request | One page of Google results per request, pages 1 to 10 | pageSize 1 to 20; up to 60 results across pages |
| Location input | location (a Google city name such as Austin,Texas,United States) or uule | locationBias (circle up to 50,000 m or rectangle) or locationRestriction (rectangle) |
List prices in USD, excluding tax, as published on October 20, 2026. "Not published" means we could not find it on Google Places API's public pages. Per-1,000 figures marked "our arithmetic" divide a plan price by its volume.
Both calls take a text query and a place. The difference is the output: Places returns place records, CrawlerData returns the local results in the order Google lists them, with a position for each.
| Google Places API | CrawlerData |
|---|---|
| POST places.googleapis.com/v1/places:searchText | POST api.crawlerdata.com/v1/jobs with "endpoint": "google-local" |
| X-Goog-Api-Key header | Authorization: Bearer YOUR_API_KEY |
| X-Goog-FieldMask | Not needed: every request returns all fields |
| textQuery | params.query |
| locationBias / locationRestriction | params.location (a Google city name) or uule |
| pageSize, pageToken | params.page (1 to 10) |
| places[] | result.local_results[] |
| places[].displayName.text | title |
| places[].formattedAddress | address |
| places[].rating / userRatingCount | rating / reviews |
| places[].nationalPhoneNumber / websiteUri | phone / website |
| Array order (perceived relevance) | position: the rank in Google's local results |
const res = await fetch('https://places.googleapis.com/v1/places:searchText', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Goog-Api-Key': API_KEY,
'X-Goog-FieldMask': 'places.displayName,places.formattedAddress,places.rating,places.userRatingCount',
},
body: JSON.stringify({ textQuery: 'italian restaurant in Austin, Texas' }),
});
const { places = [] } = await res.json();
const results = places.map((p, i) => ({ position: i + 1, name: p.displayName?.text, rating: p.rating, reviews: p.userRatingCount }));const res = await fetch('https://api.crawlerdata.com/v1/jobs', {
method: 'POST',
headers: { Authorization: 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json' },
body: JSON.stringify({ endpoint: 'google-local', params: { query: 'italian restaurant', country: 'us', location: 'Austin,Texas,United States' }, queue: 'live' }),
});
const { job, result } = await res.json(); // job.status "failed" => result is null, 0 credits
const results = (result?.local_results ?? []).map((r) => ({ position: r.position, name: r.title, rating: r.rating, reviews: r.reviews }));Full request and response schemas are in the OpenAPI spec, with runnable code in the examples repo. AI clients can connect to the MCP server at https://api.crawlerdata.com/mcp with the same API key.
Places that match a text query, from POST places.googleapis.com/v1/places:searchText. You must send a field mask. pageSize is 1 to 20, and Google says Text Search returns a maximum of 60 results across all pages. Rating, review count, phone and website are in the Enterprise field tier.
On Google's pricing page (updated 2026-10-16, checked 2026-10-20) the first volume tier is $32.00 per 1,000 billable events for Text Search Pro, with 5,000 free a month, and $35.00 for Text Search Enterprise, with 1,000 free. Enterprise + Atmosphere, which adds fields such as reviews, is $40.00 per 1,000 with 1,000 free. Text Search Essentials (IDs only) has an unlimited free cap.
Google's documentation does not say. It says Text Search orders results by perceived relevance and that the list is not guaranteed to be consistent for identical requests, and it does not describe how the order relates to Google Maps or Search results. To get the order a searcher sees in a city, request the results page itself: CrawlerData's Google Local endpoint returns it for the city you set.
Send a google-search request with params.location set to a Google city name, such as Austin,Texas,United States, or with uule. The local_pack array holds the pack. The google-local endpoint returns the longer list of local results with rating, review count, address, phone, hours and website.
The request body and the parsing: textQuery becomes params.query, locationBias becomes params.location, and places[] becomes result.local_results[] with title, rating, reviews, address, phone and website. The key moves from the X-Goog-Api-Key header to a Bearer token.
For reading the local results a searcher sees, yes. It is a different job from Places: CrawlerData returns what Google's search results list, not place records by ID.
All checked on (as of Oct 2026). Spotted something out of date? Email contact@crawlerdata.com and we will correct it.
Local businesses with rating, reviews, category, address, phone, hours and website.
from $0.30 / 1,000 requests
Organic results with real destination links, ads, AI Overview, People Also Ask, local pack, top stories, knowledge panel and related searches. Desktop or mobile.
from $0.30 / 1,000 requests
Businesses by category and place, with rating, address, phone and website.
See how it works
Organic positions and SERP features, desktop or mobile, per keyword and country.
See how it works
Guides · 8 min read
Build a local rank tracker with an API: find a business's position in Google's local results for any city, handle chains, and log the history. Python.
Guides · 7 min read
We ran 13 searches in 4 cities with location set. Local searches shared 0.2 links between cities, others 6.3. The local pack stayed stable on repeats.
Guides · 7 min read
Turn Google local results into a clean lead list: category and city searches, pagination, deduplication and CSV export, in Python, used responsibly.
Prepaid packs from $1.00 per 1,000 vs SerpApi's monthly subscription from $25.00 per 1,000.
See the comparison
CompareSame pack prices. CrawlerData adds Google Shopping sellers, async queues with webhooks and MCP.
See the comparison
CompareOne price on every queue, live included, vs queue-based pricing for SERPs and Shopping.
See the comparison
CompareGoogle's own results and Shopping prices for agents vs LLM-ready web content summaries.
See the comparison
CompareThe Custom Search JSON API ends January 1, 2027. Migrate by changing the base URL.
See the comparison
CompareThe Bing Search APIs were retired August 11, 2025. Field mapping and code to move.
See the comparison
Get 50 free credits when you sign up with your work email and verify it. Failed requests are never charged.
We use Google Analytics cookies to understand how the site is used. See our privacy policy.