Type a place and Web Unlocker returns its Google reviews page: the rating, how many ratings each star got, the topics people mention and the top reviews with their text, billed as one page. A page that fails to load costs nothing.
1,000 free requests · Pay only on success · 195+ countries · Claude ready
A Google Maps page takes 5 to 20 seconds, and a page that comes back empty is asked for again. It is still working, no need to click again.
Ready for your own places? Get an API key or book a demo.
Tell us a little about your team and get:
A place's Google Maps page carries its rating, the count for each star, the topics people mention and the top reviews, and Web Unlocker bills it as one page. The Google Places API bills every call and returns 5 reviews. Review scrapers bill every review.
A hard page costs
the same as an easy one.
A page that fails to load costs nothing. You pay for a rendered page, nothing else.
What Google reviews for 1,000 places cost
1,000 place pages with their top reviews, at published prices
Web Unlocker on the Growth plan, $0.98 per 1,000 pages. The others bill the 3,000 reviews on those pages, or 1,000 calls with 5 reviews each.
The official API stops at 5 reviews a place and bills every call. Review scrapers bill every review. Here is what each route takes for the same 1,000 places.
| What it takes | Google Places API | Apify | Outscraper | |
|---|---|---|---|---|
| Start without a Google API key | Yes | No | Yes | Yes |
| You pay for | A page | Each call | Each review | Each review |
| 1,000 places with their top reviews | $0.98 | $25 | $1.80 | $9 |
| Ratings split by stars, 5 to 1 | Yes | No, the average only | No | Yes |
| Review topics with counts | Yes | No | No | No |
| The whole page in HTML or Markdown | Yes | No | No | No |
Scraping more than Google reviews? Web Unlocker returns any page the same way, at the same price.
Web Unlocker has no alerts of its own. Your script opens each location's page once a day: when the rating or the review count has moved, there are new reviews to read. 1,000 locations come to $0.98 a day.
Review monitoring tools start at $65 a month per location.
Your own check costs $0.001.
One request per place: send the Google Maps address of the place, get the rendered page back, read the rating, the star counts, the topics and the reviews. The demo above runs the same parser.
Fill in the form above. The key arrives by email within one business day.
google.com/maps/search/ plus the place and its city, and the country to open it from.
The page carries the rating, the count for each star, the topics with their counts and the top reviews, each with the author, the stars, the date and the text.
pip install requestsGOLOGIN_SCRAPING_API_KEY=your_key python google_reviews.pyhttps://parsing.webunlocker.gologin.com/v1/scrapeimport json
import os
import re
import time
from urllib.parse import quote_plus
import requests
place = "Franklin Barbecue Austin"
address = f"https://www.google.com/maps/search/{quote_plus(place)}?hl=en&ucbcb=1"
html = ""
for attempt in range(3):
response = requests.get(
"https://parsing.webunlocker.gologin.com/v1/scrape",
headers={"apikey": os.environ["GOLOGIN_SCRAPING_API_KEY"]},
params={
"url": address if attempt == 0 else f"{address}&_r={int(time.time())}",
"render_js": "true",
"wait": "9000",
"geo": "us",
"format": "json",
},
timeout=120,
)
html = response.json().get("data", {}).get("html", "")
if 'data-review-id="' in html:
break
def first(pattern):
match = re.search(pattern, html)
return match.group(1) if match else None
blocks = {}
for match in re.finditer(r'data-review-id="([^"]+)"', html):
blocks.setdefault(match.group(1), match.start())
starts = sorted(blocks.values()) + [len(html)]
reviews = []
for start, end in zip(starts, starts[1:]):
block = html[start:end]
author = re.search(r'class="d4r55[^"]*"[^>]*>([^<]+)<', block)
text = re.search(r'class="wiI7pd"[^>]*>([^<]*)<', block)
if author and text:
stars = re.search(r'aria-label="(\d) stars?"', block)
date = re.search(r'class="rsqaWe"[^>]*>([^<]+)<', block)
reviews.append({
"author": author.group(1),
"stars": int(stars.group(1)) if stars else None,
"date": date.group(1) if date else None,
"text": text.group(1),
})
print(json.dumps({
"name": first(r"<h1[^>]*>([^<]+)"),
"rating": first(r'class="F7nice[^"]*"[^>]*>\s*<span><span aria-hidden="true">([\d.]+)<'),
"ratings": first(r'aria-label="([\d,]+) reviews?">\('),
"stars": {level: first(rf'aria-label="{level} stars?, ([\d,]+) reviews?"') for level in "54321"},
"topics": dict(re.findall(r'aria-label="([^",]+), mentioned in ([\d,]+) reviews?"', html)),
"reviews": reviews,
}, indent=2, ensure_ascii=False))GOLOGIN_SCRAPING_API_KEY=your_key node reviews-batch.mjshttps://parsing.webunlocker.gologin.com/v1/scrapeconst places = [
'Franklin Barbecue Austin',
'Katz Delicatessen New York',
'Relax and Smile Dental Care Miami',
];
const number = (text) => (text ? Number(text.replace(/,/g, '')) : null);
async function pageOf(place, attempt) {
const address = `https://www.google.com/maps/search/${encodeURIComponent(place).replace(/%20/g, '+')}?hl=en&ucbcb=1`;
const params = new URLSearchParams({
url: attempt === 1 ? address : `${address}&_r=${Date.now()}`,
render_js: 'true',
wait: '9000',
geo: 'us',
format: 'json',
});
const response = await fetch(`https://parsing.webunlocker.gologin.com/v1/scrape?${params}`, {
headers: { apikey: process.env.GOLOGIN_SCRAPING_API_KEY },
});
return (await response.json()).data?.html ?? '';
}
async function reviewsOf(place) {
let html = '';
for (let attempt = 1; attempt <= 3 && !html.includes('data-review-id='); attempt += 1) {
html = await pageOf(place, attempt);
}
const star = (level) => number(html.match(new RegExp(`aria-label="${level} stars?, ([\\d,]+) reviews?"`))?.[1]);
return {
place: html.match(/<h1[^>]*>([^<]+)/)?.[1] ?? place,
rating: number(html.match(/class="F7nice[^"]*"[^>]*>\s*<span><span aria-hidden="true">([\d.]+)</)?.[1]),
ratings: number(html.match(/aria-label="([\d,]+) reviews?">\(/)?.[1]),
fiveStar: star(5),
oneStar: star(1),
topReview: html.match(/class="wiI7pd"[^>]*>([^<]{0,80})/)?.[1],
};
}
const rows = [];
for (const place of places) rows.push(await reviewsOf(place));
console.table(rows);GOLOGIN_SCRAPING_API_KEY=your_key node reviews-watch.mjshttps://parsing.webunlocker.gologin.com/v1/scrapeimport { readFile, writeFile } from 'node:fs/promises';
const places = ['Franklin Barbecue Austin', 'Katz Delicatessen New York', 'Relax and Smile Dental Care Miami'];
const FILE = 'reviews.json';
const number = (text) => (text ? Number(text.replace(/,/g, '')) : null);
async function pageOf(place, attempt) {
const address = `https://www.google.com/maps/search/${encodeURIComponent(place).replace(/%20/g, '+')}?hl=en&ucbcb=1`;
const params = new URLSearchParams({
url: attempt === 1 ? address : `${address}&_r=${Date.now()}`,
render_js: 'true',
wait: '9000',
geo: 'us',
format: 'json',
});
const response = await fetch(`https://parsing.webunlocker.gologin.com/v1/scrape?${params}`, {
headers: { apikey: process.env.GOLOGIN_SCRAPING_API_KEY },
});
return (await response.json()).data?.html ?? '';
}
async function countOf(place) {
let html = '';
for (let attempt = 1; attempt <= 3 && !html.includes('data-review-id='); attempt += 1) {
html = await pageOf(place, attempt);
}
return {
rating: number(html.match(/class="F7nice[^"]*"[^>]*>\s*<span><span aria-hidden="true">([\d.]+)</)?.[1]),
ratings: number(html.match(/aria-label="([\d,]+) reviews?">\(/)?.[1]),
};
}
const before = JSON.parse(await readFile(FILE, 'utf8').catch(() => '{}'));
const today = { ...before };
for (const place of places) {
const now = await countOf(place);
const was = before[place]?.ratings ?? null;
if (now.ratings === null) console.log(`${place}: no page today, ask again`);
else if (was === null) console.log(`${place}: first check, ${now.ratings} ratings, ${now.rating} stars`);
else if (now.ratings > was) console.log(`${place}: ${now.ratings - was} new, now ${now.ratings} ratings, ${now.rating} stars`);
else console.log(`${place}: nothing new`);
if (now.ratings !== null) today[place] = now;
}
await writeFile(FILE, JSON.stringify(today, null, 2));Need the places first? The Google Maps scraper lists every place of a category in a city, and each one is one more page here.
One account, one proxy network, one ecosystem. Pick the product the job needs.
Scraping the places too? See the Google Maps scraper, the Reddit and YouTube scrapers, or every web scraping tool.
Send the place's Google Maps address to Web Unlocker: google.com/maps/search/ plus the name and the city. It opens the page in a real browser from the country you pick and returns it with the rating, the count for each star, the topics people mention and the top reviews, each with the author, the stars, the date and the text. The code above does exactly that.
Send the place address to Web Unlocker with the requests library and read the fields from the page. The Python tab above is a complete script, tested on the live API.
Yes. A place's Google Maps page is public and loads without a login. Web Unlocker returns it the way a visitor's browser sees it, with no Google Cloud project, no API key and no approval.
Two official ones. The Google Places API returns a place's rating and up to 5 reviews, at $25 per 1,000 calls. The Google Business Profile API returns every review, free, but only for locations you own or manage. For other places' reviews beyond those 5, with the star breakdown, Web Unlocker returns the Maps page itself.
That is its documented limit: Place Details returns at most 5 reviews a place, sorted by relevance, on the SKU that costs $25 per 1,000 calls. It gives the average rating and no star breakdown. The Maps page carries the count for each star and the review topics, and Web Unlocker returns the whole page.
The top 3 reviews with their full text, plus the rating, the count for each star level and the topics with their counts. Since September 2026 Google Maps shows the full list of a place's reviews only after a sign-in, so that is what every tool reading the public page gets. For your own locations, the Google Business Profile API lists every review free.
Not from the public page: Google keeps the full list and the sort options behind a Google sign-in. What stays public is the summary and the top reviews, and that comes back as one page at one price.
Sorting sits behind the sign-in too. The page carries the top reviews. To catch new ones, compare the review count and the rating with your last run: the Daily check tab above does that for a list of places.
Yes: how many ratings each star level got, 5 to 1, for every place. Franklin Barbecue in Austin on the day of our test: 6,053 five-star, 695 four-star, 285 three-star, 104 two-star and 199 one-star ratings.
Yes, in two steps. The Google Maps scraper lists the places of a category tile by tile, then each place is one more page here. 146 dentists in Miami came from 25 search pages; their 146 review pages make it 171 pages, about 17 cents in all.
If you own or manage the listing, use the Google Business Profile API: it lists every review of your locations free, 50 a page, once Google approves your project. Web Unlocker is for places you do not manage.
Web Unlocker returns the page, not a table, so nothing is cut before you see it. Turning it into a CSV takes a few lines of code, or one prompt: hand the page to Claude with the Gologin scraping skill and ask for a CSV.
Under $1 per 1,000 pages, and the same price for every page: 1,000 places with their reviews come to $0.98. A page that fails to load costs nothing. Plans start at $49 a month for 50,000 requests.
Yes, to start: Web Unlocker comes with 1,000 free requests, enough for 1,000 places with their reviews.
No. Web Unlocker picks the IP for you, in 195+ countries, and opens the page from the country you choose.
It depends on what you need. Apify and Outscraper sell ready rows and bill every review. Web Unlocker returns the whole Maps page at one price per page, with the star breakdown and the topics the rows leave out, and you parse it your way.
A place's Maps page is public and loads without a login. Web Unlocker loads it the way a visitor's browser does and returns the page. What you collect and how you use it is your call, so check it against the rules that apply to your project.
Tell us a little about your team and get: