# Talabat Scraper: Restaurant Menus, Prices, Reviews (`automation_craft/talabat-scraper`) Actor

Talabat scraper for UAE, Kuwait, Qatar, Bahrain, Oman, Jordan and Egypt, no login: restaurants by area, city, search or chain. Each row nests the full menu with dish prices and old prices, plus rating and, from area lists, delivery fee and minimum order. Options and reviews on request.

- **URL**: https://apify.com/automation_craft/talabat-scraper.md
- **Developed by:** [Automation Craft](https://apify.com/automation_craft) (community)
- **Categories:** E-commerce, Lead generation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.66 / 1,000 restaurants

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

### Talabat Scraper: Restaurant Menus, Prices, Reviews

**Talabat scraper** for restaurants with their full menus, dish prices, options and customer reviews, from the United Arab Emirates, Kuwait, Qatar, Bahrain, Oman, Jordan and Egypt. No login, no cookies, no Talabat account: give an area, a city, a delivery point, search words, a chain or a link, and get one row per restaurant branch with its whole menu nested, its rating, and the delivery fee, minimum order and delivery time of the area it was listed in.

### Quick start

1. Open the Actor's **Input** tab. The prefilled input reads the first five restaurants of Abu Hail, Dubai.
2. Replace the link with any Talabat area list, menu or brand link, or fill **Areas**, **Cities**, **Delivery points**, **Search words**, **Chains** or **Branch ids**, with **Markets** where the entry does not name its market (`uae/1169`).
3. Turn on the add-ons you need: **Dish options**, **Customer reviews**, **One row per dish**, **Exact review figures**, **Chain figures**, Arabic menus.
4. Set **Max restaurants** (empty means 200) and click **Start**.
5. Download the dataset as JSON, CSV, Excel or HTML, or read it through the Apify API. The **Restaurants**, **Reviews**, **Dishes** and **Coverage** views split the rows by kind.

### What you get

Every restaurant row is one Talabat branch (`type: "restaurant"`), charged as one Restaurant event, with the menu nested in `menu.dishes`. Review rows (`type: "review"`) and dish rows (`type: "dish"`) come only when you turn them on. Each entry of the input also gets one free `coverage` row, and the run ends with a free `summary` row (also stored as `RUN-SUMMARY` in the run's key-value store).

#### Main fields and measured fill rates

Measured on 2026-10-15 from 14 Talabat area list pages (two in each of the seven markets, 208 restaurants), 63 menu pages across the seven markets and the 6,653 distinct dishes on them. Field names are exactly what the dataset holds.

| Field | What it holds | Filled (measured) |
|---|---|---|
| `branchId`, `name`, `branchName`, `url` | Talabat's branch id, the restaurant and branch names, the menu link | 208 of 208 list rows, 63 of 63 menu pages |
| `country` | Market code, name, ISO code, Talabat's country id, currency | every row |
| `deliveryArea`, `city` | The area (and its city) whose list found the branch | every branch found through an area list |
| `cuisines` | The branch's cuisines | 208 of 208 list rows, 63 of 63 menu pages |
| `rating`, `ratingCount` | Stars out of 5 and Talabat's rating count bucket (100, 500, 1000 ...) | above 0 on 205 of 208 list rows, 62 of 63 menu pages; count 1000 on 158 of 208 |
| `latitude`, `longitude` | The branch's coordinates | 208 of 208 list rows, 63 of 63 menu pages |
| `deliveryFee` | The delivery fee to the area, in the market's currency | 208 of 208 list rows (0 on 200, above 0 on 8) |
| `minimumOrder` | The minimum order to the area | 208 of 208 list rows, above 0 on 151 |
| `deliveryTimeMinutes`, `deliveryTimeText` | The delivery time Talabat shows ("Within 15 mins") | 208 of 208 list rows |
| `isOpen`, `openStatus` | Open or closed at read time | 208 of 208 list rows |
| `isTalabatPro`, `isTalabatGo`, `isSponsored`, `isPaidPlacement` | Talabat Pro and Talabat GO; Talabat's sponsored flag (mostly its organic placements, `sponsoredCategory` says which) and a paid place (the flag outside the organic placements) | 208 of 208 list rows (Pro true on 159, sponsored on 70, all 70 organic placements) |
| `paymentMethods` | Payment options (visa, mastercard, cash ...) | 208 of 208 list rows, 63 of 63 menu pages |
| `offerText` | The offer Talabat shows ("30% off select items") | 477 of 951 search results; list rows and menu pages carry none (0 of 208, 0 of 63) |
| `menu.dishCount`, `menu.priceMin`, `menu.priceMax` | Menu size and price range | 62 of 63 menu pages had dishes (23, 79 and 568 dishes at the minimum, median and maximum) |
| `menu.dishes[].price` | The dish price | above 0 on 6,078 of 6,653 dishes (91.4 percent); 572 of the 575 at 0 have options |
| `menu.dishes[].priceFrom` | The real starting price of a dish listed at 0, from its options | with Dish options on: every listed-at-0 dish whose options were read |
| `menu.dishes[].description`, `image` | Dish text and photo | 5,926 (89.1 percent) and 6,326 (95.1 percent) of 6,653 |
| `menu.dishes[].oldPrice`, `discountPercent` | The struck-through price and the discount | 881 of 6,653 (13.2 percent) |
| `menu.dishes[].hasOptions`, `isTopRated` | Has an option tree; marked top rated | 2,611 (39.3 percent) and 929 (14.0 percent) of 6,653 |
| `menu.repeatedDishRowsRemoved` | Dish rows Talabat repeats in "Picks for you" and other sections, removed | 1,229 of 7,882 raw dish rows (15.6 percent) were repeats |
| `leadScore` | 0 to 100 from the branch's own figures (rating count 40, rating 30, menu breadth 15, open, Pro, new and several cuisines 15) | every restaurant row |
| review `text` | Review rows: the review text | 2,500 of 2,898 reviews of one Kuwait branch |

#### Example row (real, trimmed)

A restaurant from an area list (Muharraq, Bahrain), read on 2026-10-15 with the menu off:

```json
{
  "type": "restaurant",
  "branchId": "31034",
  "restaurantId": "17610",
  "name": "Mango Talaat",
  "branchName": "Mango Talaat, Muharraq",
  "url": "https://www.talabat.com/bahrain/restaurant/31034/mango-talaat-muharraq?aid=997",
  "country": { "code": "bahrain", "name": "Bahrain", "iso": "BH", "talabatId": 3, "currency": "BHD" },
  "deliveryArea": { "id": "997", "name": "Muharraq", "slug": "muharraq" },
  "city": { "id": "31", "name": "Bahrain" },
  "cuisines": ["Desserts", "Juices", "..."],
  "rating": 5,
  "ratingCount": 1000,
  "ratingCountIsBucketed": true,
  "latitude": 26.262941971751026,
  "longitude": 50.616654538419,
  "deliveryFee": 0,
  "minimumOrder": 1,
  "deliveryTimeMinutes": 15,
  "deliveryTimeText": "Within 15 mins",
  "deliveryTermsSource": "area_list",
  "isOpen": true,
  "openStatus": "Open",
  "isTalabatPro": true,
  "isTalabatGo": true,
  "isSponsored": true,
  "sponsoredCategory": "organic_placements",
  "isPaidPlacement": false,
  "listPosition": 0,
  "leadScore": 83,
  "found": { "subjectKind": "area", "areaId": "997", "page": 1, "positionOnPage": 1 },
  "scrapedAt": "2026-10-15T07:49:44.967Z"
}
```

The menu part of a restaurant row with **Dish options** on (% Arabica, Al Safa, Dubai, read by branch id):

```json
{
  "menu": {
    "dishCount": 62,
    "dishesDelivered": 62,
    "sectionCount": 10,
    "priceMin": 11,
    "priceMax": 202,
    "pricedAtZero": 0,
    "withOptions": 38,
    "repeatedDishRowsRemoved": 6,
    "dishes": [
      {
        "id": "3679950903",
        "name": "Cafe Latte (Hot)",
        "price": 25,
        "oldPrice": null,
        "priceFrom": 25,
        "section": "Hot Espresso Based",
        "sections": ["Picks for you 🔥", "Hot Espresso Based"],
        "image": "https://talabat.dhmedia.io/image/talabat/MenuItems/456BF2CF4A04938C32892D12E9EF08AF",
        "hasOptions": true,
        "isTopRated": false,
        "options": [
          {
            "name": "Your Choice Of Size",
            "selectionText": "Choose 1",
            "minChoices": 1,
            "maxChoices": 1,
            "required": true,
            "choices": [
              { "name": "8Oz", "price": 0, "preselected": false },
              { "name": "12Oz", "price": 2, "preselected": false }
            ]
          }
        ]
      }
    ]
  }
}
```

### How it works

- **Area lists**: an area is read page by page, 15 restaurants a page, A to Z unless you choose an order (or paste a link that has one). A to Z is the only order that stays the same between two reads, so a capped read always gets the same restaurants. A page Talabat answers short, or in a fallback order, is asked again and the area's coverage row says so.
- **Menus**: one menu page per restaurant carries the whole menu. The delivery fee, minimum order, delivery time and open status come from the area list, because the menu page shows placeholders for them.
- **Options and reviews**: with the add-ons on, the options of each dish with options and the restaurant's reviews are read through Talabat's own calls. A dish the menu lists at 0 gets its real starting price from its options (`priceFrom`). A dish whose options could not be read carries `options: null` and is not charged (`menu.optionTreesNotRead` counts them); option trees stop at about 4 MB of text per restaurant, because a dataset row holds at most 9 MB. A restaurant whose reviews were asked for says whether they were read (`reviewsStatus`).
- **Repeats removed**: a branch found by two entries of the run is delivered and charged once; a dish Talabat repeats in several menu sections is kept once, with every section it appears in.
- **Empty menus**: Talabat switches some menus by time of day and briefly answers with no dish. Such a menu is asked again at least a minute later in the run (when the run's allowance for unpaid work can pay the wait); if it is still empty, or is not asked again, a free status row says so and it is not charged.
- **Misses**: an unknown branch, area, city, chain or a point Talabat does not deliver to gets a free status row. A name shared by several areas is not guessed: the free row lists them.

### Input

Give at least one of: links, areas, cities, delivery points, search words, chains, branch ids, markets alone, `wholeCountry` or `listAreasOnly`. An input with none of them reads the sample (the first five restaurants of Abu Hail, Dubai). Markets are `uae`, `kuwait`, `qatar`, `bahrain`, `oman`, `jordan`, `egypt` (ISO codes `ae`, `kw`, `qa`, `bh`, `om`, `jo`, `eg` work too), several in one run.

#### An area link (its filter, sort and cuisine are kept)

```json
{ "startUrls": [{ "url": "https://www.talabat.com/uae/restaurants/1169/abu-hail" }], "maxRestaurants": 50 }
```

#### A whole city, central areas first

```json
{ "cities": ["uae/Dubai"], "maxRestaurants": 500 }
```

#### A delivery point (the area Talabat delivers it from)

```json
{ "locations": ["25.2048,55.2708"], "maxRestaurants": 100 }
```

#### Search words around every city centre of a market

```json
{ "countries": ["qatar"], "searchQueries": ["shawarma"], "searchMatch": "name", "maxRestaurants": 100 }
```

Every page of a search is read (Talabat gives up to 1,000 results a page; "burger" around Dubai lists about 1,560). Talabat answers any word, even one nothing matches, with unrelated restaurants, so a search result is delivered only when it matches: `any` (name, cuisine or a dish), `name`, or `exact_name` (the restaurant's name without the branch part Talabat adds after a comma equals the words, for checking a list of restaurant names; no match gives a free row).

#### Every branch of a chain in a market

```json
{ "chains": ["uae/mcdonalds"], "includeChainInfo": true }
```

Talabat's brand list gives every branch of most chains at once (McDonald's UAE: 161), checked once from a second point. For some brands it gives only the branch serving the point asked (KFC UAE): when it gives one branch or none, or a different list from the second point, the branches are collected around every city centre of the market and the coverage row says a branch serving no city centre may be missed.

#### Branch ids with options and reviews

```json
{ "branchIds": ["uae/38382"], "includeOptions": true, "includeReviews": true, "maxReviewsPerRestaurant": 200, "reviewsSince": "2026-01-01" }
```

#### Markets alone (the most central area of every city)

```json
{ "countries": ["bahrain", "oman"], "maxRestaurants": 200 }
```

#### Every brand of a market (Talabat's sitemap)

```json
{ "countries": ["bahrain"], "wholeCountry": true, "maxRestaurants": 1000 }
```

UAE has about 30,600 brand pages, so bound it with **Max restaurants**. Each brand is asked once, from the market's first point; brands that give one branch from a point are counted in the coverage row, which is then partial (read such a brand with `chains`).

#### The cities and areas of a market only (no result fee)

```json
{ "countries": ["jordan"], "listAreasOnly": true }
```

One free row per market with every area id, name, slug, city and coordinates; no result is charged, only the run's start fee. Name areas next to it (by id, link or name) to get their cuisines, filters and sorts too; other entries are read in a run without it.

#### Filters and order

```json
{ "areas": ["uae/1169"], "cuisines": ["burgers"], "listFilters": ["top_rated", "free_delivery"], "minRating": 4.2, "onlyOpen": true, "sortBy": "a_z" }
```

`listFilters` takes Talabat's eight list filters: `top_rated`, `free_delivery`, `fast_delivery`, `newly_added`, `offers`, `pickup`, `veg_only`, `exceptional`. Also `onlyTalabatPro`, `chainFilter`, and the orders `rating`, `fastest_delivery`, `delivery_fee`, `minimum_order`. `chainFilter` keeps only the named chains in area lists (areas, cities, delivery points, area links, markets alone): it takes brand slugs (`kfc`, `mango-talaat-juffair`, as in the brand's Talabat link), each resolved through Talabat's brand list at the area's centre, and a restaurant is kept by its branch id, never by its name. The area's first list page is read, then the brand's branches that Talabat's search shows around the area's centre are added (they serve that point, and can include a branch the area list itself does not show; Talabat's lists have no name filter; search rows carry no delivery fee, minimum order or open status, so `chainFilter` is not combined with `onlyOpen` or `listFilters`).

#### A monitor

```json
{ "startUrls": [{ "url": "https://www.talabat.com/uae/restaurants/1169/abu-hail" }], "maxRestaurants": 500, "monitorName": "abu-hail-menus", "monitorMode": "changes" }
```

Other settings: `language` (`en`, `ar`, `en_ar` for Arabic dish, description and section names next to the English ones; left empty, an `/ar/` link reads Arabic and everything else English; a cuisine filter is judged on Talabat's English cuisine names, so with Arabic only reads it is refused: use `en_ar`), `maxDishesPerRestaurant`, `maxOptionDishesPerRestaurant`, `includeReviewStats`, `includeSearchFlags`, `includeNonRestaurants`, `dishRows`, `omitEmptyFields`, `transformFunction` (a plain JavaScript function that takes a row and returns it; async functions are refused), `maxRestaurantsPerSubject`, `maxPagesPerArea`, `maxConcurrency` (1 to 3).

### How much does it cost to scrape Talabat?

You pay per event, per 1,000 events, by your Apify plan:

| Event | What it is | FREE | BRONZE | SILVER | GOLD |
|---|---|---|---|---|---|
| Restaurant (primary) | One restaurant branch with its full menu nested | $0.92 | $0.84 | $0.76 | $0.66 |
| Dish option set | The option tree of one dish (add-on) | $0.20 | $0.18 | $0.16 | $0.15 |
| Review | One customer review row (add-on) | $0.20 | $0.18 | $0.15 | $0.12 |
| Dish row | One dish as its own row (add-on) | $0.05 | $0.045 | $0.04 | $0.035 |
| Menu check | A monitored restaurant read again and found unchanged | $0.21 | $0.19 | $0.17 | $0.15 |

Platinum and Diamond plans pay the Gold price. The Actor start is $0.004 per run, flat on every plan, with no discount (charged per GB of run memory; the default 256 MB run pays it once).

The Store pricing card shows these prices per 1,000 events: "$0.66 / 1,000" on the Restaurant row means one restaurant with its full menu costs $0.00066.

#### Worked examples (GOLD)

- **1,000 restaurants with full menus**: 1,000 x $0.00066 = $0.66, plus the $0.004 start = **$0.664**.
- **A monitor run of 500 known restaurants of which 20 changed**: 480 Menu checks x $0.00015 = $0.072, plus 20 Restaurants x $0.00066 = $0.0132, plus the $0.004 start = **$0.0892**.

#### What is free

Misses (unknown branches, areas, cities, chains, points Talabat does not deliver to, ambiguous names), shops left out of area lists (groceries, pharmacies, flowers), empty menus, filtered restaurants, repeats within a run, known restaurants a new only monitor skips, dishes whose options could not be read, and every `coverage`, `status`, `areas` and `summary` row. If you set a maximum charge for the run, add-on rows are cut first and the run stops before it passes the limit.

### The monitor

Set `monitorName` and schedule the run. The Actor remembers what it delivered under that name in a key-value store it creates itself.

- **`changes` (default)**: new restaurants are delivered as usual. A known restaurant is read again and compared with its last delivery: dish prices and old prices, dishes added and removed, rating, delivery fee, minimum order and the Talabat Pro flag, plus new reviews when reviews are on. A changed one is delivered again with a `changes` object (each price change carries the previous price) and charged as a Restaurant. An unchanged one gives one short `restaurant_unchanged` row: that is a **Menu check** (with reviews on, its `reviewsChecked` says whether the reviews were read). An unchanged restaurant is judged before the option trees, the Arabic menu and the chain figures are read, so a Menu check never pays for them (with **Offer and label flags** on, that one search is read first, because it carries the Pro flag the monitor compares).
- **Reviews under a monitor**: each review is delivered once. The first run delivers the newest, up to `maxReviewsPerRestaurant`; later runs deliver the reviews not delivered yet, newest first and up to the same number a run, back to the oldest day the first run delivered (one the cap left out comes in a later run; older reviews are never counted as new).
- **`new_only`**: only restaurants never delivered before; known ones are skipped without being read, free.
- `resetMonitor: true` forgets the memory and starts again.
- **Max restaurants** counts Menu checks too, so set it at least as high as the number of restaurants you watch.

Some menus change by time of day (breakfast and the rest of the day), and the monitor shows that as dish changes. Schedule a monitor at the same hour every day.

### Use it from the API

Each call runs the Actor and returns its dataset (restaurant rows plus the free coverage and summary rows; filter on `type`). The synchronous endpoint waits up to 300 seconds, so keep these runs small or start a normal run for large ones. Replace `MY_APIFY_TOKEN` with your Apify API token.

#### curl

```bash
curl -X POST "https://api.apify.com/v2/acts/automation_craft~talabat-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer MY_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"areas": ["uae/1169"], "maxRestaurants": 20}'
```

#### Node.js

```js
const res = await fetch('https://api.apify.com/v2/acts/automation_craft~talabat-scraper/run-sync-get-dataset-items', {
    method: 'POST',
    headers: { Authorization: 'Bearer MY_APIFY_TOKEN', 'Content-Type': 'application/json' },
    body: JSON.stringify({ chains: ['uae/mcdonalds'], maxRestaurants: 20 }),
});
const rows = await res.json();
const restaurants = rows.filter((row) => row.type === 'restaurant');
console.log(restaurants.length, restaurants[0]?.menu?.dishCount);
```

#### Python

```python
import requests

rows = requests.post(
    "https://api.apify.com/v2/acts/automation_craft~talabat-scraper/run-sync-get-dataset-items",
    headers={"Authorization": "Bearer MY_APIFY_TOKEN"},
    json={"countries": ["kuwait"], "searchQueries": ["burger"], "maxRestaurants": 20},
    timeout=320,
).json()
restaurants = [row for row in rows if row["type"] == "restaurant"]
print(len(restaurants))
```

### Use it from AI agents (MCP)

An AI agent connected to the Apify MCP server can call this Actor by its name, `automation_craft/talabat-scraper`, with the same input JSON as above. The dataset's field descriptions and views tell the agent what each column holds, and the free coverage row tells it what was read and why each entry stopped.

### FAQ

#### Is there a Talabat API for restaurant menus?

This Actor works as one: it needs no Talabat partner account, key or login, reads the public talabat.com pages a logged out visitor sees, and you call it through the Apify API (examples above) with JSON in and rows out.

#### How do I get the list of all restaurants in a Talabat area or city?

Put the area in **Areas** (`uae/1169`, an area link or its name) or the city in **Cities** (`uae/Dubai`): every page of the area list is read, A to Z, and a city is read area by area from the centre out, each restaurant delivered once. **List the cities and areas only** returns every area id of a market as one free row.

#### Can I get the Talabat delivery fee and minimum order?

Yes, for every branch found through an area list (areas, cities, delivery points, markets alone, area links): `deliveryFee`, `minimumOrder` and `deliveryTimeMinutes` are the values the area list shows for that area. A branch reached by its menu link, branch id or chain gets `null` there, because Talabat's menu page shows placeholders for them.

#### Can I scrape Talabat reviews?

Turn on **Customer reviews**: each review is a row with its date, the reviewer's name from Talabat's first name field (sometimes a full name; Talabat's placeholder "First Name" is left empty), stars and text, newest first, up to 5,000 per restaurant (100 by default), optionally only since a date. **Exact review figures** adds the exact number of reviews and their average stars to the restaurant row at no extra charge.

#### Can I track Talabat menu price changes over time?

Yes. Name a monitor and schedule the run: each run delivers new restaurants and those whose dish prices, dishes, rating, delivery fee or minimum order changed, with the previous prices, and charges a small Menu check for each unchanged one.

#### Why does this Actor run with limited permissions?

It follows least privilege: it only writes its own run's dataset and key-value store. A monitor's memory is a named key-value store the Actor creates itself under your account.

### What this Actor does NOT do

- **No street addresses, phone numbers or e-mail addresses**: Talabat's logged out pages carry none (no such field on 63 menu pages or 208 list rows). The branch name usually names the neighbourhood, and coordinates are included.
- **No dish ratings**: the field is 0 on 6,653 of 6,653 dishes measured, so delivering it would be a false figure.
- **No opening hours, nutrition, calories, option photos or "Popular" option labels**: not served. Area lists show only open or closed now.
- **No grocery or pharmacy catalogues (Talabat Mart products)**: they are another product, on talabat.com's grocery and pharmacy pages, which this Actor does not read. Shops in area lists are left out free, or delivered with their list facts when you turn them on.
- **Delivery fee, minimum order, delivery time and open status only for branches found through an area list**. Search results carry the delivery time only.
- **Offer text only from Talabat's search**: search results, or **Offer and label flags** for other restaurants.
- **No login, no orders, no account data**, and no prices or fees from Talabat's app or checkout: the values are those talabat.com shows a logged out visitor at read time.
- **No Saudi Arabia or Iraq**: Saudi Arabia is no longer served on talabat.com and Iraq moved to a separate site this Actor does not read; both are refused with a free row.
- **No residential proxy**: requests leave from the run's own address, then Apify datacenter proxy sessions (one at a time, kept while Talabat accepts it) if Talabat refuses that address, or your own proxies. Your own proxy link needs a password of 8 or more characters with letters and digits, and no other setting may repeat part of its user name or password.
- **Setting names are checked**: a setting name the input does not have (a misspelt `cuisine` for `cuisines`) refuses the run before anything is read (only the run's start fee is charged), so a run never reads wider than you meant.
- **No review ids or restaurant replies**: Talabat's reviews carry none.

### Changelog

- 0.1 (2026-10-18): first release. Restaurants by area, city, delivery point, search, chain, branch id and whole market, with full menus, dish options, reviews and monitors.

### More data tools by Automation Craft

- [UK Food Hygiene Ratings Scraper - FSA Register](https://apify.com/automation_craft/uk-food-hygiene-ratings-scraper)
- [Facebook Marketplace Scraper with Sold Tracker](https://apify.com/automation_craft/facebook-marketplace-scraper)
- [Leboncoin Scraper: Ads, Prices, Real Estate & Cars](https://apify.com/automation_craft/leboncoin-scraper)
- [Amazon Product Scraper - Search, Best Sellers](https://apify.com/automation_craft/amazon-data-scraper)
- [Trustpilot Reviews Scraper: Coverage Per Company](https://apify.com/automation_craft/trustpilot-reviews-scraper)
- [G2 Reviews Scraper: Ratings, Pros and Cons](https://apify.com/automation_craft/g2-reviews-scraper)

# Changelog

This Actor's version history is a separate document: https://apify.com/automation_craft/talabat-scraper/changelog.md

# Actor input Schema

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

Links copied from talabat.com: an area list (https://www.talabat.com/uae/restaurants/1169/abu-hail, its filter, sort and cuisine are kept unless you set your own below), a restaurant menu (https://www.talabat.com/uae/restaurant/38382/bucket-restaurant-nadd-al-hamar?aid=1169) or a brand page (https://www.talabat.com/uae/mcdonalds, every branch of the chain in that market). Arabic links (/ar/...) read the Arabic menu. You can also link a remote text file with one Talabat link per line.

## `countries` (type: `array`):

The Talabat markets your areas, cities, search words, chains and branch ids belong to: uae, kuwait, qatar, bahrain, oman, jordan, egypt (the ISO codes ae, kw, qa, bh, om, jo, eg work too). Several markets in one run are fine. Saudi Arabia and Iraq are not served on talabat.com and are refused with a free row.

## `areas` (type: `array`):

Delivery areas, each read as its full restaurant list (15 a page, A to Z by default): an area number with its market (uae/1169), an area link, or an area name as Talabat writes it (Abu Hail) within the markets above. A name shared by several areas is not guessed: a free row lists them.

## `cities` (type: `array`):

Whole cities (Dubai, Kuwait City, Cairo), read area by area from the centre out with every restaurant delivered once. Delivery zones overlap, so later areas add fewer new restaurants; use the limits below to bound the run. Write uae/Dubai when a city name exists in several markets.

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

Points as latitude,longitude (25.2048,55.2708). Each point is read as the restaurant list of the area Talabat delivers it from; with search words below, the searches run around these points instead. A point Talabat does not deliver to gets a free row.

## `searchQueries` (type: `array`):

Words to search on Talabat (pizza, shawarma, a restaurant name), around the delivery points above, or around the centre of every city of the markets above. Talabat answers any word, even one nothing matches, with unrelated restaurants, so a result is delivered only when it matches (see Search match).

## `chains` (type: `array`):

Every branch of a chain in a market, by the brand's slug as it appears in its Talabat link (talabat.com/uae/mcdonalds is mcdonalds), or by the brand link itself. A slug can differ between markets (McDonald's Bahrain is mcdonalds--adliya); write uae/mcdonalds to name the market. Talabat's brand list is checked from a second point; when it gives one branch or none, or another list there, the branches are collected around every city centre (the coverage row says so).

## `branchIds` (type: `array`):

Single restaurant branches by Talabat's branch id, the number in a menu link (talabat.com/uae/restaurant/38382/...): 38382 with one market above, or uae/38382.

## `wholeCountry` (type: `boolean`):

Read every brand of each market above from Talabat's public sitemap (UAE about 30,600 brand pages), every branch of each brand. Large: bound it with Max restaurants.

## `listAreasOnly` (type: `boolean`):

Read nothing but the markets' cities and areas (one free row per market with every area id, name, slug and coordinates), and for each area you name its cuisines, filters and sorts. Use it to find the areas to read. No restaurant is delivered.

## `includeMenu` (type: `boolean`):

Nest the whole menu in each restaurant row: every dish with its price, old price, discount, description, photo, sections and flags, repeats removed. Off: list facts only (an area list row needs no extra request then).

## `includeOptions` (type: `boolean`):

Read the option tree of every dish that has options: sizes, add-ons and extras with prices, minimum and maximum choices, required sections and nested options. Gives the real starting price of dishes the menu lists at 0. Charged as one Dish option set per dish read.

## `maxOptionDishesPerRestaurant` (type: `integer`):

The most option trees read per restaurant (the first dishes with options in menu order). Empty: up to 1,000.

## `includeReviews` (type: `boolean`):

Deliver each restaurant's customer reviews as rows, newest first: date, the reviewer's name from Talabat's first name field (sometimes a full name; its placeholder First Name is left empty), stars and text. Charged as one Review per review delivered.

## `maxReviewsPerRestaurant` (type: `integer`):

The most reviews delivered per restaurant (newest first). Empty: 100. Up to 5,000.

## `reviewsSince` (type: `string`):

Only reviews dated on or after this day (YYYY-MM-DD).

## `includeReviewStats` (type: `boolean`):

Count every review of the restaurant (Talabat shows rating counts in buckets such as 1000+): the exact number of reviews, their average stars, how many have text, the newest and oldest dates. Included in the Restaurant event.

## `includeChainInfo` (type: `boolean`):

Add the chain's own rating and its exact rating count across all its branches in the market. Included in the Restaurant event.

## `includeSearchFlags` (type: `boolean`):

For restaurants not found by a search, look each one up in Talabat's search once to add its offer text (30% off select items), rating label (Very good), price tag, Talabat Pro flag and pickup time. Included in the Restaurant event.

## `language` (type: `string`):

English, Arabic, or both (the Arabic dish, description and section names added next to the English ones). Left empty: the language of a pasted link (an /ar/ link reads Arabic), else English. A cuisine filter needs English names: with Arabic only it is refused, use English and Arabic.

## `dishRows` (type: `boolean`):

Also deliver every dish as its own dataset row, for spreadsheets. Charged as one Dish row per dish. The dishes stay nested in the restaurant row either way.

## `maxDishesPerRestaurant` (type: `integer`):

Keep only the first dishes of each menu (menu order). Empty: the whole menu.

## `includeNonRestaurants` (type: `boolean`):

Area lists also carry grocery, pharmacy and flower shops. Off: they are left out free. On: they are delivered with their list facts (a flower shop with its catalogue as the menu).

## `omitEmptyFields` (type: `boolean`):

Drop fields that are empty (null, empty text, empty lists) from restaurant, review and dish rows.

## `transformFunction` (type: `string`):

Optional JavaScript function that receives each restaurant, review or dish row and returns the object to store, for example (row) => ({ name: row.name, rating: row.rating }). It runs with a 100 ms limit per row; the row type, branch id, market, position and dish id are kept; a failure stores the row unchanged.

## `cuisines` (type: `array`):

Keep only restaurants of these cuisines, by Talabat's cuisine slug (burgers, pizza, fish-chips). Applied by Talabat on area lists and checked on every row.

## `listFilters` (type: `array`):

Talabat's own list filters: top_rated (4.0 and above), free_delivery, fast_delivery (within 30 minutes), newly_added, offers, pickup, veg_only, exceptional. Several are combined (all must hold).

## `sortBy` (type: `string`):

The order an area list is read in. A to Z is the only order that stays the same between two reads, so a capped read always gets the same restaurants. Left empty: a pasted area link's own order, else A to Z.

## `minRating` (type: `number`):

Keep only restaurants rated at least this (0 to 5).

## `onlyOpen` (type: `boolean`):

Keep only restaurants open at read time (known from area lists; a restaurant found another way does not pass).

## `onlyTalabatPro` (type: `boolean`):

Keep only restaurants marked for Talabat Pro (known from area lists and searches).

## `chainFilter` (type: `array`):

Keep only these chains in area lists (areas, cities, delivery points, area links, markets alone): brand slugs as in the brand's Talabat link (kfc, mango-talaat-juffair). Each is resolved at the area's centre and a restaurant is kept by its branch id. The area's first list page is read, then the brand's branches that Talabat's search shows around the area's centre (they serve that point, and can include a branch the area list itself does not show; search rows carry no delivery fee or minimum order). Not combined with Only open now or list filters.

## `searchMatch` (type: `string`):

Which search results are delivered: any (the words are in the name, a cuisine, or Talabat matched a dish), name (in the name only), or exact_name (the restaurant's name, without the branch part Talabat adds after a comma, equals the words; for checking a list of restaurant names; no match gives a free row).

## `maxRestaurants` (type: `integer`):

The most restaurants delivered (or checked by a monitor) in the run. Empty: 200.

## `maxRestaurantsPerSubject` (type: `integer`):

The most restaurants delivered for each area, city, point, search or chain. Empty: no limit per entry.

## `maxPagesPerArea` (type: `integer`):

The most list pages (15 restaurants each) read per area. Empty: every page.

## `monitorName` (type: `string`):

Name a monitor to remember what was delivered across scheduled runs (a memory this Actor keeps for this name). Changes mode: delivers new restaurants and those whose dishes, prices, rating, fee, minimum order or Talabat Pro flag changed (with the previous values), or that have new reviews when reviews are on, and one short Menu check row for each unchanged one. New only mode: delivers restaurants never delivered before and skips known ones without reading them.

## `monitorMode` (type: `string`):

changes (default) or new_only. Needs a monitor name.

## `resetMonitor` (type: `boolean`):

Forget what the named monitor remembered and start again.

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

Restaurants read at the same time (1 to 3). The pace stays near one request a second each.

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

Requests leave from the run's own address. If Talabat refuses it, the run moves to one Apify datacenter proxy session (default), or to your own proxies. Turn the Apify proxy off with no links to never use a proxy. Residential groups are read as the datacenter pool. Your own proxy link needs a password of 8 or more characters with letters and digits, and no other setting may repeat part of its user name or password (the run is refused, so they can never reach a row).

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.talabat.com/uae/restaurants/1169/abu-hail"
    }
  ],
  "countries": [
    "uae"
  ],
  "wholeCountry": false,
  "listAreasOnly": false,
  "includeMenu": true,
  "includeOptions": false,
  "includeReviews": false,
  "includeReviewStats": false,
  "includeChainInfo": false,
  "includeSearchFlags": false,
  "dishRows": false,
  "includeNonRestaurants": false,
  "omitEmptyFields": false,
  "onlyOpen": false,
  "onlyTalabatPro": false,
  "searchMatch": "any",
  "maxRestaurants": 5,
  "resetMonitor": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `items` (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 = {
    "startUrls": [
        {
            "url": "https://www.talabat.com/uae/restaurants/1169/abu-hail"
        }
    ],
    "countries": [
        "uae"
    ],
    "maxRestaurants": 5,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation_craft/talabat-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.talabat.com/uae/restaurants/1169/abu-hail" }],
    "countries": ["uae"],
    "maxRestaurants": 5,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("automation_craft/talabat-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 '{
  "startUrls": [
    {
      "url": "https://www.talabat.com/uae/restaurants/1169/abu-hail"
    }
  ],
  "countries": [
    "uae"
  ],
  "maxRestaurants": 5,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call automation_craft/talabat-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation_craft/talabat-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/iFBfEQ3oHVEfsL67B/builds/cw1bJOeBve5Nhl36K/openapi.json
