# TripAdvisor Places Scraper - Most Comprehensive (`kaix/tripadvisor-places-scraper`) Actor

🔥 ~$0.1/1K places 🔥 Collect TripAdvisor hotels, restaurants, and things to do for cities and supported neighborhoods.

- **URL**: https://apify.com/kaix/tripadvisor-places-scraper.md
- **Developed by:** [Kai](https://apify.com/kaix) (community)
- **Categories:** Lead generation, Travel, Real estate
- **Stats:** 2 total users, 2 monthly users, 84.9% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.08 / 1,000 places

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

### What does TripAdvisor Places Scraper do?

**TripAdvisor Places Scraper collects normalized restaurants, hotels, attractions, and bookable attraction products from [TripAdvisor](https://www.tripadvisor.com/).** Enter a city for a quick run, or use a bounding box, a nearby-place search, or exact TripAdvisor place links when you need tighter control. Results are saved as one dataset record per place, with optional reviews, photos, profile sections, and booking data.

Running it on Apify adds API access, schedules, integrations, proxy rotation, run monitoring, and exportable datasets without requiring your own server. The default input is intentionally simple: enter a location and start the Actor.

### Why use TripAdvisor Places Scraper?

- Compare tourism and hospitality supply across destinations.
- Build prospect or research lists for restaurants, hotels, and attractions.
- Monitor ratings, review totals, badges, and TripAdvisor category positions.
- Collect exact POIs or bookable attraction products without broadening them to a city.
- Add only the data you need, from lightweight listings to reviews, photos, amenities, questions, or current booking offers.
- Use human-readable filters instead of maintaining TripAdvisor's changing internal filter IDs.

The Actor follows TripAdvisor's geography definitions and response-provided pagination, then removes duplicate places before applying your result limit.

### How to use TripAdvisor Places Scraper

1. Open the Actor's **Input** tab.
2. In section **1. Where do you want to search?**, keep **Cities, regions, or neighborhoods** for a normal destination search and enter a value such as `Boston`.
3. Choose the place types and maximum result count in section 2.
4. Optionally refine results, request extra data, or enter trip dates in sections 3–5.
5. Start the run, then open the default dataset to inspect or export the records.

The smallest input is:

```json
{
    "locations": ["Boston"]
}
```

Existing four-field integrations remain supported. `includeDetails` is now hidden in the Console, but it still controls the preset when `dataPreset` is omitted:

```json
{
    "locations": ["Boston"],
    "placeTypes": ["restaurant", "hotel", "attraction"],
    "maxItemsPerType": 30,
    "includeDetails": true
}
```

For new integrations, prefer `dataPreset` because it states the intended data depth directly. The Console prefills `listings` so a first run finishes quickly; choose `coreProfiles` or `fullProfiles` when profile-level fields are required.

### Input

The Console groups inputs into five workflow sections.

#### 1. Where do you want to search?

`searchMode` defaults to `area`, and `locations` is required.

| Mode          | Accepted location input                                                                  | Constraints                                                                                                                       |
| ------------- | ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `area`        | City, town, island, region, numeric geography ID, geography URL, or `Neighborhood, City` | Street addresses and postal codes are not reliable area boundaries.                                                               |
| `boundingBox` | Exactly one parent geography plus `boundingBox`                                          | Requires north, south, east, and west; north must exceed south, east must exceed west, and the box cannot cross the antimeridian. |
| `nearby`      | Exact TripAdvisor POI IDs or URLs                                                        | `boundingBox` is optional. A city ID is not a nearby anchor.                                                                      |
| `exact`       | Exact TripAdvisor POI or product IDs/URLs                                                | Place type is inferred. Bounding boxes are not accepted.                                                                          |

Neighborhood input is resolved against TripAdvisor's current filters for each selected place type. If the neighborhood is unavailable or ambiguous, the Actor reports an error rather than collecting the entire parent city.

#### 2. What places do you need?

`placeTypes` defaults to restaurants, hotels, and Things to do. `maxItemsPerType` defaults to `30` and is applied to every location × selected type stream. Things-to-do results can include `attraction_product` records when a category group such as Tours switches TripAdvisor to bookable inventory. Exact mode can also return an exact product.

#### 3. Refine the results

`restaurantFilters`, `hotelFilters`, and `attractionFilters` accept human-readable values such as `Italian`, `Free Wifi`, `4`, or `Tours`. Type-specific sort fields default to TripAdvisor's recommended order. `reviewFilters` applies only when reviews are requested.

Place filters and list ordering apply to `area` and `boundingBox` searches. They are rejected in `nearby` and `exact` modes, where TripAdvisor does not provide the same per-type list contract. Review filters still work whenever reviews are requested.

Filters and sorts are dynamic: their available values can change by destination, place type, selected category, dates, and earlier filters. The Actor discovers the current choices, maps your labels to them, and rejects unavailable or ambiguous choices. It also verifies explicit sorting rather than accepting TripAdvisor's silent fallback.

#### 4. What data should be collected?

Choose one `dataPreset`:

- `listings` for the fastest list-card collection and the Console's initial selection.
- `coreProfiles` for authoritative place details. Legacy API calls that omit `dataPreset` retain this behavior through `includeDetails: true`.
- `fullProfiles` for core details plus every applicable non-paginated profile section.

`additionalData` can add about text, amenities, menus, opening hours, health and safety, AI review summaries, reviews, tips, questions and answers, question-form metadata, photos, attraction products, product information, or booking offers. Separate maximum fields cap reviews, tips, questions, photos, and attraction products per place.

#### 5. Dates, guests, prices, and units

`currency` defaults to `USD`, and `unitLength` defaults to `MILES`. Optional `hotelStay`, `restaurantReservation`, and `attractionVisit` objects request context-specific availability. Dates must be valid and today or later, hotel checkout must follow check-in, and attraction traveler age bands must be unique. Each context requests offers only for its matching place type. Offer availability remains dependent on TripAdvisor and the selected dates, destination, and place.

An advanced bounding-box request can look like this:

```json
{
    "searchMode": "boundingBox",
    "locations": ["Boston"],
    "boundingBox": {
        "north": 42.373,
        "south": 42.338,
        "east": -71.03,
        "west": -71.09
    },
    "placeTypes": ["restaurant"],
    "restaurantFilters": [{ "field": "cuisines", "values": ["Italian"] }],
    "restaurantSort": "popularity",
    "dataPreset": "coreProfiles",
    "additionalData": ["reviews", "openingHours", "photos"],
    "maxReviewsPerPlace": 10,
    "maxPhotosPerPlace": 10
}
```

### Output

Each dataset item contains stable place fields and, when requested, optional feature data. A shortened record is:

```json
{
    "contentId": "5572598",
    "contentType": "restaurant",
    "name": "Ostra",
    "url": "https://www.tripadvisor.com/Restaurant_Review-g60745-d5572598-Reviews-Ostra.html",
    "sourceLocation": {
        "input": "Boston",
        "geoId": 60745,
        "name": "Boston",
        "neighborhood": null,
        "mode": "area"
    },
    "rating": 4.6,
    "reviewCount": 1140,
    "address": "1 Charles St S, Boston, MA 02116",
    "detailStatus": "fetched",
    "additionalData": {
        "openingHours": {},
        "reviews": []
    },
    "additionalDataErrors": {
        "aiReviewSummary": "Not available for this place"
    },
    "scrapedAt": "2026-08-11T12:00:00.000Z"
}
```

`additionalData` is keyed by requested feature. `additionalDataErrors` contains safe per-feature messages when optional enrichment fails; the base place record is retained. Fields that were not requested can be absent. You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

### Data table

| Field                              | Description                                                                                 |
| ---------------------------------- | ------------------------------------------------------------------------------------------- |
| `contentId`, `contentType`         | TripAdvisor identity and family: restaurant, hotel, attraction, or exact attraction product |
| `name`, `url`                      | Place name and canonical public TripAdvisor URL                                             |
| `sourceLocation`                   | Original input, resolved geography, optional neighborhood, and search mode                  |
| `listPosition`                     | Displayed result-card position, not an authoritative category rank                          |
| `rating`, `reviewCount`            | Current overall traveler rating and review count                                            |
| `primaryInfo`, `secondaryInfo`     | Type-specific list summary text                                                             |
| `photoUrls`, `labels`, `badge`     | Listing images and visible distinctions                                                     |
| `description`, `tags`              | Profile description and TripAdvisor tags                                                    |
| `address`, `latitude`, `longitude` | Place address and coordinates when available                                                |
| `contactLinks`, `ownerStatus`      | Public contacts and claimed-owner status                                                    |
| `ranking`                          | Category-ranking text and context when TripAdvisor supplies it                              |
| `ratingHistogram`, `subRatings`    | Rating distribution and type-specific subratings                                            |
| `detailStatus`                     | Whether core details were skipped, fetched, or failed                                       |
| `additionalData`                   | Optional feature results keyed by the requested feature name                                |
| `additionalDataErrors`             | Safe errors for optional features that could not be fetched                                 |
| `scrapedAt`                        | UTC collection timestamp                                                                    |

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

Cost depends on the number of location/type streams, result caps, data preset, and optional paginated collections. A listings-only run makes fewer requests than a full profile run with reviews and photos. Under pay-per-event pricing, each persisted place produces one place event and each review object saved in `additionalData.reviews` produces one `review-scraped` event. The aggregate `reviewCount` field is informational and is never charged as if those reviews were downloaded. Start with one location and a small limit, inspect the result and cost, and increase scope only when needed.

### Tips and advanced options

- Use `listings` while testing filters, then enable deeper profiles for a smaller final run.
- Copy filter labels as users see them on TripAdvisor; raw numeric filter IDs are intentionally unsupported.
- Use a bounding box for a known rectangle. Do not approximate an address or postal code with area mode.
- Keep review, question, photo, and product caps modest because each can require multiple pages.
- Optional data is type-specific. A menu may not apply to a hotel, and attraction products may not exist for every attraction.
- Result pages can repeat promoted or overlapping cards; deduplication occurs before the cap is applied.

### FAQ, disclaimers, and support

**Can I search an address or postal code as an area?** No. TripAdvisor content search is not a dependable postal geocoder. Use a verified geography, a bounding box, or an exact POI.

**Why was my filter or sort rejected?** TripAdvisor exposes different choices for different searches, and attraction categories can change the available sort family. The Actor rejects a choice it cannot verify instead of silently changing your request.

**Why is optional data missing?** Some features are unavailable for particular place types or dates. When a requested operation fails, check `additionalDataErrors`; core list data is retained whenever possible.

**Are attraction products ranked as Things to do?** Not necessarily. `attraction_product` represents bookable tour or experience inventory and can lack an attraction-category rank.

Web scraping may be regulated by website terms and applicable law. Use the Actor responsibly, collect only data you are permitted to process, and avoid unnecessary request volume. For problems or feature requests, use the Actor's **Issues** tab with a sanitized input example. Custom location modes or output fields can be discussed there as a custom solution.

# Actor input Schema

## `searchMode` (type: `string`):

Choose how the values in Locations should be interpreted.

## `locations` (type: `array`):

Area mode accepts cities, towns, islands, regions, numeric geography IDs, geography URLs, or Neighborhood, City. Nearby and exact modes require TripAdvisor POI IDs or URLs. Street addresses and postal codes are not area boundaries.

## `boundingBox` (type: `object`):

Required for bounding-box mode and optional for nearby mode. The box must not cross the antimeridian.

## `placeTypes` (type: `array`):

Collect restaurants, hotels, Things to do, or any combination.

## `maxItemsPerType` (type: `integer`):

Maximum unique places saved for each location and selected place type.

## `restaurantFilters` (type: `array`):

Examples: Cuisines = Italian, Minimum rating = 4, Open now = true.

## `restaurantSort` (type: `string`):

The Actor verifies that TripAdvisor honored this order.

## `hotelFilters` (type: `array`):

Examples: Amenities = Free Wifi, Classes = 4 stars, Minimum rating = 4.

## `hotelSort` (type: `string`):

The Actor verifies that TripAdvisor honored this order.

## `attractionFilters` (type: `array`):

Examples: Category group = Tours, Categories = Museums, Minimum rating = 4, Duration = 1–2 hours.

## `attractionSort` (type: `string`):

Available choices can change after selecting a category.

## `reviewFilters` (type: `array`):

Applied only when Reviews are selected under Additional data.

## `dataPreset` (type: `string`):

Listings is fastest. Core profiles adds authoritative place details. Full profiles adds every applicable non-paginated profile section.

## `additionalData` (type: `array`):

Select optional sections and collections. Core details are controlled by Data preset.

## `maxReviewsPerPlace` (type: `integer`):

Used when Reviews are selected.

## `maxTipsPerPlace` (type: `integer`):

Used when Traveler tips are selected.

## `maxQuestionsPerPlace` (type: `integer`):

Used when Questions and answers are selected.

## `maxPhotosPerPlace` (type: `integer`):

Used when Photos are selected.

## `maxAttractionProductsPerPlace` (type: `integer`):

Used when Attraction products are selected.

## `includeDetails` (type: `boolean`):

Retained for existing API integrations. Data preset takes precedence when supplied.

## `currency` (type: `string`):

Three-letter currency code. Price availability depends on TripAdvisor.

## `unitLength` (type: `string`):

Unit used for distances returned by TripAdvisor.

## `hotelStay` (type: `object`):

Optional. Supplying this requests dated hotel offers. Select Booking offers without this object for undated hotel offers.

## `restaurantReservation` (type: `object`):

Optional. Supplying this requests restaurant availability.

## `attractionVisit` (type: `object`):

Optional. Supplying this requests attraction and tour availability.

## Actor input object example

```json
{
  "searchMode": "area",
  "locations": [
    "Boston"
  ],
  "placeTypes": [
    "restaurant",
    "hotel",
    "attraction"
  ],
  "maxItemsPerType": 30,
  "restaurantSort": "auto",
  "hotelSort": "auto",
  "attractionSort": "auto",
  "dataPreset": "listings",
  "additionalData": [],
  "maxReviewsPerPlace": 20,
  "maxTipsPerPlace": 20,
  "maxQuestionsPerPlace": 20,
  "maxPhotosPerPlace": 20,
  "maxAttractionProductsPerPlace": 20,
  "includeDetails": true,
  "currency": "USD",
  "unitLength": "MILES"
}
```

# Actor output Schema

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

Normalized restaurants, hotels, attractions, and exact attraction products, including any requested optional data.

# 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 = {
    "locations": [
        "Boston"
    ],
    "dataPreset": "listings"
};

// Run the Actor and wait for it to finish
const run = await client.actor("kaix/tripadvisor-places-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 = {
    "locations": ["Boston"],
    "dataPreset": "listings",
}

# Run the Actor and wait for it to finish
run = client.actor("kaix/tripadvisor-places-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 '{
  "locations": [
    "Boston"
  ],
  "dataPreset": "listings"
}' |
apify call kaix/tripadvisor-places-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kaix/tripadvisor-places-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/KcwA9tG7Sibt34ubF/builds/hjni7E7Tbja2VNRV4/openapi.json
