Google Maps Extractor with Reservation & Order Online Links avatar

Google Maps Extractor with Reservation & Order Online Links

Pricing

from $2.99 / 1,000 results

Go to Apify Store
Google Maps Extractor with Reservation & Order Online Links

Google Maps Extractor with Reservation & Order Online Links

Analyze local markets with fresh data from Google Maps. This actor helps you scrape key info on businesses in any region—great for research, expansion planning, or mapping competitors by category and location.

Pricing

from $2.99 / 1,000 results

Rating

0.0

(0)

Developer

SimpleAPI

SimpleAPI

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

6 days ago

Last modified

Share

Google Maps Extractor With Reservation & Order Online Links scrapes Google Maps business listings and, for every listing in the same request, the online-booking action Google carries in the same payload: the reservation or appointment deep link, the platform domain behind it (OpenTable, Resy, SevenRooms, TheFork, Tripleseat, Vagaro, and others Google surfaces), Google's own Reserve URL, and the button text shown on the listing. Each row also carries the standard place fields — name, full_address, phone, website, avg_rating, place_id, coordinates and today's opening hours. It's built for restaurant-tech and booking-platform vendors, local lead-gen agencies, and market researchers who need to know not just where a business is, but how someone books it.

It's a Google Maps scraper that reads the same map-search payload your browser gets when you search Google Maps, decodes the place record, and — in this build — also decodes the booking-action block Google ships alongside it. No Google account, API key, or Places API billing is required. Search is driven by keyword and location pairs (e.g. "restaurants" in "New York") or by pasting Google Maps links directly; results are deduplicated across every search by Google's own place_id.

Key capabilities, from the source:

  • 🔎 Discovery by keyword × location, or by URL. Every keywords entry is searched in every locations entry; urls (Google Maps /maps/search/ or /maps/place/ links) are worked in addition, not instead.
  • 📇 Core identifying and contact fields on every row — name, full address, phone, website, coordinates, Google's stable place_id.
  • 🍽️ The booking action as structured data, not a screenshot — channel classification (third_party / direct_site / google_reserve / none), provider domain and display name, the deep link itself, and Google's own Reserve URL — extracted from the same response, with no extra HTTP request per place.
  • 🎯 A bookable-only / no-booking filter (bookingPresence) and a provider allow-list (bookingProviders), so the output is already segmented into the list you actually sell against.
  • 📍 Area-accurate results — a bounding-box check (restrictToRequestedArea) discards places outside the geocoded area instead of letting Google's radiating search leak neighbouring regions into your data.
  • 📦 Exports to JSON, CSV, Excel, or via the Apify API through the standard Apify dataset — no separate export step.

Every row combines the base place record with the booking columns this build adds and two run-context fields. Field names below are the exact JSON keys src/main.py and src/booking.py write to each row.

FieldExample valueUse case
rowType"place"Row-type discriminator (this build only emits "place" rows)
name"Katz's Delicatessen"Business name
full_address"205 E Houston St, New York, NY 10002"Google's own one-line formatted address
street_address"205 E Houston St"Address component
city"New York"Address component
state"New York"Address component
zip"10002"Address component
country_code"US"Address component
phone"(212) 254-2246"Contact / cold-outreach field
website"https://www.katzsdelicatessen.com/"Contact field; also used to decide whether a booking link is the venue's own site
avg_rating4.5Google's average rating
tags["Deli"]Google's own category tags
place_id"ChIJCar0f49ZwokR6ozLV-dHNTE"Google's stable place identifier; used to dedupe across the whole run
lat / long40.7223 / -73.9874Coordinates
hours[{"day":"Sunday","hours":"8 AM-10:45 PM","opens_at":"08:00","closes_at":"22:45"}]Opening hours — current day only, see the limitation below
has_booking_actiontrueFilled on every row; the field to test before reading any other booking column
booking_channel"third_party"third_party | direct_site | google_reserve | none
booking_provider_count1Count of distinct third-party platforms detected (0 when none)
booking_providers["opentable.com"]Third-party platform domains only
booking_provider_names["OpenTable"]Google's display names for those platforms
booking_domains["opentable.com"]Every domain seen in the booking block, including the venue's own site if it hosts booking
booking_urls["https://www.opentable.com/r/katzs-delicatessen"]The booking/reservation deep links themselves
google_reserve_url"https://www.google.com/maps/reserve/v/dine/c/..."Google's own Reserve link, with per-request echo parameters stripped
booking_action_labels["Reserve a table"]The CTA button text Google shows on the listing
provider_logo_urls["https://lh3.googleusercontent.com/...=w80-h80"]Platform logo images, resized to 80×80 — only present when includeProviderLogos is true
search_term"restaurants"The keyword that produced this row
search_area"New York"The location (or URL) that produced this row

🎟️ Booking-platform signals

booking_channel is the field to filter and segment on. It is derived, in order: any domain that isn't the venue's own site and isn't Google itself → third_party; otherwise a booking link that resolves to the venue's own website → direct_site; otherwise a Google Reserve link with no named platform behind it → google_reserve; otherwise none. A restaurant-tech vendor building a switch-target list filters on booking_channel == "third_party" and reads booking_providers for the platform name; a booking aggregator prospecting for new venues filters on has_booking_action == false.

📍 Location and area-targeting fields

lat/long, city, state, country_code and place_id are what you group, map, or dedupe on. search_term and search_area record which keyword/location (or which pasted URL) produced each row, so a multi-city, multi-keyword run can still be sliced back apart after the fact.

Google's own Places API (New) can return place details, but the reservation data this Actor is built around isn't in it: Place.reservable is a plain boolean — it tells you a venue supports reservations, with no link, no provider name, and no way to tell OpenTable from a venue's own booking widget (Google Places API Place reference, checked 2026-08-04). This Actor reads the same map-search response your browser gets and pulls the actual deep link, the provider domain, and the CTA text out of it.

FeatureGoogle Places API (New)This Actor
Booking/reservation datareservable boolean only — no URL, no providerDeep link, provider domain + display name, Google Reserve URL, CTA label
SetupGoogle Cloud project, API key, billing account enabledApify account only — no Google credentials
Billing modelPer-field SKU tiers (Essentials / Pro / Enterprise / Enterprise + Atmosphere); reviews and reservable sit in the Enterprise + Atmosphere tierApify pay-per-event (row_result)
Opening hoursFull 7-day schedule (regularOpeningHours.periods)Current day only (see below)
Bulk multi-city sweepOne place per request, billed per requestOne run sweeps every keyword × location pair, deduplicated on place_id
Area-leak protectionNot applicable — a Place Details call always returns the place you asked forBounding-box filter plus a pre-run connection check

Why doesn't the official API expose the booking platform?

Google's Places API is built around structured place metadata, and reservable is deliberately a capability flag, not a link — Google's own field reference documents it as "Specifies if the place supports reservations," with no companion field for the provider or the URL (checked 2026-08-04). The reservation deep link, the provider's domain, and the Reserve button text only exist in the Maps front-end's own search response, which is the surface this Actor reads. If your workflow only needs to know whether a place takes reservations, the Places API's reservable field is enough. If you need to know who runs that booking — the actual platform and link — that data isn't in the official API's Place resource at all, and this is what this build extracts instead.

Use the official Places API when you need billed, per-place lookups tied to a Google Cloud project. Use this Actor when you need a keyword-and-area sweep of many places at once, with the booking-platform breakdown Google's own API doesn't expose.

💡 How to use data extracted from Google Maps?

🏢 Restaurant, salon and clinic tech vendors

Filter bookingPresence to bookable_only and bookingProviders to a competitor's domain (e.g. ["opentable"]) to build a switch-target list: every venue currently running a named competitor's booking platform, with name, full_address and phone ready for outreach and booking_provider_names confirming which platform to pitch against.

📈 Booking and delivery aggregators

Run the same keyword/area sweep with bookingPresence set to not_bookable_only. The output is the actual sales pipeline: venues Google shows no reservation or ordering action for at all, which has_booking_action == false on every row confirms without needing to check each listing by hand.

📊 Market researchers and analysts

Sweep several cities or categories (e.g. hair salon, dentists, restaurants) and compare the share of has_booking_action == true rows and the booking_channel split per category or metro — a density and adoption view of who has moved online-booking to a third-party platform versus their own site versus nothing at all.

🤖 AI agents and automated pipelines

Because the Actor is a standard Apify Actor, it's callable from any agent framework as an HTTP-triggered run: pass keywords/locations as tool parameters, poll the run, and read the dataset back as structured JSON for RAG context or downstream enrichment — no scraping or HTML-parsing logic to maintain on the agent side.

🔼 Input sample

Read directly from .actor/actor.json. keywords is the only required field.

ParameterRequiredTypeDescriptionExample value
keywordsYesarray of stringsOne search term per line — e.g. restaurants, italian restaurant, sushi, hair salon, dentists.["restaurants"]
locationsNoarray of stringsFree-text areas — e.g. New York, Brooklyn NY, London, Kyoto Japan. Each is resolved to a bounding box and swept with a grid of map searches.["New York"]
bookingPresenceNostring (enum)all keeps everything; bookable_only keeps only venues with a working online booking action; not_bookable_only keeps only venues with none at all."all"
bookingProvidersNoarray of stringsPlatform domains to keep, e.g. opentable.com, resy.com. A bare name like opentable also matches opentable.co.uk. Empty keeps every platform.[]
includeProviderLogosNobooleanAdds provider_logo_urls (Google-hosted 80×80 platform logos). Off by default — only useful for building a UI.false
maxResultsNointeger (1–10000)Total unique places across all search terms, areas and links. Duplicates are merged on Google place_id.20
restrictToRequestedAreaNobooleanDiscards places outside the geocoded bounding box of the area you asked for.true
deepTileScanNobooleanTriples the places examined per search point. Applied automatically whenever a booking filter is active.false
urlsNoarray of stringsGoogle Maps links, e.g. https://www.google.com/maps/search/restaurants/@40.7128,-74.0060,13z.[]
proxyConfigurationNoobjectYour proxy groups and country, passed through unchanged to every request.{"useApifyProxy": true}
{
"keywords": ["restaurants"],
"locations": ["New York"],
"bookingPresence": "bookable_only",
"bookingProviders": ["opentable", "resy.com"],
"maxResults": 50,
"restrictToRequestedArea": true,
"deepTileScan": false,
"urls": [],
"proxyConfiguration": { "useApifyProxy": true }
}

Common pitfall: urls only supports /maps/search/<terms>/@lat,lng,zoom and /maps/place/<Name>/@lat,lng,zoom links. A link copied from Maps' "Share" button that identifies a place only by place_id, ftid, or cid is not supported and is skipped with an error in the run log — paste the address-bar URL from a search or place page instead.

🔽 Output sample

Every run pushes one dataset item per unique place as typed, normalized JSON — no HTML, no nested scraping needed. Export straight from the Apify Console or API as JSON, CSV, Excel, or XML.

{
"rowType": "place",
"name": "Katz's Delicatessen",
"full_address": "205 E Houston St, New York, NY 10002",
"street_address": "205 E Houston St",
"city": "New York",
"state": "New York",
"zip": "10002",
"country_code": "US",
"phone": "(212) 254-2246",
"website": "https://www.katzsdelicatessen.com/",
"avg_rating": 4.5,
"tags": ["Deli"],
"place_id": "ChIJCar0f49ZwokR6ozLV-dHNTE",
"lat": 40.7223,
"long": -73.9874,
"hours": [
{ "day": "Sunday", "hours": "8 AM-10:45 PM", "opens_at": "08:00", "closes_at": "22:45" }
],
"has_booking_action": true,
"booking_channel": "third_party",
"booking_provider_count": 1,
"booking_providers": ["opentable.com"],
"booking_provider_names": ["OpenTable"],
"booking_domains": ["opentable.com"],
"booking_urls": ["https://www.opentable.com/r/katzs-delicatessen"],
"google_reserve_url": "https://www.google.com/maps/reserve/v/dine/c/abc123",
"booking_action_labels": ["Reserve a table"],
"provider_logo_urls": [],
"search_term": "restaurants",
"search_area": "New York"
}

🎯 How do you filter and target specific places?

Four real controls determine what ends up in your dataset:

  1. Keyword vs. URL. keywords + locations runs a category sweep across a grid of map points — the right choice for "every restaurant in Chicago." urls targets a specific Maps search or place link directly and skips geocoding — the right choice when you already have a Maps URL in hand and want that exact scope, not a citywide sweep.
  2. Area precision. locations free text is geocoded to a bounding box and padded before the sweep starts; restrictToRequestedArea (on by default) then discards any place outside that box, so a "New York" search doesn't leak New Jersey venues. Turn it off only if you'd rather see everything Google's radiating search returns.
  3. Booking-status targeting. bookingPresence splits the output into bookable-only, no-booking-only, or everything; bookingProviders narrows further to specific platform domains. Either filter automatically triples the depth of each map point scanned (the same effect as deepTileScan), since a strict filter needs a bigger pool of raw places to draw from.
  4. Volume. maxResults caps total unique places (1–10,000) across every keyword/location/URL combination, deduplicated on place_id. The budget is split across your combinations as the run progresses, and a booking filter searches more of the map — it never silently returns fewer rows than you asked for without a reason logged.
{ "keywords": ["hair salon"], "locations": ["Chicago"], "bookingPresence": "bookable_only", "maxResults": 200 }
{ "keywords": ["restaurants"], "locations": ["London"], "bookingPresence": "bookable_only", "bookingProviders": ["opentable"], "maxResults": 100 }
{ "urls": ["https://www.google.com/maps/search/dentists/@34.0522,-118.2437,13z"], "keywords": ["dentists"], "bookingPresence": "not_bookable_only", "maxResults": 50 }

🔗 Want to try other Google Maps scrapers?

This account doesn't currently list another Google Maps scraper, but if you're building out a directory-and-leads workflow, these two cover adjacent ground:

ScraperWhat it extracts
Tripadvisor Review Scraper: Photo & Visual Content FiltersHospitality reviews and visual content from Tripadvisor listings
Otomoto.pl Scraper With Dealer Contact LeadsVehicle listings plus the dealer's phone, address and storefront behind each one

🔌 How to extract Google Maps data programmatically

This Actor runs like any Apify Actor: start it from the Apify Console, via the apify_client SDK, or with a direct API call, and read results back as structured JSON from the run's dataset.

Python example

from apify_client import ApifyClient
client = ApifyClient("<APIFY_API_TOKEN>")
run = client.actor("<username>/google-maps-extractor-with-reservation-order-online-links").call(
run_input={
"keywords": ["restaurants"],
"locations": ["New York"],
"bookingPresence": "bookable_only",
"maxResults": 100,
}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item["name"], item["booking_channel"], item["booking_urls"])

Export to spreadsheets or CRM

Every dataset can be exported directly as CSV or Excel from the Apify Console or API — map name, full_address, phone and website to your CRM's contact columns, and booking_channel / booking_provider_names to a custom field for lead segmentation.

Yes — this Actor reads publicly rendered Google Maps listings, the same business information (name, address, phone, hours, booking links) any visitor's browser receives when they search Maps. These are business directory records, not personal profiles, so the relevant framework is Google's own Terms of Service and database/intellectual-property rights around the Maps platform, not GDPR or CCPA. Automated collection at scale should still respect Google's Terms of Service, and results should not be republished as a competing map product. Consult legal counsel for commercial applications involving bulk storage or redistribution of this data.

❓ FAQ

Does the output flag venues that have closed or moved?

No. This build does not extract a closed/business-status field — it returns whatever Google's live map-search payload contains for each place at request time. Permanently closed venues typically stop appearing in Maps search results at all rather than being flagged in the data, so treat every row as current as of the run.

Yes, on the same row, from the same request. has_booking_action, booking_channel, booking_urls, booking_domains, booking_provider_names and google_reserve_url are all populated from the same Google Maps response the place data comes from — no second request per place, no extra credit. Coverage varies by category: Google's own input description reports the booking block was present on 44.0% of places in an 840-place measured sample, ranging from 90.8% for London Italian restaurants down to 0.8% for New York hotels. has_booking_action is filled on every row (true or false either way), so filtering never returns a blank column.

How accurate is the contact and booking data?

The Actor returns data exactly as Google's Maps payload carries it at request time — it does not call the venue, the booking platform, or the venue's own site to verify anything. Phone numbers, websites and booking links are only as current as Google's own listing; treat a batch of leads with the usual validation step (a deliverability or reachability check) before an outreach campaign.

How many places can I get per run?

maxResults accepts 1 to 10,000 and defaults to 20. That cap is a total across every keywords × locations pair and every urls entry combined, deduplicated on Google's place_id — not a per-search-term limit. A tight bookingPresence filter searches more of the map to fill the same target rather than returning fewer rows, and the run log reports how many places were found, filtered, and discarded as duplicates or out-of-area.

How do I build a list of venues with no online booking at all?

Set bookingPresence to not_bookable_only. The Actor automatically scans each map point more deeply (the same 3x multiplier deepTileScan applies) whenever a booking filter is active, since discarding most of what it finds needs a bigger raw pool to draw from — you don't need to set deepTileScan yourself for this to work.

It isn't currently reachable through an MCP server. It is callable as a standard HTTP-triggered Apify Actor by any agent framework that can make an authenticated API call and poll for run completion — via apify_client, a direct REST call, or Apify's own integrations.

Can I use this without a Google API key or developer account?

Yes. No Google account, API key, or Places API billing is required — only an Apify account. Apify Proxy is enabled by default in the input; the Actor escalates from datacenter to residential exits on its own if Google starts refusing requests, so no proxy setup is required to get started either.

✅ Conclusion

google-maps-extractor-with-reservation-order-online-links turns a Google Maps keyword-and-area sweep into structured leads that already know how each venue takes bookings — the reservation link, the platform behind it, and Google's own Reserve URL, with no extra request and no extra charge over the base place data. It's built for restaurant-tech and booking-platform vendors building switch-target or prospecting lists, and for researchers tracking booking-platform adoption across cities and categories. Start a run from the Apify Console with a keyword and a city, or call it through apify_client, and read the results back as clean JSON.