# Efood Scraper - Greek Food Delivery Restaurants & Prices (`studio-amba/efood-scraper`) Actor

Scrape restaurants, ratings, delivery info, cuisines, and prices from efood.gr — Greece's largest food delivery platform with 20,000+ stores.

- **URL**: https://apify.com/studio-amba/efood-scraper.md
- **Developed by:** [Studio Amba](https://apify.com/studio-amba) (community)
- **Categories:** E-commerce
- **Features:** Limited permissions
- **Stats:** 6 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 result scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/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

## Efood Scraper - Restaurants & Delivery Data from Greece's #1 Food Platform

Extract restaurant data, ratings, delivery times, cuisines, pricing, and availability from [efood.gr](https://www.e-food.gr) — Greece's dominant food delivery platform (Delivery Hero) with 20,000+ stores across 100+ cities.

### What is Efood Scraper?

Efood Scraper collects structured restaurant and store data from efood.gr's public API. It returns detailed information for every restaurant available for delivery at a given location — including ratings, delivery time estimates, minimum order amounts, delivery fees, cuisine types, opening hours, offers, and full address data with coordinates.

Efood (e-food.gr) is Greece's largest food delivery service, owned by Delivery Hero. It dominates the Greek market with over 20,000 partner stores covering restaurants, supermarkets, pharmacies, and retail shops across 100+ cities. No other food delivery platform comes close in Greece.

**No login or cookies required.** This actor uses efood's public restaurant listing API.

**Popular use cases:**

- **Market research** — Map the Greek food delivery landscape. Analyze restaurant density, cuisine distribution, and pricing by city or neighborhood.
- **Competitive intelligence** — Track delivery fees, minimum orders, and ratings across competing restaurants in any Greek city.
- **Location analytics** — Identify underserved areas, popular cuisines by neighborhood, and delivery coverage gaps.
- **Price monitoring** — Monitor delivery costs, minimum order thresholds, and promotional offers across the platform.
- **Investment research** — Analyze the Greek food delivery market for investment due diligence or franchise opportunities.

### How to scrape Efood data

#### Option 1: Search by city name

Set `location` to any major Greek city. The scraper automatically resolves city names to coordinates.

**Supported cities include:** Athens, Thessaloniki, Heraklion, Patras, Larissa, Volos, Ioannina, Chania, Kavala, Rhodes, Corfu, Piraeus, Kalamata, Mykonos, Santorini, and 20+ more.

#### Option 2: Search by exact coordinates

Provide `latitude` and `longitude` for precise location control. This is useful for targeting specific neighborhoods or areas not in the built-in city list.

#### Option 3: Filter by cuisine or keyword

Add a `searchQuery` to filter by restaurant name or cuisine keyword (e.g., "pizza", "souvlaki", "McDonald's"). Use `cuisineFilter` for exact cuisine type matching (e.g., "Burgers", "Sushi", "Souvlakia").

#### Option 4: City-wide grid sweep

By default, efood returns the shops that deliver TO the given point — around 4,000 in central Athens. That is not the full city. Set `coverage` to `city-wide` and the scraper sweeps a grid of points across the whole metro area, querying each point and deduplicating by shop id. For Athens this finds roughly 7,800 unique shops instead of 4,100.

Built-in metro bounds cover Athens (including Piraeus) and Thessaloniki. Other known cities get a ~15 km box around the center, and custom coordinates get a ~10 km box. `gridStepKm` controls the grid density; the actor caps the sweep at 36 API calls and widens the step automatically when needed, with a small delay between calls.

Remember to raise `maxResults` (e.g. 20,000) in city-wide mode, otherwise the extra shops get cut off.

#### Option 5: Ratings breakdown per shop

Set `includeRatings` to `true` to fetch each shop's detailed ratings breakdown: per-attribute scores (quality, service, delivery speed) and thumbs up/down counts (flavor, portion size, value for money, order consistency). The data lands in a `ratingsBreakdown` field per shop.

This adds one API call per shop, so combine it with a sensible `maxResults` or a filter. Individual review texts (author, comment, date) are not public on efood — they require a logged-in user — so the breakdown is the deepest ratings data available without login.

#### Input parameters

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `searchQuery` | String | — | Filter restaurants by name, cuisine, or address keyword |
| `location` | String | `Athens` | City name (Athens, Thessaloniki, Heraklion, etc.) |
| `latitude` | Number | — | Exact latitude (overrides location) |
| `longitude` | Number | — | Exact longitude (overrides location) |
| `coverage` | String | `point` | `point` = single location query, `city-wide` = grid sweep over the metro area |
| `gridStepKm` | Number | `2.5` | Grid spacing in km for city-wide mode (auto-widened to stay within 36 calls) |
| `includeRatings` | Boolean | `false` | Fetch per-shop ratings breakdown (one extra call per shop) |
| `cuisineFilter` | String | — | Exact cuisine type filter (Pizza, Burgers, Sushi, etc.) |
| `onlyOpen` | Boolean | `false` | Only return currently open restaurants |
| `maxResults` | Integer | `100` | Maximum restaurants to return (up to 50,000) |
| `proxyConfiguration` | Object | — | Proxy settings (Greek residential recommended) |

**Tips:**

- The default location is Athens city center. Change it to target other Greek cities.
- Efood returns ALL restaurants available for delivery at the given coordinates — this can be 1,000-4,000+ in large cities.
- Use `maxResults` to limit output. Set it high (e.g., 10,000) for full city dumps.
- The `onlyOpen` filter is time-dependent — results change based on when you run the scraper.
- Cuisine names are in Greek on efood. Common ones: "Souvlakia" (souvlaki), "Pizza", "Burgers", "Sushi", "Ελληνική" (Greek), "Ασιατική" (Asian), "Ιταλική" (Italian).

### What data does Efood Scraper extract?

Each restaurant includes:

| Field | Type | Example |
|-------|------|---------|
| `name` | String | `"McDonald's"` |
| `efoodId` | Number | `1803651` |
| `cuisines` | Array | `["Burgers"]` |
| `primaryCuisine` | String | `"Burgers"` |
| `rating` | Number | `4.7` |
| `reviewCount` | Number | `10418` |
| `deliveryTimeMin` | Number | `30` |
| `minimumOrder` | Number | `0` |
| `deliveryCost` | Number | `0` |
| `freeDelivery` | Boolean | `true` |
| `isOpen` | Boolean | `true` |
| `hasPickup` | Boolean | `false` |
| `hasCashOnDelivery` | Boolean | `true` |
| `hasCreditCard` | Boolean | `true` |
| `address` | String | `"Ermou 2, Syntagma 10563"` |
| `street` | String | `"Ermou 2"` |
| `area` | String | `"Syntagma"` |
| `city` | String | `"Athens"` |
| `postalCode` | String | `"10563"` |
| `latitude` | Number | `37.9758` |
| `longitude` | Number | `23.7337` |
| `phone` | String | `"+302113110700"` |
| `logoUrl` | String | Restaurant logo URL |
| `coverUrl` | String | Restaurant cover image URL |
| `chainName` | String | `"McDonald's"` |
| `vertical` | String | `"food"` |
| `isNew` | Boolean | `false` |
| `hasOffers` | Boolean | `true` |
| `offers` | Array | `["1+1 Deal"]` |
| `timetable` | Object | Opening hours by day |
| `distance` | Number | `1041` (meters from search point) |
| `slug` | String | `"/athina/mcdonald-s"` |
| `url` | String | Full restaurant URL on efood.gr |
| `ratingsBreakdown` | Object | Per-attribute scores + thumbs counts (only with `includeRatings`) |
| `scrapedAt` | String | ISO timestamp |

With `includeRatings` enabled, `ratingsBreakdown` looks like this:

```json
{
  "averageRating": 4.7,
  "totalRatings": 10635,
  "attributeScores": [
    { "id": "quality", "label": "Ποιότητα", "score": 4.7 },
    { "id": "service", "label": "Εξυπηρέτηση", "score": 4.7 },
    { "id": "od_delivery_time", "label": "Ταχύτητα (delivered by efood)", "score": 4.9 }
  ],
  "thumbs": [
    { "id": "flavor", "label": "Γεύση", "up": 1877, "down": 89 },
    { "id": "price_match", "label": "Σχέση ποιότητας - τιμής", "up": 1816, "down": 157 },
    { "id": "size", "label": "Μέγεθος μερίδας", "up": 1840, "down": 127 }
  ]
}
```

### Example output

```json
[
  {
    "name": "McDonald's",
    "efoodId": 1803651,
    "cuisines": ["Burgers"],
    "primaryCuisine": "Burgers",
    "rating": 4.7,
    "reviewCount": 10418,
    "deliveryTimeMin": 30,
    "minimumOrder": 0,
    "deliveryCost": 0,
    "freeDelivery": true,
    "isOpen": true,
    "hasPickup": false,
    "hasCashOnDelivery": true,
    "hasCreditCard": true,
    "address": "Ermou 2, Syntagma 10563",
    "street": "Ermou 2",
    "area": "Syntagma",
    "city": "Athens",
    "postalCode": "10563",
    "latitude": 37.9758132,
    "longitude": 23.7336797,
    "phone": "+302113110700",
    "chainName": "McDonald's",
    "vertical": "food",
    "isNew": false,
    "hasOffers": true,
    "offers": ["1+1 Deal"],
    "timetable": {
      "monday": "06:00-06:00",
      "tuesday": "06:00-06:00",
      "wednesday": "06:00-06:00",
      "thursday": "06:00-06:00",
      "friday": "06:00-06:00",
      "saturday": "06:00-06:00",
      "sunday": "06:00-06:00"
    },
    "distance": 1041,
    "slug": "/athina/mcdonald-s",
    "url": "https://www.e-food.gr/athina/mcdonald-s",
    "scrapedAt": "2026-06-07T14:30:00.000Z"
  },
  {
    "name": "Domino's Pizza",
    "efoodId": 5707412,
    "cuisines": ["Pizza", "Pasta"],
    "primaryCuisine": "Pizza",
    "rating": 4.6,
    "reviewCount": 3842,
    "deliveryTimeMin": 35,
    "minimumOrder": 5,
    "deliveryCost": 1.5,
    "freeDelivery": false,
    "isOpen": true,
    "hasPickup": true,
    "hasCashOnDelivery": true,
    "hasCreditCard": true,
    "address": "Stadiou 28, Athens 10564",
    "street": "Stadiou 28",
    "area": "Athens Center",
    "city": "Athens",
    "postalCode": "10564",
    "latitude": 37.9795,
    "longitude": 23.7312,
    "phone": "+302103259000",
    "chainName": "Domino's Pizza",
    "vertical": "food",
    "isNew": false,
    "hasOffers": true,
    "offers": ["Heineken Deals"],
    "distance": 580,
    "slug": "/athina/domino-s-pizza",
    "url": "https://www.e-food.gr/athina/domino-s-pizza",
    "scrapedAt": "2026-06-07T14:30:02.000Z"
  }
]
```

### How much does it cost?

Efood Scraper uses direct API calls (no browser needed), making it extremely fast and cheap.

| Scenario | Restaurants | Estimated cost | Time |
|----------|-------------|---------------|------|
| Single city center | 100 | ~$0.005 | ~5 sec |
| City center point (Athens) | 4,000+ | ~$0.01 | ~10 sec |
| City-wide sweep (Athens) | 7,800+ | ~$0.02 | ~2 min |
| Multiple cities | 10,000+ | ~$0.05 | ~3 min |
| Nationwide scan | 20,000+ | ~$0.10 | ~5 min |

Point mode makes a single API call per location. City-wide mode makes up to 36 calls with a polite delay between them. The `includeRatings` option adds one call per shop.

### Can I integrate?

Efood Scraper connects to the full Apify integration ecosystem:

- **Apify API** — Trigger runs programmatically, stream results in real-time
- **Webhooks** — Notify your systems when scraping completes
- **Google Sheets** — Auto-export restaurant data for analysis
- **Zapier / Make** — Build no-code automations with delivery data
- **Slack alerts** — Get notified about new restaurants or rating changes
- **BigQuery / Snowflake** — Stream to your data warehouse
- **Scheduled runs** — Set up daily monitoring with Apify Schedules
- **Direct download** — CSV, JSON, XML, or Excel export

### Can I use it as an API?

Use Efood Scraper as a Greek restaurant data API.

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

run = client.actor("studio-amba/efood-scraper").call(run_input={
    "location": "Thessaloniki",
    "cuisineFilter": "Souvlakia",
    "maxResults": 50,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    rating = item.get("rating", "N/A")
    fee = item.get("deliveryCost", 0)
    print(f"{item['name']} — {rating}/5, delivery: EUR {fee}")
```

#### JavaScript

```javascript
import { ApifyClient } from "apify-client";

const client = new ApifyClient({ token: "YOUR_API_TOKEN" });

const run = await client.actor("studio-amba/efood-scraper").call({
  location: "Athens",
  searchQuery: "pizza",
  maxResults: 200,
});

const { items } = await client
  .dataset(run.defaultDatasetId)
  .listItems();

items.forEach((item) => {
  const open = item.isOpen ? "OPEN" : "CLOSED";
  console.log(`${item.name} — ${item.rating}/5 [${open}] ${item.cuisines.join(", ")}`);
});
```

### FAQ

#### What cities does efood cover?

Efood operates in 100+ Greek cities. The scraper has built-in coordinates for 30+ major cities including Athens, Thessaloniki, Heraklion, Patras, Larissa, Volos, Ioannina, Chania, Rhodes, Corfu, Mykonos, and Santorini. For other locations, provide exact latitude/longitude coordinates.

#### Does efood only have restaurants?

No. Efood has expanded beyond food delivery to include supermarkets, pharmacies, pet shops, flower shops, and retail stores. The `vertical` field indicates the store type ("food", "grocery", etc.) and `cuisines` may include non-food categories like "Supermarket", "Pet shop", or "Pharmacy".

#### Why do some restaurants have 0 rating?

New restaurants on efood may not have accumulated enough ratings to display an average. The `reviewCount` field shows how many ratings exist. Restaurants with `rating: null` and `reviewCount: 0` are typically new additions to the platform.

#### Can I get menu items and individual dish prices?

The current version extracts restaurant-level data (delivery info, ratings, cuisines, hours). Menu/catalog data requires authentication on efood's API. If menu scraping is critical for your use case, let us know.

#### Why does the city center query miss shops?

Efood's API returns the shops that deliver TO the given coordinates. A shop in a northern suburb that doesn't deliver to the city center never shows up in a center query. Use `coverage: "city-wide"` to sweep the whole metro area — in Athens this roughly doubles the unique shop count.

#### Can I get individual review texts?

No. Efood shows individual reviews (author, comment, date) only to logged-in users, and this actor deliberately works without login or cookies. What you can get is the public per-shop ratings breakdown via `includeRatings`: average rating, total count, per-attribute scores, and thumbs up/down counts.

#### What is the difference between searchQuery and cuisineFilter?

`searchQuery` is a fuzzy keyword search that matches against restaurant name, cuisine, address, and chain name. `cuisineFilter` matches the exact cuisine category as defined by efood (e.g., "Pizza", "Burgers", "Souvlakia"). Use `cuisineFilter` when you know the exact category, and `searchQuery` for broader searches.

### Limitations

- **Menu data** — Individual menu items and dish prices require authentication and are not currently available. The actor focuses on restaurant-level data.
- **Location precision** — In point mode, results depend on the delivery radius from the given coordinates. Moving the point by a few kilometers may change which restaurants appear. Use city-wide mode when you need full metro coverage.
- **Review texts** — Individual review texts are login-gated on efood. Only the aggregate ratings breakdown is available (see `includeRatings`).
- **Real-time availability** — The `isOpen` field reflects the restaurant's status at scrape time. Availability changes throughout the day.
- **API rate limits** — Efood may rate-limit aggressive scraping. The actor uses Greek residential proxies by default for reliability.
- **Delivery Hero changes** — As part of Delivery Hero, efood's API may change without notice. We monitor and update the scraper to keep pace.

### Other European delivery scrapers

Build a complete view of European food delivery with companion scrapers from our catalog. Check [our Apify Store page](https://apify.com/studio-amba) for the full list of European scrapers.

### Your feedback

If you notice data quality issues, missing fields, or broken runs, let us know through the Apify Console or GitHub. We actively monitor and update this scraper to maintain reliability.

# Actor input Schema

## `searchQuery` (type: `string`):

Search for restaurants by name or cuisine (e.g., 'pizza', 'souvlaki', 'McDonald's'). Works as a keyword filter on results for the given location.

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

City or area name to search in (e.g., 'Athens', 'Thessaloniki', 'Heraklion'). The scraper converts this to coordinates automatically. If you provide latitude/longitude below, this field is ignored.

## `latitude` (type: `number`):

Latitude of the delivery location (e.g., 37.9838 for Athens center). Overrides the 'location' field if provided.

## `longitude` (type: `number`):

Longitude of the delivery location (e.g., 23.7275 for Athens center). Overrides the 'location' field if provided.

## `coverage` (type: `string`):

How much of the city to cover. 'Single point' (default) queries only the given location — efood returns the shops that deliver to that exact point (~4,000 in central Athens). 'City-wide' sweeps a grid of points across the whole metro area and dedupes, finding shops the center point misses (~7,800 in Athens, at the cost of up to 36 API calls).

## `gridStepKm` (type: `number`):

Distance between grid points in city-wide mode. Smaller steps mean more API calls; the actor widens the step automatically if it would exceed 36 calls. Ignored in single-point mode.

## `includeRatings` (type: `boolean`):

Fetch the detailed ratings breakdown for each shop (per-attribute scores like quality/service/speed plus thumbs up/down counts for flavor, portion size, value for money). Adds one extra API call per shop — use with a reasonable maxResults. Note: individual review texts are not public on efood (login required), so this returns the aggregate breakdown only.

## `cuisineFilter` (type: `string`):

Filter by cuisine type. Must match efood's cuisine categories exactly (e.g., 'Pizza', 'Burgers', 'Sushi', 'Souvlakia', 'Ελληνικη').

## `onlyOpen` (type: `boolean`):

If true, only return restaurants that are currently open for orders.

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

Maximum number of restaurants to return.

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

Proxy settings. Efood's API is generally accessible, but Greek residential proxies improve reliability for large runs.

## Actor input object example

```json
{
  "searchQuery": "souvlaki",
  "location": "Athens",
  "coverage": "point",
  "gridStepKm": 2.5,
  "includeRatings": false,
  "onlyOpen": false,
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "GR"
  }
}
```

# Actor output Schema

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

No description

# 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 = {
    "searchQuery": "souvlaki",
    "location": "Athens",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "GR"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/efood-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 = {
    "searchQuery": "souvlaki",
    "location": "Athens",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "GR",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/efood-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 '{
  "searchQuery": "souvlaki",
  "location": "Athens",
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "GR"
  }
}' |
apify call studio-amba/efood-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,studio-amba/efood-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/A3HH4CCUIxktXMBjn/builds/xhmp0o4gfMfYrnLu1/openapi.json
