# Tiqets Scraper — Attraction Tickets, Tours & Activities (`studio-amba/tiqets-scraper`) Actor

Scrape attraction tickets, tours and activities from tiqets.com for any city. Extract titles, prices, currencies, ratings, review counts and images. No login or API credentials required.

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

## Pricing

from $2.00 / 1,000 result scrapeds

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

## How to integrate an Actor?

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

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

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

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

# README

## Tiqets Scraper

Scrape attraction tickets, tours and activities from [tiqets.com](https://www.tiqets.com) for any city — titles, prices, currencies, ratings, review counts, and images.

### Why use this actor?

Tiqets aggregates bookable tickets for museums, tours, cruises, and attractions across hundreds of cities worldwide. This actor pulls a city's activity list into structured data: useful for price monitoring, competitive research on attraction pricing, or feeding a travel content site with live ticket prices and ratings.

No login, no API credentials, no anti-bot workaround needed — Tiqets serves plain server-rendered HTML with no bot protection at all.

### Input

| Field | Type | Required | Description |
|---|---|---|---|
| `city` | String | No | City name or Tiqets slug, e.g. `"amsterdam"`, `"paris"`, `"new york"`. Default/prefill: `"amsterdam"` |
| `fetchDetails` | Boolean | No | When `true`, fetches each product's detail page for its full ld+json `Product` data (rating, review count, availability). Doubles the request count. Default: `false` |
| `maxResults` | Integer | No | Maximum activities to return. Default: `100`, prefill `20` |
| `proxyConfiguration` | Object | No | Apify Proxy configuration. Prefill: `{"useApifyProxy": true}` — plain datacenter proxy, no residential/Bright Data needed |

Empty input (`{}`) works — all fields have prefills and fall back to `amsterdam` / `maxResults: 100` / `fetchDetails: false`.

### Output

Each result contains:

| Field | Type | Description |
|---|---|---|
| `activityTitle` | String | Name of the ticket/tour/activity |
| `city` | String | Destination city display name |
| `price` | Number | Ticket price (lowest available option) |
| `currency` | String | Currency code (EUR, USD, GBP, ...) |
| `rating` | Number | null | Average rating (0-5), when present |
| `reviewCount` | Integer | null | Number of reviews, when present |
| `duration` | String | null | Activity duration, when present (see Limitations — currently always null) |
| `imageUrl` | String | null | Primary listing photo URL |
| `url` | String | Full Tiqets activity URL |
| `scrapedAt` | String | ISO 8601 scrape timestamp |

### Example output

```json
{
    "activityTitle": "Seine River: Cruise by BATEAUX-MOUCHES®",
    "city": "Paris",
    "price": 17.00,
    "currency": "EUR",
    "rating": 4.4,
    "reviewCount": 8857,
    "duration": null,
    "imageUrl": "https://aws-tiqets-cdn.imgix.net/images/content/53ba4090a775461d8ec94a87fa976ab2.jpg?auto=format%2Ccompress&fit=crop&q=70",
    "url": "https://www.tiqets.com/en/things-to-do-in-paris-c66746/tickets-for-seine-river-cruise-by-bateaux-mouches-p982823/",
    "scrapedAt": "2026-07-13T01:12:04.881Z"
}
```

### How to scrape Tiqets data

1. Set `city` to any city name — free text or a known Tiqets slug both work (`"amsterdam"`, `"rome"`, `"new york"`).
2. Leave `fetchDetails` off for a fast run (one request total): title, price, currency, and — for most activities — rating and review count come straight off the city page.
3. Turn `fetchDetails` on if you need the most reliable rating/review-count/availability values, at the cost of one extra request per activity.
4. Run the actor. Results land in the default dataset, ready to export as JSON/CSV/Excel or pull via the Apify API.
5. To cover more than one city, run the actor again with a different `city` value — see Limitations for why a single run is capped at one city's activity list.

Typical run: default input scrapes ~20-44 activities for one city in under 10 seconds without `fetchDetails`, or roughly one request per activity (a few seconds to ~1 minute depending on `maxResults`) with `fetchDetails` on.

### City URL resolution (how it works internally)

Tiqets city pages need a numeric suffix in the URL, e.g. `/en/things-to-do-in-paris-c66746/`. This actor was built to test two resolution strategies live before picking one:

- **Redirect-following** (`https://www.tiqets.com/en/things-to-do-in-{slug}/` without the `-c{id}` suffix): tested live on 2026-07-13 for both `amsterdam` and `paris` — the un-suffixed URL returns a clean HTTP 404 with no `Location` header and no CloudFront redirect chain. This does **not** work for Tiqets.
- **Sitemap lookup** (the mechanism actually used): fetches `https://www.tiqets.com/sitemapindex.xml`, finds `site-map-city-en.xml.gz` among the ~189 gzipped per-language/per-type sub-sitemaps, gunzips it with Node's `zlib.gunzipSync`, and matches the input city against the sitemap's `<loc>` URLs by comparing hyphen-separated slug tokens. This is necessary (not just a fallback of convenience) because city URL slugs are **not** uniform across the site — verified live the sitemap contains both `amsterdam-attractions-c75061` and `things-to-do-in-paris-c66746`, so a fixed `things-to-do-in-{slug}` template would silently fail for most cities. The sitemap is fetched and cached in memory once per run.

### Limitations

- **No pagination on city pages.** A Tiqets city page returns a fixed ~44 product cards; requesting `?page=2` returns the identical 44 products (verified live). `maxResults` above ~44 will simply return everything the city page has. To scale up, run the actor again with different `city` inputs rather than expecting one run to paginate deeper into a single city.
- **`fetchDetails` doubles request volume.** With it off, this actor makes one request total (fast). With it on, it makes one additional request per activity to fetch the product detail page's ld+json, which yields more reliable rating/review-count/availability data at the cost of proportionally longer run time. Because this multiplies requests per result, the actor persists a resume ledger (`Actor.useState`, key `CRAWL_STATE`) tracking already-pushed URLs and pending detail fetches, so a migration or restart never re-fetches or duplicates an already-scraped activity.
- **`duration` is currently always `null`.** The field is included in the output schema and code (with a defensive extractor checking for `duration`/`timeRequired` on the ld+json `Event`/`Product` nodes) because Tiqets' schema could add it later, but as verified live on 2026-07-13 neither the city page's `ItemList` `Event` objects nor the product page's `Product` object carry any such field. The only "duration" key found anywhere in the HTML is inside unrelated review-metadata JSON (`{"duration": null, ...}`, always null, not activity length).
- **City resolution depends on the sitemap being current.** Very new cities not yet in `site-map-city-en.xml.gz` won't resolve. In practice Tiqets covers 600+ cities and the sitemap is regenerated daily (per its own `<!-- auto generated -->` comment).

### Related Scrapers

- [GetYourGuide Scraper](https://apify.com/studioamba/getyourguide-scraper) — tours, activities and attraction tickets from getyourguide.com, a direct Tiqets competitor
- [Blablacar Scraper](https://apify.com/studioamba/blablacar-scraper) — intercity rideshare listings, another European travel data source
- [Touring Scraper](https://apify.com/studioamba/touring-scraper) — Belgian automobile club travel guides and road-assistance data

### Cost estimate

Tiqets has no anti-bot protection, so this actor runs on plain Apify datacenter proxy — the cheapest proxy tier. A default run (20 activities, `fetchDetails` off) uses well under 1 Compute Unit. A `fetchDetails` run at `maxResults: 100` still stays under 1 CU for most cities (Tiqets city pages cap out around 44 activities, so a single run rarely exceeds ~45 total requests even with detail fetches on).

### Use cases

- **Price monitoring**: track ticket prices for a set of cities over time by scheduling this actor to run daily per city and comparing dataset snapshots.
- **Competitive research**: compare Tiqets' catalogue and pricing for a destination against GetYourGuide or Viator for the same attractions.
- **Travel content**: pull live prices, ratings, and images to populate a destination guide or "things to do in {city}" page without manually maintaining the data.
- **Demand signal**: review counts and ratings across a city's top activities give a rough popularity ranking without needing Tiqets' own analytics.

### FAQ

**Does this need a Tiqets account or API key?**
No. Tiqets pages are public and unauthenticated — the actor reads the same HTML and structured data any visitor's browser would receive.

**Why is currency sometimes USD instead of EUR for a European city?**
Tiqets localizes currency by the visiting IP. Apify's default proxy (`{"useApifyProxy": true}`, no country pinned, per this actor's tested configuration) can exit from any datacenter location, so the price/currency pair reflects whatever the site served that IP — not a fixed EUR default. The `price` and `currency` fields are always consistent with each other; if you need a specific currency, add a `apifyProxyCountry` field to `proxyConfiguration` (e.g. `"NL"` for EUR pricing from Amsterdam).

**Can I scrape more than ~44 activities for one city in a single run?**
Not from a single city page — Tiqets doesn't paginate them (verified live, `?page=2` returns identical results). Run the actor again with a different `city` input to cover more ground, or run it on a schedule across a list of cities.

**What happens if the city name doesn't match anything?**
The actor fails with a clear error naming the city it couldn't resolve. Try the plain English city name (e.g. `"rome"`, `"new york"`) — the sitemap lookup covers Tiqets' full city catalogue in English.

# Actor input Schema

## `city` (type: `string`):

City name or Tiqets city slug (e.g. 'amsterdam', 'paris', 'new york'). Resolved to the canonical Tiqets city page via the city sitemap.

## `fetchDetails` (type: `boolean`):

When enabled, fetches each product's detail page for its full ld+json Product data (rating, review count, availability that may be missing from the city page). Doubles the request count — one extra request per result.

## `maxResults` (type: `integer`):

Maximum number of activities to return. A single city page has ~44 products with no pagination — to scrape more, run the actor again with a different city.

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

Proxy settings. Tiqets has no bot protection, so plain Apify datacenter proxy is enough.

## Actor input object example

```json
{
  "city": "amsterdam",
  "fetchDetails": false,
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# 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 = {
    "city": "amsterdam",
    "fetchDetails": false,
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/tiqets-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 = {
    "city": "amsterdam",
    "fetchDetails": False,
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/tiqets-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 '{
  "city": "amsterdam",
  "fetchDetails": false,
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call studio-amba/tiqets-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/6gM1s4DEFimNwPmQq/builds/J8GP0LUt94ggfyLSj/openapi.json
