# TripAdvisor Photos Scraper (`romy/tripadvisor-photos-scraper`) Actor

Pull the full photo gallery — real image URLs at multiple sizes, captions, upload dates — for TripAdvisor hotel, restaurant, or attraction listing ids, with genuine offset pagination through galleries of 1000+ photos. No account or API key needed. Derived from romy/tripadvisor-all-in-one-api.

- **URL**: https://apify.com/romy/tripadvisor-photos-scraper.md
- **Developed by:** [Romy](https://apify.com/romy) (community)
- **Categories:** Travel
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.78 / 1,000 photo returneds

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

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does TripAdvisor Photos Scraper do?

**TripAdvisor Photos Scraper** takes one or more TripAdvisor listing ids (hotel, restaurant, or attraction) and pushes the full photo gallery for each — real image URLs at multiple sizes, captions, upload dates, and uploader attribution — one dataset row per listing.

It talks directly to the same internal API the official [TripAdvisor](https://www.tripadvisor.com/) Android app uses, reverse-engineered by capturing live traffic from a real device. Unlike many reverse-engineered mobile APIs, TripAdvisor needs **no per-request signature at all** — just a static API key and self-generated device/session ids, confirmed live and standalone-reproducible. No TripAdvisor account, no API key of your own. This is the photo-gallery slice of [TripAdvisor All-in-One API](https://apify.com/romy/tripadvisor-all-in-one-api), split out as its own focused Actor.

### Why use TripAdvisor Photos Scraper?

- **Genuinely paginates the full gallery, not a first-page cap** — confirmed live: paging by offset returns real, non-overlapping photo windows all the way through a 1000+ photo hotel gallery
- **One vertical, one code path** — hotels, restaurants, and attractions are all identified the same way (a plain content id), so the same endpoint serves every listing type
- **Multiple real sizes per photo** — every item carries both a `sizes` array (thumbnail through large) and a dynamic `urlTemplate` you can request any width/height from
- **No account needed** — every request works fully anonymously
- **Use cases:** listing enrichment, image datasets for ML, photo-freshness monitoring, travel content aggregation

### Input

| Field        | Type                  | Description                                                                                                                                                                                                                                                    |
| ------------ | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `listingIds` | string\[]              | **Required.** Plain numeric TripAdvisor content ids (hotel, restaurant, or attraction) — e.g. from [tripadvisor-all-in-one-api](https://apify.com/romy/tripadvisor-all-in-one-api) or a TripAdvisor URL.                                                       |
| `currency`   | string                | ISO code, default `GBP`. Doesn't affect photos, only kept for API-call consistency with the parent.                                                                                                                                                            |
| `maxPhotos`  | integer               | Stop once this many photos have been collected for a listing. Leave empty to fetch the whole gallery.                                                                                                                                                          |
| `pageSize`   | integer, default `50` | Not sent to the API — TripAdvisor's gallery endpoint always returns up to 50 items per call regardless of any client-requested size (confirmed live). Used only to detect the last page: a response with fewer items than this means the gallery is exhausted. |

Example:

```json
{
    "listingIds": ["25246100"],
    "maxPhotos": 20
}
```

### Output

One dataset row per listing id:

```json
{
    "listingId": "25246100",
    "photos": [
        {
            "id": 667714552,
            "caption": "",
            "publishedDateTime": "2023-01-12T12:40:45.522Z",
            "uploadDateTime": "2023-01-12T12:40:45.522Z",
            "thumbsUpVotes": 34,
            "attribution": "Photo provided by management",
            "urlTemplate": "https://dynamic-media-cdn.tripadvisor.com/media/photo-o/27/cc/83/f8/villa-deva-resort-and.jpg?w={width}&h={height}&s=1",
            "maxWidth": 1999,
            "maxHeight": 1333,
            "sizes": [
                {
                    "width": 50,
                    "height": 50,
                    "url": "https://media-cdn.tripadvisor.com/media/photo-t/27/cc/83/f8/villa-deva-resort-and.jpg"
                },
                {
                    "width": 1280,
                    "height": 854,
                    "url": "https://media-cdn.tripadvisor.com/media/photo-m/1280/27/cc/83/f8/villa-deva-resort-and.jpg"
                }
            ]
        }
    ]
}
```

`urlTemplate` accepts arbitrary `{width}`/`{height}` values (e.g. `?w=1600&h=1200&s=1`) for a size not already covered by `sizes`.

### Data notes

Confirmed live against a real hotel gallery (id `25246100`, 1188 total photos):

- The raw `MediaGalleryQuery` response's `sections` array is a mix of UI blocks: an `AppPresentation_AlbumsSection` (album/category chrome — "All photos", "Traveller", "Hotel & Amenities", etc. with per-album counts), the actual `AppPresentation_MediaPageSection` (the flat, unfiltered photo stream this Actor extracts from its `mediaList`), and an `AppPresentation_SecondaryButton` ("see all" link). Only the middle one carries discrete photo items.
- **`offset` is a literal start index, not a page number.** A call with `offset=30` returns items starting at position 30 of the same underlying stream a call with `offset=0` would return — confirmed by an exact 20-item overlap between an `offset=0`/50-item response and an `offset=30` response (items 30-49 of the first call equal items 0-19 of the second).
- **The response window is fixed at 50 items per call**, with no way to request a different size — there's no size/limit parameter on the endpoint, only `offset`. This Actor pages by incrementing `offset` by however many items the previous call actually returned, and stops when a call returns fewer than 50 (or zero).
- Every item observed was a photo (`AppPresentation_MediaPageItemPhoto` / `Media_PhotoResult`) — no video items appeared in the sampled gallery, but the extractor only picks items from the photo-shaped `mediaList`, so a video-only item (if TripAdvisor ever serves one there) is silently skipped rather than crashing the run.

### Known limitations

- **No album/category filtering.** This Actor pulls the flat "all photos" stream only — per-album breakdowns (e.g. just "Pool & Beach") aren't wrapped; that data is visible in `AppPresentation_AlbumsSection` but not currently exposed by this Actor.
- This is an unofficial, reverse-engineered integration, not affiliated with or endorsed by Tripadvisor LLC. Behavior may change if TripAdvisor changes its API.

### Pricing

Pay per event: **$0.001** per `photo` — charged once for each photo returned in a listing's gallery (Free plan price; lower on paid Apify plans). See the Actor's Pricing tab for current tiered rates.

# Actor input Schema

## `listingIds` (type: `array`):

Plain numeric TripAdvisor content ids (hotel, restaurant, or attraction) — e.g. from tripadvisor-all-in-one-api or a TripAdvisor URL.

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

ISO 4217 currency code for returned prices.

## `maxPhotos` (type: `integer`):

Stop once this many photos have been collected for a listing. Leave empty to fetch the whole gallery.

## `pageSize` (type: `integer`):

TripAdvisor's gallery endpoint always returns up to 50 items per call (confirmed live) — this isn't sent to the API, it's only used to detect the last page (a response with fewer items than this means the gallery is exhausted).

## Actor input object example

```json
{
  "listingIds": [
    "25246100"
  ],
  "currency": "GBP",
  "pageSize": 50
}
```

# Actor output Schema

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

No description

# API

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

## JavaScript example

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

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

// Prepare Actor input
const input = {
    "listingIds": [
        "25246100"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("romy/tripadvisor-photos-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 = { "listingIds": ["25246100"] }

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

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

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

```

## CLI example

```bash
echo '{
  "listingIds": [
    "25246100"
  ]
}' |
apify call romy/tripadvisor-photos-scraper --silent --output-dataset

```

## MCP server setup

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

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

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/9r7QmErc8fOEyX3Es/builds/2Y5iTh7i0oF0wxUic/openapi.json
