# TripAdvisor Only $0.45💰 Search | Hotels | Restaurants |Reviews (`memo23/tripadvisor-scraper`) Actor

💰$0.45 per 1,000 Scrape TripAdvisor hotel reviews: title, rating, language, text, dates, owner response, photos, sub-ratings, and optional reviewer profiles. Each review is enriched with place metadata (rating, address, geo, website, histogram). Filter by rating, language, date and per-place limit

- **URL**: https://apify.com/memo23/tripadvisor-scraper.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** Travel, Automation, Agents
- **Stats:** 28 total users, 6 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $0.45 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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 Reviews Scraper

**Turn TripAdvisor hotel pages into structured review datasets.** Pull every public review for a property — title, rating, language, text, travel date, owner response, photos, sub‑ratings — already enriched with the host place's full metadata (address, geo, ranking, ratingHistogram). One run, one clean dataset.

#### How it works

![How TripAdvisor Reviews Scraper Works](https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-tripadvisor.png)

#### ✨ Why use this scraper?

Manually opening hotel pages and copying reviews? Stitching together separate "reviews" and "place details" scrapes? Getting blocked by DataDome the moment you scale?

- 🏨 **Reviews + place metadata in the same row.** Every review already carries `placeInfo` (rating, address, lat/lng, ranking, histogram). No follow‑up enrichment.
- 🎯 **Server‑side filters wired through TripAdvisor's GraphQL.** Star ratings, languages, per‑place limits and dates are pushed down to the API — you get back what you asked for.
- 📅 **Absolute or relative date cutoff.** `"2026-01-01"` or `"22 days"`, `"3 weeks"`, `"6 months"`, `"1 year"` — all valid for `lastReviewDate`.
- 👤 **Optional reviewer profiles.** Flip `scrapeReviewerInfo` to switch from the lean review‑centric output to a reviewer‑centric output with username, hometown, contributions, avatar, profile link.
- 🧩 **Three output modes.** Default `flat` is one row per review (good for tabular consumers). `outputShape: "nested"` collapses each place into a single row with `reviews[]` nested. `scrapeReviews: false` skips reviews entirely and emits a place‑only snapshot — fast, low‑cost.
- 🛡️ **Hardened anti‑bot path.** Mobile‑Safari UA fallback through `undici` for HTML, real browser fingerprinting via `ImpitHttpClient` for the GraphQL endpoint, single‑shot DataDome detection.
- 📑 **Per‑location failure dataset.** Skipped or blocked hotels land in a side dataset (`tripadvisor-failures`) instead of getting buried in logs.
- ⚡ **Parallel pagination.** Each hotel pages through GraphQL in concurrent batches (default 3), respecting your global and per‑place caps.

#### 🎯 Use cases

| Team | What they build |
|------|----------------|
| **Hotel ops** | Daily review monitoring + owner‑response SLA tracking |
| **Reputation managers** | Multi‑property reputation dashboards with ratingHistogram drift over time |
| **Market analysts** | Competitive benchmarks across cities or chains using `placeInfo.rating` + `numberOfReviews` |
| **Content / NLP teams** | Multilingual review corpora for sentiment and topic models, filtered by language and rating |
| **Travel media** | Curated "best of" articles backed by recent verified reviews |
| **Data teams** | One‑shot dataset exports for BI, lake or warehouse ingestion (JSON, CSV, Excel) |

#### 🔧 How it works (pipeline)

1. **Detect location ID** from each `*_Review-...` URL (`-d{id}-`) — works for hotels, restaurants and attractions.
2. **Fetch the place HTML** with a mobile‑Safari User‑Agent. Falls back to a direct `undici` fetch when DataDome blocks the desktop fingerprint, and to URL‑derived `placeInfo` when even that is blocked (reviews still come through over GraphQL).
3. **Extract `placeInfo`** from the page's JSON‑LD + meta description (rating, review count, address, geo, ranking position).
4. **Page through GraphQL reviews** at `/data/graphql/ids` in concurrent batches, with `reviewRatings` / `reviewsLanguages` / `maxItems` pushed into the filter payload.
5. **Apply `lastReviewDate`** client‑side after each page, and break early once an entire page is older than the cutoff.
6. **Map and push** each review enriched with `placeInfo` to the default dataset; skipped or blocked places go to `tripadvisor-failures`.

#### 📥 Supported inputs

Currently supported start URLs (mix and match in a single run):

| Pattern | Example |
|---------|---------|
| `Hotel_Review-g{geoId}-d{locationId}-Reviews-{slug}.html` | `https://www.tripadvisor.com/Hotel_Review-g60763-d208453-Reviews-Hilton_New_York_Times_Square-New_York_City_New_York.html` |
| `Restaurant_Review-g{geoId}-d{locationId}-Reviews-{slug}.html` | `https://www.tripadvisor.com/Restaurant_Review-g60763-d25324283-Reviews-Allora_Fifth_Ave-New_York_City_New_York.html` |
| `Attraction_Review-g{geoId}-d{locationId}-Reviews-{slug}.html` | `https://www.tripadvisor.com/Attraction_Review-g60763-d105123-Reviews-Statue_of_Liberty-New_York_City_New_York.html` |
| **`Restaurants-g{geo}-…html`** GEO restaurant hub — expands to each matching restaurant | `https://www.tripadvisor.com/Restaurants-g35805-Chicago_Illinois.html` |
| **`Hotels-g{geo}-…-Hotels.html`** GEO hotel hub — expands to each matching hotel | `https://www.tripadvisor.com/Hotels-g60763-New_York_City_New_York-Hotels.html` |
| **`Attractions-g{geo}-Activities-…html`** GEO attractions hub — expands to each matching attraction (optional `-cNN-` category) | `https://www.tripadvisor.com/Attractions-g60763-Activities-New_York_City_New_York.html` |
| **`FindRestaurants` search URL** — expands to each matching restaurant | `https://www.tripadvisor.com/FindRestaurants?geo=188673&establishmentTypes=10591&mealTypes=10597&broadened=false` |

Place detail URLs share the same GraphQL endpoint and review schema — only `placeInfo.type` differs (`HOTEL`, `EATERY`, `ATTRACTION`). A **`FindRestaurants`** start URL is resolved via TripAdvisor’s listing GraphQL into many `Restaurant_Review` venues (paginated, up to **10 × 30 = 300** venues per search by default); then each venue is scraped like a standalone restaurant URL — `maxItems` applies **per restaurant** discovered from that listing (subject to your plan’s overall cap).

Not currently supported:
- Search / hub pages **other than** `FindRestaurants` (for example generic `Hotels-g…`, `Attractions-g…`).
- `tripadvisor.co.*` country domains (use `.com`).
- Non‑TripAdvisor hosts.
#### ⚙️ Input parameters

##### Discovery (use `searchQuery` and/or `startUrls`)

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `searchQuery` | string | — | Free-text location, e.g. `"Chicago"`, `"Brooklyn"`, `"London"`. Resolved to a TripAdvisor geoId via the typeahead GraphQL endpoint, then expanded into venues based on the include* toggles below. Use **alongside** or **instead of** `startUrls`. |
| `startUrls` | array of `{ url }` | `[]` | TripAdvisor **`Hotel_Review`**, **`Restaurant_Review`**, **`Attraction_Review`**, and **`FindRestaurants?…`** URLs. Listing URLs expand to discovered restaurants; plain place URLs scrape that place directly. Run in parallel up to `maxConcurrency`. |
| `includeRestaurants` | boolean | `true` | When `searchQuery` is set, include `Restaurant_Review` venues for the resolved geo. Wired through the existing `FindRestaurants?geo=…` expansion. |
| `includeHotels` | boolean | `true` | When `searchQuery` is set, include `Hotel_Review` venues. Wired through the `Hotels-g{geo}-…-Hotels.html` listing expander (paginated, up to ~300 hotels per query). |
| `includeThingsToDo` | boolean | `true` | When `searchQuery` is set, include `Attraction_Review` venues. Wired through the `Attractions-g{geo}-Activities-…html` listing expander (paginated, up to ~300 attractions per query). |
| `includeNearby` | boolean | `false` | When `true`, after each main place is scraped the actor expands up to **5** nearby venues from the page's nearby carousel as additional place-detail-only snapshot rows tagged with `isNearbyResult: true`. Reviews are NOT fetched for nearby venues. Depth capped at 1. |

> One of `searchQuery` or `startUrls` should be provided. Empty input produces a clean no-op run.

##### Filters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `maxItems` | integer | `50` | Max reviews to fetch **per place / per URL**. Applied to each entry in `startUrls` independently — e.g. `maxItems: 50` with 3 URLs ⇒ up to 150 reviews total. `0` = unlimited (paginate to the end of each place). |
| `reviewRatings` | array | `[]` (all) | Star ratings to keep. Values: `"1"`, `"2"`, `"3"`, `"4"`, `"5"`, or `"ALL_REVIEW_RATINGS"`. Pushed down into the GraphQL filter payload. |
| `reviewsLanguages` | array | `[]` (all) | ISO 639‑1 codes (e.g. `["en", "de", "fr"]`) or `"ALL_REVIEW_LANGUAGES"`. Pushed down into the GraphQL filter payload. |
| `lastReviewDate` | string | — | Skip reviews published before this date. Accepts an **absolute** date `YYYY-MM-DD` or a **relative** duration: `"22 days"`, `"2 weeks"`, `"3 months"`, `"1 year"` (singular or plural). |
| `scrapeReviewerInfo` | boolean | `true` | When `true`, the `user` object on each review is populated with the reviewer's profile (username, display name, avatar, hometown, contributions, profile link). When `false`, `user` is `null`. The rest of the review fields (`id`, `lang`, `helpfulVotes`, `tripType`, `subratings`, `photos`, …) are emitted in **both** modes. |

> **Migration note:** `maxItemsPerQuery` was merged into `maxItems` — `maxItems` is now the per-place cap (it used to be a run-wide ceiling). Saved configs that still pass `maxItemsPerQuery` keep working: it's accepted as a deprecated alias and overrides `maxItems` for that run, with a warning logged.

##### Place vs reviews

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `scrapeReviews` | boolean | `true` | When `true` (default), paginate reviews via GraphQL up to `maxItems` per place. When `false`, skip reviews entirely and emit **one** dataset row per start URL with `{ "placeDetailOnly": true, "placeInfo": … }` parsed from the page HTML. Best for fast place snapshots. |
| `includeReviewTags` | boolean | `true` | When `true` (default), include `placeInfo.reviewTags` (theme phrases like `"sushi: 14 reviews"`) on emitted rows when TripAdvisor embeds them. Set `false` to drop them for smaller payloads. |
| `outputShape` | string (`"flat"` \| `"nested"`) | `"flat"` | Controls the dataset shape **when reviews are scraped**. `"flat"` (default) keeps today's row‑per‑review layout, each row carrying `placeInfo`. `"nested"` collapses each place into a single row of the form `{ "placeDetailOnly": false, "placeInfo": …, "reviews": [...] }`. No effect when `scrapeReviews: false`. |

> **Note on nested mode + billing:** under `PRICE_PER_DATASET_ITEM` (the default Apify pricing model), nested mode bills **once per place** instead of once per review — so a place with 200 reviews charges `1` dataset item, not `200`. If you switch the default, also review your actor's pricing config.

##### Advanced

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `maxConcurrency` | integer | `100` | Max start URLs (hotels) processed concurrently. |
| `minConcurrency` | integer | `1` | Crawler floor. |
| `maxRequestRetries` | integer | `15` (range `0`–`50`) | Retries per request before giving up. Lower = surface failures fast, higher = absorb transient anti‑bot blocks. |
| `proxy` | object | `{ useApifyProxy: true, apifyProxyGroups: ["RESIDENTIAL"] }` | Standard Apify proxy block. Apify Residential is strongly recommended for TripAdvisor. |

#### 📊 Output overview

The actor emits **one of three row shapes** depending on `scrapeReviews` and `outputShape`. Default settings produce a flat **row‑per‑review** dataset enriched with the host place's `placeInfo` — the rest of this section walks the review schema first, then shows how nested and place‑only rows differ.

| Mode | `scrapeReviews` | `outputShape` | Rows per place | Row shape |
|------|----------------|---------------|----------------|-----------|
| **Flat reviews** (default) | `true` | `"flat"` | up to `maxItems` | `{ ...review, placeInfo }` — one row per review |
| **Nested reviews** | `true` | `"nested"` | exactly `1` | `{ placeDetailOnly: false, placeInfo, reviews: [...] }` |
| **Place snapshot** | `false` | (ignored) | exactly `1` | `{ placeDetailOnly: true, placeInfo }` |

The full review schema below is emitted in **both** `scrapeReviewerInfo` modes — the only difference is whether the `user` object is populated (`true`) or set to `null` (`false`).

##### Review schema (both modes)

```json
{
    "id": "1003456789",
    "url": "https://www.tripadvisor.com/ShowUserReviews-g60763-d208453-r1003456789-Hilton_New_York_Times_Square-New_York_City_New_York.html",
    "title": "Great location, friendly staff",
    "lang": "en",
    "language": "en",
    "originalLanguage": "en",
    "locationId": "208453",
    "publishedDate": "2026-03-14",
    "publishedPlatform": "OTHER",
    "rating": 5,
    "helpfulVotes": 2,
    "text": "We stayed three nights and...",
    "travelDate": "2026-03",
    "stayDate": "2026-03-14",
    "tripType": "COUPLES",
    "user": null,
    "ownerResponse": {
        "id": "987654",
        "text": "Thank you for staying with us...",
        "lang": "en",
        "publishedDate": "2026-03-16",
        "responder": "Hilton Times Square",
        "connectionToSubject": "Manager"
    },
    "subratings": [
        { "name": "Service", "value": 5 },
        { "name": "Cleanliness", "value": 5 },
        { "name": "Value", "value": 4 },
        { "name": "Location", "value": 5 },
        { "name": "Rooms", "value": 4 },
        { "name": "Sleep Quality", "value": 5 }
    ],
    "photos": [
        { "id": "812340000", "width": 4032, "height": 3024, "image": "https://media-cdn.tripadvisor.com/media/photo-o/30/68/0c/00/lobby.jpg" }
    ],
    "placeInfo": {
        "id": "208453",
        "name": "Hilton New York Times Square",
        "rating": 4.0,
        "numberOfReviews": 8944,
        "locationString": "New York City, New York",
        "latitude": 40.756,
        "longitude": -73.989,
        "webUrl": "https://www.tripadvisor.com/Hotel_Review-g60763-d208453-Reviews-Hilton_New_York_Times_Square-New_York_City_New_York.html",
        "website": "https://www.hilton.com/...",
        "path": "/Hotel_Review-g60763-d208453-Reviews-Hilton_New_York_Times_Square-New_York_City_New_York.html",
        "phone": "+12125551234",
        "address": "234 W 42nd St, New York City, NY 10036",
        "addressObj": {
            "street1": "234 W 42nd St",
            "city": "New York City",
            "state": "NY",
            "postalcode": "10036",
            "country": "United States"
        },
        "ratingHistogram": { "count1": 412, "count2": 480, "count3": 1100, "count4": 2680, "count5": 4272 }
    }
}
````

With `scrapeReviewerInfo: true` the only field that changes is `user` — it is replaced with the reviewer's profile object:

```json
{
    "user": {
        "userId": "ABCDEF12345",
        "name": "Traveler 123",
        "contributions": { "totalContributions": 42 },
        "username": "traveler123",
        "userLocation": { "shortName": "Berlin", "name": "Berlin, Germany", "id": "187323" },
        "avatar": { "id": "5567890", "width": 200, "height": 200, "image": "https://media-cdn.tripadvisor.com/media/photo-l/...jpg" },
        "link": "www.tripadvisor.com/Profile/traveler123"
    }
}
```

#### 🗂️ Output fields

##### Review core

All fields below are emitted in **both** `scrapeReviewerInfo` modes.

| Field | Type | Description |
|-------|------|-------------|
| `id` | string | TripAdvisor review ID |
| `url` | string | Permalink to the review on TripAdvisor |
| `title` | string | Review headline |
| `text` | string | Review body |
| `rating` | integer (1–5) | Stars left by the reviewer |
| `lang` | string (ISO 639‑1) | Source language (preserves `originalLanguage` for machine‑translated reviews) |
| `language` | string (ISO 639‑1) | Current API language (may be the translated language) |
| `originalLanguage` | string (ISO 639‑1) | Source language before machine translation |
| `publishedDate` | string (ISO date) | When the review was published |
| `publishedPlatform` | string | Source platform (e.g. `OTHER`, `MOBILE`) |
| `helpfulVotes` | integer | Helpful‑vote count |
| `travelDate` | string (`YYYY-MM`) | Month/year of the stay |
| `stayDate` | string (`YYYY-MM-DD`) | Full stay date |
| `tripType` | string | null | `COUPLES`, `FAMILY`, `BUSINESS`, `SOLO`, `FRIENDS`, … |
| `locationId` | string | TripAdvisor location ID for the place |

##### Owner response

| Field | Type | Description |
|-------|------|-------------|
| `ownerResponse.id` | string | Response ID |
| `ownerResponse.text` | string | Response body |
| `ownerResponse.lang` | string | Response language |
| `ownerResponse.publishedDate` | string | Response date |
| `ownerResponse.responder` | string | Display name (e.g. property name or manager) |
| `ownerResponse.connectionToSubject` | string | `Manager`, `Owner`, etc. |

##### Subratings

`subratings` is an **array** of `{ name, value }`:

| Field | Type | Description |
|-------|------|-------------|
| `subratings[].name` | string | `Service`, `Cleanliness`, `Value`, `Location`, `Rooms`, `Sleep Quality`, … |
| `subratings[].value` | integer (1–5) | Per‑aspect rating |

##### Photos

`photos` is an **array** of `{ id, width, height, image }`:

| Field | Type | Description |
|-------|------|-------------|
| `photos[].id` | string | TripAdvisor photo ID |
| `photos[].width` / `height` | integer | Native pixel dimensions |
| `photos[].image` | string | Bare CDN URL (no `?w=...` query) |

##### Reviewer (only when `scrapeReviewerInfo: true`)

| Field | Type | Description |
|-------|------|-------------|
| `user.userId` | string | null | Internal TripAdvisor user ID |
| `user.name` | string | null | Display name |
| `user.username` | string | null | URL handle |
| `user.contributions.totalContributions` | integer | Lifetime contribution count |
| `user.userLocation` | object | null | `{ shortName, name, id }` resolved from hometown |
| `user.avatar` | object | null | `{ id, width, height, image }` |
| `user.link` | string | null | Profile link without scheme (`www.tripadvisor.com/Profile/...`) |

##### Place metadata (`placeInfo`)

| Field | Type | Description |
|-------|------|-------------|
| `placeInfo.id` | string | Numeric location ID |
| `placeInfo.name` | string | Place display name (hotel, restaurant, attraction) |
| `placeInfo.rating` | number | Aggregate 1–5 rating |
| `placeInfo.numberOfReviews` | integer | Total review count on TripAdvisor |
| `placeInfo.locationString` | string | Human‑readable city/state/country |
| `placeInfo.latitude` / `longitude` | number | Geo coordinates |
| `placeInfo.address` | string | Single‑line address |
| `placeInfo.phone` | string | undefined | Telephone when TA exposes it |
| `placeInfo.path` | string | undefined | Relative TripAdvisor path (e.g. `/Restaurant_Review-g…-Reviews-…`) — often set from **FindRestaurants** listing GraphQL |
| `placeInfo.webUrl` | string | Full `https://www.tripadvisor.com/…` URL for the place |
| `placeInfo.cuisines` | string\[] | undefined | Cuisine labels when present (listing or HTML) |
| `placeInfo.priceLevel` | string | undefined | Price band, e.g. `$$ - $$$` |
| `placeInfo.menuUrl` | string | undefined | External menu / pub chain URL when present on the listing |
| `placeInfo.addressObj` | object | `{ street1, street2, city, state, postalcode, country }` |
| `placeInfo.website` | string | Official business website (when known) |
| `placeInfo.ratingHistogram` | object | `{ count1, count2, count3, count4, count5 }` |
| `placeInfo.type` | string | `HOTEL`, `EATERY`, `ATTRACTION`, … |

When you start from a **`FindRestaurants?…`** URL, the actor first calls TripAdvisor’s listing GraphQL and **seeds** each review row’s `placeInfo` with whatever the listing card returns (name, relative `path`, lat/lon, cuisines, price band, review count, address, phone, menu URL). The detail HTML pass (when not blocked) can still refine or override overlapping fields.

##### Alternative output shapes

Set `outputShape: "nested"` to collapse a place's reviews into a single row:

```json
{
    "placeDetailOnly": false,
    "placeInfo": {
        "id": "208453",
        "name": "Hilton New York Times Square",
        "rating": 4.0,
        "numberOfReviews": 8944,
        "address": "234 W 42nd St, New York City, NY 10036",
        "ratingHistogram": { "count1": 412, "count2": 480, "count3": 1100, "count4": 2680, "count5": 4272 }
    },
    "reviews": [
        { "id": "1003456789", "rating": 5, "title": "Great location, friendly staff", "text": "We stayed three nights...", "publishedDate": "2026-03-14", "lang": "en", "...": "..." },
        { "id": "1003456790", "rating": 4, "title": "Solid choice for Times Square", "text": "Rooms were quieter than expected...", "publishedDate": "2026-03-13", "lang": "en", "...": "..." }
    ]
}
```

Set `scrapeReviews: false` (regardless of `outputShape`) to skip reviews entirely and get a fast place snapshot. The snapshot row carries the **full** parsed `placeInfo` — description, amenities, room tips, neighborhood + ancestor + metro context, hotel class, offers, category review scores, cuisines + hours (restaurants), and more — pulled from JSON-LD and the page's embedded redux/apollo state:

```json
{
    "placeDetailOnly": true,
    "placeInfo": {
        "id": "208453",
        "name": "Hilton New York Times Square",
        "description": "Wake Up to the Best Views in Times Square. Perched above the energy and heart of the city...",
        "rating": 4.0,
        "rawRanking": 3.898643732070923,
        "rankingPosition": 289,
        "rankingDenominator": "520",
        "rankingString": "#289 of 520 hotels in New York City",
        "rankingSource": "HTML",
        "numberOfReviews": 8944,
        "hotelClass": "4.0",
        "hotelClassAttribution": "Classified by Giata.",
        "amenities": ["Wifi", "Pool", "Fitness center", "..."],
        "categoryReviewScores": [
            { "categoryName": "Service", "score": 4.36, "roundedScore": 4.4 },
            { "categoryName": "Cleanliness", "score": 4.58, "roundedScore": 4.6 }
        ],
        "neighborhoodLocations": [
            { "id": "15565670", "name": "Times Square" },
            { "id": "7102352", "name": "Midtown" }
        ],
        "ancestorLocations": [
            { "id": "60763", "name": "New York City", "subcategory": "City" },
            { "id": "28953", "name": "New York", "abbreviation": "NY", "subcategory": "State" }
        ],
        "nearestMetroStations": [
            { "name": "42nd St – Port Authority", "distance": 0.08, "lines": [{ "lineName": "A" }, { "lineName": "C" }] }
        ],
        "offers": [{ "pricePerNight": 169, "vendor": "Booking.com" }],
        "roomTips": [{ "id": "1055595676", "text": "Perfect Location in the Heart of Times Square." }],
        "address": "234 W 42nd St, New York City, NY 10036",
        "ratingHistogram": { "count1": 412, "count2": 480, "count3": 1100, "count4": 2680, "count5": 4272 },
        "reviewTags": [ { "text": "times square", "reviews": 1988 } ]
    }
}
```

Restaurant snapshots additionally surface `cuisines`, `hours`, `dishes`, `mealTypes`, `dietaryRestrictions`, `features`, `menuWebUrl`, `establishmentTypes`, and the open/closed flags (`isClosed`, `isLongClosed`, `openNowText`).

> The same rich `placeInfo` is emitted at the top level when you use `outputShape: "nested"` — the nested `reviews[]` underneath carry the slim variant to avoid duplicating tens of fields per review.

**Example `placeInfo` shaped like a listing card** (values match what TripAdvisor often returns for a London pub — your dataset may use string `id`):

```json
{
    "id": "944622",
    "name": "The Yacht",
    "path": "/Restaurant_Review-g186338-d944622-Reviews-The_Yacht-London_England.html",
    "webUrl": "https://www.tripadvisor.com/Restaurant_Review-g186338-d944622-Reviews-The_Yacht-London_England.html",
    "latitude": 51.48476,
    "longitude": -0.003814,
    "menuUrl": "https://www.greeneking.co.uk/pubs/greater-london/yacht/menu?utm_source=exnet&utm_medium=locations&utm_campaign=UC_menu",
    "cuisines": ["Bar", "British", "Pub"],
    "priceLevel": "$$ - $$$",
    "rating": 4,
    "numberOfReviews": 401,
    "address": "5 Crane St Greenwich, London SE10 9NP England",
    "phone": "+44 20 8858 0175",
    "type": "EATERY"
}
```

#### 🚀 Examples

##### Single hotel, defaults

```json
{
    "startUrls": [
        { "url": "https://www.tripadvisor.com/Hotel_Review-g60763-d208453-Reviews-Hilton_New_York_Times_Square-New_York_City_New_York.html" }
    ],
    "maxItems": 50
}
```

##### Multiple hotels, English‑only, last 30 days

```json
{
    "startUrls": [
        { "url": "https://www.tripadvisor.com/Hotel_Review-g60763-d208453-Reviews-Hilton_New_York_Times_Square-New_York_City_New_York.html" },
        { "url": "https://www.tripadvisor.com/Hotel_Review-g60763-d93589-Reviews-The_Manhattan_at_Times_Square_Hotel-New_York_City_New_York.html" }
    ],
    "maxItems": 100,
    "reviewsLanguages": ["en"],
    "lastReviewDate": "30 days"
}
```

##### Recent 3‑star reviews with full reviewer profiles

```json
{
    "startUrls": [
        { "url": "https://www.tripadvisor.com/Hotel_Review-g60763-d208453-Reviews-Hilton_New_York_Times_Square-New_York_City_New_York.html" }
    ],
    "maxItems": 50,
    "reviewRatings": ["3"],
    "reviewsLanguages": ["en"],
    "lastReviewDate": "2026-01-01",
    "scrapeReviewerInfo": true
}
```

##### Mix hotels and restaurants in one run

```json
{
    "startUrls": [
        { "url": "https://www.tripadvisor.com/Hotel_Review-g60763-d208453-Reviews-Hilton_New_York_Times_Square-New_York_City_New_York.html" },
        { "url": "https://www.tripadvisor.com/Restaurant_Review-g60763-d25324283-Reviews-Allora_Fifth_Ave-New_York_City_New_York.html" }
    ],
    "maxItems": 50,
    "reviewsLanguages": ["en"]
}
```

##### Place snapshots only (no reviews)

Skip review pagination entirely — useful for bulk place metadata:

```json
{
    "startUrls": [
        { "url": "https://www.tripadvisor.com/Hotel_Review-g60763-d208453-Reviews-Hilton_New_York_Times_Square-New_York_City_New_York.html" },
        { "url": "https://www.tripadvisor.com/Restaurant_Review-g60763-d25324283-Reviews-Allora_Fifth_Ave-New_York_City_New_York.html" }
    ],
    "scrapeReviews": false
}
```

Each start URL produces exactly **one** dataset row of `{ "placeDetailOnly": true, "placeInfo": … }`.

##### Nested output (one row per place, reviews under `reviews[]`)

```json
{
    "startUrls": [
        { "url": "https://www.tripadvisor.com/Hotel_Review-g60763-d208453-Reviews-Hilton_New_York_Times_Square-New_York_City_New_York.html" }
    ],
    "maxItems": 200,
    "outputShape": "nested",
    "reviewsLanguages": ["en"]
}
```

The dataset will contain exactly **one** row per place with `reviews` nested under it — easier to consume when you want a single object per hotel/restaurant rather than joining N review rows back to a place.

##### Free-text search query

Resolve a city or neighborhood name to a geoId without pasting a URL — combines naturally with the include\* toggles:

```json
{
    "searchQuery": "Chicago",
    "includeRestaurants": true,
    "includeHotels": false,
    "includeThingsToDo": false,
    "maxItems": 30,
    "reviewsLanguages": ["en"]
}
```

The actor calls TripAdvisor's typeahead GraphQL, picks the first GEO/NEIGHBORHOOD result, and seeds the run with `FindRestaurants?geo=<id>` (when `includeRestaurants`), `Hotels-g<id>-Hotels.html` (when `includeHotels`), and/or `Attractions-g<id>-Activities.html` (when `includeThingsToDo`). All three listing types share the same `-oa30-` HTML pagination pipeline.

##### `FindRestaurants` search (listing → many restaurants)

```json
{
    "startUrls": [
        {
            "url": "https://www.tripadvisor.com/FindRestaurants?geo=188673&establishmentTypes=10591&mealTypes=10597&broadened=false"
        }
    ],
    "maxItems": 50,
    "reviewsLanguages": ["en"]
}
```

Each review row carries `placeInfo` seeded from the listing card (coordinates, cuisines, `priceLevel`, `menuUrl`, relative `path`, etc., when TripAdvisor returns them).

#### 💻 Integrations

##### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

run = client.actor("muhamed-didovic/apify-tripadvisor").call(run_input={
    "startUrls": [
        {"url": "https://www.tripadvisor.com/Hotel_Review-g60763-d208453-Reviews-Hilton_New_York_Times_Square-New_York_City_New_York.html"},
    ],
    "maxItems": 50,
    "reviewsLanguages": ["en"],
    "lastReviewDate": "30 days",
})

for review in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"{review['rating']}★  {review['title']}  ({review['lang']})")
    print(f"   place: {review['placeInfo']['name']}  rating: {review['placeInfo']['rating']}")
```

##### JavaScript / Node

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

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });

const run = await client.actor('muhamed-didovic/apify-tripadvisor').call({
    startUrls: [
        { url: 'https://www.tripadvisor.com/Hotel_Review-g60763-d208453-Reviews-Hilton_New_York_Times_Square-New_York_City_New_York.html' },
    ],
    maxItems: 50,
    scrapeReviewerInfo: true,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((r) => {
    console.log(`${r.rating}★  ${r.title}  by ${r.user?.username ?? 'anon'}`);
});
```

#### 📈 Performance

| Metric | Value |
|--------|-------|
| Reviews per hotel page (GraphQL) | 10 |
| Concurrent review pages per hotel | up to 3 (auto‑capped to 1 when many hotels run in parallel) |
| Anti‑bot path | Mobile‑Safari UA + `ImpitHttpClient` GraphQL fingerprint, single‑shot DataDome detection |
| Failure visibility | Per‑location rows in `tripadvisor-failures` named dataset |
| Output formats | JSON, CSV, Excel, RSS, XML, HTML (via Apify dataset views) |

#### 💡 Tips for best results

1. **Start with one place and `maxItems: 10` to validate the schema.** Works the same for hotels, restaurants and attractions — confirm the fields you care about land in the dataset before launching big runs.
2. **Use server‑side filters.** `reviewRatings` and `reviewsLanguages` are pushed into the GraphQL payload — much cheaper than fetching everything and filtering downstream.
3. **Prefer relative dates over absolute when running on a schedule.** `"30 days"` always means "last 30 days from now"; an absolute `2026-01-01` will silently widen as time passes.
4. **Lower `maxRequestRetries` for fast feedback.** The default `15` absorbs anti‑bot blocks but can hide a misconfigured proxy. Try `3` while iterating, raise it for production.
5. **Toggle `scrapeReviewerInfo` only when you need profiles.** All review fields are kept in both modes; the only thing that changes is whether `user` is populated. Disabling it makes the dataset smaller and the run faster.
6. **Check the `tripadvisor-failures` dataset after each run.** Empty = perfect run. Rows = location‑level issues you can replay.

#### ❓ FAQ

**Which TripAdvisor URLs are supported?**
`Hotel_Review-…`, `Restaurant_Review-…`, and `Attraction_Review-…` URLs on `www.tripadvisor.com` (anything that follows the `…-g{geoId}-d{locationId}-Reviews-…` slug pattern). You can also pass a **`FindRestaurants?geo=…&…`** search URL from the site’s restaurant finder — the actor expands it to individual restaurant places and scrapes reviews per venue. They share the same review GraphQL endpoint; only `placeInfo.type` differs. Other search hub pages (e.g. generic `Hotels-g…` lists) are not supported. Use `www.tripadvisor.com` — not `tripadvisor.co.*` mirrors.

**How many reviews can I scrape per run?**
As many as your Apify plan and `maxItems` allow. `maxItems` is **per place** (per `Hotel_Review` / `Restaurant_Review` / `Attraction_Review` URL, and **per restaurant** after a `FindRestaurants` listing is expanded). Rough upper bound: `maxItems × total_places` — where `total_places` counts every expanded restaurant from searches plus every direct detail URL (`startUrls`). Runs are still subject to platform limits (e.g. free-tier item caps). The actor paginates reviews in batches of 20 per GraphQL page, in parallel where possible.

**What does `scrapeReviewerInfo` actually change?**
The only field that changes is `user`. With `true` (default) the `user` object is populated with the reviewer's profile (username, display name, avatar, hometown, contributions, profile link). With `false` it's `null`. All other review fields (`id`, `lang`, `subratings`, `photos`, `helpfulVotes`, `tripType`, …) are emitted in both modes.

**Do I need to know the URL to scrape a city?**
No. Pass `searchQuery: "Chicago"` (or any city/neighborhood name) and the actor resolves it to a geoId via TripAdvisor's typeahead, then expands into venues based on the `includeRestaurants` / `includeHotels` / `includeThingsToDo` toggles. Today only `includeRestaurants` is wired through the listing expander; for hotels and attractions, paste the corresponding `Hotel_Review-…` / `Attraction_Review-…` URLs into `startUrls` directly. You can mix `searchQuery` and `startUrls` in the same run.

**What's the difference between `scrapeReviews: false` and `outputShape: "nested"`?**
`scrapeReviews: false` **skips** all review pagination — you only get the place metadata (one fast row per URL with `placeDetailOnly: true`). `outputShape: "nested"` **still scrapes reviews** but groups them under a single dataset row per place (`{ placeDetailOnly: false, placeInfo, reviews: [...] }`). Pick `false` for cheap bulk place snapshots; pick `nested` when you want reviews + a place‑centric layout for downstream consumers.

**What date formats does `lastReviewDate` accept?**
Both absolute (`2026-01-01`, ISO `YYYY-MM-DD`) and relative durations: `"22 days"`, `"3 weeks"`, `"6 months"`, `"1 year"` (singular and plural both work). Reviews older than the resolved date are dropped client‑side, with an early‑break optimisation that stops paginating once an entire page is older than the cutoff.

**Why is `lang` sometimes different from the on‑site language toggle?**
TripAdvisor machine‑translates reviews. We always emit the **source** language (`originalLanguage`), not the displayed translation, so analytics groupings stay accurate.

**Can I scrape multiple places in one run?**
Yes — pass any number of `startUrls`. Hotels, restaurants and attractions can be mixed in the same run; they're processed concurrently up to `maxConcurrency`. Intra‑place pagination is auto‑capped to 1 in that case so the GraphQL endpoint isn't hammered with `concurrency × pages` requests.

**Where do failed locations end up?**
In a named dataset called `tripadvisor-failures` with rows like `{ url, locationId, locationType, reason, message, timestamp }`. The reason field is one of `invalid-location-id`, `html-blocked`, `datadome-block`, `reviews-fetch-failed`, `no-reviews-saved`. The Apify run page surfaces a direct link.

**Is private content accessible?**
No. The actor only sees public TripAdvisor pages and the public review GraphQL endpoint.

#### 📬 Support

- Bug reports / feature requests: use the [Issues](https://console.apify.com/actors/ftbw0YFo17iTQ2qjv/issues) tab on the actor page.
- Direct contact: <muhamed.didovic@gmail.com>
- Author's website: [muhamed-didovic.github.io](https://muhamed-didovic.github.io/)

#### 🛠️ Additional services

- Custom output schemas, one‑off datasets, scheduled exports.
- Other platforms (Booking, Yelp, Google Maps, etc.) on request.
- API integrations and automation pipelines.

Email: <muhamed.didovic@gmail.com>.

#### 🔭 Explore more scrapers

If this actor was useful, browse other scrapers from [memo23 on Apify](https://apify.com/memo23).

#### ⚖️ Legal & compliance

This scraper targets publicly accessible TripAdvisor content for legitimate research, monitoring, and analytics. You are responsible for:

- Complying with TripAdvisor's terms of service.
- Respecting `robots.txt` and reasonable rate limits.
- Using scraped data lawfully (privacy, copyright, GDPR/CCPA where applicable).
- Obtaining any necessary permissions for commercial reuse of the data.

# Actor input Schema

## `searchQuery` (type: `string`):

Optional free-text location query, e.g. `"Chicago"`, `"Brooklyn"`, `"London"`. Resolved via TripAdvisor's autocomplete GraphQL into a geoId, then expanded into venues based on the `Include hotels` / `Include restaurants` / `Include things to do` toggles below. Use this **instead of or alongside** `startUrls`. Leave empty to skip text-search and use only the URLs in `startUrls`.

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

Add TripAdvisor URLs to scrape reviews. Supported:

- **Place pages:** `Hotel_Review`, `Restaurant_Review`, `Attraction_Review` URLs (`…/<Type>_Review-g{geoId}-d{locationId}-Reviews-{slug}.html`).
- **GEO restaurant listing:** `Restaurants-g{geo}-…-{City}_{State}.html` — HTML listing + `-oa30-` pagination, expanded to `Restaurant_Review` venues.
- **GEO hotel listing:** `Hotels-g{geo}-…-Hotels.html` — HTML listing + `-oa30-` pagination, expanded to `Hotel_Review` venues.
- **GEO attractions listing:** `Attractions-g{geo}-Activities-…html` — HTML listing + `-oa30-` pagination, expanded to `Attraction_Review` venues. Optional `-cNN-` category subfilter is preserved.
- **Restaurant search:** `FindRestaurants?geo=…&establishmentTypes=…` — listing expansion calls **`api.tripadvisor.com` `AppListRestaurants`** (same as the TA iPhone app), then falls back to www `/data/graphql/ids`, then HTML link harvest if needed. **`maxItems` still caps reviews per scraped `Restaurant_Review` URL** (each listing produces many URLs).

Examples:

- Hotel — `https://www.tripadvisor.com/Hotel_Review-g60763-d208453-Reviews-Hilton_New_York_Times_Square-New_York_City_New_York.html`
- Restaurant — `https://www.tripadvisor.com/Restaurant_Review-g60763-d25324283-Reviews-Allora_Fifth_Ave-New_York_City_New_York.html`
- Chicago restaurants hub — `https://www.tripadvisor.com/Restaurants-g35805-Chicago_Illinois.html`
- New York hotels hub — `https://www.tripadvisor.com/Hotels-g60763-New_York_City_New_York-Hotels.html`
- Find Restaurants — `https://www.tripadvisor.com/FindRestaurants?geo=188673&establishmentTypes=10591&mealTypes=10597&broadened=false`

Mix detail URLs and listing URLs in one run.

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

Maximum number of reviews to scrape **per place / per URL**. Applied to each entry in `startUrls` independently. Use 0 for unlimited (the actor will paginate every review the API exposes for that place).

## `scrapeReviewerInfo` (type: `boolean`):

When enabled, populate the `user` object on each review with the reviewer's profile (username, display name, avatar, hometown, profile link, contributions). When disabled, `user` is set to null.

## `scrapeReviews` (type: `boolean`):

When **true** (default), fetch reviews for each `Hotel_Review` / `Restaurant_Review` URL using TripAdvisor GraphQL (paginated), up to **`maxItems` per place**. When **false**, skip review pagination and emit **one dataset row per place** with `{ "placeDetailOnly": true, "placeInfo": … }` extracted from the HTML page (fast, low cost).

## `includeReviewTags` (type: `boolean`):

When **true** (default), include `placeInfo.reviewTags` (theme phrases and counts) when TripAdvisor embeds them on the page. Set **false** to omit tags for smaller payloads.

## `includeNearby` (type: `boolean`):

When `true`, after each main place is scraped the actor expands up to **5** nearby venues from the page's nearby carousel as additional **place-detail-only** snapshot rows tagged with `isNearbyResult: true`. Reviews are NOT fetched for nearby venues. Depth is capped at 1 (no recursive expansion).

## `includeThingsToDo` (type: `boolean`):

When `searchQuery` is set, include `Attraction_Review` venues for the resolved geo. Wired through the `Attractions-g{geo}-Activities-…html` listing expander (paginated, up to ~300 attractions per query).

## `includeRestaurants` (type: `boolean`):

When `searchQuery` is set, include `Restaurant_Review` venues for the resolved geo. Wired through the existing `FindRestaurants?geo=…` expansion (paginated, up to 300 venues per query).

## `includeHotels` (type: `boolean`):

When `searchQuery` is set, include `Hotel_Review` venues for the resolved geo. Wired through the new `Hotels-g{geo}-…-Hotels.html` listing expander (paginated, up to ~300 hotels per query).

## `outputShape` (type: `string`):

Controls how reviews are returned in the dataset.

- **`flat`** (default): one dataset row **per review**, each carrying `placeInfo`. Best for tabular consumers and Apify's UI.
- **`nested`**: one dataset row **per place** of the form `{ ...placeInfo, placeDetailOnly: false, reviews: [...] }`. Best when you want a single object per hotel/restaurant with reviews nested.

No effect when **`scrapeReviews: false`** — that path always emits one `{ placeDetailOnly: true, placeInfo }` row per place.

**Note on billing:** under `PRICE_PER_DATASET_ITEM`, nested mode collapses N reviews into 1 row, so the bill drops by ~Nx. Review your actor pricing before switching the default.

## `lastReviewDate` (type: `string`):

Skip any review published before this date. Pick an absolute date (YYYY-MM-DD) or a relative duration like `22 days`, `2 weeks`, `3 months`, `1 year`.

## `reviewRatings` (type: `array`):

Filter reviews by overall rating. Leave empty to include every rating.

## `reviewsLanguages` (type: `array`):

Filter reviews by language (ISO 639-1 codes). Leave empty to include every language.

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

Maximum number of pages that can be processed at the same time.

## `minConcurrency` (type: `integer`):

Minimum number of pages that will be processed at the same time.

## `maxRequestRetries` (type: `integer`):

Number of times each failed request is retried before giving up. Lower values surface persistent failures quickly; higher values absorb transient anti-bot blocks at the cost of long-tail latency.

## `proxy` (type: `object`):

Specifies proxy servers that will be used by the scraper in order to hide its origin.<br><br>For details, see <a href='https://apify.com/apify/web-scraper#proxy-configuration' target='_blank' rel='noopener'>Proxy configuration</a> in README.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.tripadvisor.com/Hotel_Review-g60763-d208453-Reviews-Hilton_New_York_Times_Square-New_York_City_New_York.html"
    },
    {
      "url": "https://www.tripadvisor.com/Restaurant_Review-g60763-d25324283-Reviews-Allora_Fifth_Ave-New_York_City_New_York.html"
    },
    {
      "url": "https://www.tripadvisor.com/FindRestaurants?geo=188673&establishmentTypes=10591&mealTypes=10597&broadened=false"
    },
    {
      "url": "https://www.tripadvisor.com/Restaurants-g35805-Chicago_Illinois.html"
    }
  ],
  "maxItems": 50,
  "scrapeReviewerInfo": true,
  "scrapeReviews": true,
  "includeReviewTags": true,
  "includeNearby": false,
  "includeThingsToDo": true,
  "includeRestaurants": true,
  "includeHotels": true,
  "outputShape": "flat",
  "reviewRatings": [
    "ALL_REVIEW_RATINGS"
  ],
  "reviewsLanguages": [
    "ALL_REVIEW_LANGUAGES"
  ],
  "maxConcurrency": 100,
  "minConcurrency": 1,
  "maxRequestRetries": 15,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

Direct link to the run's default dataset items.

## `failures` (type: `string`):

Locations that produced 0 reviews or failed mid-pagination. Empty if the run was perfect.

# 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": [
        {
            "url": "https://www.tripadvisor.com/Hotel_Review-g60763-d208453-Reviews-Hilton_New_York_Times_Square-New_York_City_New_York.html"
        },
        {
            "url": "https://www.tripadvisor.com/Restaurant_Review-g60763-d25324283-Reviews-Allora_Fifth_Ave-New_York_City_New_York.html"
        },
        {
            "url": "https://www.tripadvisor.com/FindRestaurants?geo=188673&establishmentTypes=10591&mealTypes=10597&broadened=false"
        },
        {
            "url": "https://www.tripadvisor.com/Restaurants-g35805-Chicago_Illinois.html"
        }
    ],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/tripadvisor-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": [
        { "url": "https://www.tripadvisor.com/Hotel_Review-g60763-d208453-Reviews-Hilton_New_York_Times_Square-New_York_City_New_York.html" },
        { "url": "https://www.tripadvisor.com/Restaurant_Review-g60763-d25324283-Reviews-Allora_Fifth_Ave-New_York_City_New_York.html" },
        { "url": "https://www.tripadvisor.com/FindRestaurants?geo=188673&establishmentTypes=10591&mealTypes=10597&broadened=false" },
        { "url": "https://www.tripadvisor.com/Restaurants-g35805-Chicago_Illinois.html" },
    ],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("memo23/tripadvisor-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 '{
  "startUrls": [
    {
      "url": "https://www.tripadvisor.com/Hotel_Review-g60763-d208453-Reviews-Hilton_New_York_Times_Square-New_York_City_New_York.html"
    },
    {
      "url": "https://www.tripadvisor.com/Restaurant_Review-g60763-d25324283-Reviews-Allora_Fifth_Ave-New_York_City_New_York.html"
    },
    {
      "url": "https://www.tripadvisor.com/FindRestaurants?geo=188673&establishmentTypes=10591&mealTypes=10597&broadened=false"
    },
    {
      "url": "https://www.tripadvisor.com/Restaurants-g35805-Chicago_Illinois.html"
    }
  ],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call memo23/tripadvisor-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "TripAdvisor Only $0.45💰 Search | Hotels | Restaurants |Reviews",
        "description": "💰$0.45 per 1,000 Scrape TripAdvisor hotel reviews: title, rating, language, text, dates, owner response, photos, sub-ratings, and optional reviewer profiles. Each review is enriched with place metadata (rating, address, geo, website, histogram). Filter by rating, language, date and per-place limit",
        "version": "0.0",
        "x-build-id": "3gqRiPYV4rCtO9eoM"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/memo23~tripadvisor-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-memo23-tripadvisor-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/memo23~tripadvisor-scraper/runs": {
            "post": {
                "operationId": "runs-sync-memo23-tripadvisor-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/memo23~tripadvisor-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-memo23-tripadvisor-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "searchQuery": {
                        "title": "Search Query",
                        "type": "string",
                        "description": "Optional free-text location query, e.g. `\"Chicago\"`, `\"Brooklyn\"`, `\"London\"`. Resolved via TripAdvisor's autocomplete GraphQL into a geoId, then expanded into venues based on the `Include hotels` / `Include restaurants` / `Include things to do` toggles below. Use this **instead of or alongside** `startUrls`. Leave empty to skip text-search and use only the URLs in `startUrls`."
                    },
                    "startUrls": {
                        "title": "Start URLs",
                        "type": "array",
                        "description": "Add TripAdvisor URLs to scrape reviews. Supported:\n\n- **Place pages:** `Hotel_Review`, `Restaurant_Review`, `Attraction_Review` URLs (`…/<Type>_Review-g{geoId}-d{locationId}-Reviews-{slug}.html`).\n- **GEO restaurant listing:** `Restaurants-g{geo}-…-{City}_{State}.html` — HTML listing + `-oa30-` pagination, expanded to `Restaurant_Review` venues.\n- **GEO hotel listing:** `Hotels-g{geo}-…-Hotels.html` — HTML listing + `-oa30-` pagination, expanded to `Hotel_Review` venues.\n- **GEO attractions listing:** `Attractions-g{geo}-Activities-…html` — HTML listing + `-oa30-` pagination, expanded to `Attraction_Review` venues. Optional `-cNN-` category subfilter is preserved.\n- **Restaurant search:** `FindRestaurants?geo=…&establishmentTypes=…` — listing expansion calls **`api.tripadvisor.com` `AppListRestaurants`** (same as the TA iPhone app), then falls back to www `/data/graphql/ids`, then HTML link harvest if needed. **`maxItems` still caps reviews per scraped `Restaurant_Review` URL** (each listing produces many URLs).\n\nExamples:\n- Hotel — `https://www.tripadvisor.com/Hotel_Review-g60763-d208453-Reviews-Hilton_New_York_Times_Square-New_York_City_New_York.html`\n- Restaurant — `https://www.tripadvisor.com/Restaurant_Review-g60763-d25324283-Reviews-Allora_Fifth_Ave-New_York_City_New_York.html`\n- Chicago restaurants hub — `https://www.tripadvisor.com/Restaurants-g35805-Chicago_Illinois.html`\n- New York hotels hub — `https://www.tripadvisor.com/Hotels-g60763-New_York_City_New_York-Hotels.html`\n- Find Restaurants — `https://www.tripadvisor.com/FindRestaurants?geo=188673&establishmentTypes=10591&mealTypes=10597&broadened=false`\n\nMix detail URLs and listing URLs in one run.",
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "maxItems": {
                        "title": "Limit reviews per place",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Maximum number of reviews to scrape **per place / per URL**. Applied to each entry in `startUrls` independently. Use 0 for unlimited (the actor will paginate every review the API exposes for that place).",
                        "default": 50
                    },
                    "scrapeReviewerInfo": {
                        "title": "Scrape reviewer info",
                        "type": "boolean",
                        "description": "When enabled, populate the `user` object on each review with the reviewer's profile (username, display name, avatar, hometown, profile link, contributions). When disabled, `user` is set to null.",
                        "default": true
                    },
                    "scrapeReviews": {
                        "title": "Scrape reviews",
                        "type": "boolean",
                        "description": "When **true** (default), fetch reviews for each `Hotel_Review` / `Restaurant_Review` URL using TripAdvisor GraphQL (paginated), up to **`maxItems` per place**. When **false**, skip review pagination and emit **one dataset row per place** with `{ \"placeDetailOnly\": true, \"placeInfo\": … }` extracted from the HTML page (fast, low cost).",
                        "default": true
                    },
                    "includeReviewTags": {
                        "title": "Include review theme tags",
                        "type": "boolean",
                        "description": "When **true** (default), include `placeInfo.reviewTags` (theme phrases and counts) when TripAdvisor embeds them on the page. Set **false** to omit tags for smaller payloads.",
                        "default": true
                    },
                    "includeNearby": {
                        "title": "Include nearby results",
                        "type": "boolean",
                        "description": "When `true`, after each main place is scraped the actor expands up to **5** nearby venues from the page's nearby carousel as additional **place-detail-only** snapshot rows tagged with `isNearbyResult: true`. Reviews are NOT fetched for nearby venues. Depth is capped at 1 (no recursive expansion).",
                        "default": false
                    },
                    "includeThingsToDo": {
                        "title": "Include things to do (attractions)",
                        "type": "boolean",
                        "description": "When `searchQuery` is set, include `Attraction_Review` venues for the resolved geo. Wired through the `Attractions-g{geo}-Activities-…html` listing expander (paginated, up to ~300 attractions per query).",
                        "default": true
                    },
                    "includeRestaurants": {
                        "title": "Include restaurants",
                        "type": "boolean",
                        "description": "When `searchQuery` is set, include `Restaurant_Review` venues for the resolved geo. Wired through the existing `FindRestaurants?geo=…` expansion (paginated, up to 300 venues per query).",
                        "default": true
                    },
                    "includeHotels": {
                        "title": "Include hotels",
                        "type": "boolean",
                        "description": "When `searchQuery` is set, include `Hotel_Review` venues for the resolved geo. Wired through the new `Hotels-g{geo}-…-Hotels.html` listing expander (paginated, up to ~300 hotels per query).",
                        "default": true
                    },
                    "outputShape": {
                        "title": "Output shape (when reviews are scraped)",
                        "enum": [
                            "flat",
                            "nested"
                        ],
                        "type": "string",
                        "description": "Controls how reviews are returned in the dataset.\n\n- **`flat`** (default): one dataset row **per review**, each carrying `placeInfo`. Best for tabular consumers and Apify's UI.\n- **`nested`**: one dataset row **per place** of the form `{ ...placeInfo, placeDetailOnly: false, reviews: [...] }`. Best when you want a single object per hotel/restaurant with reviews nested.\n\nNo effect when **`scrapeReviews: false`** — that path always emits one `{ placeDetailOnly: true, placeInfo }` row per place.\n\n**Note on billing:** under `PRICE_PER_DATASET_ITEM`, nested mode collapses N reviews into 1 row, so the bill drops by ~Nx. Review your actor pricing before switching the default.",
                        "default": "flat"
                    },
                    "lastReviewDate": {
                        "title": "Only reviews since date",
                        "pattern": "^$|^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$|^(\\d+)\\s*(day|week|month|year)s?$",
                        "type": "string",
                        "description": "Skip any review published before this date. Pick an absolute date (YYYY-MM-DD) or a relative duration like `22 days`, `2 weeks`, `3 months`, `1 year`."
                    },
                    "reviewRatings": {
                        "title": "Review ratings",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Filter reviews by overall rating. Leave empty to include every rating.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "1",
                                "2",
                                "3",
                                "4",
                                "5",
                                "ALL_REVIEW_RATINGS"
                            ],
                            "enumTitles": [
                                "Terrible",
                                "Poor",
                                "Average",
                                "Very Good",
                                "Excellent",
                                "All ratings"
                            ]
                        },
                        "default": [
                            "ALL_REVIEW_RATINGS"
                        ]
                    },
                    "reviewsLanguages": {
                        "title": "Reviews languages",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Filter reviews by language (ISO 639-1 codes). Leave empty to include every language.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "ALL_REVIEW_LANGUAGES",
                                "ab",
                                "aa",
                                "af",
                                "ak",
                                "sq",
                                "am",
                                "ar",
                                "an",
                                "hy",
                                "as",
                                "av",
                                "ae",
                                "ay",
                                "az",
                                "bm",
                                "ba",
                                "eu",
                                "be",
                                "bn",
                                "bh",
                                "bi",
                                "bs",
                                "br",
                                "bg",
                                "my",
                                "ca",
                                "ch",
                                "ce",
                                "ny",
                                "zh",
                                "cv",
                                "kw",
                                "co",
                                "cr",
                                "hr",
                                "cs",
                                "da",
                                "dv",
                                "nl",
                                "dz",
                                "en",
                                "eo",
                                "et",
                                "ee",
                                "fo",
                                "fj",
                                "fi",
                                "fr",
                                "ff",
                                "gl",
                                "ka",
                                "de",
                                "el",
                                "gn",
                                "gu",
                                "ht",
                                "ha",
                                "he",
                                "hz",
                                "hi",
                                "ho",
                                "hu",
                                "ia",
                                "id",
                                "ie",
                                "ga",
                                "ig",
                                "ik",
                                "io",
                                "is",
                                "it",
                                "iu",
                                "ja",
                                "jv",
                                "kl",
                                "kn",
                                "kr",
                                "ks",
                                "kk",
                                "km",
                                "ki",
                                "rw",
                                "ky",
                                "kv",
                                "kg",
                                "ko",
                                "ku",
                                "kj",
                                "la",
                                "lb",
                                "lg",
                                "li",
                                "ln",
                                "lo",
                                "lt",
                                "lu",
                                "lv",
                                "gv",
                                "mk",
                                "mg",
                                "ms",
                                "ml",
                                "mt",
                                "mi",
                                "mr",
                                "mh",
                                "mn",
                                "na",
                                "nv",
                                "nd",
                                "ne",
                                "ng",
                                "nb",
                                "nn",
                                "no",
                                "ii",
                                "nr",
                                "oc",
                                "oj",
                                "cu",
                                "om",
                                "or",
                                "os",
                                "pa",
                                "pi",
                                "fa",
                                "pl",
                                "ps",
                                "pt",
                                "qu",
                                "rm",
                                "rn",
                                "ro",
                                "ru",
                                "sa",
                                "sc",
                                "sd",
                                "se",
                                "sm",
                                "sg",
                                "sr",
                                "gd",
                                "sn",
                                "si",
                                "sk",
                                "sl",
                                "so",
                                "st",
                                "es",
                                "su",
                                "sw",
                                "ss",
                                "sv",
                                "ta",
                                "te",
                                "tg",
                                "th",
                                "ti",
                                "bo",
                                "tk",
                                "tl",
                                "tn",
                                "to",
                                "tr",
                                "ts",
                                "tt",
                                "tw",
                                "ty",
                                "ug",
                                "uk",
                                "ur",
                                "uz",
                                "ve",
                                "vi",
                                "vo",
                                "wa",
                                "cy",
                                "wo",
                                "fy",
                                "xh",
                                "yi",
                                "yo",
                                "za",
                                "zu"
                            ],
                            "enumTitles": [
                                "All review languages",
                                "Abkhaz",
                                "Afar",
                                "Afrikaans",
                                "Akan",
                                "Albanian",
                                "Amharic",
                                "Arabic",
                                "Aragonese",
                                "Armenian",
                                "Assamese",
                                "Avaric",
                                "Avestan",
                                "Aymara",
                                "Azerbaijani",
                                "Bambara",
                                "Bashkir",
                                "Basque",
                                "Belarusian",
                                "Bengali",
                                "Bihari",
                                "Bislama",
                                "Bosnian",
                                "Breton",
                                "Bulgarian",
                                "Burmese",
                                "Catalan",
                                "Chamorro",
                                "Chechen",
                                "Chichewa",
                                "Chinese",
                                "Chuvash",
                                "Cornish",
                                "Corsican",
                                "Cree",
                                "Croatian",
                                "Czech",
                                "Danish",
                                "Divehi",
                                "Dutch",
                                "Dzongkha",
                                "English",
                                "Esperanto",
                                "Estonian",
                                "Ewe",
                                "Faroese",
                                "Fijian",
                                "Finnish",
                                "French",
                                "Fula",
                                "Galician",
                                "Georgian",
                                "German",
                                "Greek",
                                "Guaraní",
                                "Gujarati",
                                "Haitian Creole",
                                "Hausa",
                                "Hebrew",
                                "Herero",
                                "Hindi",
                                "Hiri Motu",
                                "Hungarian",
                                "Interlingua",
                                "Indonesian",
                                "Interlingue",
                                "Irish",
                                "Igbo",
                                "Inupiaq",
                                "Ido",
                                "Icelandic",
                                "Italian",
                                "Inuktitut",
                                "Japanese",
                                "Javanese",
                                "Kalaallisut",
                                "Kannada",
                                "Kanuri",
                                "Kashmiri",
                                "Kazakh",
                                "Khmer",
                                "Kikuyu",
                                "Kinyarwanda",
                                "Kyrgyz",
                                "Komi",
                                "Kongo",
                                "Korean",
                                "Kurdish",
                                "Kwanyama",
                                "Latin",
                                "Luxembourgish",
                                "Ganda",
                                "Limburgish",
                                "Lingala",
                                "Lao",
                                "Lithuanian",
                                "Luba-Katanga",
                                "Latvian",
                                "Manx",
                                "Macedonian",
                                "Malagasy",
                                "Malay",
                                "Malayalam",
                                "Maltese",
                                "Māori",
                                "Marathi",
                                "Marshallese",
                                "Mongolian",
                                "Nauru",
                                "Navajo",
                                "Northern Ndebele",
                                "Nepali",
                                "Ndonga",
                                "Norwegian Bokmål",
                                "Norwegian Nynorsk",
                                "Norwegian",
                                "Nuosu",
                                "Southern Ndebele",
                                "Occitan",
                                "Ojibwe",
                                "Old Church Slavonic",
                                "Oromo",
                                "Oriya",
                                "Ossetian",
                                "Panjabi",
                                "Pāli",
                                "Persian",
                                "Polish",
                                "Pashto",
                                "Portuguese",
                                "Quechua",
                                "Romansh",
                                "Kirundi",
                                "Romanian",
                                "Russian",
                                "Sanskrit",
                                "Sardinian",
                                "Sindhi",
                                "Northern Sami",
                                "Samoan",
                                "Sango",
                                "Serbian",
                                "Scottish Gaelic",
                                "Shona",
                                "Sinhala",
                                "Slovak",
                                "Slovenian",
                                "Somali",
                                "Southern Sotho",
                                "Spanish",
                                "Sundanese",
                                "Swahili",
                                "Swati",
                                "Swedish",
                                "Tamil",
                                "Telugu",
                                "Tajik",
                                "Thai",
                                "Tigrinya",
                                "Tibetan Standard",
                                "Turkmen",
                                "Tagalog",
                                "Tswana",
                                "Tonga",
                                "Turkish",
                                "Tsonga",
                                "Tatar",
                                "Twi",
                                "Tahitian",
                                "Uyghur",
                                "Ukrainian",
                                "Urdu",
                                "Uzbek",
                                "Venda",
                                "Vietnamese",
                                "Volapük",
                                "Walloon",
                                "Welsh",
                                "Wolof",
                                "Western Frisian",
                                "Xhosa",
                                "Yiddish",
                                "Yoruba",
                                "Zhuang",
                                "Zulu"
                            ]
                        },
                        "default": [
                            "ALL_REVIEW_LANGUAGES"
                        ]
                    },
                    "maxConcurrency": {
                        "title": "Max Concurrency",
                        "type": "integer",
                        "description": "Maximum number of pages that can be processed at the same time.",
                        "default": 100
                    },
                    "minConcurrency": {
                        "title": "Min Concurrency",
                        "type": "integer",
                        "description": "Minimum number of pages that will be processed at the same time.",
                        "default": 1
                    },
                    "maxRequestRetries": {
                        "title": "Max Request Retries",
                        "minimum": 0,
                        "maximum": 50,
                        "type": "integer",
                        "description": "Number of times each failed request is retried before giving up. Lower values surface persistent failures quickly; higher values absorb transient anti-bot blocks at the cost of long-tail latency.",
                        "default": 15
                    },
                    "proxy": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Specifies proxy servers that will be used by the scraper in order to hide its origin.<br><br>For details, see <a href='https://apify.com/apify/web-scraper#proxy-configuration' target='_blank' rel='noopener'>Proxy configuration</a> in README.",
                        "default": {
                            "useApifyProxy": true,
                            "apifyProxyGroups": [
                                "RESIDENTIAL"
                            ]
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
