# SkipTheDishes Scraper — Restaurants, Menus, Prices & Offers (`yugenox/skipthedishes-scraper`) Actor

Scrape SkipTheDishes across Canada — every restaurant in a city (open and closed), full menus with prices, item options, delivery fees by address, offers, phone numbers, addresses, hours and grocery/convenience/liquor store catalogs. No login.

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

## Pricing

from $2.00 / 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.

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

## SkipTheDishes Scraper — Restaurants, Menus, Prices & Offers

Scrape **SkipTheDishes**, Canada's food delivery app, city by city. You get every restaurant and store in a city (open and closed), full menus with prices, item options, delivery fees for a specific address, active offers, and restaurant phone numbers, addresses and ordering hours. It also covers grocery, convenience and liquor store catalogs.

No SkipTheDishes account or login is needed. It runs on plain HTTP requests (no browser), so it's fast: Toronto's full list of ~5,000 restaurants takes under 15 seconds.

### What you can scrape

| Input | What you get |
|---|---|
| **A city** (`Toronto`, `Vancouver`, `Montréal`, `St. John's`…) | Every restaurant and store listed there, open and closed: name, cuisines, Skip score, delivery time, street and coordinates, image and offers |
| **A province** (`ON`, `BC`, `QC`…) or **`all`** | Every city in that province, or all ~180 SkipTheDishes cities in Canada, de-duplicated |
| **A delivery location** (`43.6532, -79.3832`) | Only the restaurants that deliver to that spot, with the **live delivery fee** (including "free over $X" tiers), **order minimum**, **distance** and **delivery time** for that address |
| **Restaurant URLs** | Details and menus for exactly those restaurants |
| **A dish** (`butter chicken`, `poutine`, `pho`) | Only the restaurants whose menu has that dish (SkipTheDishes' dish search covers restaurants open at run time) |

Optional add-ons:

- **Restaurant details** add:
  - the full address with postal code
  - the phone number
  - a rating out of 10
  - whether it's open now, and when it next opens
  - today's ordering hours
  - the delivery-time range
  - every active offer: the free item and its order minimum, BOGO items, and "$X off orders over $Y"
- **Full menus** give every item with its price (CAD), description, image, availability and a *popular* flag. Grocery, convenience and liquor stores return their whole product catalog instead, with size, sold-by-weight and estimated-price flags. A 7-Eleven, for example, has 1,000+ products.
- **Item options** give each item's option groups, such as "Choose a size" or "Add toppings". Each group has its minimum and maximum picks and the price of every option.

### Use cases

- **Menu price monitoring.** Track what restaurants and chains charge on delivery, compare prices across cities, and watch price changes over time.
- **Delivery fee research.** Compare delivery fees, order minimums and delivery times by neighbourhood or postal-code area.
- **Restaurant lead generation.** Build lists of Canadian restaurants with their phone number, street address, postal code, cuisine and rating, for POS, marketing, supplier and local-services sales.
- **Market research.** Measure cuisine mix, chain footprint, new openings (`isNew`), sponsored placements and how common deals are in any Canadian city.
- **Competitor analysis.** Pull every location of a chain and its menu, or find everyone who sells a dish in your area.
- **Retail and liquor pricing.** Get convenience, grocery and beer/wine/spirits store catalogs with prices.

### Input examples

**All restaurants in two cities, list only (fastest):**

```json
{ "cities": ["Toronto", "Calgary"] }
```

**Restaurants delivering to an address, with fees, open now, with a deal:**

```json
{ "location": "43.6532, -79.3832", "includeClosed": false, "onlyWithOffers": true }
```

**Who sells poutine in Montréal, with phone numbers and menus:**

```json
{ "cities": ["Montréal"], "dishQuery": "poutine", "includeDetails": true, "includeMenus": true }
```

**Menus of specific restaurants as a flat item table:**

```json
{
  "restaurantUrls": ["https://www.skipthedishes.com/asian-gourmet-dundas-street-east"],
  "outputFormat": "menuItems",
  "includeModifiers": true
}
```

**A sample of every city in Ontario:**

```json
{ "cities": ["ON"], "maxRestaurantsPerCity": 20, "restaurantTypes": ["FULL_SERVICE"] }
```

### Output

One row per restaurant (menu nested), or one row per menu item with `"outputFormat": "menuItems"`. All prices are in **Canadian dollars**. This row is shortened:

```json
{
  "id": "bca27578-d0ce-4d02-88b3-07cdeef8e125",
  "name": "4 Brothers Pizza",
  "url": "https://www.skipthedishes.com/4-brothers-pizza-commercial-dr",
  "type": "FULL_SERVICE",
  "cuisines": ["Pizza", "American", "Canadian", "Fast Food"],
  "isOpen": true,
  "skipScore": 83,
  "rating": 8.3,
  "estimatedDeliveryMinutes": 19,
  "street": "1914 Commercial Dr",
  "city": "Vancouver",
  "province": "BC",
  "postalCode": "V5L 3Y4",
  "fullAddress": "1914 Commercial Dr, Vancouver, BC, V5L 3Y4",
  "phone": "(604) 215-0111",
  "phoneE164": "+16042150111",
  "latitude": 49.2674196,
  "longitude": -123.0694239,
  "timeZone": "America/Vancouver",
  "etaMinMinutes": 24,
  "etaMaxMinutes": 34,
  "orderingHours": [{ "opens": "2026-09-23T17:00:07Z", "closes": "2026-09-24T06:35:07Z", "local": "Wed 10:00 – Wed 23:35" }],
  "offers": [{ "type": "bogo", "orderMinimum": null }],
  "offerDetails": {
    "bogoItems": [{ "item": "Cheesey Garlic Bread (10 pcs)", "itemPrice": 8.95 }],
    "freeItems": [],
    "flatDiscounts": []
  },
  "menuType": "menu",
  "menuItemCount": 237,
  "menu": [
    {
      "category": "Deals",
      "items": [
        { "id": "8ab48ab5-…", "name": "Deal 2 - Everyday Value Pack - Large Four-Topping Pizza", "price": 17.99,
          "description": "One order comes with a large pizza with your choice of four toppings.", "available": true, "popular": false }
      ]
    }
  ],
  "scrapedAt": "2026-09-24T05:20:05.636Z"
}
```

In **location mode**, each row also carries the live delivery pricing for that address:

```json
{ "name": "Pizza St Laurent", "deliveryFee": 3, "orderMinimum": 0,
  "deliveryFeeTiers": [{ "fee": 3, "orderMinimum": 0 }], "distanceKm": 1.08, "estimatedDeliveryMinutes": 21 }
```

#### Field notes

- `type` is one of:
  - `FULL_SERVICE` (restaurant)
  - `QUICK_SERVICE` (fast food)
  - `GROCERY` (grocery and bakery)
  - `CONVENIENCE_STORE`
  - `ALCOHOL` (liquor and beer stores)
- `skipScore` is SkipTheDishes' 0–100 score. `rating` is the same score out of 10, as shown in the app.
- `deliveryFee`, `orderMinimum`, `deliveryFeeTiers` and `distanceKm` are filled only when you give a delivery `location`. City-wide lists have no single address to price against.
- `deliveryFeeTiers` lists every fee tier. For example, `[{fee: 1.79, orderMinimum: 0}, {fee: 0, orderMinimum: 20}]` means $1.79 delivery, free on orders over $20.
- `isOpen` shows whether the restaurant is taking orders at run time. The details add-on also gives:
  - `closedReason`
  - `opensAt`, the next opening time
  - `orderingHours`, in UTC plus the restaurant's local time
- `phone` is the phone number the restaurant publishes on SkipTheDishes for allergy questions. A few restaurants don't publish one.
- `popular: true` marks the items SkipTheDishes lists under "Popular Items". Each item appears only once, in its real category.
- `menuType` is `menu` for restaurants and `retailCatalog` for grocery, convenience and liquor stores. Catalog products add `size`, `soldBy` (`SOLD_BY_EACH` / `SOLD_BY_WEIGHT`) and `isPriceEstimated`.
- `menuTruncated` / `modifiersDropped` appear only on the rare row that would exceed Apify's 9 MB item limit (a huge menu with every option group). Use the "One row per menu item" output to get such a menu in full.

### FAQ

**Do I need an account, a login or cookies?** No login needed. The actor reads the same public restaurant lists, menus and store details anyone sees on SkipTheDishes without signing in. No SkipTheDishes account, cookies or API key.

**Is it legal to scrape SkipTheDishes?** This Actor only collects publicly available business data: restaurant and store listings, menus and prices, fees, offers, opening hours, addresses and the phone numbers restaurants publish for customers. It never collects data about people: no customer accounts, no order history, no reviews or reviewer names. Collecting publicly available data is generally legal, but you're responsible for how you use it. You must follow SkipTheDishes' terms and the privacy and anti-spam laws that apply to you (for example PIPEDA and CASL in Canada) — especially before contacting businesses with the phone numbers. If you're unsure, check with a lawyer. More on this: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

**Does it access any private data?** No. It never logs in and never queries customer or order data. It also never gets around SkipTheDishes' bot protection: if SkipTheDishes refuses requests, the run stops early, keeps what it saved, ends successfully and says so in the status message.

**How many restaurants can I get?** A city returns its entire list at once: Toronto has ~5,000, Vancouver ~2,400, Calgary ~2,600 and Winnipeg ~1,200. The lists of neighbouring cities overlap, and duplicates across cities are removed automatically.

**Why are most restaurants "closed"?** Restaurants are only "open" during their ordering hours. Run the scraper during lunch or dinner for more open restaurants, or turn off **Include restaurants that are closed right now** to keep only the open ones.

**How fast is it?** A city list takes 2–15 seconds. With details and full menus, it handles about 60 restaurants (20,000+ menu items) in roughly 10 seconds at the default concurrency.

**Do I need a residential proxy?** No. The default automatic Apify Proxy (datacenter, included in every Apify plan) works. If a request is refused, the scraper retries on a fresh IP; if SkipTheDishes keeps refusing, the run stops early with what it has.

**What if my timeout is short?** The run stops a little before its timeout, keeps everything it saved and ends successfully. If the timeout was too short to get anything, the status message says what to set (120 s is plenty for a city list). A short summary of every run is saved as `RUN_REPORT` in the run's key-value store.

**What does it cost?** You pay per restaurant row, per menu item and per store product delivered, plus a small fee when a run starts. A run that finds nothing saves nothing.

**Is it in French?** Menus come back exactly as each restaurant wrote them, so Québec restaurants are often bilingual.

**What if a city isn't found?** The log suggests close matches. Use a two-letter province code or `all` to see every city SkipTheDishes serves.

**Can I get reviews?** SkipTheDishes doesn't publish written reviews. The Skip score and rating are its only public rating signals, and both are included.

### Tips

- Leave the add-ons off to get just the restaurant list: it's one request per city and the cheapest way to cover a region.
- Use **Max restaurants per city** with `all` or a province to get a balanced sample across Canada.
- **Item options** make one request per menu item, so pair them with **Max menu items per restaurant**.
- Schedule the actor daily or weekly to track menu prices, deals and new restaurants over time.

# Actor input Schema

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

SkipTheDishes cities to scrape, e.g. "Toronto", "Vancouver", "Montréal", "St. John's". A two-letter province code ("ON", "BC", "QC"…) adds every city in that province, and "all" adds all ~180 cities in Canada. Each city returns every restaurant and store that delivers there — open and closed.

## `location` (type: `string`):

Optional. Coordinates of an address, e.g. "43.6532, -79.3832". Returns only the restaurants that deliver to that spot, with the live delivery fee, order minimum, distance and delivery time for that address.

## `restaurantUrls` (type: `array`):

Optional. SkipTheDishes restaurant or store pages, e.g. https://www.skipthedishes.com/asian-gourmet-dundas-street-east (or just the last part of the URL). Returns details and menus for exactly these.

## `dishQuery` (type: `string`):

Optional. Keep only restaurants whose menu has this dish, e.g. "butter chicken", "poutine", "pho". Works with cities and with a delivery location. Uses SkipTheDishes' own dish search, which only covers restaurants open at run time (closed ones are never matched).

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

Full street address with postal code, phone number, rating out of 10, open now / next opening time, today's ordering hours, delivery time range and every active offer (free items, BOGO, $ off). One extra request per restaurant.

## `includeMenus` (type: `boolean`):

Every menu item with price, description, image, availability and a popular flag. Grocery, convenience and liquor stores return their full product catalog (sizes, sold-by-weight, estimated prices).

## `includeModifiers` (type: `boolean`):

For each menu item, its option groups (e.g. "Choose a size", "Add toppings") with minimum/maximum picks and the price of each option. One extra request per menu item — combine with "Max items per restaurant" to keep runs fast.

## `outputFormat` (type: `string`):

"One row per restaurant" nests the menu inside each restaurant. "One row per menu item" gives a flat table of items with the restaurant name, city and URL on every row (menus are turned on automatically).

## `restaurantTypes` (type: `array`):

Optional. Keep only these kinds of stores. Leave empty for all.

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

Optional. Keep only restaurants tagged with one of these cuisines, e.g. "Pizza", "Indian", "Sushi", "Vegan" (partial, case-insensitive match).

## `includeClosed` (type: `boolean`):

Most restaurants are closed outside business hours. Turn off to get only the ones taking orders at run time.

## `onlyWithOffers` (type: `boolean`):

Keep only restaurants running a deal right now (free item, buy-one-get-one, or $ off).

## `orderType` (type: `string`):

Delivery or pickup — changes which restaurants are listed and menu prices where they differ.

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

Stop after this many restaurants in total. Leave empty for no limit (Toronto alone has ~5,000).

## `maxRestaurantsPerCity` (type: `integer`):

Optional cap per city — useful with many cities or "all".

## `maxItemsPerRestaurant` (type: `integer`):

Optional cap on menu items (or store products) per restaurant. Leave empty for the full menu.

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

Parallel requests. The default is fast and gentle; higher values only help for large menu jobs.

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

Apify Proxy is required. The default (automatic) works — no residential proxy needed.

## Actor input object example

```json
{
  "cities": [
    "Winnipeg"
  ],
  "includeDetails": true,
  "includeMenus": true,
  "includeModifiers": false,
  "outputFormat": "restaurants",
  "restaurantTypes": [
    "FULL_SERVICE",
    "QUICK_SERVICE"
  ],
  "includeClosed": true,
  "onlyWithOffers": false,
  "orderType": "DELIVERY",
  "maxRestaurants": 5,
  "maxConcurrency": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

All scraped restaurants, stores and menu items.

## `run` (type: `string`):

Status and statistics for this run.

# 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": [
        "Winnipeg"
    ],
    "includeDetails": true,
    "includeMenus": true,
    "restaurantTypes": [
        "FULL_SERVICE",
        "QUICK_SERVICE"
    ],
    "maxRestaurants": 5,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("yugenox/skipthedishes-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": ["Winnipeg"],
    "includeDetails": True,
    "includeMenus": True,
    "restaurantTypes": [
        "FULL_SERVICE",
        "QUICK_SERVICE",
    ],
    "maxRestaurants": 5,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("yugenox/skipthedishes-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": [
    "Winnipeg"
  ],
  "includeDetails": true,
  "includeMenus": true,
  "restaurantTypes": [
    "FULL_SERVICE",
    "QUICK_SERVICE"
  ],
  "maxRestaurants": 5,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call yugenox/skipthedishes-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yugenox/skipthedishes-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/YiJKYZ0nePxfgRwUw/builds/1OxwrAKzhVXxaeVkv/openapi.json
