What is restoapi.org for Google Maps?
restoapi.org wraps Google Maps restaurant pages in a clean async API. You send the URL of any restaurant on Google Maps, we return a complete structured snapshot — the restaurant's card, every review we can fetch, every photo category, opening hours per day, amenities, popular times graphs.
Unlike Google Places API (which limits photos, requires API quota management, charges per request, and gives you a paginated mess for reviews), we deliver one comprehensive download. One URL in, one ZIP out.
What we extract from every Google Maps restaurant
Restaurant card
- Name, full address, phone, website
- Coordinates (lat/lon) + Plus Code
- Category tags ("Italian restaurant", "Family-friendly")
- Overall rating (0.0–5.0) + breakdown by 1★/2★/3★/4★/5★
- Total review count
- Price level ($ / $$ / $$$ / $$$$)
- Opening hours per day of week
- Current open/closed status with next change
- Popular times (hourly histogram per day)
- Amenities list (wheelchair accessible, outdoor seating, kids menu, etc)
- Order providers (Uber Eats, DoorDash, GrubHub) with deep links
Reviews — up to 2000 with full text
We scroll the reviews panel to fetch as many as you want. Default
target_reviews: 300. Each review includes:
- Author name + profile image URL
- Rating (1–5 stars)
- Date (relative + parsed absolute)
- Full review text (we expand "see more" automatically)
- Photos attached to the review
- Owner's response (when present)
- Stable
review_idfor de-duplication across runs
Output as both reviews.json (structured) and reviews.csv
(Excel-friendly).
Photos — every category
cover— the restaurant's hero shotplace— interior, food, atmosphere shotsmenu— menu strip photos (when Google has them)reviews— photos uploaded by reviewers
Configurable via photos_mode option:
"full"— every category, every photo (~450 photos for popular spots)"menu_only"— only menu strip, ~50–150 photos, no dupes"skip"— only hero+cover, ~2 photos, fastest run
Menu items (when Google has them)
For restaurants with a "Menu" tab in Google Maps, we walk through every sub-tab and extract each item: name, price (when shown), description, photo. Canonical format same as Wolt — drop-in compatibility if you process both platforms in the same pipeline.
Why us vs Google Places API
| Aspect | restoapi.org | Google Places API |
|---|---|---|
| Reviews per restaurant | ✓ Up to 2000 | 5 reviews max |
| Photo count | ✓ Hundreds | 10 max per request |
| Photos downloaded as files | ✓ in ZIP | URLs only, expiring |
| Popular times (hourly graph) | ✓ | Not in API |
| Order provider deep links | ✓ | Not in API |
| Quota management | ✓ Pay per task | Quotas, billing tier complexity |
| Free tier | $0.50 credit on signup | $200/month with caveats |
| Per-restaurant price | $0.15 full media | Variable, often higher with all add-ons |
Data examples
1. Restaurant card
{
"name": "La Trattoria Romana",
"address": "Via dei Foraggi 1, 00184 Roma RM, Italy",
"coordinates": {"lat": 41.8902, "lon": 12.4845},
"phone": "+39 06 1234 5678",
"website": "https://trattoriaromana.it",
"categories": ["Italian restaurant", "Pizza", "Family-friendly"],
"price_level": "$$",
"plus_code": "VFR8+CV Roma",
"is_open": true,
"open_status": "Closes 23:00",
"hours": {
"monday": ["12:00–15:00", "19:00–23:00"],
"tuesday": ["12:00–15:00", "19:00–23:00"],
...
"sunday": ["Closed"]
},
"amenities": [
"Wheelchair accessible",
"Outdoor seating",
"Kids menu",
"Reservations",
"Wi-Fi"
],
"order_providers": [
{"name": "Uber Eats", "url": "https://ubereats.com/..."},
{"name": "Just Eat", "url": "https://just-eat.it/..."}
]
}
2. Rating breakdown
{
"overall": 4.6,
"total_count": 2847,
"fetched_count": 300, // what we scrolled
"distribution": {
"5": 2102,
"4": 524,
"3": 142,
"2": 45,
"1": 34
}
}
3. Single review with all fields
{
"review_id": "ChdDSUhNMG9nS0VJQ0FnSUM4LXJ...",
"author": "Marco Bianchi",
"author_photo": "https://lh3.googleusercontent.com/...",
"author_reviews_count": 37,
"rating": 5,
"date": "2 weeks ago",
"date_iso": "2026-05-08",
"text": "Eccellente trattoria romana, atmosfera autentica...",
"photos": [
"photos/reviews/marco_bianchi_001.jpg",
"photos/reviews/marco_bianchi_002.jpg"
],
"owner_reply": {
"text": "Grazie Marco! Ci fa piacere...",
"date_iso": "2026-05-10"
}
}
4. Popular times (hourly histogram)
{
"day": "tuesday",
"hours": [
{"hour": 11, "busy_percent": 5},
{"hour": 12, "busy_percent": 35},
{"hour": 13, "busy_percent": 82}, // lunch peak
{"hour": 14, "busy_percent": 68},
{"hour": 15, "busy_percent": 20},
...
{"hour": 20, "busy_percent": 95}, // dinner peak
{"hour": 21, "busy_percent": 88}
]
}
5. Photos archived (with categorization)
{
"cover": [{"local_url": "photos/cover/hero01.jpg", "size_kb": 412}],
"place": [
{"local_url": "photos/place/interior_01.jpg", "category": "Interior"},
{"local_url": "photos/place/food_01.jpg", "category": "Food & drink"},
...
],
"menu": [{"local_url": "photos/menu/strip_01.jpg"}],
"reviews": [{"local_url": "photos/reviews/r001.jpg", "review_id": "ChdD..."}]
}
What people build with Google Maps data
- Review sentiment analysis — 2000 reviews per restaurant fed into an LLM or sentiment classifier to identify trends: what do people love / complain about?
- Popular-times-aware booking systems — "best time to visit" features based on historical busy-ness data.
- Photo content moderation training — labelled photo categories (Interior, Food, Drink, Menu, Outside) are gold for vision-model training sets.
- Competitive intelligence — track competitor's rating and review velocity. New 1★ review wave? Send an alert.
- Restaurant aggregator metadata — pre-fill restaurant cards on your aggregator with phone, hours, photos, all in one call.
- SEO / local search content — build curated "best Italian in Rome" pages with rich data: photos, reviews quotes, hours, popular times.
Code: Google Maps scrape in Python
import requests, time H = {"Authorization": "Bearer rk_live_xxx"} job = requests.post("https://restoapi.org/v1/jobs", headers=H, json={ "source_url": "https://maps.google.com/?cid=14245678901234567890", "platform": "googlemaps", "export_type": "full_media", "options": { "target_reviews": 500, "photos_mode": "full" } }).json() while True: time.sleep(20) s = requests.get(f"https://restoapi.org/v1/jobs/{job['job_id']}/status", headers=H).json() if s["status"] == "completed": break import zipfile, json zip_url = s["downloads"]["full_export_zip"]["url"] open("gm.zip", "wb").write(requests.get(zip_url).content) with zipfile.ZipFile("gm.zip") as z, z.open("reviews.json") as f: reviews = json.load(f) print(f"fetched {len(reviews)} reviews")