# Clover Menu Scraper: Restaurant Menus, Prices & Store Leads (`yugenox/clover-menu-scraper`) Actor

Scrape restaurant menus and store details from Clover online ordering: exact prices, modifiers, photos, availability, hours, delivery fees. Find Clover restaurants by city, state, ZIP or name across 14,000+ US and Canadian stores. No login.

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

## Pricing

from $10.00 / 1,000 store with 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?

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

## Clover Menu Scraper: Restaurant Menus, Prices & Store Leads

Scrape the **exact menus, prices and store details** of restaurants, cafés, bakeries and shops that take online orders through **Clover** (the Fiserv point-of-sale used by hundreds of thousands of US and Canadian merchants).

Give it Clover ordering links, **or just a city, state, ZIP code or keyword**, and it returns:

- 🍔 **Full menus**: every category and item with the store's **real price** (to the cent), description, photos, availability and stock count
- 🧩 **Modifiers**: option groups like sizes, toppings and sides, with min/max selections and add-on prices
- 🏪 **Store details**: name, address, phone, time zone, logo, website, and which order types are live (pickup, delivery, curbside, dine-in)
- 🕒 **Hours & status**: hours per order type, store hours, open-now, lead time, scheduled-ordering window
- 🚚 **Delivery terms**: delivery fee, delivery minimum, free-delivery threshold, tipping options
- 📊 **Menu summary**: item and category counts, min / median / max price

No login, no cookies, no browser. The data comes straight from each store's own Clover online-ordering page, so prices are exactly what the customer pays at checkout (before tax). They are not estimates read off a photo of a menu.

### Who uses it

- **Restaurant tech & POS sales teams**: build lists of businesses running Clover in any city, with phone, address, website and whether they take online orders.
- **Delivery, marketing and loyalty agencies**: find independent restaurants with online ordering switched off, or with no delivery, and pitch them.
- **Market & pricing research**: compare burrito, pizza or bubble-tea prices across hundreds of stores; track menu price changes over time with scheduled runs.
- **Food apps & aggregators**: import structured menus (categories, items, modifiers, photos) without typing them in.
- **Consumer-goods brands and distributors**: see which stores list your products and at what price.

### How to use

#### Option 1: Paste store links

```json
{
  "startUrls": [
    "https://www.clover.com/online-ordering/bnk-bao-toronto",
    "https://loadedfusion.cloveronline.com"
  ]
}
```

Any of these work: `https://www.clover.com/online-ordering/<store>`, `https://<store>.cloveronline.com`, the bare store slug (`bnk-bao-toronto`), or a 13-character Clover merchant ID.

#### Option 2: Search by location and/or name

```json
{
  "cities": ["Houston, TX"],
  "searchTerms": ["taco", "taqueria"],
  "maxMerchants": 100
}
```

Location search uses a directory of **about 14,600 live Clover online-ordering stores** (13,500 US, 1,100 Canada) built from public web archives and refreshed regularly. Filters combine: `cities`, `states` (codes or names), `postalCodes` (prefixes such as `770` or `M5V`), `country`, and `searchTerms` (words in the store name).

**Paging a big area:** run with `maxMerchants: 200`. When more stores match, the run's status message ends with *"set skipMerchants to N to continue"*; run again with that exact `skipMerchants`. Pages never skip a store (closed stores in the directory are why N can be larger than 200). A run stopped by its time limit may finish a few stores out of order; its message says how many the next page will repeat.

#### Output formats

| `outputMode` | One row per | Best for |
|---|---|---|
| `merchants` (default) | store, with the full menu nested inside | apps, JSON pipelines |
| `items` | menu item, with store columns on every row | spreadsheets, price comparison |
| `leads` | store, details only (no menu) | sales prospecting; fastest and cheapest |

### Output example (`merchants`, trimmed)

```json
{
  "merchantId": "VAX0D5NW9X3D1",
  "slug": "bnk-bao-toronto",
  "name": "Bảnk Bao",
  "orderingUrl": "https://www.clover.com/online-ordering/bnk-bao-toronto",
  "phone": "+14165859097",
  "address": "375 SPADINA AVE",
  "city": "Toronto",
  "state": "ON",
  "postalCode": "M5T 2G3",
  "country": "CA",
  "currency": "CAD",
  "timezone": "America/Toronto",
  "isOrderingEnabled": true,
  "orderTypes": ["DINE_IN", "PICKUP"],
  "openNow": true,
  "services": [
    { "type": "PICKUP", "enabled": true, "openNow": true,
      "hours": { "monday": ["11:00-21:00"], "friday": ["11:00-21:30"], "sunday": ["11:30-21:00"] } }
  ],
  "leadTimeMinutes": 10,
  "scheduledOrderingMaxDays": 3,
  "tipSuggestions": [25, 20, 15, 12],
  "menuAvailable": true,
  "categoryCount": 5,
  "itemCount": 59,
  "priceMin": 2.5,
  "priceMedian": 8.95,
  "priceMax": 35,
  "menu": [
    {
      "name": "Baos",
      "sortOrder": 0,
      "items": [
        {
          "id": "88HGCT98QJQ3G",
          "name": "Ebi Shrimp Bao",
          "description": "Crispy breaded shrimp with spicy mayo and hot honey glaze / red pickled cabbage/ lettuce / cilantro.",
          "price": 8.95,
          "available": true,
          "stock": null,
          "imageUrl": "https://cloverstatic.com/menu-assets/items/88HGCT98QJQ3G_576x576.jpeg",
          "modifierGroups": []
        }
      ]
    }
  ],
  "scrapedAt": "2026-09-24T06:00:00.000Z"
}
```

A modifier group looks like `{ "name": "Choose a size", "minRequired": 1, "maxAllowed": 1, "modifiers": [{ "name": "Large", "price": 2.0, "available": true }] }`. `maxAllowed: null` means unlimited.

Prices are in the store's currency (`currency`: USD, CAD…), as decimals.

### Good to know

- **Closed or mistyped stores** are skipped and not charged. The run's status message and the `RUN_REPORT` record in the run's key-value store list them.
- **Stores with online ordering switched off** still return their last published menu, flagged `menuMayBeStale: true`. Use `onlyOrderingEnabled` to skip them.
- **Stores with no menu published** come back with `menuAvailable: false` and `itemCount: 0`.
- **Menus don't page**: each store's whole menu arrives in one request, even 1,700-item grocery catalogs.
- **Very large catalogs in `merchants` mode**: a dataset row is capped at 9 MB. If a store's nested menu would exceed that, its modifier groups are listed once on the store (`modifierGroups`, items get `modifierGroupIds`, `menuCompacted: true`); in the rare case it is still too big, whole categories are kept while they fit (`menuTruncated: true`). `items` mode never truncates.
- **Billing**: `merchant-with-menu` per store saved with a menu (in `items` mode, one per started block of 200 item rows, so a typical 80-item restaurant is one event); `merchant` per store saved without a menu (`leads` mode, or no menu published); plus the small per-run start fee shown on the Pricing tab. Closed, not-found, filtered-out stores and failed menu loads are free.
- **Runs never fail on you**: a bad link, a closed store, a short timeout or a Clover hiccup ends the run as *Succeeded* with whatever was saved and a plain status message saying what happened and what to change. If your timeout is too short for even one store, the message says so (60 s is plenty for a few stores).
- **Coverage**: menus come from Clover's online-ordering service and work for stores on both the classic Clover ordering pages and the newer `cloveronline.com` sites. Stores that opened very recently may not be in the location directory yet; paste their link directly.
- The location directory covers stores that use Clover **online ordering**, not every business with a Clover terminal.

### FAQ

**Do I need a Clover account or API key?** No. No login needed: no Clover account, cookie, API key or browser. Datacenter proxies are enough (the free automatic Apify Proxy group works).

**Is it legal to scrape Clover menus?** This actor collects only publicly available information that each store publishes on its own Clover online-ordering page for any visitor, without logging in: the store's name, business address and phone, hours, ordering options and its menu with prices. It does not collect information about individual people (no customers, orders, owners or reviews). Scraping public data is generally lawful, but how you use the results is up to you: follow the laws that apply to you (for example GDPR, PIPEDA or CCPA) and Clover's terms, and check with a lawyer if you are unsure. Apify's guide is a good starting point: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

**Does it access any private data?** No. It reads only the public ordering pages' data. It never touches carts, checkout, payments, customer accounts or anything behind a login.

**How fast is it?** About 2–10 seconds per store with the default 10 in parallel, so 100 stores with full menus take roughly 1–2 minutes. `leads` mode is faster.

**Can I monitor price changes?** Yes. Schedule the actor daily or weekly with the same stores, then compare `price` by `merchantId` + item `id`, which are stable Clover IDs.

**Which countries?** Mostly the United States and Canada, plus other countries where Clover online ordering is used. Filter with `country`.

**Is tax included in prices?** No. Prices are menu prices before tax and tip, exactly as listed by the store.

# Actor input Schema

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

Clover online-ordering links: https://www.clover.com/online-ordering/<store>, https://<store>.cloveronline.com, a bare store slug (bnk-bao-toronto) or a 13-character Clover merchant ID. Leave empty to search by location below.

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

Find Clover stores in these cities, e.g. "Toronto", "Houston, TX", "London, ON". Add the state/province after a comma to avoid same-name cities.

## `states` (type: `array`):

Two-letter codes or full names: TX, Ontario, BC, New York…

## `postalCodes` (type: `array`):

Match the start of the store's ZIP or postal code: "770" (Houston area), "M5" (downtown Toronto), "10001".

## `country` (type: `string`):

Limit the location search to one country.

## `searchTerms` (type: `array`):

Keep stores whose name contains any of these words, e.g. pizza, sushi, bakery, taqueria. Works alone (nationwide) or with the location filters.

## `skipMerchants` (type: `integer`):

Page through a large location: when a run ends with "set skipMerchants to N to continue", run again with that N.

## `maxMerchants` (type: `integer`):

Maximum number of stores to save in this run. Stores that are closed or not found don't count.

## `outputMode` (type: `string`):

Stores with menus: one row per store, full menu nested inside. Menu items: one flat row per item (with store columns), ideal for spreadsheets and price comparison. Store leads: store details only (address, phone, hours, ordering status, website), no menu, fastest and cheapest.

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

Add each item's option groups (sizes, toppings, sides) with min/max selections and add-on prices.

## `includeImages` (type: `boolean`):

Add photo URLs (square 576px and large 1500px) for items that have them.

## `includeExtraDetails` (type: `boolean`):

One extra lookup per store: opening hours (when published), the store's Clover website, and the official country and currency.

## `onlyOrderingEnabled` (type: `boolean`):

Skip stores that have switched online ordering off (their menus may be out of date).

## `onlyAvailableItems` (type: `boolean`):

Leave out items the store marked unavailable.

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

How many stores to fetch at once.

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

Apify Proxy is required. Datacenter proxies work and are the cheapest; the run switches to residential automatically if needed.

## `mode` (type: `string`):

Internal maintenance mode.

## `refreshConcurrency` (type: `integer`):

Internal.

## `refreshMaxRefs` (type: `integer`):

Internal.

## `publish` (type: `boolean`):

Internal.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.clover.com/online-ordering/bnk-bao-toronto",
    "https://www.clover.com/online-ordering/mi-taco-taqueria-houston",
    "https://loadedfusion.cloveronline.com"
  ],
  "country": "any",
  "skipMerchants": 0,
  "maxMerchants": 50,
  "outputMode": "merchants",
  "includeModifiers": true,
  "includeImages": true,
  "includeExtraDetails": true,
  "onlyOrderingEnabled": false,
  "onlyAvailableItems": false,
  "maxConcurrency": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Stores and menus scraped in this run.

## `summary` (type: `string`):

Status message, counts, stores not found or closed, directory paging info and HTTP stats.

# 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": [
        "https://www.clover.com/online-ordering/bnk-bao-toronto",
        "https://www.clover.com/online-ordering/mi-taco-taqueria-houston",
        "https://loadedfusion.cloveronline.com"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("yugenox/clover-menu-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": [
        "https://www.clover.com/online-ordering/bnk-bao-toronto",
        "https://www.clover.com/online-ordering/mi-taco-taqueria-houston",
        "https://loadedfusion.cloveronline.com",
    ],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("yugenox/clover-menu-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": [
    "https://www.clover.com/online-ordering/bnk-bao-toronto",
    "https://www.clover.com/online-ordering/mi-taco-taqueria-houston",
    "https://loadedfusion.cloveronline.com"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call yugenox/clover-menu-scraper --silent --output-dataset

```

## MCP server setup

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