# TheFork Scraper — European Restaurant Listings & Prices (`studio-amba/thefork-scraper`) Actor

Scrape restaurant listings from TheFork.com, TripAdvisor's European restaurant reservation platform. Search by city and get name, cuisine, price range, rating, review count, address, and offers. No login required.

- **URL**: https://apify.com/studio-amba/thefork-scraper.md
- **Developed by:** [Studio Amba](https://apify.com/studio-amba) (community)
- **Categories:** Other
- **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 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

## TheFork Scraper

Extract restaurant listings from TheFork.com (TripAdvisor's European restaurant reservation platform) — search by city and get name, cuisine, price range, rating, review count, address, and current offers for every restaurant.

### Why use this actor?

TheFork lists tens of thousands of restaurants across Europe, each with TripAdvisor-backed ratings, price levels, and live promotions. Restaurant discovery apps, hospitality market researchers, and local business analysts benchmarking competitors all need this data at scale rather than clicking through paginated search results by hand. This actor turns a city name into a clean, structured dataset of every restaurant listed for that city.

### How to scrape TheFork data

TheFork runs DataDome anti-bot protection site-wide, and its `robots.txt` explicitly disallows the query-string search endpoints (`/search`, `/search-web*`, `/list*`). Hitting those paths directly returns either a DataDome challenge page or is against the site's own crawl rules.

Instead, this actor uses TheFork's own city landing pages — `/restaurants/{city-slug}-c{cityId}` (for example `/restaurants/paris-c415144`). These pages are explicitly allowed by `robots.txt`, are what Google indexes, and are server-rendered (Next.js) with the full restaurant list — up to 25 restaurants per page, with name, cuisine, price level, average price, TripAdvisor-style rating, review count, full address, geolocation, and any active offers — all embedded in the page's `__NEXT_DATA__` JSON payload.

To reach these pages reliably, the actor routes requests through Bright Data's Web Unlocker, which handles TheFork's DataDome challenge automatically. Pagination beyond the first 25 results requires **both** a `p` and a `page` query parameter set to the same page number (the `page` parameter alone is silently ignored server-side) — the actor builds these URLs correctly and walks as many pages as needed to reach your requested result count.

City names are matched against a curated map of major European cities (Paris, London, Rome, Madrid, Munich, Milan, Amsterdam, Barcelona, Berlin, and more); unrecognized cities fall back to Paris.

### Input

| Field | Type | Required | Description |
|-------|------|----------|--------------|
| `city` | String | No | City to search (default: `Paris`). Examples: `London`, `Rome`, `Madrid`, `Munich`, `Milan`, `Amsterdam`, `Barcelona`, `Berlin`, `Lyon`, `Marseille`. |
| `maxResults` | Integer | No | Maximum restaurants to return (default: 20, max: 1000). TheFork returns 25 per page. |
| `brightDataApiKey` | String | No | Your own Bright Data Web Unlocker API key. Leave empty to use the built-in unlocking service. |
| `proxyConfiguration` | Object | No | Legacy field, kept for backwards compatibility. Ignored — fetching goes through Bright Data. |

### Output

Each result contains:

| Field | Type | Example |
|-------|------|---------|
| `id` | String | `"e3a4ef96-0b29-46b5-8ac6-66788a4c4435"` |
| `name` | String | `"Restaurant Auguste - Gaël Orieux"` |
| `cuisine` | String | `"French"` |
| `priceRange` | String | `"€€€€"` |
| `avgPrice` | Number | `100` |
| `currency` | String | `"EUR"` |
| `rating` | Number | `9.5` |
| `reviewCount` | Number | `3314` |
| `address` | String | `"54, rue de Bourgogne"` |
| `city` | String | `"Paris"` |
| `postalCode` | String | `"75007"` |
| `latitude` | Number | `48.85616` |
| `longitude` | Number | `2.31712` |
| `imageUrl` | String | Main restaurant photo URL |
| `offers` | Array | `["Menu Instant Michelin €96", "Yums x2"]` |
| `isBookable` | Boolean | `true` |
| `url` | String | Full TheFork restaurant URL |

### Example output

```json
{
    "id": "e3a4ef96-0b29-46b5-8ac6-66788a4c4435",
    "name": "Restaurant Auguste - Gaël Orieux",
    "cuisine": "French",
    "priceRange": "€€€€",
    "avgPrice": 100,
    "currency": "EUR",
    "rating": 9.5,
    "reviewCount": 3314,
    "address": "54, rue de Bourgogne",
    "city": "Paris",
    "postalCode": "75007",
    "latitude": 48.85616,
    "longitude": 2.31712,
    "imageUrl": "https://cdn.thefork.com/tf-lab/image/upload/restaurant/e3a4ef96-0b29-46b5-8ac6-66788a4c4435/4f06eca7-c9f1-466f-83e9-870610815ef8.jpg",
    "offers": ["Menu Instant Michelin €96", "Yums x2"],
    "isBookable": true,
    "url": "https://www.thefork.com/restaurant/restaurant-auguste-gael-orieux-r26201",
    "scrapedAt": "2026-07-14T21:24:18.487Z"
}
````

### Cost estimate

This actor uses approximately **1 compute unit per 200 results** (one Bright Data Web Unlocker request returns a full page of 25 restaurants). At standard Apify pricing, that's roughly **$0.25-$0.50 per 1,000 restaurants**.

### Limitations

- City coverage is limited to a curated map of major European cities. Smaller towns not in the map fall back to Paris — request a specific city and check the output's `city` field to confirm the match.
- Data reflects TheFork's own listings and TripAdvisor-sourced ratings at the time of the run, and may change without notice (prices, offers, and availability update frequently).
- Very large `maxResults` values (multiple hundreds) mean multiple sequential page fetches and a longer run time.
- Respect TheFork's terms of service and use responsibly.

### Frequently asked questions

**Does this require a TheFork account or login?**
No. The actor scrapes TheFork's public city listing pages, which don't require authentication.

**Can I filter by cuisine, price, or promotions?**
Not directly through the input — this actor returns the full restaurant list for a city, including each restaurant's cuisine, price range, and current offers, so you can filter the output dataset however you need after the run.

**Why does a smaller town fall back to Paris?**
City IDs on TheFork are internal numeric identifiers, not derived from the city name, so this actor uses a curated map of major European cities. Smaller towns not yet in that map default to Paris — check the output's `city` field to confirm what was actually scraped.

**How fresh is the data?**
Every run scrapes live pages at request time, so ratings, review counts, and active offers reflect TheFork's current listings.

### Need this data on a schedule, or a custom version?

We run this scraper as a managed service for businesses: scheduled runs,
deduplication, delta detection, and delivery to your inbox, Google Sheets,
or API — maintenance included. We can also build a custom version with your
exact fields and filters, or combine multiple sources into one feed.

See [studioamba.dev/services](https://studioamba.dev/services/) or email
<hello@studioamba.dev> for a free data sample.
We maintain 300+ European web scrapers and answer within one business day.

# Actor input Schema

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

City to search restaurants in. Example: 'Paris', 'London', 'Rome', 'Madrid', 'Munich', 'Milan', 'Amsterdam', 'Barcelona', 'Berlin'. Unrecognized cities fall back to Paris.

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

Maximum number of restaurants to return. TheFork returns 25 restaurants per page.

## `brightDataApiKey` (type: `string`):

Optional: your own Bright Data API key for the Web Unlocker zone. Leave empty to use the built-in unlocking service.

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

Legacy field, kept for backwards compatibility. Fetching goes through the built-in Bright Data Web Unlocker (required to pass TheFork's DataDome anti-bot), so this is ignored.

## Actor input object example

```json
{
  "city": "Paris",
  "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": "Paris",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

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

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

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "TheFork Scraper — European Restaurant Listings & Prices",
        "description": "Scrape restaurant listings from TheFork.com, TripAdvisor's European restaurant reservation platform. Search by city and get name, cuisine, price range, rating, review count, address, and offers. No login required.",
        "version": "0.1",
        "x-build-id": "chJxgP4itNLnEWEOd"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/studio-amba~thefork-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-studio-amba-thefork-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/studio-amba~thefork-scraper/runs": {
            "post": {
                "operationId": "runs-sync-studio-amba-thefork-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/studio-amba~thefork-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-studio-amba-thefork-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": {
                    "city": {
                        "title": "City",
                        "type": "string",
                        "description": "City to search restaurants in. Example: 'Paris', 'London', 'Rome', 'Madrid', 'Munich', 'Milan', 'Amsterdam', 'Barcelona', 'Berlin'. Unrecognized cities fall back to Paris."
                    },
                    "maxResults": {
                        "title": "Max Results",
                        "minimum": 1,
                        "maximum": 1000,
                        "type": "integer",
                        "description": "Maximum number of restaurants to return. TheFork returns 25 restaurants per page.",
                        "default": 20
                    },
                    "brightDataApiKey": {
                        "title": "Bright Data API Key (optional)",
                        "type": "string",
                        "description": "Optional: your own Bright Data API key for the Web Unlocker zone. Leave empty to use the built-in unlocking service."
                    },
                    "proxyConfiguration": {
                        "title": "Proxy Configuration",
                        "type": "object",
                        "description": "Legacy field, kept for backwards compatibility. Fetching goes through the built-in Bright Data Web Unlocker (required to pass TheFork's DataDome anti-bot), so this is ignored."
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
