# 🍴Uber Eats Scraper \[PPR] (`borderline/uber-eats-scraper-ppr`) Actor

Pay per result - Fast and cost-effective Uber Eats Scraper requiring just a search query and location or using stores urls. Instantly retrieve comprehensive restaurant data, including names, phone, ratings, locations, and menus. Seamlessly integrates, offering a highly efficient data solution.

- **URL**: https://apify.com/borderline/uber-eats-scraper-ppr.md
- **Developed by:** [borderline](https://apify.com/borderline) (community)
- **Categories:** Lead generation, Automation
- **Stats:** 604 total users, 66 monthly users, 95.7% runs succeeded, 11 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

$5.00 / 1,000 restaurants

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

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## 🚀 Uber Eats Scraper Actor | (PPR) Pay per results version

🎉 **Uber Eats Scraper** extracts comprehensive restaurant data from Uber Eats in two ways: **by address** (or address + query) or **by store URLs**. Perfect for gathering restaurant insights, menus, and pricing.

### ✨ Features

- **📍 Option A – By address or address + query**: Provide a delivery **address** (required). Optionally add a **query** (e.g. cuisine, restaurant name) and a **storeType** (Uber Eats vertical tab: restaurants, grocery, pharmacy, etc.).

- **🔗 Option B – By URLs**: Provide a list of Uber Eats store page URLs to scrape those restaurants directly. When **urls** is not empty, **query**, **address**, and **storeType** are ignored.

- **🏪 Store type filter**: Target restaurants only, grocery, convenience, pharmacy, and other Uber Eats category tabs—without mixing unrelated verticals in your dataset.

- **📊 Rich Detailed Data**: For each restaurant you get:
  - 🏠 **Restaurant Name & Sanitized Title**
  - ⭐ **Ratings & Customer Reviews**
  - 📍 **Complete Address (latitude, longitude)**
  - 🍕 **Full Menus & Pricing Details**
  - 🕑 **Opening Hours & Availability**
  - 📞 **Contact Information (Phone Number & Emails)**
  - 🖼️ **High-Quality Images (Logo & Hero Image)**
  - 📐 **Distance & Delivery ETA**
  - 🚧 **Open/Closed Status & Messages**

- **💻 Integrations**: Google Sheets, Slack, Zapier & Make.

***

### What does the Uber Eats Scraper do?

**Extract restaurant details and menus from [Uber Eats](https://www.ubereats.com/), with one restaurant per result.** Search near an address, at coordinates, or scrape a list of store URLs. Menu items stay nested inside the restaurant row.

Use the results to compare menus and prices, research restaurant markets, track availability, or build a restaurant directory. Apify provides API access, schedules, dataset exports, integrations and run monitoring. Start with one location and a small `maxRows` value to check coverage.

### What data can I extract?

The scraper returns information Uber Eats makes available for each store. Missing source information can be absent or null; menu and promotion collections can be empty.

| Fields | Meaning |
|---|---|
| `uuid`, `title`, `sanitizedTitle`, `url` | Store identity, name and public URL |
| `slug`, `citySlug`, `merchantType` | Store and city identifiers, merchant category |
| `location` | Address, city, postcode, country and store coordinates |
| `phoneNumber`, `emails` | Contact information exposed by Uber Eats; emails are often empty |
| `cuisineList`, `categories`, `categoriesLink` | Cuisines and category links |
| `priceBucket` | Store price category, from `$` to `$$$$` |
| `parentChain`, `isChain` | Parent chain `{uuid, name}` when available, and chain flag |
| `rating` | Existing rating fields plus `exactValue` and `ratingCount`; counts can be strings such as `"5,000+"` |
| `isOpen`, `isOrderable`, `isLost` | Open now, accepting orders, and whether the store has left the platform |
| `storeAvailablityStatus`, `closedMessage` | Availability details reported by Uber Eats |
| `etaRange`, `etaMinutes` | Original ETA text and numeric `{min, max}` in minutes, or null |
| `fareBadge`, `deliveryFee` | Original fee text and `{amount, currencyCode, text}`, or null; amount is in major currency units, e.g. `2.99` USD |
| `hours`, `workingHoursTagline` | Opening-hour ranges and readable summary |
| `promotions` | Non-empty promotion text supplied by Uber Eats |
| `menu`, `featuredItems` | Menu sections/items and featured items: prices, images, descriptions and availability |
| `analytics` | Menu counts, price statistics and content coverage |
| `logoImageUrl`, `heroImageUrl` | Store branding and header image |
| `distance`, `supportedDiningModes` | Distance information and supported ordering modes |
| `storeReviews`, `featuredReviews` | Review snippets in the store response; not a paginated review export |
| `diningMode` | Requested `DELIVERY` or `PICKUP` mode |
| `searchAddress` | Location producing this result; coordinates use Uber's resolved full address. Direct URL mode has no search address |
| `scrapedAt` | UTC ISO timestamp of extraction |

#### What does menu analytics measure?

`analytics` is computed from the exported `menu`, excluding the separate featured-items list. It includes `totalSections`, `totalItems`, `itemsWithPrice`, `itemsWithImage`, `itemsWithDescription`, `itemsWithCustomizations` and `itemsSoldOut`.

`minPrice`, `maxPrice` and `averagePrice` use the same units as menu-item `price`: cents for USD/EUR, so `1299` means $12.99 or €12.99. Missing prices are excluded; zero is valid. Price aggregates are null when no usable price exists.

`priceCoverage`, `imageCoverage`, `descriptionCoverage` and `customizationCoverage` are fractions from 0 to 1, using total menu items as the denominator. Empty menus have zero coverage. Customization coverage measures the presence of customizable items; enable `getMenuCustomizations` to retrieve option trees.

### How do I scrape Uber Eats?

1. Open the Input tab and choose one of the location or URL options below.
2. Set the locale and optional store type or search query.
3. Set `maxRows` and the run's spending limit, then start the Actor.
4. Inspect the Output tab. You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

#### How do I search near one address?

```json
{
  "address": "1600 Pennsylvania Avenue NW, Washington, DC",
  "query": "pizza",
  "storeType": "RESTAURANTS",
  "locale": "en-US",
  "addressCountry": "US",
  "maxRows": 20
}
```

Include the city and country for reliable resolution. Omit `query` to browse nearby stores.

#### How do I use coordinates or pickup mode?

```json
{
  "latitude": 48.8566,
  "longitude": 2.3522,
  "locale": "fr-FR",
  "addressCountry": "FR",
  "diningMode": "PICKUP",
  "maxRows": 10
}
```

Provide both coordinates: latitude −90 to 90 and longitude −180 to 180. Uber resolves the point to a location. `DELIVERY` is the default; pickup requests use `PICKUP` availability and results. Coverage depends on the market and store.

#### How do I scrape known store URLs?

```json
{
  "urls": [
    "https://www.ubereats.com/fr/store/mcdonalds-paris-alesia/eHoH6Q_2RRikwI-xKk7qaQ",
    "https://www.ubereats.com/es-en/store/kebaba-haus-%26-pizzeria-bulevar-de-peguera-17/"
  ],
  "locale": "fr-FR",
  "getMenuCustomizations": false
}
```

Direct URLs override all location inputs, `query` and `storeType`. `maxRows` does not limit URL mode. Filters, dining mode, exclusions and the run's paid-item limit still apply. Invalid non-Uber-Eats URLs are dropped with a warning; input with no valid URL is rejected.

### Which inputs are available?

| Input | Default / accepted values | Behavior |
|---|---|---|
| `address` | Non-empty string | One search location |
| `latitude`, `longitude` | Numeric coordinate pair | Overrides both text-location inputs |
| `urls` | Non-empty list of store URLs | Overrides discovery inputs |
| `locale` | `en-US` | Language/region; see Input tab for supported locales |
| `addressCountry` | `US` | Country code used for address resolution; set it to the country being searched |
| `query` | Omitted | Cuisine, store name or keyword |
| `storeType` | `ALL` | Uber Eats vertical/category tab |
| `maxRows` | 1,500 if omitted | Successful rows per address; `0` requests all available subject to the paid-item limit. Input form prefills 100 |
| `diningMode` | `DELIVERY` | `DELIVERY` or `PICKUP` |
| `excludeStores` | Empty | Store UUIDs to skip in every mode, including URLs; case-insensitive |
| `getMenuCustomizations` | `false` | Retrieve modifier groups and choices; increases duration and payload size |

Excluded stores are not saved, billed, or counted toward `maxRows`. Location precedence is `urls` → coordinates → `address`, with warnings when lower-priority inputs are ignored.

#### Which store types support a query?

| Store type | With a query | Without a query |
|---|---|---|
| `ALL` | Search across categories | Home feed |
| `RESTAURANTS` | Restaurant search | Restaurant-focused feed |
| `GROCERY` | Shop search | Grocery browse feed |
| `SHOP` | Grocery and retail search | General browse behavior |
| `ALCOHOL` | Alcohol search | General browse behavior |
| `CONVENIENCE`, `PHARMACY`, `PRESCRIPTIONS`, `PERSONAL_CARE`, `BABY`, `SPECIALITY_FOODS`, `PET_SUPPLIES`, `FLOWERS`, `RETAIL`, `BEAUTY`, `ELECTRONICS` | Query ignored | Category browse feed |

Aliases: `HEALTH` means `PHARMACY`; `UNKNOWN` means `ALL`. Set `RESTAURANTS` explicitly for restaurant-only searches.

### What does an output row look like?

This shortened, illustrative row shows the structure and units. Actual values depend on Uber Eats.

```json
{
  "uuid": "bff91760-2d67-54d7-91db-9f6f875086a6",
  "title": "Example Pizza",
  "url": "https://www.ubereats.com/store/example-pizza/v_kXYC1nVNeR259vh1CGpg",
  "slug": "example-pizza",
  "citySlug": "washington-dc",
  "priceBucket": "$$",
  "parentChain": null,
  "isChain": false,
  "emails": [],
  "currencyCode": "USD",
  "rating": { "ratingValue": 4.4, "reviewCount": "700+", "exactValue": 4.4077, "ratingCount": "700+" },
  "isOpen": true,
  "isOrderable": true,
  "etaRange": "Delivered in 35 to 55 min",
  "etaMinutes": { "min": 35, "max": 55 },
  "fareBadge": "Delivery Fee: $0.99",
  "deliveryFee": { "amount": 0.99, "currencyCode": "USD", "text": "Delivery Fee: $0.99" },
  "workingHoursTagline": "Open until 10:00 PM",
  "promotions": [],
  "diningMode": "DELIVERY",
  "searchAddress": "1600 Pennsylvania Avenue NW, Washington, DC",
  "scrapedAt": "2026-09-05T12:00:00.000Z",
  "menu": [{
    "catalogName": "Pizza",
    "catalogItems": [{
      "uuid": "b7ac95d8-11ea-4917-bc31-dd20c2407f29",
      "title": "Margherita",
      "itemDescription": "Tomato, mozzarella and basil",
      "price": 1299,
      "priceTagline": "$12.99",
      "isSoldOut": false,
      "hasCustomizations": true
    }]
  }],
  "featuredItems": [],
  "analytics": {
    "totalSections": 1, "totalItems": 1,
    "itemsWithPrice": 1, "itemsWithImage": 0, "itemsWithDescription": 1,
    "itemsWithCustomizations": 1, "itemsSoldOut": 0,
    "minPrice": 1299, "maxPrice": 1299, "averagePrice": 1299,
    "priceCoverage": 1, "imageCoverage": 0,
    "descriptionCoverage": 1, "customizationCoverage": 1
  }
}
```

### How much does it cost to scrape Uber Eats?

The [Actor's listed price](https://apify.com/borderline/uber-eats-scraper-ppr/pricing) is **$5 per 1,000 restaurant rows**, or $0.005 per restaurant. The menu is included in that row; menu items are not separate billable results. Check the Pricing tab for the current rate.

| Successful restaurant rows | Result charge at this rate |
|---|---|
| 100 | $0.50 |
| 1,000 | $5.00 |
| 100 stores | $0.50 |

Use the run's spending/paid-item limit as the global budget. `maxRows` limits restaurant rows for the selected location or URLs. Duplicate and excluded stores within a run produce no additional rows. Separate runs can return and bill the same restaurant again. Account credits and applicable platform charges are shown in Apify Console.

### What are the limitations?

- Results reflect stores visible to Uber Eats for the chosen location and mode. They are not a complete census; `maxRows` is a ceiling, not a guaranteed count.
- Opening status, fees, promotions and ETA change with location and time. Unrecognized ETA/fee text produces null numeric metrics while the original text remains available.
- Some stores omit menu sections, prices, chain metadata, ratings or contacts. Empty emails do not imply that a restaurant has no email address.
- Searches can return zero rows. The Actor currently marks zero-result runs as failed, including searches where nothing matches.
- Removed stores and temporary access failures can prevent retrieval. Direct-target failures go into the separate `errors` dataset rather than billable restaurant placeholders.
- Menus remain nested. Flat menu rows, paginated reviews, automatic change detection and external website contact enrichment are not included.
- Full customizations require additional requests and can make runs substantially longer.

### Frequently asked questions

#### Can I call the scraper through an API?

Use the Actor's [API tab](https://apify.com/borderline/uber-eats-scraper-ppr/api) for authenticated run examples, pass the same input JSON, and retrieve results from the run's default dataset. Keep tokens in your application's secret storage.

#### Can AI agents or MCP clients use this Actor?

Invoke the Actor through Apify's API from an agent workflow. Apify also provides an [Actors MCP server](https://docs.apify.com/platform/integrations/mcp); configure it for this Actor and your account. This Actor does not expose a separate custom MCP server. Set small row and spending limits when allowing an agent to start runs.

#### Can I schedule exports to Sheets or other tools?

Use Apify schedules for recurring runs and the Integrations tab for destinations such as Google Sheets, Slack, Make or Zapier. Retain `uuid` and `scrapedAt` when comparing exports over time. Change detection belongs in your downstream workflow.

#### Are prices in dollars or cents?

Menu-item `price` and analytics price aggregates use the source menu's minor units, such as cents for USD/EUR. `deliveryFee.amount` uses major units. Read `currencyCode` alongside either value; missing data is not a zero price.

#### Can I use the data for my project?

Check the source website's terms and the rules applicable to your intended use. Treat contact details and review content responsibly; this tool does not grant rights to republish third-party content or contact people without an appropriate basis.

#### Where can I get help?

Open an issue in the [Issues tab](https://apify.com/borderline/uber-eats-scraper-ppr/issues), ideally with the run URL, input location and expected result. Remove secrets from examples. Contact the developer there for custom requirements.

# Actor input Schema

## `locale` (type: `string`):

Select locale (default is en-US). Applies to both search and URL mode.

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

Query to search for. (ex: McDonald's, pizza, etc.) Optional when using address.

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

Address, city or postcode to search near. Optional when using coordinates or urls.

## `addressCountry` (type: `string`):

Country code that can improve delivery address resolution. Optional; defaults to US.

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

Latitude of the search point. Provide longitude too. Coordinates override address. API input also accepts numeric strings.

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

Longitude of the search point. Required together with latitude. API input also accepts numeric strings.

## `diningMode` (type: `string`):

Availability and results for delivery or pickup. Applies to location searches and direct URLs.

## `storeType` (type: `string`):

Uber Eats category tab to scrape. **Default when omitted: ALL** (same as the “All” tab). Use **RESTAURANTS** for restaurant-only results. Browse-only types (CONVENIENCE, PHARMACY, RETAIL, …) use the category feed and **ignore query**. Ignored when **urls** is set. Aliases: `HEALTH` → PHARMACY, `UNKNOWN` → ALL.

## `maxRows` (type: `integer`):

Maximum successful, matching restaurants (0 = all available, subject to the run's paid-item limit). Ignored in URL mode. The run's paid-item limit is global.

## `urls` (type: `array`):

List of Uber Eats restaurant/store page URLs to scrape. When provided, address and query are ignored.

## `getMenuCustomizations` (type: `boolean`):

When enabled, the scraper loads full customization trees for each menu item (modifiers, add-ons, etc.).

## `excludeStores` (type: `array`):

Uber Eats store UUIDs to skip in all input modes, including urls. Excluded stores are not saved, counted toward maxRows, or billed.

## Actor input object example

```json
{
  "locale": "en-US",
  "query": "Pizza",
  "address": "71 Avenue Du Général Leclerc, Paris",
  "addressCountry": "US",
  "diningMode": "DELIVERY",
  "maxRows": 100,
  "urls": [
    "https://www.ubereats.com/fr/store/mcdonalds-paris-alesia/eHoH6Q_2RRikwI-xKk7qaQ"
  ],
  "getMenuCustomizations": false,
  "excludeStores": [
    "198143de-5fc7-4488-b751-6c32604454d3",
    "93a4dbc2-6c72-4789-81c5-73556737e311"
  ]
}
```

# Actor output Schema

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

Restaurant and store rows with the overview fields shown in the Output tab, including menu, rating, availability, ETA, fees and analytics.

## `rawItems` (type: `string`):

The complete dataset with every field emitted by the scraper. Use this view for database imports, API consumers and AI agents.

# 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 = {
    "locale": "en-US",
    "query": "Pizza",
    "address": "1600 Pennsylvania Avenue, Washington DC",
    "addressCountry": "US",
    "maxRows": 100,
    "getMenuCustomizations": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("borderline/uber-eats-scraper-ppr").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 = {
    "locale": "en-US",
    "query": "Pizza",
    "address": "1600 Pennsylvania Avenue, Washington DC",
    "addressCountry": "US",
    "maxRows": 100,
    "getMenuCustomizations": False,
}

# Run the Actor and wait for it to finish
run = client.actor("borderline/uber-eats-scraper-ppr").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 '{
  "locale": "en-US",
  "query": "Pizza",
  "address": "1600 Pennsylvania Avenue, Washington DC",
  "addressCountry": "US",
  "maxRows": 100,
  "getMenuCustomizations": false
}' |
apify call borderline/uber-eats-scraper-ppr --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,borderline/uber-eats-scraper-ppr"
        }
    }
}

```

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/nrQeUJPbeJLVVsXPH/builds/47qkyFIsqIsJfgkQv/openapi.json
