Google Reviews API: your own reviews vs ratings for any business
Two different things hide behind 'Google Reviews API'. Which one gives review text, which gives ratings for any business, and a Python rating monitor.
CrawlerData teamPublished 6 min read
Contents
“Google Reviews API” means two different things, and mixing them up is why most guides on it disappoint. One is an official API that returns the reviews of businesses you manage. The other is data about any business on Google, which Google does not offer as an API at all.
This guide covers both: what the official route gives you and what it needs, then how to collect ratings and review counts for any local business in Python, and a small monitor that tells you when a competitor’s rating or review count changes. The numbers below come from requests we ran in October 2026; Google’s local results change over time and by location.
Option 1: your own reviews, from Google
The Google Business Profile API has a reviews method. According to Google’s documentation, checked in October 2026, you list reviews for a location with:
GET https://mybusiness.googleapis.com/v4/accounts/{accountId}/locations/{locationId}/reviews
You register an application and call it with OAuth 2.0 credentials. Google’s reviews page describes the review fields through its client-library accessors: review ID, comment, reviewer, star rating, create time and review reply. This is the right tool when the question is “what are our customers saying” about your own locations, because it returns the review text and replies.
It does not help when the question is about someone else’s business: a competitor, a prospect, or a list of 500 dentists. That is the second option.
Option 2: ratings and review counts for any business
When you search Google for dentist in austin tx, the local results show each business with its star rating and how many reviews it has. The Google Local API returns that list as JSON. Put your key in an environment variable:
export CRAWLERDATA_API_KEY="YOUR_API_KEY"
import os
import requests
API_URL = "https://api.crawlerdata.com/v1/jobs"
HEADERS = {"Authorization": f"Bearer {os.environ['CRAWLERDATA_API_KEY']}"}
def local_results(query, country="us", language="en", page=1):
body = {
"endpoint": "google-local",
"params": {"query": query, "country": country, "language": language, "page": page},
"queue": "live",
}
resp = requests.post(API_URL, json=body, headers=HEADERS, timeout=180)
resp.raise_for_status()
data = resp.json()
if data["job"]["status"] != "completed":
raise RuntimeError(f"Local search failed: {data['job']['error']}")
return data["result"]["local_results"]
The first result for dentist in austin tx looked like this:
{
"position": 1,
"title": "ATX Family Dental",
"rating": 4.9,
"reviews": 916,
"type": "Dentist",
"address": "1700 S 1st St, Austin, TX 78704",
"phone": "(512) 717-3147",
"hours": "Closed · Opens 8 AM Fri",
"website": "https://www.atxfamilydental.com/",
"sponsored": false
}
Things worth knowing before you build on it:
- It is a rating and a count, not the review text. There are no individual reviews, reviewer names or review dates in the response.
- 20 businesses per page for the English queries we tried.
pagegoes from 1 to 10, each page is its own request, and page 2 of our query returned 20 different businesses. - Counts over 1,000 look rounded. In our samples, smaller counts looked exact (916, 742) while larger ones came back as 1200, 3600, 9800 and 7100. Treat big counts as approximate.
- Some fields can be empty. A German query,
zahnarzt berlin, returned 21 results with ratings and review counts for every one, butaddress,phone,hoursandwebsitewerenullon the first result we inspected. Always handleNone. sponsoredmarks ads, so you can leave paid listings out of a ranking.
Monitor competitor ratings in SQLite
A rating on its own is a snapshot. The useful signal is the change: a competitor gaining 40 reviews in a week, or a rating dropping from 4.8 to 4.5. Store one row per business per day and compare the last two days.
import sqlite3
from datetime import date
def init_db(path="reviews.db"):
db = sqlite3.connect(path)
db.execute(
"""CREATE TABLE IF NOT EXISTS snapshots (
day TEXT, query TEXT, name TEXT, address TEXT,
rating REAL, reviews INTEGER,
PRIMARY KEY (day, query, name, address))"""
)
return db
def snapshot(db, query, pages=2, **kwargs):
today = date.today().isoformat()
rows = 0
for page in range(1, pages + 1):
for r in local_results(query, page=page, **kwargs):
db.execute(
"INSERT OR REPLACE INTO snapshots VALUES (?, ?, ?, ?, ?, ?)",
(today, query, r["title"], r["address"] or "", r["rating"], r["reviews"]),
)
rows += 1
db.commit()
return rows
The key is name plus address, because two branches of a chain share a name. Where Google gives no address, the address is stored as an empty string, so two such branches with the same name would overwrite each other. Run snapshot() once a day, from cron or Task Scheduler. On our first run, two pages for dentist in austin tx stored 40 businesses for 2 credits.
To see what changed between the last two days:
def changes(db, query):
"""Compare the two most recent days stored for this query."""
days = [d for (d,) in db.execute(
"SELECT DISTINCT day FROM snapshots WHERE query = ? ORDER BY day DESC LIMIT 2", (query,))]
if len(days) < 2:
return []
new_day, old_day = days
return db.execute(
"""SELECT n.name, o.rating, n.rating, o.reviews, n.reviews
FROM snapshots n JOIN snapshots o
ON o.query = n.query AND o.name = n.name AND o.address = n.address
WHERE n.query = ? AND n.day = ? AND o.day = ?
AND (n.rating != o.rating OR n.reviews != o.reviews)
ORDER BY n.reviews - o.reviews DESC""",
(query, new_day, old_day),
).fetchall()
db = init_db()
query = "dentist in austin tx"
snapshot(db, query)
for name, old_rating, new_rating, old_reviews, new_reviews in changes(db, query):
print(f"{name}: {old_rating} -> {new_rating} stars, {old_reviews} -> {new_reviews} reviews")
Straight after the first snapshot, changes() returns an empty list because there is only one day of data. We also checked the comparison by editing a stored review count and taking a second snapshot: the changed business came back with its old and new counts. From the second day of real data, the loop prints one line per business whose rating or count moved.
Send those lines to Slack or email, or add a threshold, such as only businesses that gained more than 20 reviews, and you have a local competitor watch. Because the count is rounded above 1,000, the most reliable movers are businesses below that mark, and for the large ones compare weeks rather than days.
Other things you can do with the same data
- Rank by rating inside a market. Sort a query’s results by
ratingandreviewsto see who leads a category in a city. Search the same query for several cities to compare them. - Build a lead list. Filter a city and category by rating or review count.
website,phoneandaddresscome back with each result where Google shows them. - Compare countries.
countrytakes one of 31 two-letter codes, andlanguagea two-letter code, so you can run the same category in the UK and Germany.
Cost
Every request is 1 credit on every queue. Starter is $1.00 per 1,000 requests and the largest pack $0.30 per 1,000, see pricing. Watching 50 queries daily with 2 pages each is 3,000 credits a month. Failed requests are not charged. Batch code for many queries at once is in Get Google search results as JSON with Python, and works with endpoint set to google-local.
Next steps
You know which route fits which question: Google’s Business Profile API for your own reviews, and the Local API for ratings and review counts across any set of businesses, with a monitor that records every change. The Google Local API page lists every parameter with a full example response, and the local business data page shows more ways teams use it.
Frequently asked questions
- Is there a Google Reviews API?
- Yes, through the Google Business Profile API. It lists the reviews of a location through accounts.locations.reviews.list, and you call it with OAuth 2.0 credentials, using the accounts and locations in your Business Profile. For businesses that are not yours, there is no Google API, so you read the rating and review count from Google's local results instead.
- Can I get the text of reviews for any business?
- Not with the CrawlerData Local API. It returns each business's rating and review count, plus name, category, address, phone, hours and website where Google shows them. It does not return the text of individual reviews.
- How do I get the rating and number of reviews for a business in Python?
- POST to https://api.crawlerdata.com/v1/jobs with endpoint google-local and a query such as dentist in austin tx. Each item in local_results has a rating and a reviews count. This guide has the full code and a SQLite monitor.
- How many businesses does one request return?
- In our October 2026 tests, 20 per page for the queries we tried, 21 for one German query. Pages 1 to 10 are available, each page is a separate request of 1 credit, and page 2 returned different businesses from page 1.
- Are review counts exact?
- Small counts looked exact in our sample (916, 742), but counts over 1,000 looked rounded, for example 1200, 3600 and 9800. For tracking how fast a business collects reviews, use businesses with under 1,000 reviews or compare over longer periods.
- How much does it cost to monitor competitor ratings?
- 1 credit per request. Tracking 50 queries a day with 2 pages each is 50 × 2 × 30 = 3,000 credits a month, $3.00 at the Starter rate of $1.00 per 1,000, and less on larger packs.
- Google Reviews API
- Google Local API
- Local SEO
- Python
- Tutorial