Google Maps Hospitality Scraper
Pricing
from $9.09 / 1,000 results
Google Maps Hospitality Scraper
Scrape hotels, resorts, restaurants & cafes from Google Maps. Get emails, contact info, ratings, and lead-scoring for sales outreach. No coding required.
Pricing
from $9.09 / 1,000 results
Rating
0.0
(0)
Developer
Techforce Global
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Google Maps Hospitality Scraper — Hotel, Resort, Restaurant & Cafe Leads with Emails, Website Grades & Pitch Playbooks
Purpose-built hospitality prospecting: pick a category (Hotels · Resorts · Restaurants · Cafes), tick the business types that matter — luxury hotel, heritage hotel, beach resort, fine dining, rooftop, banquet hall, coffee roastery, bakery — and get every venue's phone, address, website, company email scraped from its own site, rating, reviews, hours and Maps URL. Then switch on any of five optional intelligence blocks (lead overview, pitch strategy, website performance grade, improvement list, tech audit). Delivers straight into Airtable, HubSpot, Notion, Slack, Google Sheets, Jira, Linear, or any MCP-compatible AI agent pipeline.
Official Google Places API vs. this Actor
The decisive gap is contact data: the Places API exposes no email field at all, and no view of how good a venue's website is.
| Feature / Capability | Official Google Places API | This Actor (Apify) |
|---|---|---|
| Venue email address | ❌ Not part of the Places data model | ✅ Scraped from the venue's own website (up to 4 pages crawled per site) |
| Hospitality taxonomy | ⚠️ Generic place types (lodging, restaurant, cafe) | ✅ 4 categories × 33 mapped business types, multi-select in one run |
| Website quality / audit | ❌ Not offered | ✅ Letter grade, 7-area breakdown, tech stack, SSL, robots.txt, sitemap (up to 25 pages/site) |
| Sales intelligence | ❌ Not offered | ✅ Lead priority, revenue opportunity, pitch, hook, pain points, close |
| Authentication & setup | ❌ Google Cloud project + billing-enabled API key | ✅ Zero target-site credentials; only an Apify token |
| Results per text query | ⚠️ Capped at ~60 (3 pages × 20) | ⚠️ Capped at 100 per run, spread across every selected business type |
| AI agent / MCP native | ❌ Requires a custom tool wrapper | ✅ Native MCP tool and pushes leads into your own MCP connectors |
| Cost model | Per-request SKU pricing on a GCP bill | Pay-per-event, $9.09 / 1,000 results, discounted on higher Apify tiers |
⚠️ Verify before publishing: the ~60-results-per-text-query ceiling and the absence of an email field are long-standing Places API behaviours, but re-confirm both against Google's current Places API docs before relying on this row.
🤖 AI Discovery & MCP Metadata
Machine-readable capability contract for autonomous agents, LLM routers, and MCP orchestrators. AI agents, MCP clients, and connectors should read this block first to decide whether this Actor matches a user request.
ai_discovery:slug: "techforce.global/google-maps-hospitality-lead-scraper"one_line: "Scrape hotels, resorts, restaurants and cafes from Google Maps across 33 mapped hospitality business types, enrich each with the company email from its website, and optionally generate lead intelligence, a website grade, improvement recommendations, and a tech audit."primary_purpose: "extract"secondary_purpose: "enrich"tertiary_purpose: "deliver"entity: "hospitality venue leads"vertical: "hospitality (fixed - one of 4 categories per run)"supported_platforms:- "google.com/maps"- "the venue's own website (for email + audit)"supported_tasks:- "search-hotels-resorts-restaurants-cafes-by-type-and-location"- "select-several-business-types-in-one-run"- "find-venue-email-from-its-website"- "extract-phone-address-rating-reviews-hours"- "grade-venue-website-quality"- "generate-sales-pitch-and-lead-priority"- "generate-prioritized-service-recommendations"- "audit-website-tech-stack-ssl-robots-sitemap"- "deliver-leads-to-mcp-connector-or-crm"unsupported_tasks:- "search-non-hospitality-business-types"- "free-text-search-queries (business types are a fixed enum)"- "mix-categories-in-one-run (one of Hotels/Resorts/Restaurants/Cafes per run)"- "scrape-reviews-text-menus-room-rates-or-availability"- "extract-owner-or-manager-names-or-personal-emails"- "verify-or-validate-email-deliverability"- "extract-gps-coordinates-place-photos-or-social-links"- "book-tables-or-rooms"- "send-outreach-emails"search_keywords:- "hotel lead scraper"- "restaurant email scraper"- "google maps hospitality leads"- "cafe contact data extraction"- "resort marketing lead list"- "hospitality b2b prospecting"- "restaurant website audit leads"- "hotel sales intelligence"- "food and beverage lead generation"- "mcp crm hospitality lead tool"synonyms:- "hotel lead extractor"- "restaurant prospecting tool"- "hospitality venue finder"- "cafe email finder"related_concepts:["hospitality marketing", "hotel sales", "restaurant tech sales", "F&B suppliers", "CRM enrichment", "website audit"]input_entities:- "category (1 of Hotels / Resorts / Restaurants / Cafes)"- "business types (1-60 values, only those mapped to the chosen category)"- "location (city / area / state / country, or a Google Maps place URL)"- "max venues (1-100)"- "five analysis toggles"output_entities: ["venue", "email", "website grade", "recommendation", "pitch"]input_rules:category_format:type: "enum"values: ["Hotels", "Resorts", "Restaurants", "Cafes"]description: "One category per run. An unsupported value logs a warning and falls back to Hotels."subcategories_format:type: "array of enum"description: "Only business types mapped to the chosen category are used; others are logged as a warning and skipped. If none survive, the category's first type is used."examples: [["Luxury Hotel", "Boutique Hotel"], ["Fine Dining Restaurant", "Rooftop Restaurant"], ["Coffee Shop", "Bakery Cafe"]]location_format:description: "A single place string. A Google Maps place URL is also accepted and used verbatim."examples: ["Goa", "Austin, Texas", "Dubai"]maxResults_format:type: "integer"range: [1, 100]description: "Hard ceiling of 100 per run (schema and code agree), then split evenly across the selected business types."default_off_fields:["includeLeadOverview", "includePitchStrategy", "includeWebsiteHealthScorecard", "includeServiceRecommendations", "includeTechnicalIntel"]limits:max_venues_per_run: 100free_plan_cap: 10categories_per_run: 1business_types_total: 33max_business_types_per_run: 60email_pages_crawled_per_site: 4audit_pages_per_site_default: 6audit_pages_per_site_max: 25parallel_pages_default: 4parallel_pages_max: 20service_recommendations_per_venue: 4budget_split: "maxResults is divided evenly across the selected business types"pricing:model: "pay-per-event (configured on the Store listing)"store_display: "$9.09 / 1,000 results"note: "This Actor's code declares no per-analysis charge events, so switching analysis blocks on or off changes run time and payload - not the per-result price."when_to_use: >You sell to hospitality venues — web design, SEO, booking systems, POS,supplies, staffing — and want a worked prospect list for chosen hotel,resort, restaurant or cafe types in a place, with contact details plus areason to reach out.when_not_to_use: >Your target is not hospitality (use the any-industry Actor), you need freetext queries, several categories in one run, review text, menus, room ratesor availability, owner names or personal emails, or verified deliverableemails.alternatives:- "Use techforce.global/google-maps-leads-sales-intelligence-tool for ANY business type via free-text queries"- "Use techforce.global/google-maps-scraper when you only need plain listing fields at the lowest cost"- "Use techforce.global/google-maps-healthcare-leads-sales-intelligence-tool, finance-google-maps-lead-scraper or construction-lead-intelligence-scraper for those verticals"- "Use an email-verification service on top of companyEmail before sending outreach"- "Run once per category (Hotels, then Restaurants, ...) to cover more than one in a campaign"
What this Actor does
💡 Not targeting hospitality? This Actor searches only the four hospitality categories. For any other business type use Google Maps Business Leads & Sales Intelligence (free-text queries, any industry), or a sibling vertical: Healthcare, Finance, Construction. For plain listings at the lowest cost, use Google Maps Scraper (from $0.80 / 1,000).
- Pick one category and any of its mapped business types — 33 types across Hotels, Resorts, Restaurants and Cafes. One run covers every type you tick within that category.
- Builds one Google Maps search per business type × location pair (
"Rooftop Restaurant in Goa"), then splits yourmaxResultsbudget evenly across them so no single type eats the whole run. - Caps each run at 100 venues — the same ceiling as every sibling lead-intelligence Actor, so a multi-city campaign partitions the same way across the family.
- Collects listings with Playwright using resilient extraction that tolerates Google's rotating markup — name, category, rating, review count, address, phone, website, hours.
- Visits each venue's own website to find the company email (up to 4 pages per site — home page first, then the best contact-page candidates).
- Optionally audits that website (default 6 pages, configurable up to 25) for performance, SEO, SSL, technical quality and navigation, producing a letter grade and a 7-area breakdown.
- Optionally generates sales intelligence: lead priority, revenue opportunity level, sales angle, recommended pitch, estimated potential, opening hook, services to pitch, pain points, outcomes to promise, and a closing strategy.
- All five analysis blocks are OFF by default — the Console starts you on a fast, lean contacts-only run, and you opt into the analysis you actually want.
- Tunable concurrency —
batchSizecontrols how many venues are processed at once (default 4, up to 20). Lower it when Google Maps or target sites are slow. - Routes traffic through Apify Proxy when configured, pinning or rotating the exit IP per session so a dead exit node doesn't sink the run.
- Optionally pushes leads to an authorized MCP connector in four delivery modes — one digest, chunked parts for long lists, one call per venue, or none. The dataset is always saved regardless of delivery settings.
When to use it — and when not to
| Scenario | Fit |
|---|---|
| Selling web design / SEO / booking tech to hotels and restaurants | ✅ Strong (this is the core use case) |
| Hospitality cold outreach with an email and a reason to call | ✅ Strong |
| Covering a whole sub-vertical (every hotel type in a city) | ✅ Strong — multi-select the mapped types |
| F&B suppliers, POS, staffing, linen, delivery-platform sales | ✅ Strong |
| CRM / Airtable / HubSpot enrichment via connector | ✅ Strong (deliveryMode: "perLead") |
| Mapping a destination's hospitality landscape | ✅ Strong — up to 100 venues per run |
| More than 100 venues in one execution | ⚠️ Hard cap of 100 — split by destination or business type across runs |
| Hotels and restaurants in the same run | ⚠️ One category per run — run it twice |
| A business type outside the 33 mapped types | ❌ Use the any-industry Actor |
| Free-text search terms | ❌ Business types are a fixed enum — no free text |
| Guaranteed-deliverable email addresses | ⚠️ Emails are scraped, not verified — validate before sending |
| Menus, room rates, availability, or booking | ❌ Not extracted — read-only listing + website data |
| Review text, reviewer names, place photos, GPS coordinates | ❌ Not extracted |
| Social profile links | ❌ Not in this Actor's output (the any-industry sibling returns socialMedia) |
| Owner / manager names or personal emails | ❌ Not supported — venue-level public contacts only |
⚡ Execution Rules (Avoid Common Agent Failures)
- Nothing is required, and most fields have defaults.
requiredis empty: an input of{}scrapesHotelinAhmedabad(the first business type of the defaultHotelscategory). It will not raise a validation error. API and MCP callers must always sendcategory,subcategories,locationandmaxResultsexplicitly. subcategoriesmust be mapped to the chosencategory. Sending"Coffee Shop"withcategory: "Hotels"logsBusiness type 'Coffee Shop' is not supported for Hotels. Skipping it.and it is dropped. If every value is dropped, the Actor silently falls back to the category's first type. See the mapping table below.- One category per run. There is no way to mix Hotels and Restaurants — run the Actor twice and merge the datasets.
- The five analysis toggles are
falsein the schema buttruein the code when omitted. The Console pre-fills them as off; an API/MCP payload that simply leaves them out gets all five blocks enabled (actor_input.get(key, True)). Always send the booleans explicitly — passfalsefor the blocks you don't want. includeLeadOverviewandincludePitchStrategyare separate toggles here. The healthcare and any-industry siblings merge them into oneincludeSalesStrategy; this Actor lets you take the triage summary without the full playbook.maxResultsis capped at 100 per run, matching the healthcare and any-industry siblings. Unlike those two, the schema and the code agree here — the Console will not let you enter more than 100, so there is no silent clamp to discover at runtime.maxResultsis split evenly across your selected business types. Five types withmaxResults: 100is ~20 venues each, not 100 each.locationcan be a Google Maps place URL, which is then used verbatim instead of being combined with a business type.- Empty fields are removed from the item, not set to
null. A venue with no website produces an item with nowebsitekey at all. Test key presence ("website" in item), neveritem["website"] is None. - A missing email is the string
"NA", not an empty value. ReademailStatusfirst:ok·no_email_found·failed(site wouldn't load) ·no_website. - Rows with no resolvable business name are still written. Filter on
businessNamepresence in your consumer. - There is no
socialMediafield in this Actor's output, even though sibling Actors return one. deliveryModedefaults tosummary, notnone. With a connector selected and nodeliveryModepassed, one digest call fires. For dataset-only runs leavemcpConnectorempty or setdeliveryMode: "none".- Free Apify plans are capped at 10 venues per run. That is a successful run, not a failure.
dependencies:- rule: "subcategories are validated against the SELECTED category's mapped list"on_violation: "unmapped values are warned and skipped; an all-invalid list falls back to the category's first type"- rule: "analysis toggles default to true in code when the key is absent"on_violation: "API callers who omit them get - and pay run time for - all five blocks"- rule: "audit pages per site only matter when at least one analysis block is enabled"note: "maxAuditPagesPerSite is ignored on a contacts-only run"- rule: "delivery requires mcpConnector AND mcpTool"on_violation: "delivery step is skipped with a warning; the dataset is still written in full"- rule: "mcpArguments must reference {message} for the rendered template to appear anywhere"on_violation: "message body is empty; the tool is still called"- rule: "mcpConnector only resolves when the Actor runs on the Apify platform"on_violation: "local runs log 'APIFY_MCP_PROXY_URL is not set' and skip delivery; the dataset is unaffected"- rule: "email and audit crawling only happen when the listing has a website"on_violation: "emailStatus is 'no_website' and audit blocks carry no website grades"authentication:actor_input: noneplatform: "Apify API token required for API / SDK / MCP invocation"target_site: "no Google account, API key, or GCP billing project required (public listings and public website content only)"
📥 Input Contract
.actor/input_schema.json is authoritative — if any table on this page disagrees with the schema files, the schema files win. The one place they diverge is the analysis toggles' absent-key behaviour (see Rule 4).
Scraping Parameters
| Field | Type | Required | Default | Allowed Values / Format | Example |
|---|---|---|---|---|---|
category | string (enum) | ⬜ No | Hotels | Hotels · Resorts · Restaurants · Cafes | Restaurants |
subcategories | array of string (enum) | ⬜ No (no default) | first type of the category | 1–60 values mapped to the chosen category | ["Rooftop Restaurant"] |
location | string | ⬜ No | Ahmedabad | City / area / state / country, or a Google Maps place URL | Goa |
maxResults | integer | ⬜ No | 20 | 1–100, split across types | 100 |
batchSize | integer | ⬜ No | 4 | 1–20 parallel browser pages | 8 |
maxAuditPagesPerSite | integer | ⬜ No | 6 | 1–25 (only used when a block is on) | 12 |
includeLeadOverview | boolean | ⬜ No | false | LEAD_OVERVIEW block | true |
includePitchStrategy | boolean | ⬜ No | false | PITCH_STRATEGY block | true |
includeWebsiteHealthScorecard | boolean | ⬜ No | false | WEBSITE_HEALTH_SCORECARD block | true |
includeServiceRecommendations | boolean | ⬜ No | false | SERVICE_RECOMMENDATIONS block | true |
includeTechnicalIntel | boolean | ⬜ No | false | TECHNICAL_INTEL block | true |
proxyConfiguration | object | ⬜ No | none | Apify proxy editor object | { "useApifyProxy": true } |
subcategory | string | ⬜ No (hidden) | "" | Legacy compatibility field — use subcategories | — |
Category → business type mapping (33 types)
Only the types listed under your chosen category are accepted; anything else is warned and skipped.
| Category | Mapped business types |
|---|---|
| Hotels (9) | Hotel · Luxury Hotel · Business Hotel · Boutique Hotel · Budget Hotel · Resort Hotel · Heritage Hotel · Apartment Hotel · Extended Stay Hotel |
| Resorts (8) | Resort · Resort Hotel · Luxury Resort · Wellness Resort · Spa Resort · Beach Resort · Eco Resort · Family Resort |
| Restaurants (10) | Restaurant · Family Restaurant · Fine Dining Restaurant · Rooftop Restaurant · Fast Food Restaurant · Pizza Restaurant · Burger Restaurant · Banquet Hall · Catering Service · Food Court |
| Cafes (7) | Cafe · Coffee Shop · Bakery Cafe · Dessert Cafe · Coffee Roastery · Ice Cream Shop · Bakery |
Resort Hotel is the only type shared by two categories (Hotels and Resorts). There is no Bar, Pub, Nightclub, Hostel, Guest House, or Cloud Kitchen entry — use the any-industry Actor for those.
Toggle → output block map
| Toggle | Output block |
|---|---|
includeLeadOverview | LEAD_OVERVIEW |
includePitchStrategy | PITCH_STRATEGY |
includeWebsiteHealthScorecard | WEBSITE_HEALTH_SCORECARD |
includeServiceRecommendations | SERVICE_RECOMMENDATIONS |
includeTechnicalIntel | TECHNICAL_INTEL |
The venue profile (name, category, address, phone, website, email, hours, rating, reviews, Maps URL, query) is always included.
Examples
Contacts only — fastest and leanest (the Console default):
{"category": "Restaurants","subcategories": ["Fine Dining Restaurant", "Rooftop Restaurant"],"location": "Goa","maxResults": 100,"includeLeadOverview": false,"includePitchStrategy": false,"includeWebsiteHealthScorecard": false,"includeServiceRecommendations": false,"includeTechnicalIntel": false,"deliveryMode": "none"}
Agency prospecting — grade plus fix list, no full playbook:
{"category": "Hotels","subcategories": ["Boutique Hotel", "Heritage Hotel", "Luxury Hotel"],"location": "Udaipur","maxResults": 90,"includeLeadOverview": true,"includePitchStrategy": false,"includeWebsiteHealthScorecard": true,"includeServiceRecommendations": true,"includeTechnicalIntel": false,"maxAuditPagesPerSite": 12,"deliveryMode": "none"}
Full intelligence on a small, high-value set:
{"category": "Resorts","subcategories": ["Luxury Resort", "Spa Resort", "Wellness Resort"],"location": "Bali","maxResults": 40,"batchSize": 3,"includeLeadOverview": true,"includePitchStrategy": true,"includeWebsiteHealthScorecard": true,"includeServiceRecommendations": true,"includeTechnicalIntel": true,"maxAuditPagesPerSite": 20,"deliveryMode": "none"}
MCP Delivery Configuration (Optional)
| Parameter | Type | Default | Description |
|---|---|---|---|
mcpConnector | string | "" | Authorized MCP connector on your Apify account (Airtable, HubSpot, Notion, Slack, Sheets, Jira, GitHub, Linear, …). Leave empty for dataset-only runs. |
deliveryMode | enum | summary | summary (one digest with the full lead list) · chunked (split a long list across calls) · perLead (one call per venue) · none. |
mcpTool | string | "" | Tool name on the connector: send_message, create_page, create_record, create_issue. Run once with a connector selected — the log lists the connector's available tools. |
mcpArguments | object | {} | Arguments passed to the tool. String leaves support {placeholders}. |
mcpMessageTemplate | string | "" | Template rendered and exposed to mcpArguments as {message}. |
Placeholders by mode — note these differ from the sibling Actors:
| Mode | Placeholders |
|---|---|
summary | {totalLeads}, {locations} (distinct resolved queries), {categories} (distinct Google categories seen), {leadList} (every lead, one line each), {message} |
chunked | the above, plus {part} and {partCount} — and {leadList} holds one part |
perLead | {businessName}, {category}, {address}, {phone}, {website}, {companyEmail}, {emailStatus}, {workingHours}, {googleRating}, {totalReviews}, {googleMapsUrl}, {searchQuery}, {message} (plus {totalLeads}, {locations}, {categories}, {leadList}) |
Chunked delivery packs lead lines into ~1,800-character blocks and groups them into parts under ~72,000 characters, so services with per-request block or timeout caps (Notion in particular) never reject the call.
One Slack digest for the whole run:
{"category": "Cafes","subcategories": ["Coffee Shop", "Bakery Cafe"],"location": "Bengaluru","maxResults": 60,"mcpConnector": "<your-authorized-slack-connector>","deliveryMode": "summary","mcpTool": "send_message","mcpArguments": { "channel": "#hospitality-leads", "text": "{message}" },"mcpMessageTemplate": "Found {totalLeads} leads across {locations} ({categories}):\n\n{leadList}"}
One Airtable/CRM record per venue:
{"category": "Hotels","subcategories": ["Luxury Hotel"],"location": "Dubai","maxResults": 80,"mcpConnector": "<your-authorized-airtable-connector>","deliveryMode": "perLead","mcpTool": "create_record","mcpArguments": {"fields": {"Name": "{businessName}","Type": "{category}","Phone": "{phone}","Email": "{companyEmail}","Website": "{website}","Rating": "{googleRating}","Address": "{address}","Maps": "{googleMapsUrl}"}}}
Chunked into Notion pages for a long list:
{"category": "Restaurants","subcategories": ["Restaurant", "Family Restaurant", "Fast Food Restaurant"],"location": "Mumbai","maxResults": 100,"mcpConnector": "<your-authorized-notion-connector>","deliveryMode": "chunked","mcpTool": "notion-create-pages","mcpArguments": {"parent": { "page_id": "<your-page-id>" },"pages": [{"properties": { "title": "Mumbai restaurants (part {part}/{partCount})" },"content": "{leadList}"}]}}
📤 Output Contract & Data Structure
Storage: Apify Dataset (one JSON object per venue).
Pagination: limit & offset on the dataset items endpoint.
Duplicates: places are deduplicated across business types within a run. Cross-run deduplication is the consumer's responsibility — use googleMapsUrl as the key.
Venue profile — present when non-empty
| Field | Type | Key omitted when empty | Meaning |
|---|---|---|---|
businessName | string | ✅ | Venue name as listed — can be absent; filter these out |
category | string | ✅ | Google Maps category for the venue |
address | string | ✅ | Full address as displayed |
phone | string | ✅ | Phone number as displayed |
website | string | ✅ | Website URL from the listing — absent when the venue has none |
companyEmail | string | ✅ | Email found on the venue's website; the literal string "NA" when the site had none |
emailStatus | string | ✅ | ok · no_email_found · failed · no_website |
workingHours | object | ✅ | Opening hours keyed by day |
googleRating | string | ✅ | Star rating as a string — e.g. "4.6" |
totalReviews | string | ✅ | Review count as a string |
googleMapsUrl | string | ✅ | Listing URL — use as the dedupe key |
searchQuery | string | ✅ | The resolved query that produced this record — e.g. "Rooftop Restaurant in Goa" |
There is no socialMedia field in this Actor — a difference from the healthcare and any-industry siblings.
LEAD_OVERVIEW — toggle includeLeadOverview
| Key | Type | Meaning |
|---|---|---|
leadPriority | string | Triage label — e.g. High |
revenueOpportunityLevel | string | Opportunity size — e.g. High |
salesAngle | string | Why this venue is worth calling |
recommendedPitch | string | The pitch to lead with |
estimatedMonthlyServicePotential | string | Recurring revenue estimate |
estimatedOneTimeProjectPotential | string | Project revenue estimate |
PITCH_STRATEGY — toggle includePitchStrategy
| Key | Type | Meaning |
|---|---|---|
openingHook | string | Opening line tailored to the venue's rating/reviews/site |
bestServicesToPitch | array | Services worth proposing (up to 4) |
painPointsToHighlight | array | Up to 5 concrete weaknesses to raise |
outcomesToPromise | array | Results to promise |
closingStrategy | string | Suggested close |
WEBSITE_HEALTH_SCORECARD — toggle includeWebsiteHealthScorecard
| Key | Type | Meaning |
|---|---|---|
finalGrade | string | Letter grade for the website overall |
finalClassification | string | Plain-language verdict — e.g. Needs Improvement |
gradeBreakdown | array of {area, grade, status} | Per-area grades. Areas: Technical Quality · Technical SEO · SSL / Security · Navigation Structure · Performance · SEO Readiness · SEO Parameters. Areas with no grade are omitted. |
SERVICE_RECOMMENDATIONS — toggle includeServiceRecommendations
Array, at most 4 items, sorted High → Medium → Low priority:
| Key | Type | Meaning |
|---|---|---|
priority | string | High · Medium · Low |
service | string | Service to sell, in human-readable form |
currentGrade | string | The area's current grade |
whatToFix | string | The concrete work required |
whyItMatters | string | Business rationale |
outcomeAfterFix | string | Expected result once fixed |
sellingPoint | string | The line to use in the proposal |
TECHNICAL_INTEL — toggle includeTechnicalIntel
| Key | Type | Meaning |
|---|---|---|
techStack | string | Detected stack, or Unknown |
sslStatus | string | Status with grade — e.g. "Good (Grade A)" |
robotsTxtStatus | string | HTTP status label for robots.txt |
sitemapUrl | string | Sitemap URL if found |
auditedPages | integer | How many pages of that site were audited (up to maxAuditPagesPerSite) |
auditedUrls | array | The exact URLs audited |
navigationNotes | string | Navigation-structure summary |
keyTechnicalIssues | array | Notable problems found |
Consumer rules: empty values are removed rather than nulled, so test key presence; googleRating and totalReviews are strings; a missing email is the literal "NA"; nameless rows are possible; there is no socialMedia; and any of the five analysis blocks is simply absent when its toggle is off.
Example output item
{"businessName": "Sunset Rooftop Kitchen","category": "Rooftop restaurant","address": "12 Beach Rd, Candolim, Goa 403515","phone": "+91 98250 00000","website": "https://sunsetrooftopgoa.com","companyEmail": "hello@sunsetrooftopgoa.com","emailStatus": "ok","workingHours": { "Monday": "12:00 PM – 11:00 PM" },"googleRating": "4.5","totalReviews": "1284","googleMapsUrl": "https://www.google.com/maps/place/...","searchQuery": "Rooftop Restaurant in Goa","LEAD_OVERVIEW": {"leadPriority": "High","revenueOpportunityLevel": "High","salesAngle": "Excellent reviews but no online table booking and a slow mobile site.","recommendedPitch": "Add direct reservations and speed up the site to cut third-party commission.","estimatedMonthlyServicePotential": "$600–$1,200/mo","estimatedOneTimeProjectPotential": "$2,500–$5,000"},"WEBSITE_HEALTH_SCORECARD": {"finalGrade": "C","finalClassification": "Needs Improvement","gradeBreakdown": [{ "area": "Performance", "grade": "D", "status": "Poor (Grade D)" },{ "area": "SSL / Security", "grade": "A", "status": "Good (Grade A)" }]},"SERVICE_RECOMMENDATIONS": [{"priority": "High","service": "Website performance optimization","currentGrade": "D","whatToFix": "Compress menu images and defer unused scripts.","whyItMatters": "Slow pages lose diners before they reach the reservation form.","outcomeAfterFix": "Faster load and more direct bookings.","sellingPoint": "Keep the commission you currently pay aggregators."}]}
What a successful run looks like
{"status": "SUCCEEDED","defaultDatasetId": "<datasetId>","stats": { "itemCount": 183 }}
The terminal log line reads Finished <n> companies in <t>s. plus the connector count when delivery ran. itemCount below maxResults is normal — the budget is split across business types, duplicates are removed, and Google may have fewer matches. itemCount: 0 is a successful run with no matches; check the category/type/location combination before treating it as a bug.
▶️ Invocation & Integration
Lifecycle: Discover → Understand → Configure → Execute → Retrieve → Validate. Authenticate every call with Authorization: Bearer <APIFY_TOKEN>.
Apify Console
Open the Actor → Input tab → choose a Category → tick one or more Business type values → enter a Location → set Maximum businesses → switch on any analysis blocks you want (all off by default) → (optional) pick an MCP connector, tool and template → Start → export from the Dataset tab (JSON, CSV, Excel, XML).
Model Context Protocol (MCP)
claude mcp add --transport http apify \"https://mcp.apify.com?tools=techforce.global/google-maps-hospitality-lead-scraper"
Python (apify-client)
import osfrom apify_client import ApifyClientclient = ApifyClient(os.getenv("APIFY_TOKEN"))run = client.actor("techforce.global/google-maps-hospitality-lead-scraper").call(run_input={"category": "Hotels","subcategories": ["Boutique Hotel", "Heritage Hotel"],"location": "Udaipur","maxResults": 90,# Send every toggle explicitly - omitting them enables all five blocks."includeLeadOverview": True,"includePitchStrategy": False,"includeWebsiteHealthScorecard": True,"includeServiceRecommendations": True,"includeTechnicalIntel": False,"deliveryMode": "none",})items = client.dataset(run["defaultDatasetId"]).list_items().itemsvenues = [i for i in items if i.get("businessName")] # nameless rows are possibleprint(f"{len(venues)} venues")# Keys are omitted when empty - test presence, never compare to None.emailable = [i for i in venues if i.get("companyEmail", "NA") != "NA"]print(f"{len(emailable)} with a usable email")weak = [i for i in venues if i.get("WEBSITE_HEALTH_SCORECARD", {}).get("finalGrade") in {"C", "D", "F"}]print(f"{len(weak)} with a weak website — best prospects")
JavaScript / TypeScript (apify-client)
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('techforce.global/google-maps-hospitality-lead-scraper').call({category: 'Cafes',subcategories: ['Coffee Shop', 'Bakery Cafe', 'Coffee Roastery'],location: 'Bengaluru',maxResults: 100,includeLeadOverview: false,includePitchStrategy: false,includeWebsiteHealthScorecard: false,includeServiceRecommendations: false,includeTechnicalIntel: false, // contacts only - fastest rundeliveryMode: 'none',});const { items } = await client.dataset(run.defaultDatasetId).listItems();const withPhone = items.filter((i) => i.phone);console.log(`${items.length} cafes, ${withPhone.length} with a phone number`);
cURL — synchronous (returns items directly; 300s limit)
curl -X POST \-H 'Content-Type: application/json' \-H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \-d '{"category":"Restaurants","subcategories":["Fine Dining Restaurant"],"location":"Goa","maxResults":20,"includeLeadOverview":false,"includePitchStrategy":false,"includeWebsiteHealthScorecard":false,"includeServiceRecommendations":false,"includeTechnicalIntel":false,"deliveryMode":"none"}' \'https://api.apify.com/v2/acts/techforce.global~google-maps-hospitality-lead-scraper/run-sync-get-dataset-items'
Use the async pattern below for anything beyond ~20 venues — website crawling makes this Actor far slower per record than a listings-only scraper.
cURL — asynchronous with a spend cap (recommended for production)
# 1. Start execution with a hard spend limitcurl -X POST -H 'Content-Type: application/json' \-H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \-d '{"category":"Hotels","subcategories":["Luxury Hotel","Boutique Hotel"],"location":"Dubai","maxResults":100,"deliveryMode":"none"}' \'https://api.apify.com/v2/acts/techforce.global~google-maps-hospitality-lead-scraper/runs?maxTotalChargeUsd=1.00'# 2. Pollcurl -H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \'https://api.apify.com/v2/actor-runs/<runId>'# 3. Retrieve when SUCCEEDEDcurl -H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \'https://api.apify.com/v2/datasets/<DATASET_ID>/items?clean=true&format=json&limit=1000&offset=0'
⚠️ Autonomous Agent Error Handling & Resolution Matrix
| Error Code | Detection Condition | Underlying Cause | Deterministic Agent Action |
|---|---|---|---|
AUTH_INVALID | HTTP 401 | Missing or malformed APIFY_TOKEN | Abort & Prompt User: request a valid API token. |
RATE_LIMITED | HTTP 429 | Apify API rate / concurrency limits | Retry: exponential backoff (2s, 4s, 8s). |
SYNC_TIMEOUT | HTTP 408 on the sync endpoint | Run exceeded the 300s synchronous ceiling — easy to hit here | Reconfigure: switch to async POST /runs + polling. |
SILENT_DEFAULT | Results are Hotels in Ahmedabad you never asked for | No field is required; category/subcategories/location defaulted | Modify Input: always pass all of them explicitly. |
BAD_CATEGORY | Log Category 'X' is not supported. Using Hotels. | category outside the 4-value enum | Modify Input: send Hotels, Resorts, Restaurants or Cafes. |
TYPE_NOT_MAPPED | Log Business type 'X' is not supported for <Category>. Skipping it. | The type belongs to a different category, or isn't in the 33-item list | Modify Input: use the category→type mapping table. |
ALL_TYPES_INVALID | Results are a type you didn't select | Every value was dropped, so the category's first type was used | Modify Input: fix the type strings; do not trust the fallback. |
WRONG_VERTICAL | User asked for a non-hospitality business type | This Actor only searches the four hospitality categories | Re-route: use the any-industry Actor. |
MIXED_CATEGORY_REQUEST | User wants hotels and restaurants together | One category per run | Reconfigure: run twice and merge datasets. |
UNREQUESTED_ANALYSIS | All five blocks present when you wanted none | Toggles were omitted; the code defaults them to true | Modify Input: send all five booleans explicitly as false. |
NO_QUERIES | SUCCEEDED, 0 items, log No search queries provided. | Query plan resolved to empty | Modify Input: supply a category, type and location. |
EMPTY_RESULTS | SUCCEEDED, itemCount: 0 | Type/location combination has no Google Maps matches | Modify Input: broaden the type set or widen the location. |
CAP_REACHED | itemCount == maxResults == 100 | Per-run maximum of 100 truncated the result set | Reconfigure: partition by destination or business type across sequential runs. |
MAX_RESULTS_REJECTED | Input validation rejects maxResults above 100 | The schema maximum is 100 (schema and code agree) | Modify Input: send 100 or less and run repeatedly for more. |
THIN_PER_TYPE | Only a handful of venues per business type | maxResults (≤100) is split evenly across all selected types | Reconfigure: select fewer types, or raise maxResults toward 100. |
FREE_PLAN_CAP | itemCount ≤ 10 with the free-plan notice in the log | Free Apify plan caps at 10 venues per run | Prompt User: upgrade for full-volume runs. |
NO_EMAIL | emailStatus: "no_email_found" or companyEmail: "NA" | The site published no discoverable email within 4 crawled pages | Not an error. Fall back to phone, or enrich elsewhere. |
NO_WEBSITE | emailStatus: "no_website", no website key | The listing has no website, so no email or audit is possible | Not an error. Analysis blocks will carry no website grades. |
SITE_UNREACHABLE | emailStatus: "failed", log Homepage load failed for … | The venue site timed out or refused the connection | Not an error. Retry later if the email matters. |
NAMELESS_ROW | Item has no businessName key | This Actor writes rows even when the name can't be resolved | Fix Consumer: filter on businessName presence. |
MISSING_KEY | KeyError in your consumer | Empty values are omitted from items entirely | Fix Consumer: use .get() / key-presence checks. |
MISSING_BLOCK | An analysis block is absent from every item | Its toggle was false | Modify Input: set the matching include* flag to true. |
NO_SOCIAL | socialMedia missing everywhere | This Actor does not extract social links | Re-route: use the any-industry Actor if you need them. |
SLOW_RUN | Run approaching the timeout with analysis on | High batchSize × high maxAuditPagesPerSite on slow sites | Reconfigure: lower maxAuditPagesPerSite, or drop blocks. |
DELIVERY_SKIPPED | Log no tool name was provided | mcpConnector set but mcpTool empty | Modify Input: set mcpTool; the dataset is already saved. |
DELIVERY_TOOL_UNKNOWN | Log Tool 'x' is not available on this connector | Wrong tool name for that connector | Modify Input: pick a name from the Available tools: list in the same log line. |
DELIVERY_EMPTY | Connector called, body empty | mcpArguments omitted the {message} placeholder | Modify Input: map {message} inside mcpArguments. |
DELIVERY_FLOOD | Hundreds of connector calls / connector rate limits | deliveryMode: "perLead" on a large run | Reconfigure: use summary or chunked. |
MCP_PROXY_MISSING | Log APIFY_MCP_PROXY_URL is not set | Running locally instead of on the platform | Reconfigure: apify push and run on the platform. |
CHARGE_LIMIT | Run aborted before maxResults reached | maxTotalChargeUsd spend threshold reached | Prompt User: confirm a higher spend cap. |
⚠️ Verify before publishing: the HTTP status rows reflect standard Apify API behavior; every log-line and field condition above is taken from this Actor's source. Re-confirm the
408/429rows against current platform behavior if you depend on them for automated retry logic.
🗣️ Natural Language → Actor Mapping
| User says | Intent | Constructed Actor input |
|---|---|---|
| "Find boutique hotels in Udaipur with their emails" | Hospitality lead gen | {"category":"Hotels","subcategories":["Boutique Hotel"],"location":"Udaipur"} |
| "Get me every rooftop and fine-dining restaurant in Goa" | F&B prospecting | {"category":"Restaurants","subcategories":["Rooftop Restaurant","Fine Dining Restaurant"],"location":"Goa"} |
| "List the coffee shops and roasteries in Bengaluru" | Cafe sweep | {"category":"Cafes","subcategories":["Coffee Shop","Coffee Roastery"],"location":"Bengaluru"} |
| "Which hotels have bad websites?" | Agency prospecting | {"includeWebsiteHealthScorecard":true} then sort on WEBSITE_HEALTH_SCORECARD.finalGrade |
| "Build a prospect list of spa resorts with a pitch each" | Sales enablement | {"category":"Resorts","subcategories":["Spa Resort","Wellness Resort"],"includeLeadOverview":true,"includePitchStrategy":true} |
| "Who should I call first?" | Lead triage | {"includeLeadOverview":true} then read LEAD_OVERVIEW.leadPriority |
| "What should I fix on this restaurant's site, and how do I sell it?" | Proposal input | {"includeServiceRecommendations":true,"includeTechnicalIntel":true} |
| "Just contact details for 400 restaurants in Mumbai" | Bulk contact list | all five toggles false, maxResults: 100 — then repeat across runs/areas for the rest |
| "Push these hotel leads into Airtable" | CRM delivery | {"mcpConnector":"airtable","deliveryMode":"perLead","mcpTool":"create_record"} |
| "Post a summary of today's leads to Slack" | Digest delivery | {"mcpConnector":"slack","deliveryMode":"summary","mcpTool":"send_message","mcpArguments":{"channel":"#leads","text":"{message}"}} |
| "Save a long lead list into Notion without it timing out" | Chunked delivery | {"deliveryMode":"chunked","mcpTool":"notion-create-pages"} with {part}/{partCount} in the title |
| "Map the hospitality landscape in Bali" | Market research | {"category":"Resorts","subcategories":["Resort","Luxury Resort","Beach Resort"],"location":"Bali","maxResults":100} |
| "Find hotels and restaurants in one go" | Mixed vertical | ⚠️ One category per run — run twice, or use the any-industry Actor |
| "Find bars, pubs or hostels" | Unmapped type | ⚠️ Not in the 33-item list — use the any-industry Actor |
| "Get me the menu / room rates / availability" | Booking data | ❌ Out of scope — not extracted |
| "Get the owner's personal email" | Contact discovery | ❌ Out of scope — venue-level public emails only |
| "Get the reviews people wrote" | Review mining | ❌ Out of scope — rating and count only |
Should NOT route here: any non-hospitality business type (→ any-industry Actor) · bars, pubs, nightclubs, hostels, guest houses, cloud kitchens (not in the 33-item list) · several categories in one run · plain listing data at lowest cost (→ Google Maps Scraper) · menus, room rates, availability or bookings · review text · social links · owner names or personal emails · email verification/deliverability · sending outreach.
🧭 Agent Execution & Routing Logic
[Input User Query]│▼1. Target is Google Maps business listings? NO → Route to the right platform Actor│ YES▼2. Is the target a HOSPITALITY venue? NO → Route to the any-industry Actor│ YES▼3. Does it map to one of 4 categories × 33 types? NO → (bar/pub/hostel/cloud kitchen)│ YES → Route to the any-industry Actor (free text)▼4. More than one category needed? YES → Split into one run per category│ NO▼5. Needs menus / rates / availability / reviews text? YES → Abort (not extracted)│ NO▼6. Set category + business types (must be mapped) + location│ remember: maxResults caps at 100 and is SPLIT evenly across the selected types▼6b. Volume > 100 venues? YES → Partition by destination or type across runs│ NO▼7. Send ALL FIVE analysis booleans explicitly├── triage only? → includeLeadOverview├── full playbook? → + includePitchStrategy├── site grade? → + includeWebsiteHealthScorecard├── fix list? → + includeServiceRecommendations├── tech audit? → + includeTechnicalIntel└── contacts only? → ALL FIVE false (omitting them turns them ON)▼8. Tune run speed: batchSize (1-20), maxAuditPagesPerSite (1-25)▼9. Deliver to a connector? YES → mcpConnector + mcpTool + {message}│ summary | chunked (long lists) | perLead│ NO → set deliveryMode "none" (it defaults to summary)▼10. Estimated cost within budget? NO → Lower maxResults / set maxTotalChargeUsd│▼[Execute Apify Actor]│├──► status == "SUCCEEDED" → itemCount 0 = valid empty result → consume dataset│ (dedupe on googleMapsUrl; drop nameless rows; test key presence;│ read emailStatus before companyEmail)└──► status == "FAILED" → route to Error Handling Matrix above
💰 Cost Control & Pricing Transparency
- Pay-per-event pricing: $9.09 per 1,000 results on the entry tier, discounted at higher Apify subscription tiers. No monthly subscription.
- Free Apify plans are capped at 10 venues per run.
- Autonomous spend caps: pass
maxTotalChargeUsdas a query parameter on the run endpoint for a hard per-execution ceiling — important for any agent spending on your behalf.
| Venues extracted | Total cost (entry tier) |
|---|---|
| 10 venues (free-plan cap) | $0.09 |
| 20 venues (default run) | $0.18 |
| 100 venues (per-run ceiling) | $0.91 |
| 500 venues (5 runs) | $4.55 |
| 1,000 venues (10 runs) | $9.09 |
What the toggles do and don't affect: unlike the healthcare and any-industry siblings — where each analysis block is a separately-priced billable event — this Actor's code declares no per-analysis charge events. Switching blocks off here makes the run faster and the payload smaller, but the per-result price is the same. Keep maxResults tight to control spend.
⚠️ Verify before publishing: the $9.09 / 1,000 figure is taken from the Store listing, and the listing describes a pay-per-event model while this repo contains no
pay_per_event.jsonand the code makes noActor.charge()calls. Confirm the live Store pricing configuration — and whether analysis blocks should be billed separately as they are on the sibling Actors — before publishing.
🔍 Companion machine-readable files
| File | Purpose |
|---|---|
.actor/actor.json | Identity, version, input/output/dataset wiring |
.actor/input_schema.json | Authoritative typed input contract — category enum, 33-value type enum, location, maxResults (1–100), batchSize, audit depth, five toggles, proxy, deliveryMode enum |
.actor/dataset_schema.json | Output field types and the Console table view, including labels for the five analysis blocks |
.actor/output_schema.json | Declares where results are stored |
my_actor/main.py | Category/type planning, Playwright listing extraction, email crawl, website audit, intelligence generation, MCP delivery |
my_actor/connector.py | MCP connector session handling and {placeholder} rendering |
Note: this Actor has no pay_per_event.json — billing is configured entirely on the Store listing.
If any table on this page disagrees with the schema files, the schema files win — with the single exception of the analysis toggles, where the code's absent-key default (true) differs from the schema default (false).
🛠️ Troubleshooting
| # | Symptom you see | Most likely cause | Fix |
|---|---|---|---|
| 1 | Results are Hotels in Ahmedabad you never asked for | No input field is required; category, subcategories and location silently defaulted | Always pass all of them explicitly from API / MCP / SDK calls. |
| 2 | Log: Business type 'X' is not supported for <Category> | The type belongs to a different category, or isn't in the 33-item list | Use the category→type mapping table. |
| 3 | You got a business type you never selected | Every value you sent was dropped, so the category's first type was used | Fix the strings — the fallback is deliberate but silent. |
| 4 | All five analysis blocks appeared when you wanted none | You omitted the toggles; the code defaults them to true | Send all five booleans explicitly as false. |
| 5 | Only a few venues per business type | maxResults (max 100) is divided evenly across all selected types | Select fewer types, or raise maxResults toward 100. |
| 5a | You need more than 100 venues | Hard per-run ceiling of 100, matching the sibling Actors | Partition by destination or business type across runs and merge on googleMapsUrl. |
| 6 | Exactly 10 venues every run | Free Apify plan cap | Upgrade the plan. |
| 7 | Fewer items than maxResults | Budget split + cross-type dedupe + Google having fewer matches | Expected. Check the per-query target lines in the log. |
| 8 | Hotels and restaurants in one run isn't possible | One category per run by design | Run twice and merge the datasets. |
| 9 | Consumer crashes with KeyError | Empty fields are omitted, not set to null | Use .get() or "key" in item. |
| 10 | An item has no businessName | This Actor keeps rows whose name couldn't be resolved | Filter on businessName presence in your consumer. |
| 11 | companyEmail is "NA" | No email was discoverable within the 4 pages crawled | Read emailStatus first; fall back to phone. |
| 12 | emailStatus: "no_website" | The venue has no website — nothing to crawl or audit | Expected. Website-based blocks will be thin or absent. |
| 13 | emailStatus: "failed" | The venue site timed out or refused the connection | Retry later; a single slow site does not fail the run. |
| 14 | No socialMedia field anywhere | This Actor doesn't extract social links | Use the any-industry Actor if you need them. |
| 15 | Emails bounce when you send outreach | Scraped emails are not verified | Run them through an email-verification service first. |
| 16 | googleRating won't compare numerically | It is a string ("4.6") | Cast to float before comparing. |
| 17 | Run is very slow | Analysis on, high maxAuditPagesPerSite, and up to 4 email pages per site | Lower maxAuditPagesPerSite, drop blocks, or reduce maxResults. |
| 18 | Pages time out / Google loads slowly | batchSize too high for the current network or proxy | Lower batchSize (default 4, minimum 1). |
| 19 | HTTP 408 on run-sync-get-dataset-items | The synchronous endpoint has a hard 300-second ceiling | Use async: POST /runs → poll → fetch dataset. Recommended above ~20 venues. |
| 20 | Blank or empty listing fields | Google served an empty page to that exit IP | Enable Apify Proxy, or re-run — the Actor rotates the proxy session on retry. |
| 21 | Log: Saved outputs to <dir> | The Actor also writes JSON/CSV inside the container for local development | Ignore it on the platform — the dataset is the real output; container files vanish with the run. |
| 22 | Hundreds of connector calls / connector rate-limited | deliveryMode: "perLead" on a large run | Switch to summary or chunked. |
| 23 | Notion rejects or truncates a long lead list | Single-call payload exceeded block/timeout caps | Use deliveryMode: "chunked" and put {part}/{partCount} in the page title. |
| 24 | Slack / Airtable / Notion received nothing | Delivery needs both mcpConnector and mcpTool | Set both. The dataset is still written in full. |
| 25 | Connector fired but the message body is empty | mcpArguments did not reference {message} | Map {message} in mcpArguments and populate mcpMessageTemplate. |
| 26 | Log: APIFY_MCP_PROXY_URL is not set | You ran locally; connectors only resolve on the platform | Deploy with apify push and run on the platform. |
| 27 | HTTP 401 / 403 | Missing, expired, or malformed APIFY_TOKEN | Regenerate in Apify Console → Settings → API & Integrations. |
| 28 | HTTP 429 | Apify account concurrency / rate limits — not Google blocking | Retry with exponential backoff (2s → 4s → 8s). |
Diagnostic checklist before opening an issue
- Baseline run.
category=Hotels,subcategories=["Hotel"],location= a large city,maxResults=5, all five togglesfalse,deliveryMode: "none". - Results returned? If yes, the scraper is fine — re-add types, toggles and volume one step at a time.
- Still zero? Search
"<business type> in <location>"on Google Maps in a browser. No results there means a valid empty run. - Check the run log for the
Search query: … | Target businesses: …lines — they show the exact per-type budget split — and for anynot supported for <Category>warnings. - Confirm which toggles were actually on in the Input tab before reporting a missing or unexpected analysis block.
If the issue survives all five steps, open an Issues ticket on the Actor page (or email support) with the run ID, the exact input JSON, and what you expected.
❓ FAQ
Setup & access
Do I need a Google account, API key, or Google Cloud project?
No. The Actor reads public Google Maps listings and public website content. You need an Apify account and API token only.
Is this the official Google Places API?
No. This is an independent Actor, not affiliated with, endorsed by, or sponsored by Google.
Do I need a proxy?
Not always, but it helps. Configure Apify Proxy in proxyConfiguration if Google starts serving empty pages; the Actor pins or rotates the exit IP per session so a dead node doesn't sink the run.
Can I plug it into Claude, Cursor, or a LangChain agent?
Yes — it is a native MCP tool:
claude mcp add --transport http apify "https://mcp.apify.com?tools=techforce.global/google-maps-hospitality-lead-scraper"
Categories & volume
Can I scrape hotels and restaurants in the same run?
No — one category per run. Run the Actor twice and merge the datasets.
What if my business type isn't listed?
Bars, pubs, nightclubs, hostels, guest houses and cloud kitchens are not in the 33-item list. Use the any-industry Actor with a free-text query instead.
How many venues can one run return?
Up to 100, the same ceiling as the sibling lead-intelligence Actors. For bigger jobs, partition by destination or business type across sequential runs and merge the datasets.
Why did each business type return so few venues?
maxResults is one shared budget, split evenly across the types you selected.
Output & data
Why are some fields missing entirely instead of empty?
Empty values are stripped from each item to keep payloads (and LLM token costs) down. Test key presence rather than comparing to null.
Why is companyEmail sometimes "NA"?
Because no email was discoverable on up to 4 crawled pages of that venue's site — or it has no site at all. Check emailStatus (ok · no_email_found · failed · no_website).
Are the emails verified?
No. They are scraped from public website content. Run them through an email-verification service before any real outreach.
Do I get social media links?
No. This Actor does not output a socialMedia field — the any-industry sibling does.
Do I get menus, room rates, or availability?
No. Listing fields plus website-derived analysis only — no booking or pricing data.
Do I get review text or photos?
No. You get the rating and review count, not review bodies, reviewer names, or images.
Pricing
How is this billed?
$9.09 per 1,000 results on the entry tier, less on higher Apify subscription tiers. Unlike the healthcare and any-industry siblings, the analysis toggles here do not add separate per-block charges — they change run time and payload size.
How do I make a run as cheap as possible?
Keep maxResults tight; cost scales with results, not with which blocks you enable. If you don't need emails or analysis at all, Google Maps Scraper is far cheaper per result.
How do I guarantee an agent never overspends?
Pass maxTotalChargeUsd as a query parameter on the run endpoint — a hard per-execution ceiling.
🔗 Related Actors
Same data family
This Actor is the hospitality vertical member of the family — same engine, curated hotel/resort/restaurant/cafe types. Its siblings cover other verticals, any industry, and a cheap listings-only mode.
| Actor | Best for | Why pick it over this one |
|---|---|---|
| Google Maps Business Leads & Sales Intelligence | Any industry, free-text queries, several unrelated business types in one run | Your target isn't hospitality, your type isn't in the 33-item list, or you need socialMedia (from $6.50 / 1,000) |
| Google Maps Scraper | Plain Google Maps listings — name, address, phone, website, rating, reviews, hours, coordinates, images | You don't need emails or sales intelligence, and want the lowest cost per result (from $0.80 / 1,000) |
| Google Maps Healthcare Leads & Sales Intelligence | Healthcare — 55+ preset medical categories | Clinics, dental, diagnostics, wellness instead of hospitality (from $4.00 / 1,000) |
| Finance Google Maps Lead Intelligence | CA firms, tax & GST consultants, accounting, auditors, advisors, wealth management, insurance & stock brokers, loan and mortgage agencies | Finance practices — deeper per-site auditing (up to 25 pages/business), 10-lead free tier (from $10.00 / 1,000) |
| Construction Lead Intelligence | General contractors, architecture firms, interior designers, roofing contractors, real estate agencies | Trades and property — basic contact scraping is free, analysis billed per event |
Pick by intent: hotels/resorts/restaurants/cafes (this Actor) · any other industry → any-industry · listings only, cheapest → Google Maps Scraper · clinics & dental → Healthcare · accounting/insurance → Finance · contractors/real estate → Construction.
ℹ️ Pricing and per-run limits differ between siblings (they are separate Store listings on separate tiers). Check the target Actor's own listing before switching a production pipeline over.
Enrichment & downstream pipeline
| Actor | Use it for |
|---|---|
| Advanced Website Crawling Actor | Crawl a venue's whole site from website for clean HTML/Markdown/text context beyond the audited pages |
| Eventbrite Scraper | Find events and organizers in the same destination — adjacent demand signal for hotels and venues |
| GOV.UK Business Scraper | Match UK hospitality group names against Companies House records, with PSC / ownership enrichment |
Suggested pipeline patterns
🎯 Hospitality agency prospecting engine
All hotel types in a destination + includeWebsiteHealthScorecard + includeServiceRecommendations → filter finalGrade ≤ C → deliveryMode: "perLead" into Airtable → work the queue from the fix list.
📇 CRM enrichment loop
One run per destination on a schedule → perLead delivery into HubSpot → dedupe on googleMapsUrl → verify companyEmail before any sequence.
📊 Destination landscape map
Same type set across several destinations → compare rating distributions and WEBSITE_HEALTH_SCORECARD.finalGrade → target the weakest market first.
🧠 Deep-dive on hot venues
This Actor for triage → filter LEAD_OVERVIEW.leadPriority == "High" → Advanced Website Crawling Actor on those sites → build a bespoke proposal.
Browse all Actors by Techforce Global at apify.com/techforce.global.
🔐 Compliance & Data Privacy
This is an independent Actor. It is not affiliated with, endorsed by, or sponsored by Google. Google Maps™ is a trademark of Google LLC; all trademarks are the property of their respective owners.
This Actor collects publicly available business listing data and publicly published website content for hospitality businesses. It does not log into any account, bypass authentication, or access booking, guest, or payment data.
Two points matter before you use the output:
- Venue contact data is still personal data in many jurisdictions — an owner-operated cafe's email or phone number can identify a person. GDPR and CCPA can apply to it.
- Cold outreach is regulated. Before sending anything to a scraped address, satisfy the applicable anti-spam and electronic-marketing rules (GDPR Art. 6/21, ePrivacy/PECR, CAN-SPAM, CASL). Emails here are unverified and unconsented; treat them accordingly.
You are responsible for ensuring your use complies with Google's Terms of Service and all applicable law.
🆘 Support & Custom Pipeline Engineering
Need multi-destination scheduled refreshes, extra hospitality categories (bars, hostels, cloud kitchens), email verification in-pipeline, or a full CRM / data-warehouse integration?
- Email: bhavin.shah@techforceglobal.com
- Custom Enterprise Integrations: Book a 15-Minute Technical Consultation
- Maintained by: Techforce Global — Specialists in High-Performance Web Scrapers and Agentic Workflows.
Made with ❤️ by Techforce Global Specialists in High-Performance Lead Generation Data Extraction and AI Automation.
🏷️ Structured data for search & AI discovery
{"@context": "https://schema.org","@type": "SoftwareApplication","name": "Google Maps Hospitality Scraper — Hotel, Resort, Restaurant & Cafe Leads","applicationCategory": "BusinessApplication","operatingSystem": "Cloud (Apify platform)","description": "Scrapes hotels, resorts, restaurants and cafes from Google Maps across 33 mapped hospitality business types, finds the company email on each venue's website, and optionally generates lead intelligence, a website performance grade, prioritized improvement recommendations, and a website tech audit — with optional delivery to Airtable, HubSpot, Notion, Slack, Google Sheets, or any authorized MCP connector.","url": "https://apify.com/techforce.global/google-maps-hospitality-lead-scraper","offers": {"@type": "Offer","price": "9.09","priceCurrency": "USD","description": "Per 1,000 results, pay-per-event"}}