# TripAdvisor Restaurants · Emails, Phones & Socials (`corent1robert/tripadvisor-restaurant-details-scraper`) Actor

Paste a TripAdvisor restaurant page or a city listing. Get email, phone, official website, address, hours and ranking. Optionally add extra emails and/or Instagram / Facebook / TikTok from the restaurant site — two separate options. Public pages only. No login.

- **URL**: https://apify.com/corent1robert/tripadvisor-restaurant-details-scraper.md
- **Developed by:** [Corentin Robert](https://apify.com/corent1robert) (community)
- **Categories:** Travel, Lead generation
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.50 / 1,000 restaurant with emails

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/actors/running/actors-in-store.md#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

## TripAdvisor restaurant details

**Turn a TripAdvisor restaurant URL *or* a city restaurants listing into CRM-ready rows: name, phone, email, official website, Instagram / Facebook / TikTok, address, hours, ranking, cuisine and price.**

Paste one restaurant page, a city listing, or a mix. Each dataset row is one restaurant. Export CSV or JSON.

**No login. No API key. No TripAdvisor account.**

**Free plan: 20 restaurants / run.** Paid plans follow your PPE budget.

***

### Also available

| Actor | Use when |
|-------|----------|
| [TripAdvisor restaurant URL discovery](https://console.apify.com/actors/r63zaonzpROWPHZCS) | You only need **profile URLs**, not emails/phones |
| **This Actor — details** | Restaurant page **or** city listing → phone, email, website, Instagram / Facebook |
| [Booking Pro Host](https://apify.com/corent1robert/booking-pro-host-scraper) | Hotel / apartment host contacts on Booking.com |

***

### Who is this for?

| You are… | Typical goal | Suggested setup |
|----------|--------------|-----------------|
| **Outbound / SDR** | Phone, email, website and Instagram for restaurant outreach | City listing URL · **Max restaurants** 25 · view **Outreach — CRM** |
| **CRM / RevOps** | Structured restaurant records | Bulk profile URLs · export CSV |
| **F\&B / POS / insurance sales** | Rank, neighborhood, hours, closed flag | Full JSON export |
| **Market research** | Ratings, price band, cuisine mix | View **Restaurants** · 20–50 URLs |
| **Agency / local SEO** | Competitor contacts in one city | Pair with discovery on that city listing |

**What you get by default:** name, TripAdvisor URL, location ID, phone, email when TripAdvisor **or the restaurant website** publishes it, extra mailboxes in `emails[]`, official website, **Instagram / Facebook / TikTok / etc. from the site**, street / city / postal / country, neighborhoods, rating, review count, ranking, opening hours, closed flag, owner-verified, Travelers’ Choice when present, lat/lng.

**Website:** the mobile HTML often ships an empty Website button even when desktop shows the site. The Actor then calls the same public GraphQL used to hydrate that button (`websiteUrlSource: graphql`). A real href or JSON-LD link on the page still wins (`page`). If GraphQL is empty, a **custom email domain** is guessed (`banquets@keens.com` → `https://www.keens.com`, source `email-domain`). Free mailboxes (Gmail, etc.) are not guessed. Two independent options then apply: extra emails from the site, and/or social profiles. Uncheck either — or both — if you only want TripAdvisor fields. `emailSource` is `tripadvisor` or `website`.

**When a field is empty:** it was not on the public page. Failed rows have `error` — they are not silent blanks.

**Typical fill (NYC sample, 5 public profiles):** 5/5 phone, 4/5 email, 5/5 name and address. Email and official website depend on what TripAdvisor publishes for that restaurant.

***

### Quick start

1. Paste a `Restaurant_Review` URL **or** a city `Restaurants-g…` listing (or a mix)
2. Keep **Max restaurants** at **25** for a preview (raise it for a full city)
3. Click **Start**
4. Open dataset view **Outreach — CRM** for email, phone, Instagram, website, address and hours

***

### Ready-made examples

Sixteen city/workflow presets are saved as Console tasks (New York, Paris, London, Barcelona, Rome, Los Angeles, Miami, Chicago, Berlin, Amsterdam, Lisbon, Dubai, Tokyo, Singapore, Sydney). They go live on the Store **Examples** tab after each task is published.

Until then, paste any `Restaurant_Review` URL or a city listing — the Keens Steakhouse prefill is a one-row smoke test.

***

### What does it extract?

| Category | Fields |
|----------|--------|
| **Identity** | `name`, `url`, `locationId`, `imageUrl` |
| **Contact** | `email`, `emails`, `emailSource`, `telephone`, `websiteUrl`, `websiteUrlSource`, `instagramUrl`, `facebookUrl`, `tiktokUrl`, `twitterUrl`, `youtubeUrl`, `linkedinUrl`, `pinterestUrl`, `socialUrls` |
| **Location** | `address`, `street`, `city`, `region`, `postalCode`, `countryCode`, `neighborhoods`, `latitude`, `longitude` |
| **Reputation** | `rating`, `reviews`, `ranking`, `rankingPosition`, `rankingOutOf`, `travelersChoiceYear`, `travelersChoiceAward`, `hasVerifiedOwner` |
| **Ops** | `priceRange`, `foodCategories`, `openingHours`, `isClosed`, `description`, `reviewsUrl` |

Dataset views: **Restaurants** (overview) and **Outreach — CRM** (email, phone, Instagram / Facebook / TikTok, website, address, hours).

***

### How much does it cost to scrape TripAdvisor restaurants?

HTTP-only (no browser). You pay **pay-per-event**: a restaurant row (cheaper without email, higher with email) plus a **socials add-on** only if **Collect Instagram / Facebook / TikTok** is on and a profile is found. Actor-start is a few hundredths of a cent.

List price vs the Store: generic Tripadvisor listing scrapers are about **$2.90–$5 / 1k** (Apify official) plus **$5+ / 1k** for lead add-ons. Restaurant-lead Actors sit around **$4 / 1k** (flat) to **$9.90 / 1k**. This Actor is **$3 / 1k** without email, **$5 / 1k** with email, and **+$2 / 1k** when social profiles are found (FREE plan).

| Event | FREE | Bronze | Gold |
|-------|------|--------|------|
| Restaurant without email | $3 / 1k | $2.70 | $2.10 |
| Restaurant with email | $5 / 1k | $4.50 | $3.50 |
| Social profiles (add-on) | $2 / 1k | $1.80 | $1.40 |

| Scenario | FREE |
|----------|------|
| 25 profiles, ~80% email, ~80% socials | ~$0.16 |
| 1,000 profiles without email, no socials | $3.00 |
| 1,000 profiles with email, no socials | $5.00 |
| 1,000 profiles with email + socials | $7.00 |
| 1,000 mixed (~80% email, ~70% socials) | ~$6.00 |

Residential proxy is **not** required by default. Platform compute on 1024 MB is extra and typically small next to PPE.

***

### Is it legal to scrape TripAdvisor restaurant pages?

This Actor only reads **public** restaurant profile pages (the same HTML a visitor can open without an account) and, when enabled, public pages on the restaurant’s own website. It does not log in or open host dashboards.

Phones, emails, addresses and social profile URLs can be personal data. Use them under **GDPR**, CAN-SPAM and local marketing rules. See [Apify's guide to web scraping legality](https://blog.apify.com/is-web-scraping-legal/).

***

### Input

Console: paste **TripAdvisor URL(s)** (restaurant and/or city listing) and click Start.

```json
{
  "startUrls": [
    "https://www.tripadvisor.com/Restaurants-g60763-New_York_City_New_York.html"
  ],
  "maxItems": 25
}
```

| Parameter | Console | Default | Description |
|-----------|---------|---------|-------------|
| `startUrls` | Yes | — | Restaurant `Restaurant_Review` URLs and/or city `Restaurants-g…` listings |
| `maxItems` | Yes | `25` | Max restaurants to enrich. City listings paginate (~30/page) until this cap |
| `crawlWebsite` | Yes | `true` | Extra public emails from the restaurant website |
| `collectSocials` | Yes | `true` | Instagram / Facebook / TikTok from the website (**+$2 / 1k** if found) |
| `maxConcurrency` | Hidden | `2` | Profiles in parallel |
| `delayMsBetweenBatches` | Hidden | `600` | Pause between batches (ms) |
| `maxRetries` | Hidden | `3` | Extra attempts per profile |
| `resume` | Hidden | `false` | Skip URLs already in the dataset |
| `maxPagesPerWebsite` | Hidden | `6` | Same-domain pages crawled per site |
| `proxyConfiguration` | Hidden | no proxy | Optional backup |
| `verboseLogs` | Hidden | `false` | Extra diagnostics |
| `navigationTimeoutSecs` | Hidden | `60` | Wait per TripAdvisor page |

***

### Output example

```json
{
  "url": "https://www.tripadvisor.com/Restaurant_Review-g60763-d425330-Reviews-Keens_Steakhouse-New_York_City_New_York.html",
  "name": "Keens Steakhouse",
  "email": "banquets@keens.com",
  "emails": ["banquets@keens.com", "info@keens.com"],
  "emailSource": "tripadvisor",
  "telephone": "+1 212-947-3636",
  "websiteUrl": "https://www.keens.com/",
  "websiteUrlSource": "graphql",
  "instagramUrl": "https://www.instagram.com/keenssteakhouse/",
  "facebookUrl": "https://www.facebook.com/keenssteakhouse",
  "socialUrls": [
    "https://www.instagram.com/keenssteakhouse/",
    "https://www.facebook.com/keenssteakhouse"
  ],
  "priceRange": "$$$$",
  "foodCategories": "American, Steakhouse",
  "reviews": "7030",
  "rating": 4.5,
  "address": "72 West 36th Street, New York City, New York, 10018, US",
  "street": "72 West 36th Street",
  "city": "New York City",
  "region": "New York",
  "postalCode": "10018",
  "countryCode": "US",
  "neighborhoods": "Midtown, Midtown West, Koreatown, Tenderloin",
  "ranking": "#131 of 9,100 restaurants",
  "openingHours": "Sunday 17:00-21:30; Monday 11:45-22:30; Tuesday 11:45-22:30; Wednesday 11:45-22:30; Thursday 11:45-22:30; Friday 11:45-22:30; Saturday 17:00-22:30",
  "isClosed": false,
  "hasVerifiedOwner": true
}
```

***

### How it works

1. You paste a restaurant page, a city listing, or both
2. City listings are expanded into restaurant profile URLs (up to **Max restaurants**)
3. The Actor reads each public TripAdvisor profile (and the desktop website GraphQL when the HTML button is empty)
4. If a website is known **and** you left emails and/or socials checked, it opens that site for those fields
5. Rows appear in the dataset as they complete — export CSV/JSON anytime

No TripAdvisor account. Empty fields mean they were not published.

***

### Local development

```bash
npm ci
node --test tests/*.test.js
apify run --input-file=./published-tasks/inputs/01-keens-profile.json
```

Requires [Apify CLI](https://docs.apify.com/cli). Default `INPUT.json` in `storage/` must include `startUrls` if you use `apify run` without `--input-file`.

***

### FAQ

**Do I need a proxy?** Not for typical restaurant pages. Pass `proxyConfiguration` in JSON only if a run returns empty profiles.

**Why was website missing before?** The iPhone HTML leaves the Website button with an empty href. Desktop fills it after GraphQL hydration. The Actor now replays that public call (`websiteUrlSource: graphql`). `email-domain` remains a last-resort guess.

**Where do extra emails and socials come from?** Two Console checkboxes, independent. Extra emails: crawl contact pages (`crawlWebsite`). Socials: Instagram / Facebook / TikTok / etc. (`collectSocials`), billed **$2 / 1k** only when a profile is found. Uncheck socials if you only want inboxes. Uncheck emails if you only want socials (TripAdvisor email is still kept when present).

**Can I paste a city URL?** Yes. Use the city **restaurants** listing (`Restaurants-g…`). A city tourism page (`Tourism-g…`) is converted to that listing. Hotels pages are ignored.

**Can I mix hotels?** No. Only restaurant profiles and restaurant city listings.

***

### Support

Issues tab, or <corentin@outreacher.fr> for a custom scraper or integration.

# Actor input Schema

## `startUrls` (type: `array`):

One URL per line:

- a **restaurant** page (`Restaurant_Review`)
- a **city restaurants** listing (`Restaurants-g…`, e.g. Paris or New York)

You can mix both. A city listing is paginated until **Max restaurants** is reached, then each profile is enriched.

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

Stop after this many restaurant profiles. On a city listing we paginate automatically (~30 per page: page 2 = oa30, page 3 = oa60, …) until this cap. Default **25**. Set **200** for a bigger Paris extract.

## `maxConcurrency` (type: `integer`):

How many restaurant pages to read at once.

## `maxRetries` (type: `integer`):

Extra attempts when a public page does not load on the first try.

## `delayMsBetweenBatches` (type: `integer`):

Optional pause after each parallel batch.

## `resume` (type: `boolean`):

Continue a previous run without re-enriching the same restaurant URLs.

## `crawlWebsite` (type: `boolean`):

Open the restaurant site (homepage + contact pages) and merge public mailboxes TripAdvisor did not publish. A mailbox found only on the site is billed as **with email**. Turn off to keep only the email TripAdvisor already shows.

## `collectSocials` (type: `boolean`):

From the same site (or when TripAdvisor already lists a Facebook/Instagram page as the website), keep public social profiles. Billed as a **$2 / 1k** add-on only when at least one profile is found. Turn off if you only want emails and phones.

## `maxPagesPerWebsite` (type: `integer`):

Homepage plus contact / about / legal / reservation pages, same domain only. Used when extra emails and/or socials are on.

## `maxListingPages` (type: `integer`):

How far to walk a city restaurants list. Stops earlier if Max restaurants is reached.

## `pageStep` (type: `integer`):

TripAdvisor typically shows 30 restaurants per page.

## `delayMsBetweenListingPages` (type: `integer`):

Optional pause between city listing pages.

## `proxyConfiguration` (type: `object`):

Optional backup. Direct access is the default.

## `verboseLogs` (type: `boolean`):

Print extra diagnostics in the run log.

## `navigationTimeoutSecs` (type: `integer`):

How long to wait for each restaurant page.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.tripadvisor.com/Restaurant_Review-g60763-d425330-Reviews-Keens_Steakhouse-New_York_City_New_York.html"
  ],
  "maxItems": 25,
  "maxConcurrency": 2,
  "maxRetries": 3,
  "delayMsBetweenBatches": 600,
  "resume": false,
  "crawlWebsite": true,
  "collectSocials": true,
  "maxPagesPerWebsite": 6,
  "maxListingPages": 20,
  "pageStep": 30,
  "delayMsBetweenListingPages": 800,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "verboseLogs": false,
  "navigationTimeoutSecs": 60
}
```

# Actor output Schema

## `dataset` (type: `string`):

Full restaurant rows — one profile per item

## `overview` (type: `string`):

Name, phone, email, Instagram, website, city, rating, ranking

## `outreachCrm` (type: `string`):

Email, phone, socials, website, address, hours for outreach

# 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 = {
    "startUrls": [
        "https://www.tripadvisor.com/Restaurant_Review-g60763-d425330-Reviews-Keens_Steakhouse-New_York_City_New_York.html"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("corent1robert/tripadvisor-restaurant-details-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 = { "startUrls": ["https://www.tripadvisor.com/Restaurant_Review-g60763-d425330-Reviews-Keens_Steakhouse-New_York_City_New_York.html"] }

# Run the Actor and wait for it to finish
run = client.actor("corent1robert/tripadvisor-restaurant-details-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "startUrls": [
    "https://www.tripadvisor.com/Restaurant_Review-g60763-d425330-Reviews-Keens_Steakhouse-New_York_City_New_York.html"
  ]
}' |
apify call corent1robert/tripadvisor-restaurant-details-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,corent1robert/tripadvisor-restaurant-details-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/6aXohphOwgWP96zLN/builds/85zgKJeGoc7zCWaTm/openapi.json
