# Foodpanda Restaurant & Menu Scraper | 7 Countries | $4 / 1k (`dmitrii_shifo/foodpanda-scraper`) Actor

7 countries in one run: PH, SG, MY, TW, HK, PK, BD. Scrape Foodpanda restaurants and full menus with prices. Pick cities from a dropdown, no URL building. Names, ratings, cuisines, addresses, delivery fees and promo prices.

- **URL**: https://apify.com/dmitrii\_shifo/foodpanda-scraper.md
- **Developed by:** [Dmitrii Lominskii](https://apify.com/dmitrii_shifo) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 restaurant with full menus

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/actors/running/actors-in-store.md#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

## Foodpanda Restaurant & Menu Scraper | 7 Countries | $4 / 1k

Collect public restaurant and menu data from Foodpanda across seven Asian markets. Pick cities from a dropdown, hit Start, and get clean JSON or CSV with restaurant details and every menu item with its price.

No URL building. No login. No browser automation, which is why runs are fast and cheap.

![Foodpanda Scraper output example](https://raw.githubusercontent.com/d-lominskii/apify-assets/main/output-example.png)

Three countries scraped in one run.

### Supported countries

Every market below was tested with a live request before this Actor was published.

| Country | Site |
|---|---|
| Philippines | foodpanda.ph |
| Singapore | foodpanda.sg |
| Malaysia | foodpanda.my |
| Taiwan | foodpanda.com.tw |
| Hong Kong | foodpanda.hk |
| Pakistan | foodpanda.pk |
| Bangladesh | foodpanda.com.bd |

Thailand is not supported because Foodpanda has exited that market. Laos and Cambodia are not included in this version.

### What you get

- Name, vendor code, direct link to the restaurant page
- Rating value and number of ratings
- Delivery fee, minimum order value, estimated delivery time
- Chain name and chain code for multi-branch brands
- Open or closed status, distance from your search point
- Logo and listing images

These extra fields need the restaurant details request, so they only come through when Scrape menus is on (see pricing):

- Cuisines and primary cuisine
- Full address, city, postcode, coordinates
- Weekly opening hours
- Menu categories in the order they appear on the site
- Every product with title, description, image, price and discounted price
- Sold out flag, alcoholic item flag, bundle flag

See the field table below for exactly which fields come with which mode.

### How to use it

1. Open the Cities field and tick the cities you want. You can mix countries in one run.
2. Set Max restaurants. This caps the whole run, across all cities, and is shared between them: the Actor rotates through your cities one restaurant at a time instead of filling up the first one before moving to the next.
3. Leave Scrape menus on to get full menus, or turn it off for a faster, cheaper listing-only run.
4. Press Start.

Need a point that is not in the city list? Open the Advanced section and add your own coordinates under Custom locations. Already know which restaurants you want? Put their vendor codes in Vendor codes and the Actor will skip the search step entirely.

### Input

| Field | Type | Description | Default |
|---|---|---|---|
| `cities` | array | Cities to search, picked from a list. Country is detected automatically. | `["ph_manila"]` |
| `maxRestaurants` | integer | Total restaurants to scrape across the whole run. | `50` |
| `scrapeMenus` | boolean | Fetch the full menu for each restaurant. | `true` |
| `expeditionType` | string | `DELIVERY` or `PICKUP`. | `DELIVERY` |
| `customLocations` | array | Your own search points: country, latitude, longitude, optional label. | `[]` |
| `vendorCodes` | array | Scrape only these restaurants by vendor code, skipping the search. | `[]` |
| `vendorCodesCountry` | string | Country the vendor codes belong to. Required when `vendorCodes` is used. | none |
| `proxyConfiguration` | object | Proxy settings. Off by default, this Actor does not need one. | disabled |

### Example input

```json
{
  "cities": ["ph_manila", "sg_singapore", "my_kuala_lumpur"],
  "maxRestaurants": 500,
  "scrapeMenus": true,
  "expeditionType": "DELIVERY"
}
```

### Example output

One dataset item is one restaurant. Trimmed for readability, a real item with a full menu is much longer.

```json
{
  "name": "Pizza Hut - CM Recto",
  "vendorCode": "r6xi",
  "restaurantUrl": "https://www.foodpanda.ph/restaurant/r6xi/pizza-hut-cm-recto",
  "country": "PH",
  "city": "Manila",
  "sourceLabel": "Manila, Philippines",
  "ratingValue": 5,
  "ratingCount": 2187,
  "primaryCuisine": "Pizza",
  "cuisines": ["Pizza", "Pasta"],
  "addressLine1": "1234 Claro M. Recto Avenue",
  "addressLine2": "Sampaloc",
  "latitude": 14.6042,
  "longitude": 120.9822,
  "deliveryFee": 39,
  "deliveryFeeOriginal": 49,
  "minimumOrderValue": 119,
  "deliveryTimeMinMinutes": 30,
  "deliveryTimeMaxMinutes": 40,
  "chainCode": "cp1ab",
  "chainName": "Pizza Hut",
  "availabilityStatus": "OPEN",
  "distanceInMeters": 411,
  "openingHours": {
    "monday": ["10:00-22:00"],
    "tuesday": ["10:00-22:00"],
    "wednesday": ["10:00-22:00"],
    "thursday": ["10:00-22:00"],
    "friday": ["10:00-22:00"],
    "saturday": ["10:00-22:00"],
    "sunday": ["10:00-22:00"]
  },
  "hasMenu": true,
  "menu": [
    {
      "title": "Best Sellers",
      "products": [
        {
          "title": "Super Supreme Pizza",
          "description": "Beef, pepperoni, mushroom, bell pepper",
          "price": 599,
          "discountedPrice": null,
          "isSoldOut": false
        }
      ]
    }
  ]
}
```

### Pricing

You pay per restaurant saved, and the price depends on how much data that restaurant carries.

| Event | Price |
|---|---|
| Restaurant, listing data only | $2.50 per 1,000 |
| Restaurant with full menu | $4.00 per 1,000 |

Turning Scrape menus off cuts your cost per restaurant almost in half. You still get delivery fees, minimum order, estimated delivery time and chain info, but you lose the full address, cuisines, opening hours and the menu itself. See the field table below for the exact split.

There is no separate platform usage charge on top of these prices.

#### Which fields come with which mode

| Field | Listing only (Scrape menus off) | With full menu |
|---|---|---|
| Name, vendor code, restaurant URL | Yes | Yes |
| Rating value, rating count | Yes | Yes |
| Distance from search point, open/closed status | Yes | Yes |
| Logo and listing images | Yes | Yes |
| Delivery fee, minimum order value | Yes | Yes |
| Delivery fee without an active promo | No | Yes |
| Estimated delivery time | Yes | Yes |
| Chain name, chain code | Yes | Yes |
| Cuisines, primary cuisine | No | Yes |
| Full address, city, postcode, coordinates | No | Yes |
| Weekly opening hours | No | Yes |
| Menu categories and products | No | Yes |

Restaurants scraped through the Vendor codes input always come back with the full set of fields above, menu included when Scrape menus is on. That path calls the restaurant details endpoint directly, there is no listing-only step to skip.

### What it is good for

- Price monitoring across restaurants and chains in one or several markets
- Market research on coverage, cuisine mix, delivery fees and ratings by city
- Lead lists of restaurants with addresses and chain information
- Menu databases for apps, dashboards and AI agents
- Tracking a fixed set of restaurants daily using the vendor codes input
- Promo tracking: discounted prices and reduced delivery fees show up exactly as they do on the site at run time, so a scheduled run catches restaurant-wide sales as they start and end. When a restaurant runs a promo, discountedPrice fills in across its whole menu at once, not on a handful of random items.

### Notes and limits

- Data is public information from Foodpanda listing and restaurant pages. Check Foodpanda's terms and your local rules before using it.
- Item options and toppings for customizable products are not included in this version. Base prices and variations are.
- Results depend on the search point, the same way they do on the site. Two points in one large city return overlapping but different sets. The Actor removes duplicates across all your search points automatically.
- With several cities or custom locations selected, Max restaurants is split between them by rotation, not given entirely to the first one. A city with fewer restaurants than its share simply runs out early, and the rest of the limit goes to your other search points.
- Some restaurants have no logo uploaded on Foodpanda's side, so logoUrl points to a file that does not exist for them. listingImageUrl is always available.
- Foodpanda opens and closes markets over time. The country list above reflects what was live at publication.
- This Actor is not affiliated with Foodpanda or Delivery Hero.

### Support

Found a bug or need a field that is missing? Open an issue on the Issues tab and I will look at it.

# Actor input Schema

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

Predefined major cities to search. The country for each restaurant is detected automatically from the city you pick, no coordinates needed. Combine with Custom locations in Advanced below if you need more coverage. At least one city or custom location is required.

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

Maximum number of restaurants to scrape in total, across all selected cities and custom locations combined. The Actor rotates between your search points and splits this limit between them, it does not exhaust one city before moving to the next. Protects you from unexpectedly large, and costly, runs.

## `scrapeMenus` (type: `boolean`):

Also fetch the full menu for each restaurant. This makes a second API call per restaurant and is billed as a separate, higher-priced pay-per-event charge. On by default so a first run already returns dishes, not just a restaurant listing; turn off for a faster, cheaper listing-only run.

## `expeditionType` (type: `string`):

Search for restaurants offering delivery or pickup. Most users want Delivery.

## `customLocations` (type: `array`):

Add your own search points, for example to cover more of a large city or a place not in the Cities list. Each entry needs country, latitude and longitude; label is optional and only used to tag the results. At least one city or custom location is required.

## `vendorCodes` (type: `array`):

Scrape only these specific restaurants by their Foodpanda vendor code, skipping the city/location listing step entirely. All codes must belong to the same country, set below in Vendor codes country.

## `vendorCodesCountry` (type: `string`):

Country the codes in Vendor codes belong to. Required only when Vendor codes is used.

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

Proxy settings for the scraper's requests. The Foodpanda GraphQL API is public and normally does not require a proxy; only enable this if you run into rate limiting or IP blocks. Off by default because with pay-per-event pricing, platform proxy costs are deducted from the developer's revenue, not billed to you.

## Actor input object example

```json
{
  "cities": [
    "ph_manila"
  ],
  "maxRestaurants": 50,
  "scrapeMenus": true,
  "expeditionType": "DELIVERY",
  "customLocations": [],
  "vendorCodes": [],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (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 = {
    "cities": [
        "ph_manila"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("dmitrii_shifo/foodpanda-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 = { "cities": ["ph_manila"] }

# Run the Actor and wait for it to finish
run = client.actor("dmitrii_shifo/foodpanda-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 '{
  "cities": [
    "ph_manila"
  ]
}' |
apify call dmitrii_shifo/foodpanda-scraper --silent --output-dataset

```

## MCP server setup

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