# Hotel Leads Scraper - Verified Emails + Booking Tech Stack (`flash_scraper/hotel-host-leads-scraper`) Actor

Turn any city worldwide into a hotel, guest house & B\&B lead list. Crawls each property site for MX-verified emails (deliverable/risky), phone, socials & its booking tech: channel manager/PMS + OTA presence. A-F lead scores. No API key, no proxies.

- **URL**: https://apify.com/flash\_scraper/hotel-host-leads-scraper.md
- **Developed by:** [Flash Scrape](https://apify.com/flash_scraper) (community)
- **Categories:** Lead generation, Travel, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.90 / 1,000 hotel / host leads

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Hotel & Host Leads Scraper — build a hotel owner contact list by city, enriched with booking tech stack

Get a **hotel owner contact list** for any city in minutes: hotels, guest houses, B\&Bs and vacation rental host leads, each enriched with a contact **email crawled from the property's own website** and its **hospitality tech stack** — channel manager / PMS and OTA presence. No API key, no residential proxies, and you pay only per lead actually returned.

### What does it do?

This actor finds **accommodations by city** using OpenStreetMap (Nominatim geocoding + the Overpass API), then **crawls each property's own website** (home, contact, about, booking and rooms pages) to extract contact emails, Facebook and Instagram profiles, and two premium signals no plain directory scraper gives you:

- **Channel manager / PMS detection** — SiteMinder, Cloudbeds, Mews, Guesty, Lodgify, Little Hotelier, Hostfully, Sirvoy, Beds24, eviivo, RoomRaccoon
- **OTA presence detection** — Booking.com, Expedia, Airbnb, Vrbo, Hotels.com, Tripadvisor, Hostelworld, Agoda

On top of that, every lead carries the listing basics: name, accommodation type (hotel / guest house / B\&B / motel — optionally hostels, serviced apartments and chalets), star rating and room count where OpenStreetMap has them, full parsed address, phone, website, and coordinates. Results are deduped by name + address + website, and `has_email` / `has_phone` / `has_website` flags make filtering in a spreadsheet trivial.

### Use cases

- **Channel-manager and PMS sales teams** (SiteMinder, Cloudbeds, Mews competitors) prospecting independent properties **not yet showing a channel-manager signal** — the classic greenfield pitch — or already on a rival's platform for a "switch" campaign.
- **STR and vacation-rental software vendors** building city-by-city lists of guest houses and B\&Bs — small hosts who book direct today and are the ideal upgrade target.
- **OTA and metasearch BD teams** finding properties with a website but no Booking.com / Expedia / Airbnb footprint, i.e. inventory a competitor hasn't signed yet.
- **Hospitality marketing agencies** cold-emailing hotels with weak digital setups (no booking engine, no OTA links) with a "we'll fix your direct bookings" angle.
- **CRM enrichment** — re-run monthly per market and merge on `osm_id` to keep owner emails and tech-stack fields fresh in your pipeline.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `location` | string | *(required)* | City and region/country to search, e.g. 'Marrakesh, Morocco', 'Lisbon, Portugal', 'Austin, Texas'. |
| `includeHostels` | boolean | `false` | Also include hostels. |
| `includeApartments` | boolean | `false` | Also include tourism apartments / aparthotels. |
| `includeChalets` | boolean | `false` | Also include chalets. |
| `maxItems` | integer | `100` | Maximum number of accommodations to return (1–1000). |
| `crawlEmails` | boolean | `true` | Visit each property's own website to extract contact emails and detect its channel manager / PMS and OTA presence. Turn off for a faster, listing-only run. |
| `onlyWithWebsite` | boolean | `false` | Drop accommodations with no website (required for email + tech-stack enrichment). |
| `onlyWithEmail` | boolean | `false` | Keep only properties where an email was found (best for cold email). |
| `verifyEmails` | boolean | `true` | MX-check every discovered email and label it deliverable / risky / undeliverable (adds `email_status` + `email_provider` and feeds the lead score). No SMTP handshake, no proxy needed. |
| `onlyVerifiedEmail` | boolean | `false` | Keep only leads whose email verified as deliverable or risky (drops undeliverable / no-email rows). Requires `verifyEmails`. |
| `maxPagesPerSite` | integer | `3` | How many pages (home, contact, about, booking...) to crawl per website while looking for an email (1–8). |
| `concurrency` | integer | `8` | How many websites to crawl in parallel (1–20). |

Example input:

```json
{
  "location": "Marrakesh, Morocco",
  "maxItems": 100,
  "crawlEmails": true,
  "onlyWithWebsite": false,
  "onlyWithEmail": false,
  "maxPagesPerSite": 3,
  "concurrency": 8
}
```

Only `location` is required — everything else has a sensible default.

### Output

Each dataset row is one accommodation lead. Export to CSV, JSON, or Excel, or pull it via the Apify API.

```json
{
  "name": "Riad Dar Anika",
  "type": "guest_house",
  "stars": "4",
  "rooms": "8",
  "address": "23 Derb El Ferrane, Medina",
  "city": "Marrakesh",
  "state": null,
  "postal_code": "40000",
  "country": "MA",
  "phone": "+212 5 24 38 00 00",
  "website": "https://www.riaddaranika.com",
  "email": "contact@riaddaranika.com",
  "email_status": "deliverable",
  "email_provider": "Google Workspace",
  "emails": ["contact@riaddaranika.com", "booking@riaddaranika.com"],
  "facebook": "https://www.facebook.com/riaddaranika",
  "instagram": "https://www.instagram.com/riaddaranika",
  "channel_manager": ["Cloudbeds"],
  "ota_presence": ["Booking.com", "Tripadvisor"],
  "tech_signals": ["Cloudbeds", "Booking.com", "Tripadvisor"],
  "latitude": 31.6295,
  "longitude": -7.9811,
  "osm_type": "node",
  "osm_id": 123456789,
  "source": "openstreetmap",
  "has_email": true,
  "has_phone": true,
  "has_website": true,
  "lead_score": 100,
  "lead_grade": "A",
  "lead_tier": "hot",
  "score_breakdown": { "email": 40, "phone": 20, "website": 15, "socials": 10, "signals": 15 }
}
```

`email` is the primary contact address (listing email, or the first one found on the site); `emails` holds every address discovered while crawling. `tech_signals` is `channel_manager` + `ota_presence` flattened for one-column filtering.

Every lead is also **MX-verified and scored**. `email_status` is `deliverable` / `risky` / `undeliverable` / `none` and `email_provider` names the mailbox host when known (Google Workspace, Microsoft 365, ...). `lead_score` is a 0–100 quality score (deliverable email + phone + website + socials + hospitality tech-stack signals), mapped to a `lead_grade` (A ≥ 80, B ≥ 65, C ≥ 50, D ≥ 35, else F) and a `lead_tier` (hot / warm / cold); `score_breakdown` shows how the score was earned. Rows are returned best-first.

#### Example output

A real sample from a live run:

| Name | City | Type | Phone | Email | Website | Tech signals |
|---|---|---|---|---|---|---|
| Hotel Almas | Marrakech | hotel | +212 524 425540 | reservation@hotelalmasmarrakech.com | http://www.hotelalmasmarrakech.com/ | Booking.com, Tripadvisor |
| Riad Christina |  | guest\_house | +212 5 24 38 43 84 | contact@riadchristina.com | https://www.riadchristina.com/ | eviivo, Booking.com, Expedia |
| Riad Papillon |  | guest\_house | +44 20 7193 7357 | contact@marrakech-riad.co.uk | https://www.marrakech-riad.co.uk/marrak… | Beds24 |
| Imouzzer |  | hotel |  | contact@hotel-imouzzer.com | https://www.hotel-imouzzer.com/ | Tripadvisor |

### Pricing

This actor uses **Apify pay-per-event pricing**: you're charged per lead returned, via a `result` event fired once per accommodation in the dataset. No subscription, no charge for empty runs — if a city yields nothing, you pay nothing. A **free Apify plan is enough to try it**: run a mid-size city and inspect the emails and tech signals before spending anything. See the actor's Pricing tab for the current per-result rate.

### Tips & FAQ

#### Where does the data come from?

Discovery uses **OpenStreetMap** (Nominatim + Overpass) queried live at run time; enrichment crawls each property's **own public website** live during the run. Nothing comes from a cached database, so emails and tech signals reflect what's online today.

#### Why OpenStreetMap and not Booking.com?

Booking.com is heavily bot-protected and scraping it requires expensive residential proxies. OpenStreetMap gives the same sellable core — accommodation owner contacts by city — reliably and cheaply, and the website crawl adds the emails and tech signals Booking.com wouldn't expose anyway. The trade-off: coverage depends on how well-mapped a city is. Major tourist destinations are mapped very thoroughly; a rural area may return fewer properties than actually exist.

#### How accurate is the tech-stack detection?

Detection is signal-based: the crawler looks for platform-specific domains and script references (e.g. `cloudbeds`, `siteminder`, `booking.com`) in each site's HTML. It's reliable when the platform has a public-facing widget or link on the site. A property using a PMS purely in the back office, with no embed on its website, won't show a signal — treat an empty `channel_manager` as "no public signal", not proof of no system.

#### Why do some properties have no email?

Not every property lists an email on its website, and some have no website at all. Set `onlyWithEmail: true` to keep the output cold-email-ready, and raise `maxPagesPerSite` to dig deeper into larger sites. Verify the addresses with the [Bulk Email Verifier](https://apify.com/flash_scraper/email-verifier) before sending a campaign.

#### Do I need an API key or proxies?

No. Both OpenStreetMap and the property websites are queried directly — no API keys, no anti-bot bypass, and it runs fine on datacenter IPs.

#### Is it legal?

The actor only reads **publicly available data**: OpenStreetMap listings and each property's own public web pages. It doesn't log in or bypass any access controls. Follow applicable outreach laws (CAN-SPAM, GDPR, etc.) when you contact the leads.

### Related actors

- [Bulk Email Verifier](https://apify.com/flash_scraper/email-verifier) — verify and score every scraped email before you send a campaign
- [Restaurant Leads Scraper](https://apify.com/flash_scraper/restaurant-leads-scraper) — the same enrichment approach for restaurants, with POS / reservation / delivery stack detection
- [Local Business Leads](https://apify.com/flash_scraper/local-business-leads) — any local business category by city, with website platform detection

Found a bug or need a feature? Open an issue on the actor's **Issues tab** — typical response within 1 business day.

# Actor input Schema

## `location` (type: `string`):

City and region/country to search, e.g. 'Marrakesh, Morocco', 'Lisbon, Portugal', 'Austin, Texas'.

## `includeHostels` (type: `boolean`):

Also include hostels and budget dorms in the results (off = hotels and guest houses only).

## `includeApartments` (type: `boolean`):

Also include tourism apartments / aparthotels.

## `includeChalets` (type: `boolean`):

Also include chalets and vacation cabins in the results (off = hotels and guest houses only).

## `maxItems` (type: `integer`):

Maximum number of accommodations to return.

## `crawlEmails` (type: `boolean`):

Visit each property's own website to extract contact emails and detect its channel manager / PMS and OTA presence. Turn off for a faster, listing-only run.

## `onlyWithWebsite` (type: `boolean`):

Drop accommodations with no website (required for email + tech-stack enrichment).

## `onlyWithEmail` (type: `boolean`):

Keep only properties where an email was found (best for cold email).

## `verifyEmails` (type: `boolean`):

MX-check every discovered email and label it deliverable / risky / undeliverable (adds email\_status + email\_provider, and feeds the lead score). Uses DNS-over-HTTPS - no SMTP handshake, no proxy needed. Turn off to skip verification.

## `onlyVerifiedEmail` (type: `boolean`):

Keep only leads whose email verified as deliverable or risky (drops undeliverable / no-email rows). Requires 'Verify email deliverability'.

## `maxPagesPerSite` (type: `integer`):

How many pages (home, contact, about, booking...) to crawl per website while looking for an email.

## `concurrency` (type: `integer`):

How many websites to crawl in parallel.

## Actor input object example

```json
{
  "location": "Marrakesh, Morocco",
  "includeHostels": false,
  "includeApartments": false,
  "includeChalets": false,
  "maxItems": 100,
  "crawlEmails": true,
  "onlyWithWebsite": true,
  "onlyWithEmail": false,
  "verifyEmails": true,
  "onlyVerifiedEmail": false,
  "maxPagesPerSite": 3,
  "concurrency": 8
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "location": "Marrakesh, Morocco",
    "onlyWithWebsite": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("flash_scraper/hotel-host-leads-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "location": "Marrakesh, Morocco",
    "onlyWithWebsite": True,
}

# Run the Actor and wait for it to finish
run = client.actor("flash_scraper/hotel-host-leads-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "location": "Marrakesh, Morocco",
  "onlyWithWebsite": true
}' |
apify call flash_scraper/hotel-host-leads-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=flash_scraper/hotel-host-leads-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/zVEcIWcLG2hNcS1nc/builds/3MAwdWV1bgDOIU9IZ/openapi.json
