# iFood Scraper — Anti-Block: Menus, Prices & Reviews (`scrapepilot/ifood-scraper-anti-block-menus-prices-reviews`) Actor

iFood scraper with URL enrichment and Google SERP discovery. Extract restaurants, menus with prices, reviews and ratings. Pass URLs directly OR search by city. Start FREE.

- **URL**: https://apify.com/scrapepilot/ifood-scraper-anti-block-menus-prices-reviews.md
- **Developed by:** [Scrape Pilot](https://apify.com/scrapepilot) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $15.00 / 1,000 scraped restaurant & menus

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## 🍔 iFood Scraper — Menus, Prices & Restaurant Data (Brazil)

> **Extract restaurant listings, menu items with prices, and delivery details from iFood Brazil** — by direct URL or by Google-powered keyword discovery. Anti-blocking built in with residential proxy rotation and stealth browser fallback. Structured JSON output, ready for CSV/Excel export.

***

### 📌 Table of Contents

- [What Is This Actor?](#what-is-this-actor)
- [How Extraction Works (Please Read)](#how-extraction-works-please-read)
- [Use Cases](#use-cases)
- [Input Parameters](#input-parameters)
- [Output Fields](#output-fields)
- [Example Output](#example-output)
- [Pricing](#pricing)
- [Performance & Limits](#performance--limits)
- [FAQ](#faq)
- [Legal & Terms of Use](#legal--terms-of-use)

***

### 🔍 What Is This Actor?

**iFood Scraper** pulls public restaurant data from [ifood.com.br](https://www.ifood.com.br) — either from a list of direct restaurant URLs you provide, or by discovering restaurants through Google search for a keyword + city combination.

For each restaurant it returns a structured record: name, category, rating, delivery time/fee, minimum order value, and — when requested — the full menu with item names, descriptions, and prices, plus basic price-intelligence stats (cheapest item, most expensive item, average menu price).

***

### ⚠️ How Extraction Works (Please Read)

This actor uses a layered approach to get around iFood's anti-bot measures:

1. **Direct HTTP request** with browser TLS fingerprinting (fastest, works when unblocked)
2. **Stealth headless browser fallback** if the direct request is blocked or returns no catalog data
3. **Estimated fallback values** if *both* of the above fail to return certain fields

Because iFood does not always expose every field (rating, review counts, delivery time/fee) through public endpoints, and because live scraping can be blocked despite anti-blocking measures, **some fields may be filled with reasonable estimated values rather than freshly scraped ones** when live extraction is incomplete. Every record includes a `menuExtractionStatus` field so you can see which extraction path was used for that specific run.

We're flagging this openly rather than presenting estimated fields as guaranteed live data. If your use case requires that every field be verified live (e.g. compliance, legal evidence, or pricing audits), we recommend spot-checking a sample of results against the live iFood page before relying on the dataset at scale.

***

### 🎯 Use Cases

#### 📊 Menu & Pricing Research

- Compare menu prices across restaurants, chains, or cuisine categories
- Track how a competitor's menu or pricing changes over time (with periodic re-runs)
- Build a price-benchmarking dataset for a specific city or neighborhood

#### 🤖 Datasets for AI / Analytics

- Collect restaurant and menu text for NLP, categorization, or recommendation models
- Build training data for food-delivery price prediction or demand modeling

#### 🛠️ Developer & Business Integrations

- Feed restaurant/menu data into an internal dashboard or monitoring tool
- Automate periodic snapshots of specific restaurants you track

#### 🎓 Academic & Market Research

- Study menu structure, pricing patterns, or delivery economics across restaurant categories in Brazil

***

### ⚙️ Input Parameters

```json
{
  "mode": "both",
  "restaurantUrls": [
    "https://www.ifood.com.br/delivery/sao-paulo-sp/example-restaurant/uuid-here"
  ],
  "city": "sao-paulo-sp",
  "query": "hamburgueria",
  "maxRestaurants": 3,
  "includeMenu": true,
  "includeReviews": false,
  "menuMode": "limited",
  "maxMenuItems": 50,
  "downloadImages": false
}
```

| Parameter | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `"both"` | `"direct_urls"`, `"google_serp"`, or `"both"` |
| `restaurantUrls` | array | `[]` | Direct iFood restaurant URLs to scrape |
| `city` | string | `"sao-paulo-sp"` | City slug used for Google SERP discovery |
| `query` | string | `""` | Keyword to combine with city for discovery mode |
| `maxRestaurants` | integer | `3` | Max restaurants to extract in this run |
| `includeMenu` | boolean | `true` | Whether to extract menu items |
| `includeReviews` | boolean | `false` | Whether to include a review sample (see note below) |
| `menuMode` | string | `"limited"` | `"limited"` (capped, supports image download) or `"all"` |
| `maxMenuItems` | integer | `50` | Cap on menu items per restaurant in `limited` mode |
| `downloadImages` | boolean | `false` | Download menu item images to key-value store (not compatible with `menuMode: "all"`) |

> **Note on `includeReviews`:** this currently returns a single illustrative sample entry rather than real scraped customer reviews. Live review scraping is not yet implemented — don't rely on this field for actual review content or sentiment analysis yet.

***

### 📋 Output Fields

| Field | Type | Description |
|---|---|---|
| `name` | string | Restaurant name |
| `category` | string | Cuisine category (detected or scraped) |
| `city`, `slug`, `uuid`, `url` | string | Identifiers and canonical URL |
| `rating` | float | Restaurant rating — live if available, otherwise estimated |
| `reviewsCount` | integer | Review count — live if available, otherwise estimated |
| `deliveryTime` | string | Estimated delivery window |
| `deliveryFee` | float/null | Delivery fee in BRL |
| `minimumOrderValue` | float | Minimum order value in BRL |
| `distance` | string | Distance from reference address |
| `menu` | array | Menu items (id, section, name, details, price, imageUrl) |
| `menuExtractionStatus` | string | How the data was obtained for this record — check this field to gauge data freshness |
| `menuCompletenessStatus` | string | Whether the menu is complete or capped by `maxMenuItems` |
| `menuItemsDiscovered` / `menuItemsReturned` | integer | How many items were found vs. returned |
| `topMenuItems`, `cheapestItem`, `cheapestPrice`, `mostExpensiveItem`, `mostExpensivePrice`, `avgMenuPrice` | — | Simple price-intelligence stats computed from the returned menu |
| `scrapedAt` | string | ISO 8601 timestamp of extraction |

***

### 📦 Example Output

```json
{
  "name": "Example Restaurant",
  "category": "Lanches",
  "rating": 4.6,
  "reviewsCount": 3200,
  "deliveryTime": "30-40 min",
  "deliveryFee": 6.99,
  "minimumOrderValue": 15.0,
  "menuExtractionStatus": "captured-direct-http",
  "menuItemsReturned": 22,
  "avgMenuPrice": 21.35,
  "cheapestItem": "Refrigerante Lata",
  "cheapestPrice": 6.5,
  "mostExpensiveItem": "Combo Família",
  "mostExpensivePrice": 54.9,
  "scrapedAt": "2026-09-16T17:06:18.823Z"
}
```

***

### 💰 Pricing

| Plan | Price | Includes |
|---|---|---|
| **Pay-per-result** | $17.00 per 1,000 restaurants scraped | All fields, menu extraction, price intelligence |

Charging is per successfully scraped restaurant record pushed to the dataset (Pay-Per-Event). The actor's fixed run/start cost is minimal — you're mainly paying for results, not idle run time.

***

### ⚡ Performance & Limits

| Mode | Count | Estimated Time |
|---|---|---|
| Single restaurant | 1 | ~15–40 seconds |
| Batch | 10 | ~3–6 minutes |
| Larger batch | 100+ | Varies — stealth browser fallback is slower than direct HTTP |

- Results are pushed to the dataset in real time as each restaurant is processed
- If a target site blocks extraction entirely, the actor may substitute a nearby known restaurant so your run still returns a usable result — check `uuid` and `url` in the output to confirm you got the restaurant you intended

***

### ❓ FAQ

**Q: Is every field in the output freshly scraped from the live page?**
A: Not always. When live data for rating, reviews, delivery time, or delivery fee isn't available, the actor fills those fields with a reasonable estimate rather than leaving them empty. Check `menuExtractionStatus` on each record to see how that record's data was obtained.

**Q: Can this scrape private or login-gated pages?**
A: No — only publicly accessible iFood restaurant pages.

**Q: What happens if Google SERP discovery or direct scraping fails for a target?**
A: The actor may fall back to a small set of known Brazilian restaurants (in São Paulo) to keep the run producing output. This means the restaurant returned might not be the exact one implied by your keyword — verify the `name` and `url` fields if precision matters for your use case.

**Q: Can I trust `reviewsCount` and `rating` for analytics?**
A: Treat them as directional rather than authoritative unless `menuExtractionStatus` confirms a live capture. For rigorous analysis, spot-check a sample against the live iFood app or site.

**Q: Can I export results to CSV or Excel?**
A: Yes, directly from the Apify dataset after the run.

***

### ⚖️ Legal & Terms of Use

This actor extracts publicly accessible restaurant and menu information the same way a regular user would view it through a browser.

- Use this tool for research, price monitoring, and internal business analytics
- Only use data you have the right to collect and store under applicable law
- Do not use this tool to target private individuals or facilitate harassment
- The actor developer is not responsible for how users choose to use the extracted content

***

### 🤝 Support & Feedback

- **Bug report or accuracy issue?** Contact us via the Apify actor page
- **Feature request?** Post in the Apify Community forum

***

<p align="center">
  <strong>Built on Apify</strong><br/>
  <em>Transparent about what's live-scraped and what's estimated.</em>
</p>

# Actor input Schema

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

Select Direct URL scraping, Keyword Discovery via Google SERP, or BOTH to run direct URLs and discover additional restaurants.

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

List of iFood restaurant URLs to enrich directly. Format: https://www.ifood.com.br/delivery/{city}/{slug}/{uuid}

## `city` (type: `string`):

City slug to search for restaurants (e.g. 'sao-paulo-sp', 'rio-de-janeiro-rj', 'belo-horizonte-mg').

## `address` (type: `string`):

Full delivery address to set location context (e.g. 'Av Paulista 1000'). Required for iFood delivery and distance calculation.

## `query` (type: `string`):

Keyword to find restaurants on Google SERP or filter results (e.g. 'sucos', 'pizza', 'sushi', 'hamburguer').

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

Maximum number of restaurants to extract (1-200). On Apify Free plan, this is automatically capped to 2 with a notification.

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

Whether to extract menu items with prices for each restaurant. Inspect the output coverage metadata for completeness status.

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

Whether to extract customer ratings and comments for each restaurant when available.

## `menuMode` (type: `string`):

Choose 'limited' to return at most maxMenuItems per restaurant, or 'all' to remove the local Actor cap. Beta safety gate: 'all' cannot be combined with downloadImages=true.

## `maxMenuItems` (type: `integer`):

Maximum number of menu items returned per restaurant when menuMode='limited'. Ignored when menuMode='all'.

## `downloadImages` (type: `boolean`):

Download menu item photos and save them to the Key-Value Store with imageDownloadUrl. Supported only with menuMode='limited'.

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

Apify Proxy settings. Automatic rotation: uses Google SERP proxy for Google discovery and Brazilian Residential proxy for iFood scraping.

## Actor input object example

```json
{
  "mode": "both",
  "restaurantUrls": [
    "https://www.ifood.com.br/delivery/sao-paulo-sp/bubblekill-patio-paulista-bela-vista/5024be82-d729-41b9-a64f-d44ba306f232"
  ],
  "city": "sao-paulo-sp",
  "address": "Av Paulista 1000",
  "query": "",
  "maxRestaurants": 3,
  "includeMenu": true,
  "includeReviews": false,
  "menuMode": "limited",
  "maxMenuItems": 50,
  "downloadImages": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Collection of extracted iFood restaurants, menus with prices, price intelligence, and reviews.

# 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 = {
    "restaurantUrls": [
        "https://www.ifood.com.br/delivery/sao-paulo-sp/bubblekill-patio-paulista-bela-vista/5024be82-d729-41b9-a64f-d44ba306f232"
    ],
    "city": "sao-paulo-sp",
    "address": "Av Paulista 1000",
    "maxRestaurants": 3,
    "maxMenuItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapepilot/ifood-scraper-anti-block-menus-prices-reviews").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 = {
    "restaurantUrls": ["https://www.ifood.com.br/delivery/sao-paulo-sp/bubblekill-patio-paulista-bela-vista/5024be82-d729-41b9-a64f-d44ba306f232"],
    "city": "sao-paulo-sp",
    "address": "Av Paulista 1000",
    "maxRestaurants": 3,
    "maxMenuItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("scrapepilot/ifood-scraper-anti-block-menus-prices-reviews").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 '{
  "restaurantUrls": [
    "https://www.ifood.com.br/delivery/sao-paulo-sp/bubblekill-patio-paulista-bela-vista/5024be82-d729-41b9-a64f-d44ba306f232"
  ],
  "city": "sao-paulo-sp",
  "address": "Av Paulista 1000",
  "maxRestaurants": 3,
  "maxMenuItems": 50
}' |
apify call scrapepilot/ifood-scraper-anti-block-menus-prices-reviews --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapepilot/ifood-scraper-anti-block-menus-prices-reviews"
        }
    }
}
```

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/qSHknslP1Oye2C9SN/builds/Sz3eU6rjkUWWvSpa3/openapi.json
