# iFood Restaurant Scraper (`yasmany.casanova/ifood-scraper`) Actor

Find restaurants in a nationwide index of 98,000+ iFood Brazil establishments, with address, opening hours and the public company registry, then extract live store profiles, complete menus with prices and customer reviews. Structured output, one row per record.

- **URL**: https://apify.com/yasmany.casanova/ifood-scraper.md
- **Developed by:** [Yasmany Grijalba Casanova](https://apify.com/yasmany.casanova) (community)
- **Categories:** E-commerce, Developer tools, Automation
- **Features:** Limited permissions
- **Stats:** 314 total users, 28 monthly users, 76.9% runs succeeded, 9 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $25.00 / 1,000 results

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

## iFood Restaurant Scraper

Restaurant data from iFood Brazil, the largest food delivery platform in Latin America. Find restaurants in a **nationwide index of 100,000+ establishments**, enriched with the public company registry, then extract **live store profiles, complete menus with prices, and customer reviews**. Structured output, one row per record, ready for JSON, CSV, Excel and API integration.

[![Apify Actor](https://img.shields.io/badge/Apify-Actor-blue?logo=apify)](https://apify.com)
[![Residential Proxy](https://img.shields.io/badge/Proxy-Residential-orange)](https://apify.com/proxy)
[![Brazil](https://img.shields.io/badge/Region-Brazil-green)](https://www.ifood.com.br)

***

### Overview

One Actor, four operation modes. `search` finds restaurants and returns their `store_id`; the three live modes read a restaurant from iFood at the moment of the run.

| Mode | Returns | Source | Proxy |
|------|---------|--------|-------|
| `search` | Restaurants matching name, city, state, category or rating filters: `store_id`, address, opening hours, rating, CNPJ and the company registry | Restaurant index, refreshed periodically | None |
| `store_info` | The restaurant profile: address and coordinates, CNPJ, categories, chain, ratings, opening hours, delivery terms, Pix | iFood, live | Residential |
| `menu` | Every menu item with list and promotional prices, description, image and availability | iFood, live | Residential |
| `reviews` | Customer reviews with ratings, comments, order dates and review dates | iFood, live | Residential |

**Residential proxy.** The three live modes require a residential proxy: **Apify Residential Proxy**, available on paid plans, or your own through the `customProxyUrl` input, which works on any plan including Free. A run without one stops immediately with an explanatory message, before any extraction cost. `search` uses no proxy and runs on every plan.

***

### Quick Start

The live modes take one input, the restaurant's `store_id`. The `search` mode returns it for every restaurant it finds. It is also the last segment of the restaurant's iFood URL:

```
https://www.ifood.com.br/delivery/sao-paulo-sp/pizza-hut-paraiso/f1b60ced-d490-499f-976b-6d3d717d927e
                                                                 └──────────── store_id ────────────┘
```

#### Find restaurants

```json
{
  "mode": "search",
  "city": "São Paulo",
  "state": "SP",
  "segment": "Pizza",
  "maxResults": 100
}
```

Every filter is optional and they combine: part of the name, city, state, iFood category, minimum rating, and three presence filters (CNPJ known, profile captured, company registry present). Each row carries the `store_id` the other modes take and `total_matches`, for paging with `offset`. See [Search](#search).

#### Extract a menu

```json
{
  "mode": "menu",
  "store_id": "f1b60ced-d490-499f-976b-6d3d717d927e"
}
```

#### Get restaurant details

```json
{
  "mode": "store_info",
  "store_id": "f1b60ced-d490-499f-976b-6d3d717d927e",
  "latitude": "-23.5608786",
  "longitude": "-46.6570743"
}
```

The coordinates are optional and only `store_info` reads them: they add the delivery fee, delivery time and distance **to that address**. Without them the other 31 fields of the profile are identical and those five are `null`. See [Delivery pricing](#delivery-pricing).

#### Get customer reviews

```json
{
  "mode": "reviews",
  "store_id": "f1b60ced-d490-499f-976b-6d3d717d927e",
  "maxReviews": 100
}
```

***

### Features

| Feature | Description |
|---------|-------------|
| **Restaurant Search** | 100,000+ restaurants across all 27 Brazilian states, searchable by name, city, state, category and rating, with no proxy |
| **Company Registry** | Legal name, registry status, size, legal nature, main activity (CNAE), opening date and share capital from Brazil's public company register, joined by CNPJ |
| **Store Profiles** | Address with coordinates, CNPJ, categories, chain, ratings, opening hours by day, delivery terms and Pix acceptance |
| **Complete Menus** | Every item with list price, promotional price, description, image and availability |
| **Customer Reviews** | Ratings, comments, order dates and review dates, up to 1,000 per run |
| **Live Data** | Prices, promotions, availability, delivery terms and reviews read at the moment of the run |
| **Structured Output** | One row per record, a dataset view per mode, direct export to JSON, CSV and Excel |
| **Predictable Runs** | Explicit `NO_RESULTS` rows, explicit failures, and a clear stop when no proxy is available |

***

### Use Cases

- **Market mapping**: list the restaurants of a category in a city or state, with ratings, address and CNPJ where known
- **Account qualification**: confirm a restaurant's legal entity, registry status, size, legal nature and opening date before onboarding
- **Price monitoring**: track menu prices and promotions over time
- **Competitor analysis**: compare ratings, delivery fees, delivery times and assortment
- **Menu intelligence**: measure category depth, item counts and discount depth by restaurant or chain
- **Reputation monitoring**: follow customer reviews and sentiment

***

### Input Parameters

One input selects the operation, `mode`. The three live modes also take a `store_id`. Every other parameter applies to one mode, and the input form groups them that way.

| Parameter | Applies to | Description |
|-----------|-----------|-------------|
| `mode` | all | `search`, `store_info`, `menu` or `reviews` |
| `store_id` | `store_info`, `menu`, `reviews` | **Required** for those three. Restaurant UUID, from `search` or from the last segment of its iFood URL |
| `searchTerm` | `search` | Part of the restaurant name; accents and case do not matter |
| `city` | `search` | City name |
| `state` | `search` | Two-letter state code, such as `SP` |
| `segment` | `search` | iFood category, such as `Pizza` or `Lanches` |
| `minRating` | `search` | Minimum rating, 0 to 5 |
| `onlyWithCnpj` | `search` | Only restaurants whose CNPJ is known. Default: `false` |
| `onlyWithProfile` | `search` | Only restaurants with a captured profile. Default: `false` |
| `onlyWithCompany` | `search` | Only restaurants with the company registry block. Default: `false` |
| `maxResults` | `search` | Rows per run, 1 to 1,000. Default: `100` |
| `offset` | `search` | Rows to skip, for paging. Default: `0` |
| `maxReviews` | `reviews` | Reviews to fetch, 1 to 1,000. Default: `100` |
| `latitude` | `store_info` | Delivery address, to price delivery to it |
| `longitude` | `store_info` | The other half of that address |
| `useApifyProxy` | live modes | Enable Apify Proxy. Default: `true` |
| `proxyGroups` | live modes | Proxy group for Apify Proxy. Default: `["RESIDENTIAL"]` |
| `proxyCountry` | live modes | Proxy country code. Default: `BR` |
| `customProxyUrl` | live modes | Your own residential proxy; overrides the three settings above |
| `maxRetries` | live modes | Retry attempts for failed requests, 1 to 10. Default: `3` |
| `timeout` | live modes | Request timeout in seconds. Default: `30` |

#### Search

`search` queries a restaurant index maintained by Cnova Tech and refreshed periodically. It holds one row per restaurant with the fields iFood shows on the public store page, plus the public company registry joined by CNPJ. Filters are case and accent insensitive: `acai` finds `Açaí`, `sao paulo` finds `São Paulo`. The categories are iFood's own, as shown in the app; the largest are Brasileira, Lanches, Pizza, Doces & Bolos, Açaí, Japonesa, Marmita, Padaria, Sorvetes, Salgados, Saudável, Italiana, Pastel, Carnes, Árabe, Chinesa, Hambúrguer and Cafeteria.

Coverage as of November 2026:

| | |
|---|---|
| Restaurants | 100,000+ in 170+ cities and all 27 states, across 57 categories |
| With full profile | 60,000+: street address, coordinates, price range, minimum order, service flags, opening hours, rating count |
| With CNPJ | 60,000+ |
| With company registry | 60,000+: legal name, status, size, legal nature, main activity, opening date, share capital, Simples Nacional and MEI flags |
| With corporate contact | nearly 30,000 companies proper carry the registry phone and email |

Results follow a stable order: restaurants with a captured profile first, then by rating count, so paging with `offset` is deterministic. Every row carries `total_matches`, the number of restaurants matching the filters in all, and `captured_at`, when that restaurant was last observed on iFood. Ratings, availability and menus change daily; once you hold a `store_id`, the live modes read the restaurant as it is now.

#### Delivery pricing

`store_info` prices delivery to an address only when you supply one. With `latitude` and `longitude`, five fields describe delivery to that point; without them they are `null` and the other 31 fields are identical.

| Field | With an address | Without |
|-------|-----------------|---------|
| `distance` | 1.5 | `null` |
| `delivery_fee` | 8.99 | `null` |
| `type_delivery_fee` | FIXED | `null` |
| `delivery_time` | 30 | `null` |
| `has_order_tracking` | true | `null` |

`menu` and `reviews` ignore the coordinates entirely.

***

### Data Sources and Governance

- **Public data only.** The index and the live modes carry what iFood shows on a public store page, plus Brazil's public company register (Receita Federal), the same source onboarding and credit checks read nationwide.
- **Corporate contact only.** The registry phone and email are published for companies proper. For a MEI or an individual entrepreneur (`mei: true`, or a `legal_nature` of the individual kind) the registry holds the owner's personal contact, and those two fields come back `null`.
- **Never published.** Company partners, the registry's address, the iFood merchant phone number (on smaller restaurants, the owner's personal mobile) and iFood's internal payment codes.
- **Reviews** carry the customer's first name only, as iFood displays it.
- **Null is not zero.** A number is `null` when iFood states no value and `0` only when it says zero, which keeps free delivery apart from an unpublished fee and an unrated restaurant apart from one rated zero stars.

***

### Output

The dataset holds **one item per record**: one per restaurant found, one per restaurant profile, one per menu item, one per review. Every row repeats the run context (`mode` and `scraped_at`) and carries the `store_id`, so an exported CSV or Excel file stands on its own. Each mode has its own dataset view with labelled columns.

A run that reaches its source and finds nothing writes a single row with `status: "NO_RESULTS"` and a message saying why. A run that cannot retrieve data fails with a message. A dataset is never silently empty.

If a run reaches the maximum cost you set for it, the platform keeps the records that fit and the Actor's status message states how many were stored out of how many were found. For `search` it also gives the `offset` to continue from, so the rest of the page can be fetched in a second run.

#### Search

One row per restaurant found. This one carries a captured profile and the company registry block, so every field is filled. The description and the opening hours are shortened here, and the contact values are illustrative.

```json
{
  "mode": "search",
  "scraped_at": "2026-10-20T03:52:43+00:00",
  "total_matches": 1,
  "store_id": "a10ea022-8d24-4465-b444-9dd91a8052bc",
  "name": "Outback - Moema",
  "segment": "Lanches",
  "chain_name": "Outback",
  "description": "Sejam bem-vindos ao Outback Steakhouse. ...",
  "street_name": "ALAMEDA DOS JURUPIS",
  "street_number": "1414",
  "district": "INDIANOPOLIS",
  "city": "São Paulo",
  "state": "SP",
  "zip_code": "04088004",
  "latitude": -23.610105,
  "longitude": -46.665215,
  "price_range": "EXPENSIVE",
  "minimum_order_value": 30,
  "has_delivery": true,
  "has_takeout": true,
  "has_scheduling": false,
  "uses_ifood_logistics": true,
  "business_model": "Full Service",
  "opening_hours_text": "Mon 10:45-23:00; Tue 10:45-23:00; ...; Sun 10:45-23:00",
  "opening_hours": [
    { "day_of_week": "MONDAY", "opens_at": "10:45", "closes_at": "23:00" },
    { "day_of_week": "FRIDAY", "opens_at": "10:45", "closes_at": "23:45" }
  ],
  "user_rating": 4.8,
  "user_rating_count": 918,
  "available_at_capture": true,
  "is_super_restaurant": false,
  "logo": "https://static.ifood-static.com.br/image/upload/t_medium/logosgde/a10ea022-8d24-4465-b444-9dd91a8052bc/202008102053_Khho_i.png",
  "url": "https://www.ifood.com.br/delivery/sao-paulo-sp/outback---moema-indianopolis/a10ea022-8d24-4465-b444-9dd91a8052bc",
  "profile_captured": true,
  "captured_at": "2026-10-13T18:45:02+00:00",
  "cnpj": "17.261.661/0007-69",
  "company_captured": true,
  "company_name": "OUTBACK STEAKHOUSE RESTAURANTES BRASIL S.A.",
  "trade_name": "OUTBACK STEAKHOUSE",
  "company_status": "ATIVA",
  "company_opened_at": "2013-12-18",
  "company_type": "FILIAL",
  "company_size": "DEMAIS",
  "legal_nature": "205-4 - Sociedade Anônima Fechada",
  "main_activity_code": "56.11-2-01",
  "main_activity": "Restaurantes e similares",
  "share_capital": 8887392.24,
  "simples_nacional": false,
  "mei": false,
  "company_phone": "(11) 0000-0000",
  "company_email": "contato@example.com.br",
  "company_updated_at": "2026-10-13T14:09:40+00:00"
}
```

A restaurant without a captured profile carries `name`, `segment`, `chain_name`, `city`, `state`, `user_rating`, `logo`, `url` and `captured_at`, with `profile_captured: false` and the rest `null`.

#### Store Info

Shortened where the real record is long.

```json
{
  "mode": "store_info",
  "store_id": "f1b60ced-d490-499f-976b-6d3d717d927e",
  "name": "Pizza Hut - Paraíso",
  "description": "PIMENTA VERDE ALIMENTOS LTDA.",
  "cnpj": "09.060.964/0131-88",
  "main_category": "Pizza",
  "cuisine_categories": ["Comida Italiana"],
  "chain_name": "Pizza Hut",
  "street_name": "AV BRIGADEIRO LUIS ANTONIO",
  "street_number": "2893",
  "district": "JARDIM PAULISTA",
  "city": "SAO PAULO",
  "state": "SP",
  "zip_code": "01401000",
  "latitude": "-23.571795",
  "longitude": "-46.652905",
  "user_rating": 4.7,
  "user_rating_count": 266,
  "price_range": "CHEAPEST",
  "opening_hours_text": "Mon 10:00-22:30; Tue 15:00-22:30; Wed 10:00-23:59; ...",
  "opening_hours": [
    { "day_of_week": "MONDAY", "opens_at": "10:00", "closes_at": "22:30" }
  ],
  "available": true,
  "has_delivery": true,
  "has_takeout": true,
  "delivery_fee": 6.99,
  "delivery_time": 21,
  "preparation_time": 14,
  "minimum_order_value": 30,
  "accepts_pix": true
}
```

#### Menu

One row per item, carrying its section. This one is on promotion.

```json
{
  "mode": "menu",
  "store_id": "f1b60ced-d490-499f-976b-6d3d717d927e",
  "category_code": "f297e196-e5cb-4ed3-8817-71ccbb0a2d71",
  "category_name": "Sobremesas",
  "id": "99acbd4a-729e-4d05-b911-1e21f42c1909",
  "code": "99acbd4a-729e-4d05-b911-1e21f42c1909",
  "description": "Slider Nutella",
  "details": "Mini disco de 8,5cm de massa pan coberta com Nutella",
  "logo_url": "https://static-images.ifood.com.br/image/upload/...",
  "unit_price": 15.9,
  "promotional_price": 10.34,
  "availability": "AVAILABLE",
  "external_code": "91559",
  "need_choices": false,
  "product_tags": [{ "group": "PORTION_SIZE", "tags": ["NOT_APPLICABLE"] }]
}
```

`unit_price` is always the list price. About one item in five is discounted at any time, with discounts reaching 40%, so read `promotional_price` before comparing prices.

#### Reviews

```json
{
  "mode": "reviews",
  "store_id": "f1b60ced-d490-499f-976b-6d3d717d927e",
  "total_reviews_available": 273,
  "total_ratings": 11135,
  "customer_name": "Maximo",
  "rating": 4.0,
  "grade": 4.0,
  "comment": "Comprei Grande, mas, tamanho menor, não é grande",
  "comment_date": "2026-01-09T23:36:55.725000+00:00",
  "order_date": "2026-01-09T22:41:29.799000+00:00",
  "order_number": 3635,
  "status": "ACE",
  "moderated": false
}
```

***

### Data Fields

Every row also carries `mode` and `scraped_at`.

<details>
<summary><strong>Search Mode, 48 fields</strong></summary>

Fields marked *profile* are `null` when `profile_captured` is `false`; fields marked *registry* are `null` when `company_captured` is `false`.

**Identity and location**

| Field | Type | Description |
|-------|------|-------------|
| `total_matches` | number | Restaurants matching the filters in all, repeated on every row |
| `store_id` | string | iFood identifier for the restaurant; the input of the live modes |
| `name` | string | Restaurant name |
| `segment` | string | iFood category, such as Pizza |
| `chain_name` | string | Chain the restaurant belongs to, `null` if independent |
| `description` | string | Description written by the restaurant (*profile*) |
| `street_name` | string | Street name (*profile*) |
| `street_number` | string | Street number (*profile*) |
| `district` | string | Neighborhood (*profile*) |
| `city` | string | City name |
| `state` | string | State abbreviation |
| `zip_code` | string | Postal code (*profile*) |
| `latitude` | number | The restaurant's own latitude (*profile*) |
| `longitude` | number | The restaurant's own longitude (*profile*) |

**Service**

| Field | Type | Description |
|-------|------|-------------|
| `price_range` | string | iFood's price band (*profile*) |
| `minimum_order_value` | number | Minimum order amount in BRL (*profile*) |
| `has_delivery` | boolean | Delivers to the customer (*profile*) |
| `has_takeout` | boolean | Offers takeaway (*profile*) |
| `has_scheduling` | boolean | Accepts scheduled orders (*profile*) |
| `uses_ifood_logistics` | boolean | Delivery is done by iFood's fleet rather than the restaurant's own (*profile*) |
| `business_model` | string | The restaurant's commercial model with iFood: `Full Service`, `Marketplace` or `Entrega+` (*profile*) |
| `opening_hours_text` | string | The full week on one line, for spreadsheets (*profile*) |
| `opening_hours` | array | One entry per shift: day, opening time, closing time (*profile*) |

**Reputation, links and observation**

| Field | Type | Description |
|-------|------|-------------|
| `user_rating` | number | Average rating, 0 to 5 stars |
| `user_rating_count` | number | Total number of ratings (*profile*) |
| `available_at_capture` | boolean | Whether the restaurant was open when last observed |
| `is_super_restaurant` | boolean | iFood's Super Restaurante badge |
| `logo` | string | Restaurant logo URL |
| `url` | string | The restaurant's page on ifood.com.br |
| `profile_captured` | boolean | Whether the full profile is present |
| `captured_at` | string | When this restaurant was last observed on iFood (ISO 8601) |

**Company registry** (Receita Federal, joined by CNPJ)

| Field | Type | Description |
|-------|------|-------------|
| `cnpj` | string | Company tax id, in the standard Brazilian format, when known |
| `company_captured` | boolean | Whether the registry block below is present |
| `company_name` | string | Legal name (*registry*) |
| `trade_name` | string | Trade name, when the registry has one (*registry*) |
| `company_status` | string | Registry status: `ATIVA`, `BAIXADA`, `INAPTA` or `SUSPENSA` (*registry*) |
| `company_opened_at` | string | Opening date, `YYYY-MM-DD` (*registry*) |
| `company_type` | string | `MATRIZ` (headquarters) or `FILIAL` (branch) (*registry*) |
| `company_size` | string | `MICRO EMPRESA`, `EMPRESA DE PEQUENO PORTE` or `DEMAIS` (*registry*) |
| `legal_nature` | string | Legal nature code and name, such as `206-2 - Sociedade Empresária Limitada` (*registry*) |
| `main_activity_code` | string | CNAE code of the main activity (*registry*) |
| `main_activity` | string | Main activity in words (*registry*) |
| `share_capital` | number | Share capital in BRL (*registry*) |
| `simples_nacional` | boolean | Opted into the Simples Nacional tax regime (*registry*) |
| `mei` | boolean | Registered as a MEI, an individual micro-entrepreneur (*registry*) |
| `company_phone` | string | Corporate phone; `null` for a MEI or an individual entrepreneur (*registry*) |
| `company_email` | string | Corporate email; `null` for a MEI or an individual entrepreneur (*registry*) |
| `company_updated_at` | string | When the registry was last read for this company (ISO 8601) (*registry*) |

</details>

<details>
<summary><strong>Store Info Mode, 36 fields</strong></summary>

**Identity**

| Field | Type | Description |
|-------|------|-------------|
| `store_id` | string | iFood identifier for the restaurant |
| `name` | string | Restaurant name |
| `description` | string | Description written by the restaurant |
| `cnpj` | string | Company tax id, in the standard Brazilian format |
| `main_category` | string | Primary food category |
| `cuisine_categories` | array | Cuisine types, such as Comida Italiana |
| `store_type` | string | Merchant type code |
| `chain_name` | string | Chain the restaurant belongs to, empty if independent |
| `logo` | string | Restaurant logo URL |

**Location**

| Field | Type | Description |
|-------|------|-------------|
| `street_name` | string | Street name |
| `street_number` | string | Street number |
| `district` | string | Neighborhood or district |
| `city` | string | City name |
| `state` | string | State abbreviation |
| `zip_code` | string | Postal code |
| `country` | string | Country code |
| `latitude` | string | The restaurant's own latitude |
| `longitude` | string | The restaurant's own longitude |
| `distance` | number | Km from the coordinates you sent, `null` when you sent none |

**Reputation and hours**

| Field | Type | Description |
|-------|------|-------------|
| `user_rating` | number | Average rating, 0 to 5 stars |
| `user_rating_count` | number | Total number of ratings |
| `price_range` | string | iFood's price band for the restaurant |
| `opening_hours_text` | string | The full week on one line, for spreadsheets |
| `opening_hours` | array | One entry per shift: day, opening time, closing time |

A restaurant open past midnight has a closing time smaller than its opening time, and a day with a lunch and a dinner shift has two entries.

**Service and delivery**

| Field | Type | Description |
|-------|------|-------------|
| `available` | boolean | Whether the restaurant is open right now |
| `has_delivery` | boolean | Delivers to the customer |
| `has_takeout` | boolean | Offers takeaway |
| `has_scheduling` | boolean | Accepts scheduled orders |
| `has_order_tracking` | boolean | Offers live order tracking to that address |
| `delivery_fee` | number | Delivery fee in BRL to that address |
| `type_delivery_fee` | string | How the delivery fee is charged |
| `delivery_time` | number | Estimated delivery time to that address, in minutes |
| `takeout_time` | number | Takeaway estimate, in minutes |
| `preparation_time` | number | Kitchen preparation estimate, in minutes |
| `minimum_order_value` | number | Minimum order amount in BRL |
| `accepts_pix` | boolean | Whether Pix is accepted |

`distance`, `delivery_fee`, `type_delivery_fee`, `delivery_time` and `has_order_tracking` describe delivery to the address supplied in `latitude` and `longitude`, and are `null` when none was supplied.

</details>

<details>
<summary><strong>Menu Mode, 16 fields</strong></summary>

| Field | Type | Description |
|-------|------|-------------|
| `store_id` | string | Restaurant the item belongs to |
| `category_code` | string | Identifier of the section the item belongs to |
| `category_name` | string | Name of that section |
| `id` | string | Item identifier |
| `code` | string | Item code used by iFood |
| `external_code` | string | The restaurant's own code for the item |
| `description` | string | Item name |
| `details` | string | Item description |
| `logo_url` | string | Item image URL |
| `unit_price` | number | List price in BRL |
| `promotional_price` | number | Discounted price when the item is on promotion, `null` otherwise |
| `unit_original_price` | number | Price before discount, when the item is discounted |
| `unit_min_price` | number | Lowest price among the item's options |
| `availability` | string | Whether the item is currently available |
| `need_choices` | boolean | Whether the item requires choosing options |
| `product_tags` | array | Tags iFood applies to the product |

The options behind `need_choices`, such as sizes and extras, are not included: the catalog lists items without them, and returning them would mean one extra request per item.

</details>

<details>
<summary><strong>Reviews Mode, 12 fields</strong></summary>

| Field | Type | Description |
|-------|------|-------------|
| `store_id` | string | Restaurant the review belongs to |
| `total_reviews_available` | number | How many evaluations can be retrieved, written comment or not |
| `total_ratings` | number | Every order this restaurant has had rated: the reputation volume |
| `customer_name` | string | Customer's first name |
| `rating` | number | Rating, 1 to 5 stars |
| `grade` | number | The same score as `rating`; iFood publishes both |
| `comment` | string | Customer comment. Most evaluations are a rating with no text |
| `comment_date` | string | When the review was posted (ISO 8601) |
| `order_date` | string | When the order was placed (ISO 8601) |
| `order_number` | number | Order reference number |
| `status` | string | Review status |
| `moderated` | boolean | Whether the review was moderated |

</details>

***

### Integrations

The **API** tab on the Actor page provides ready-to-use code in **Python**, **JavaScript** and **cURL**, generated with the correct parameters. The Actor also works with Apify's scheduler, webhooks and integrations (Google Sheets, Make, Zapier, n8n, LangChain and others) like any other Actor.

***

### Coverage

This Actor covers **restaurants** on iFood, anywhere in Brazil: an index to find them, then profiles, menus and reviews for the restaurant you name. iFood's grocery and pharmacy storefronts are outside its scope.

***

### About Cnova Tech

This Actor is built and maintained by [Cnova Tech](https://apify.com/yasmany.casanova), which builds scrapers, datasets and APIs for public data from marketplaces, e-commerce and delivery platforms. Teams that need the restaurant market as a continuously refreshed product, by city, neighborhood and postal code, under contract and with support, can ask about Data Food Service at [cnovatech.com.br](https://cnovatech.com.br) or contato@cnovatech.com.br.

***

### FAQ

<details>
<summary><strong>Where do I find the store_id?</strong></summary>

Run the `search` mode: every row carries it. Filter by name, city, state or category and copy the `store_id` of the restaurant you want.

Or open the restaurant on ifood.com.br and look at the address bar. The URL ends in a UUID, and that UUID is the `store_id`: `ifood.com.br/delivery/<city>/<restaurant-name>/<store_id>`. Copy only the UUID.

</details>

<details>
<summary><strong>How current is the restaurant index?</strong></summary>

The index is refreshed periodically, and every row states when that restaurant was last observed in `captured_at`. Use it to find restaurants and qualify them; use `store_info`, `menu` and `reviews` to read a restaurant as it is right now.

</details>

<details>
<summary><strong>Why does a search row have null address, CNPJ or coordinates?</strong></summary>

Its profile is not in the index yet, which `profile_captured: false` states on the row. Those rows still carry name, category, city, state, rating and the iFood page. Run `store_info` on the `store_id` to read the full profile live, or set `onlyWithProfile` to keep only complete rows.

</details>

<details>
<summary><strong>Why are company_phone and company_email null on a row that has the registry?</strong></summary>

Because that company is a MEI or an individual entrepreneur: `mei` is `true`, or `legal_nature` is `213-5 - Empresário (Individual)`. For those, the public registry holds the owner's personal phone and email, which this Actor does not publish. Companies proper carry their corporate contact. Set `onlyWithCompany` to keep only rows with the registry block.

</details>

<details>
<summary><strong>Why am I getting no results?</strong></summary>

In `search`, loosen the filters: a shorter term, the city on its own, or no segment. The `NO_RESULTS` row names the filters that were applied.

In the live modes, check that the `store_id` is current and, for `store_info` with coordinates, that they fall inside the restaurant's delivery area. Coordinates from the restaurant's own city are a good control.

</details>

<details>
<summary><strong>Why is the menu empty?</strong></summary>

Menus are served while a restaurant is open, so run `menu` during its opening hours. Some restaurants also keep incomplete catalogs on iFood.

</details>

<details>
<summary><strong>Why do I get fewer reviews than the restaurant's rating count?</strong></summary>

They count different things. `total_ratings` is every order that was rated; `total_reviews_available` is the smaller set iFood serves back, most of which carry a star rating with no text. One store measured had 11,135 rated orders behind 273 retrievable evaluations. A few hundred reviews for a restaurant with thousands of orders is expected.

</details>

<details>
<summary><strong>Why am I getting timeout errors?</strong></summary>

Confirm that a residential proxy is configured, raise `timeout` to 60, and allow for iFood being slower at peak hours (lunch and dinner).

</details>

***

### Support

Check the FAQ first. For anything else, use the **Issues** tab on the Actor page and we will get back to you.

# Actor input Schema

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

Type of data to extract: search (find restaurants and their store_id, no proxy needed), store_info (restaurant details), menu (complete menu with prices), or reviews.

## `store_id` (type: `string`):

Restaurant UUID, required for store_info, menu and reviews. The search mode returns it for every restaurant it finds. You can also open the restaurant on ifood.com.br and copy the last segment of its URL: in https://www.ifood.com.br/delivery/sao-paulo-sp/some-restaurant/f1b60ced-d490-499f-976b-6d3d717d927e the ID is f1b60ced-d490-499f-976b-6d3d717d927e.

## `searchTerm` (type: `string`):

Part of the restaurant name. Accents and case do not matter: "acai" finds "Açaí".

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

City name, with or without accents: "São Paulo" and "sao paulo" are the same. Combine with State to avoid homonyms.

## `state` (type: `string`):

Two-letter state code, such as SP, RJ or MG.

## `segment` (type: `string`):

iFood category of the restaurant, as shown in the app. The largest: Brasileira, Lanches, Pizza, Doces & Bolos, Açaí, Japonesa, Marmita, Padaria, Sorvetes, Salgados, Saudável, Italiana, Pastel, Carnes, Árabe, Chinesa, Hambúrguer, Cafeteria. Accents and case do not matter.

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

Keep restaurants rated at least this many stars (0 to 5). Unrated restaurants are left out whenever this is set.

## `onlyWithCnpj` (type: `boolean`):

Keep only restaurants whose company tax id (CNPJ) is known.

## `onlyWithProfile` (type: `boolean`):

Keep only restaurants whose full profile was captured: those carry street address, coordinates, price range, minimum order, service flags, opening hours and rating count. The others carry name, category, city, state and the iFood page.

## `onlyWithCompany` (type: `boolean`):

Keep only restaurants whose company registry block is present: legal name, status, size, legal nature, main activity, opening date, and for companies proper the corporate phone and email. These rows may be priced separately; see the Pricing tab.

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

Restaurants to return in this run, 1 to 1000. Default: 100. Every row also reports total_matches, so you know whether to page.

## `offset` (type: `integer`):

Rows to skip before returning results, for paging. Default: 0. The order is stable between runs of the same filters.

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

Maximum number of reviews to fetch (reviews mode only). Default: 100, Max: 1000.

## `latitude` (type: `string`):

Latitude of the delivery address, e.g. "-23.5608786". Give both coordinates or neither.

## `longitude` (type: `string`):

Longitude of the delivery address, e.g. "-46.6570743". Give both coordinates or neither.

## `useApifyProxy` (type: `boolean`):

Enable Apify Residential Proxy for reliable data extraction. Requires an Apify paid plan. Free-plan users can provide their own residential proxy via 'customProxyUrl' below. The search mode never uses a proxy.

## `proxyGroups` (type: `array`):

Proxy group for Apify Proxy. \['RESIDENTIAL'] is what every live mode uses.

## `proxyCountry` (type: `string`):

Country code for the proxy (ISO 3166-1 alpha-2). BR is recommended.

## `customProxyUrl` (type: `string`):

Your own proxy, in the form http://user:pass@host:port. Overrides the Apify Proxy settings above. Optional: it simply replaces Apify Proxy and works on any plan, including Free.

## `maxRetries` (type: `integer`):

Maximum retry attempts for failed requests.

## `timeout` (type: `integer`):

Request timeout in seconds.

## Actor input object example

```json
{
  "mode": "menu",
  "store_id": "f1b60ced-d490-499f-976b-6d3d717d927e",
  "searchTerm": "pizza",
  "city": "São Paulo",
  "state": "SP",
  "segment": "Pizza",
  "onlyWithCnpj": false,
  "onlyWithProfile": false,
  "onlyWithCompany": false,
  "maxResults": 100,
  "offset": 0,
  "maxReviews": 100,
  "useApifyProxy": true,
  "proxyGroups": [
    "RESIDENTIAL"
  ],
  "proxyCountry": "BR",
  "customProxyUrl": "http://user:pass@proxy.example.com:8000",
  "maxRetries": 3,
  "timeout": 30
}
```

# Actor output Schema

## `restaurants` (type: `string`):

All extracted records with every field, whatever mode the run used

## `searchView` (type: `string`):

Restaurants found by the search mode, one row per restaurant

## `storeInfoView` (type: `string`):

View of detailed store information (store_info mode)

## `menuView` (type: `string`):

View of menu categories and items (menu mode)

## `reviewsView` (type: `string`):

View of customer reviews and ratings (reviews mode)

# 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 = {
    "mode": "menu",
    "store_id": "f1b60ced-d490-499f-976b-6d3d717d927e",
    "maxResults": 100,
    "maxReviews": 100,
    "useApifyProxy": true,
    "proxyGroups": [
        "RESIDENTIAL"
    ],
    "proxyCountry": "BR",
    "maxRetries": 3,
    "timeout": 30
};

// Run the Actor and wait for it to finish
const run = await client.actor("yasmany.casanova/ifood-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 = {
    "mode": "menu",
    "store_id": "f1b60ced-d490-499f-976b-6d3d717d927e",
    "maxResults": 100,
    "maxReviews": 100,
    "useApifyProxy": True,
    "proxyGroups": ["RESIDENTIAL"],
    "proxyCountry": "BR",
    "maxRetries": 3,
    "timeout": 30,
}

# Run the Actor and wait for it to finish
run = client.actor("yasmany.casanova/ifood-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 '{
  "mode": "menu",
  "store_id": "f1b60ced-d490-499f-976b-6d3d717d927e",
  "maxResults": 100,
  "maxReviews": 100,
  "useApifyProxy": true,
  "proxyGroups": [
    "RESIDENTIAL"
  ],
  "proxyCountry": "BR",
  "maxRetries": 3,
  "timeout": 30
}' |
apify call yasmany.casanova/ifood-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yasmany.casanova/ifood-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/xmJ7nVZ3VrxjuFpmc/builds/fRf2apxkWW8HJmK6N/openapi.json
