# Chope Scraper - Singapore & Asia Restaurant Leads (`scrapesage/chope-scraper`) Actor

Scrape Chope restaurants across Singapore and Asia: name, phone, full address, area, cuisine, price band, ratings, geo, menus, photos and reviews. Turn dining venues into B2B leads. Export to JSON, CSV or Excel.

- **URL**: https://apify.com/scrapesage/chope-scraper.md
- **Developed by:** [Scrape Sage](https://apify.com/scrapesage) (community)
- **Categories:** Lead generation, Travel, Automation
- **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 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

## Chope Scraper — Singapore & Asia Restaurant Leads, Ratings & Reservations

Extract **complete restaurant data from [Chope](https://www.chope.co)** — Asia's largest restaurant-reservation platform — by market, by cuisine, or by URL. Get every venue's **name, phone, full street address, area/neighbourhood, cuisine, price band, rating, review count, geo-coordinates, menus, photos** and optional **diner reviews**. Every dining venue is a ready-to-use **B2B lead**: a contactable restaurant with phone, address, location and a quality score.

No login, no cookies, no browser — this actor reads Chope's own public restaurant pages directly, so the output is first-party and reliable.

### Why this Chope scraper?

Most restaurant scrapers return a name and a star rating and call it done. This actor pulls the **full venue record from Chope's directory and profile pages** and ships the **richest dataset in the category** — including the contact fields that turn a listing into a lead:

| Data | Typical scrapers | This actor |
|---|---|---|
| Restaurant name, cuisine, price band | ✅ | ✅ |
| Chope rating + number of reviews | partial | ✅ |
| **Phone number** | ❌ | ✅ |
| **Full street address + postal code** | partial | ✅ |
| **Area / neighbourhood** | ❌ | ✅ |
| Latitude / longitude | ❌ | ✅ |
| **Menus** (Chope-hosted menu files) | ❌ | ✅ when published |
| Photo gallery | partial | ✅ |
| **Diner reviews** (author, rating, date, full text) | ❌ | ✅ opt-in |
| Reservation link | ❌ | ✅ |
| Multi-market: Singapore, Malaysia, Indonesia, Thailand | ❌ | ✅ |
| Lead score (0–100) per venue | ❌ | ✅ |
| One clean dataset, no empty columns | ❌ | ✅ |

### Use cases

- **Lead generation** — restaurants are active buyers of POS, reservation, marketing, delivery, payroll, supply and insurance products. Score them by quality and reach (`leadScore`, `phone`, `address`) and export straight to your CRM.
- **Market & competitive research** — map a city's dining scene by cuisine, price band, area and rating; benchmark venues and track new openings across Singapore and Southeast Asia.
- **Sales territory planning** — pull every Chope restaurant in a market with full addresses and geo-coordinates for route and territory planning.
- **Directory & app enrichment** — power restaurant guides, concierge tools and travel apps with standardized records, menus, photos and coordinates.
- **Reputation & review intelligence** — collect ratings, review counts and full diner review text to monitor sentiment for a venue or a whole market.

### How to use

1. [Sign up for Apify](https://console.apify.com/sign-up) — the free plan is enough to try this actor.
2. Open the **Chope Scraper**, select one or more **Markets** (e.g. `singapore`), optionally add **Search terms** (e.g. `omakase`), and click **Start**.
3. Watch results stream into the dataset table.
4. **Export** as JSON, CSV, Excel, XML or RSS — or pull results programmatically via the [Apify API](https://docs.apify.com/api/v2).

### Input

```json
{
    "countries": ["singapore"],
    "searchQueries": ["steakhouse", "omakase"],
    "maxResults": 100,
    "includeDetails": true,
    "includeReviews": false,
    "cuisines": ["japanese"],
    "priceTiers": ["3", "4"],
    "areaFilter": ["orchard"],
    "minRating": 4,
    "monitorMode": false
}
````

- **countries** — Chope markets to scrape every restaurant in: `singapore`, `kuala-lumpur`, `bali`, `jakarta`, `bandung`, `surabaya`, `bangkok`, `phuket`. Singapore has the deepest coverage. One per row.
- **searchQueries** — keep only restaurants whose name or cuisine matches one of these (e.g. `italian`, `omakase`, `Marriott`). Leave empty for every restaurant.
- **startUrls** — direct Chope restaurant URLs (`https://www.chope.co/singapore-restaurants/restaurant/10-scotts`).
- **maxResults** *(default 100)* — cap on restaurant records for the whole run.
- **includeDetails** *(default true)* — open each restaurant's Chope profile for the full lead record (phone, full address, area, geo, price band, rating, menus, photos). One fast extra request per restaurant. Off = a quick, cheap directory pass (name, cuisine, market, profile URL).
- **includeReviews** *(default false)* — also extract visible diner reviews (author, star rating, date, full text). No extra request — parsed from the same profile page.
- **cuisines / priceTiers / areaFilter / minRating** — keep only venues matching these filters.
- **monitorMode** *(default false)* — emit only restaurants not seen in previous runs (see below).

### Output

One record per restaurant (`type: "restaurant"`):

```json
{
    "type": "restaurant",
    "chopeRid": "10scotts2282sg",
    "slug": "10-scotts",
    "name": "10|SCOTTS",
    "profileUrl": "https://www.chope.co/singapore-restaurants/restaurant/10-scotts",
    "phone": "+6567321234",
    "address": "10 Scotts Road Lobby Level Grand Hyatt Singapore Singapore (228211)",
    "area": "Orchard",
    "city": "Singapore",
    "region": "Singapore",
    "postalCode": "228211",
    "country": "Singapore",
    "countryCode": "SG",
    "market": "Singapore",
    "latitude": 1.3062616,
    "longitude": 103.8334004,
    "cuisines": ["Bar", "Mediterranean", "Coffee", "High Tea"],
    "primaryCuisine": "Bar",
    "priceTier": 3,
    "priceRange": "$$$",
    "rating": 4.1,
    "reviewCount": 11,
    "acceptsReservations": true,
    "reservationUrl": "https://www.chope.co/singapore-restaurants/restaurant/10-scotts",
    "imageUrl": "https://static.chope.co/uploads/2025/09/Group-Shot-1-1-1757584197.jpg",
    "photos": ["https://static.chope.co/uploads/..."],
    "menus": [{ "name": "À La Carte Menu", "url": "https://static.chope.co/uploads/...pdf" }],
    "leadScore": 70,
    "scrapedAt": "2026-06-26T12:00:00.000Z"
}
```

With **includeReviews** on, each record also carries `reviews` (author, rating, date, text) and `reviewsScraped`.

Use the **Restaurants**, **Leads** and **Locations** dataset views to switch between column sets.

#### What to expect (field coverage)

With `includeDetails` on, across a market you can typically expect:

| Field | Coverage |
|---|---|
| name, market, cuisine, profile URL | ~100% |
| **phone**, full address, area, latitude/longitude, price band | ~95–100% |
| rating + review count | present for venues with ≥1 diner review (newly-listed venues have none) |
| menus, photos | present when the venue publishes them on Chope |
| reviews | present (opt-in) for venues that have diner reviews |
| restaurant's own website | not published by Chope (it keeps users on-platform) |

A blank field means Chope doesn't publish that value for that venue — not that scraping failed. Nothing is dropped, so you always get the richest record available.

### Monitoring mode — only new restaurants

Turn on **monitorMode** to make the actor remember which restaurants it has already returned and emit **only restaurants not seen in previous runs** — perfect for tracking new restaurant openings in a market. It stores seen restaurant ids in a named key-value store (`monitorStoreName`, one per tracked market).

This **complements [Apify Schedules](https://docs.apify.com/platform/schedules)** and does not conflict with them: Schedules decide *when* the actor runs (e.g. every morning), and monitoring mode decides *what is new* in each run. Use both together to get a daily feed of just-opened restaurants in your target markets.

### Automate & schedule

Run this actor on autopilot and pull results into your own stack:

- **[Apify API](https://docs.apify.com/api/v2)** — start runs, fetch datasets, and manage schedules over REST.
- **[apify-client for JavaScript](https://docs.apify.com/api/client/js/)** and **[apify-client for Python](https://docs.apify.com/api/client/python/)** — official SDKs.
- **[Schedules](https://docs.apify.com/platform/schedules)** — run it daily/weekly to monitor new restaurant openings or to refresh ratings and contacts.
- **[Webhooks](https://docs.apify.com/platform/integrations/webhooks)** — trigger downstream actions (CRM import, Slack alert, email sequence) the moment a run finishes.

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

const client = new ApifyClient({ token: 'MY_APIFY_TOKEN' });

const run = await client.actor('scrapesage/chope-scraper').call({
    countries: ['singapore'],
    maxResults: 200,
    includeDetails: true,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`Got ${items.length} restaurants`);
```

### Integrate with any app

Connect the dataset to 5,000+ apps — no code required:

- **[Make](https://docs.apify.com/platform/integrations/make)** — multi-step automation scenarios.
- **[Zapier](https://docs.apify.com/platform/integrations/zapier)** — push new restaurant leads straight into your CRM.
- **[Slack](https://docs.apify.com/platform/integrations/slack)** — get notified when a monitored market adds new restaurants.
- **[Google Drive / Sheets](https://docs.apify.com/platform/integrations/drive)** — auto-export every run to a spreadsheet.
- **[Airbyte](https://docs.apify.com/platform/integrations/airbyte)** — pipe results into your data warehouse.
- **[GitHub](https://docs.apify.com/platform/integrations/github)** — trigger runs from commits or releases.

### Use with AI assistants (MCP)

The output is clean, LLM-ready JSON. Call this actor from Claude, ChatGPT, or any agent framework through the **[Apify MCP server](https://docs.apify.com/platform/integrations/mcp)** — ask your assistant to "list every Chope restaurant in Singapore with phone and area" and let it run the scraper for you.

### More scrapers from scrapesage

Build a complete **restaurant & local-business lead-gen stack**:

- **[Resy Scraper](https://apify.com/scrapesage/resy-scraper)** — premium US restaurants, ratings, contacts and reservation availability.
- **[Burpple Scraper](https://apify.com/scrapesage/burpple-scraper)** — Singapore restaurant, cafe and hawker discovery with reviews.
- **[DoorDash Scraper](https://apify.com/scrapesage/doordash-scraper)** — restaurants, full menus and prices by city.
- **[UberEats Scraper](https://apify.com/scrapesage/ubereats-scraper)** — restaurants, menus and delivery data.
- **[Foodpanda Scraper](https://apify.com/scrapesage/foodpanda-scraper)** — restaurants and menus across Asia.
- **[Zomato Scraper](https://apify.com/scrapesage/zomato-scraper)** — restaurants, ratings and reviews.
- **[Google Maps Scraper](https://apify.com/scrapesage/google-maps-scraper)** — local businesses with phone, website and reviews.
- **[Website Contact Scraper](https://apify.com/scrapesage/website-contact-scraper)** — emails, phones and socials from any website.

### Tips

- **Whole-market coverage**: put the market in `countries` (e.g. `singapore`) and leave the filters empty to pull every restaurant in that market.
- **Cuisine by market**: combine `countries` with `cuisines` or `searchQueries` for the most precise targeting.
- **Cost control**: turn off `includeDetails` for a fast, cheap directory pass (name, cuisine, market, URL); turn it on to add phone, address, area, geo, rating, menus and photos.
- **Best leads first**: sort the dataset by `leadScore` to surface contactable, rated, well-located venues at the top.
- **Recurring monitoring**: combine [Schedules](https://docs.apify.com/platform/schedules) with `monitorMode` to capture only newly listed restaurants.

### FAQ

**How do I scrape every restaurant in a market?** Put the market in `countries` (e.g. `singapore`) and leave the filters empty. The actor reads Chope's full A-Z directory for that market.

**Does it need a Chope account or API key?** No. This actor reads Chope's own public restaurant pages — the same data the website shows — with no login, cookie or key.

**Where do the phone and address come from?** From the restaurant's own Chope profile page. Phone and full address are present on nearly every venue.

**Can I get the restaurant's own website?** Chope keeps users on-platform and does not publish a venue's external website on its profile, so that field is not available. Phone, address and area are.

**Can I get individual diner reviews?** Yes — turn on `includeReviews` to capture the visible reviews (author, star rating, date and full text). Chope also reports an aggregate rating and review count, which are always included with details.

**Which countries are supported?** Singapore (deepest coverage), Malaysia (Kuala Lumpur), Indonesia (Jakarta, Bali, Bandung, Surabaya) and Thailand (Bangkok, Phuket).

**Can I export to Google Sheets, CSV, or Excel?** Yes — one click in the dataset view, or automatically on every run via the [Google Drive integration](https://docs.apify.com/platform/integrations/drive).

**How do I monitor new restaurant openings?** Turn on `monitorMode` and create a [Schedule](https://docs.apify.com/platform/schedules); each run returns only restaurants not seen before. Add a [webhook](https://docs.apify.com/platform/integrations/webhooks) to push them into your CRM.

**Is scraping Chope legal?** This actor collects publicly available data only. You are responsible for using the data in compliance with applicable laws (e.g. PDPA/GDPR for personal data) and Chope's terms.

### Need help?

Open an issue on the actor's **Issues** tab, or visit the [Apify help center](https://help.apify.com/). Feature requests are welcome — this actor is actively maintained.

# Actor input Schema

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

Chope markets to scrape every restaurant in. Pick one or more: singapore, kuala-lumpur, bali, jakarta, bandung, surabaya, bangkok, phuket. Singapore is the flagship market with the deepest coverage. One per row.

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

Keep only restaurants whose name or cuisine matches one of these (case-insensitive), e.g. "italian", "steakhouse", "omakase", "Marriott". Each term is matched against every restaurant in the selected markets. Leave empty to get every restaurant. One per row.

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

Direct Chope restaurant URLs to scrape, e.g. https://www.chope.co/singapore-restaurants/restaurant/10-scotts . Scraped in addition to any selected markets. One per row.

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

Cap on restaurant records across the whole run.

## `includeDetails` (type: `boolean`):

Open each restaurant's Chope profile for the complete lead record: phone, full street address, area/neighbourhood, geo-coordinates, price band, rating + review count, menus and photos. One fast extra request per restaurant. Off = a quick, cheap directory pass (name, cuisine, market, profile URL only).

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

Also extract the visible diner reviews on each profile (author, star rating, date and full review text). Requires 'Enrich with full details'. No extra request — parsed from the same profile page.

## `maxReviews` (type: `integer`):

Upper bound on reviews captured per restaurant when 'Include diner reviews' is on.

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

Keep only restaurants whose cuisine matches one of these (case-insensitive substring, e.g. "japanese", "seafood", "bar"). Leave empty for all cuisines.

## `priceTiers` (type: `array`):

Keep only restaurants in these price bands: 1 = $, 2 = $$, 3 = $$$, 4 = $$$$. Requires 'Enrich with full details'. Leave empty for all.

## `areaFilter` (type: `array`):

Keep only restaurants in these areas (case-insensitive substring on Chope's area label, e.g. "orchard", "chinatown", "tanjong pagar"). Requires 'Enrich with full details'. Leave empty for all areas.

## `minRating` (type: `integer`):

Keep only restaurants with a Chope rating at or above this value (1–5). Requires 'Enrich with full details'. 0 = no filter.

## `deduplicate` (type: `boolean`):

Skip a restaurant already emitted earlier in the same run (common when scraping several markets at once).

## `monitorMode` (type: `boolean`):

Remember which restaurants were already returned and emit ONLY restaurants not seen in previous runs. Pairs with Apify Schedules to track new restaurant openings in a market over time (it does not conflict with Schedules — Schedules decide when to run, this decides what is new).

## `monitorStoreName` (type: `string`):

Named key-value store that holds the 'already seen' restaurant ids for monitoring mode. Use a different name per tracked market to keep histories separate.

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

Maximum parallel requests. Lower it if you see transient blocks; raise it for speed.

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

Proxy settings. Chope's public pages are read over standard Apify Proxy with automatic IP rotation; the default works well. Blocked requests retry automatically on a fresh IP.

## Actor input object example

```json
{
  "countries": [
    "singapore"
  ],
  "maxResults": 100,
  "includeDetails": true,
  "includeReviews": false,
  "maxReviews": 20,
  "priceTiers": [],
  "minRating": 0,
  "deduplicate": true,
  "monitorMode": false,
  "monitorStoreName": "chope-scraper-monitor",
  "maxConcurrency": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All scraped restaurant records in the default dataset. Switch between the Restaurants, Leads and Locations views to focus the columns.

# 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 = {
    "countries": [
        "singapore"
    ],
    "maxResults": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapesage/chope-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 = {
    "countries": ["singapore"],
    "maxResults": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("scrapesage/chope-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 '{
  "countries": [
    "singapore"
  ],
  "maxResults": 100
}' |
apify call scrapesage/chope-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Chope Scraper - Singapore & Asia Restaurant Leads",
        "description": "Scrape Chope restaurants across Singapore and Asia: name, phone, full address, area, cuisine, price band, ratings, geo, menus, photos and reviews. Turn dining venues into B2B leads. Export to JSON, CSV or Excel.",
        "version": "0.1",
        "x-build-id": "1BrKwRuG7hEhZB5r2"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/scrapesage~chope-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-scrapesage-chope-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/scrapesage~chope-scraper/runs": {
            "post": {
                "operationId": "runs-sync-scrapesage-chope-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/scrapesage~chope-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-scrapesage-chope-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": {
                    "countries": {
                        "title": "Markets (countries / cities)",
                        "type": "array",
                        "description": "Chope markets to scrape every restaurant in. Pick one or more: singapore, kuala-lumpur, bali, jakarta, bandung, surabaya, bangkok, phuket. Singapore is the flagship market with the deepest coverage. One per row.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "singapore",
                                "kuala-lumpur",
                                "bali",
                                "jakarta",
                                "bandung",
                                "surabaya",
                                "bangkok",
                                "phuket"
                            ],
                            "enumTitles": [
                                "Singapore",
                                "Kuala Lumpur (Malaysia)",
                                "Bali (Indonesia)",
                                "Jakarta (Indonesia)",
                                "Bandung (Indonesia)",
                                "Surabaya (Indonesia)",
                                "Bangkok (Thailand)",
                                "Phuket (Thailand)"
                            ]
                        },
                        "default": [
                            "singapore"
                        ]
                    },
                    "searchQueries": {
                        "title": "Search terms (optional)",
                        "type": "array",
                        "description": "Keep only restaurants whose name or cuisine matches one of these (case-insensitive), e.g. \"italian\", \"steakhouse\", \"omakase\", \"Marriott\". Each term is matched against every restaurant in the selected markets. Leave empty to get every restaurant. One per row.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "startUrls": {
                        "title": "Chope restaurant URLs (optional)",
                        "type": "array",
                        "description": "Direct Chope restaurant URLs to scrape, e.g. https://www.chope.co/singapore-restaurants/restaurant/10-scotts . Scraped in addition to any selected markets. One per row.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxResults": {
                        "title": "Max results (restaurants)",
                        "minimum": 1,
                        "maximum": 100000,
                        "type": "integer",
                        "description": "Cap on restaurant records across the whole run.",
                        "default": 100
                    },
                    "includeDetails": {
                        "title": "Enrich with full details (phone, address, geo, rating, menus, photos)",
                        "type": "boolean",
                        "description": "Open each restaurant's Chope profile for the complete lead record: phone, full street address, area/neighbourhood, geo-coordinates, price band, rating + review count, menus and photos. One fast extra request per restaurant. Off = a quick, cheap directory pass (name, cuisine, market, profile URL only).",
                        "default": true
                    },
                    "includeReviews": {
                        "title": "Include diner reviews",
                        "type": "boolean",
                        "description": "Also extract the visible diner reviews on each profile (author, star rating, date and full review text). Requires 'Enrich with full details'. No extra request — parsed from the same profile page.",
                        "default": false
                    },
                    "maxReviews": {
                        "title": "Max reviews per restaurant",
                        "minimum": 1,
                        "maximum": 100,
                        "type": "integer",
                        "description": "Upper bound on reviews captured per restaurant when 'Include diner reviews' is on.",
                        "default": 20
                    },
                    "cuisines": {
                        "title": "Cuisine filter (optional)",
                        "type": "array",
                        "description": "Keep only restaurants whose cuisine matches one of these (case-insensitive substring, e.g. \"japanese\", \"seafood\", \"bar\"). Leave empty for all cuisines.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "priceTiers": {
                        "title": "Price bands",
                        "type": "array",
                        "description": "Keep only restaurants in these price bands: 1 = $, 2 = $$, 3 = $$$, 4 = $$$$. Requires 'Enrich with full details'. Leave empty for all.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "1",
                                "2",
                                "3",
                                "4"
                            ],
                            "enumTitles": [
                                "$",
                                "$$",
                                "$$$",
                                "$$$$"
                            ]
                        },
                        "default": []
                    },
                    "areaFilter": {
                        "title": "Area / neighbourhood filter (optional)",
                        "type": "array",
                        "description": "Keep only restaurants in these areas (case-insensitive substring on Chope's area label, e.g. \"orchard\", \"chinatown\", \"tanjong pagar\"). Requires 'Enrich with full details'. Leave empty for all areas.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "minRating": {
                        "title": "Minimum rating",
                        "minimum": 0,
                        "maximum": 5,
                        "type": "integer",
                        "description": "Keep only restaurants with a Chope rating at or above this value (1–5). Requires 'Enrich with full details'. 0 = no filter.",
                        "default": 0
                    },
                    "deduplicate": {
                        "title": "Deduplicate restaurants",
                        "type": "boolean",
                        "description": "Skip a restaurant already emitted earlier in the same run (common when scraping several markets at once).",
                        "default": true
                    },
                    "monitorMode": {
                        "title": "Monitoring mode — only new restaurants",
                        "type": "boolean",
                        "description": "Remember which restaurants were already returned and emit ONLY restaurants not seen in previous runs. Pairs with Apify Schedules to track new restaurant openings in a market over time (it does not conflict with Schedules — Schedules decide when to run, this decides what is new).",
                        "default": false
                    },
                    "monitorStoreName": {
                        "title": "Monitor store name",
                        "type": "string",
                        "description": "Named key-value store that holds the 'already seen' restaurant ids for monitoring mode. Use a different name per tracked market to keep histories separate.",
                        "default": "chope-scraper-monitor"
                    },
                    "maxConcurrency": {
                        "title": "Max concurrency",
                        "minimum": 1,
                        "maximum": 20,
                        "type": "integer",
                        "description": "Maximum parallel requests. Lower it if you see transient blocks; raise it for speed.",
                        "default": 10
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Proxy settings. Chope's public pages are read over standard Apify Proxy with automatic IP rotation; the default works well. Blocked requests retry automatically on a fresh IP.",
                        "default": {
                            "useApifyProxy": true
                        }
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
