# Uber Eats Scraper: Stores, Menus and Prices (`s-r/uber-eats-stores`) Actor

Extract Uber Eats stores and flat menu items by store URL, city and cuisine, or search near a delivery address. Get store coordinates, ratings, opening hours, menu prices, currencies and availability.

- **URL**: https://apify.com/s-r/uber-eats-stores.md
- **Developed by:** [SR](https://apify.com/s-r) (community)
- **Categories:** E-commerce, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 stores

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

## Uber Eats Scraper: Stores, Menus and Prices

This Uber Eats scraper extracts store details and flat menu items for restaurant research, menu price comparisons and delivery dashboards. Start with store URLs, discover restaurants in a city and cuisine, or search near a delivery address. Each store and menu item has a stable identity, so the resulting rows can be joined in a spreadsheet or database.

### What the Uber Eats scraper returns

The dataset contains two record types. A `place` row describes a store, including its name, address, coordinates, rating, available rating count, telephone number, opening hours and supported dining modes. A `menu_item` row describes one unique item from that store, including its name, description, menu section, price, currency, image and availability.

Both types include `_type`, `row_type`, `row_id`, `source`, `platform`, `place_id` and `fetched_at`. The store UUID is the shared `place_id`. Menu items also include their own `item_id`, the store name and the store URL. Filter on `row_type` to build separate restaurant and menu tables, then join them on `place_id`.

Useful applications include comparing menu prices between branches, collecting restaurant locations for a dashboard, tracking public item availability, studying cuisine coverage by city and building a catalogue of a chain's delivery menus. Prices describe the menu shown at collection time. They do not include a customer's final checkout total, taxes added later, optional toppings or personalised discounts.

### Input

Provide at least one of these starting points:

- `store_urls`: an array of Uber Eats store URLs or store UUIDs. Country and language prefixes in store URLs are supported. Repeated references to the same store are collected once.
- `city`: a city name or its Uber Eats city slug. Add `cuisine`, such as `pizza`, to narrow discovery. An empty cuisine discovers stores across the city.
- `search_query`: a search term together with a delivery `address`, or both `latitude` and `longitude`.

For example, the following input discovers up to ten pizza stores in New York City:

```json
{
  "city": "new-york-city",
  "cuisine": "pizza",
  "max_stores": 10,
  "include_menu": true
}
```

You can combine starting points. Explicit stores are processed first, followed by city discovery and then address search. A store found through several starting points still appears once. An invalid URL in a mixed list is skipped with a warning. If the input has no usable starting point, the run returns an input error with no result charges.

Set `locale` to a language and country, such as `en-US`, `nl-NL`, `fr-FR` or `ja-JP`. The default is `en-US`. Locale affects displayed text; it does not change the store's actual menu currency. `country` is an optional two-letter country setting and defaults to the country in the locale.

The `max_stores` default is 20, with a maximum of 1,000 unique stores. Closed stores count toward that discovery limit. `max_items_per_store` defaults to zero, meaning all menu items shown by the source. Set a positive value to limit each menu. Set `include_menu` to false when you only need restaurant details; this produces no menu item rows or menu item charges.

### Output

Store rows include `price_level` as the number of displayed price symbols, `currency`, `opening_hours`, `is_open`, `is_orderable`, `closed_message`, `menu_items_count` and `menu_is_partial`. Opening times use minutes after midnight in the store's local time. An end time earlier than its start time indicates a period crossing midnight.

Ratings are included where the source provides them. A displayed count such as `1000+` is retained as `reviews_count_text`, while the exact numeric `reviews_count` remains null. Missing values remain null rather than becoming estimates. A source availability message alone does not mean that the store is closed.

Menu prices are numeric amounts in `currency`. Japanese yen prices are returned in yen units too. A zero price can represent a free item or an item whose price depends on add-ons. Sold-out items retain their displayed price and have `is_available: false`. Item customisation details and customer review text are outside this version's output.

For delivery estimates, supply an address or coordinates. `eta_text` is omitted as a value when no delivery location is supplied. An address is resolved to its first matching location, so use a complete street address when possible. Delivery fee text and a numeric amount are returned where available; promotional fee text is kept as text and is not converted into an ordinary delivery fee.

Restaurant menus are collected across available menu pages. Some convenience and grocery stores only expose a selection of items in each category. These stores carry `menu_is_partial: true`; the output does not claim to include products that were never shown. A requested item cap also marks the menu partial. The run summary and warnings describe collection limits or skipped stores.

### Example output of the Uber Eats scraper

This is a real result for one store URL (Aunt Jake's in New York), shortened to the main fields. Every row also carries `_type`, `source`, `platform` and `row_id`.

```json
{
  "row_type": "place",
  "place_id": "adacf6aa-fb63-4667-a927-9079b932d3db",
  "name": "Aunt Jake's - Upper East Side",
  "address": "1555 2nd Avenue, New York, NY 10075",
  "lat": 40.7745425,
  "lng": -73.954377,
  "category": "Italian",
  "rating": 4.6,
  "reviews_count_text": "1000+",
  "price_level": 1,
  "currency": "USD",
  "is_open": true,
  "is_orderable": true,
  "menu_items_count": 31,
  "menu_is_partial": false,
  "billable": true,
  "charge_event": "store"
}
```

```json
{
  "row_type": "menu_item",
  "item_id": "e6516ae5-d58a-5a80-8d4d-0d8336cc88d5",
  "place_id": "adacf6aa-fb63-4667-a927-9079b932d3db",
  "place_name": "Aunt Jake's - Upper East Side",
  "name": "Kale Caesar Salad (CGF)",
  "description": "Romaine, Classic Caesar Dressing",
  "section": "Starters",
  "price": 15,
  "currency": "USD",
  "price_text": "$15.00",
  "is_available": true,
  "is_sold_out": false,
  "has_customizations": true,
  "billable": true,
  "charge_event": "menu_item"
}
```

### Use cases for Uber Eats store and menu data

- **Restaurant chains** compare their own delivery menu prices between branches and against nearby competitors.
- **Foodtech analysts** build a catalogue of restaurants and dishes per city and cuisine, and follow how it changes between runs.
- **Price researchers** track item prices and availability over time, using `fetched_at` to compare observations.
- **Delivery dashboards** need store locations, ratings and opening hours as rows they can load into a database.
- **Developers looking for an Uber Eats API** get the same public store and menu data as JSON through the Apify API, without building their own collector.

### How this Uber Eats scraper compares with other options

Many Uber Eats scrapers on the Store return one mixed row type or charge a start fee on every run. This actor separates the two record types, so a store table and a menu table load cleanly and join on `place_id`. It has no start fee, empty results and closed stores are free, and `include_menu: false` gives you stores only. Menus that are only partly shown by the source are marked `menu_is_partial` instead of being presented as complete. Customisation options and customer review text are not included; use a dedicated reviews actor for review text.

### Pricing

Result charges use two events: one `store` event per delivered open, orderable store with menu items, and one `menu_item` event per delivered unique menu item. Consult the actor's current Pricing tab for the event amounts. The two record types are billed separately, so `include_menu: false` is useful when you only need store details.

Closed or empty stores are returned as store rows with `billable: false` and are free. They produce no menu item rows. Empty results have no result charges, and this actor has no result-event start fee. Available and sold-out items on an otherwise orderable menu both count as delivered menu records.

Users without a paid Apify plan receive at most ten dataset rows per run, including both store and menu rows. Their menu limit is nine items per store. This is a delivery limit; ordinary result charges still apply to delivered billable rows. Paid users retain their requested limits.

### FAQ

#### Can I collect an entire restaurant chain?

Supply known branch URLs or discover branches through city and cuisine searches. The actor collects public stores from those starting points. It does not infer missing branches or guarantee that a city list contains every branch operated by a chain. Store and chain identifiers, where available, help you group the collected locations.

#### Does this return the full menu?

It returns unique items shown by each restaurant's available menu pages. Convenience and grocery category carousels can show a limited selection; those menus are explicitly marked partial. A positive `max_items_per_store` also limits the menu. Customisation options require a separate data source and are not included here.

#### Why are delivery fees or estimates missing?

Uber Eats may not show an ordinary delivery fee for a store or may display only a promotion. ETA values require a delivery location. Missing source values remain null so a dashboard can distinguish absent information from a real zero fee or a known estimate.

#### How are larger collections continued?

The actor follows continuation pages automatically while its run budget allows. The underlying response includes `next_cursor` when work remains. API callers can resend the same original input with that cursor. Stable row identities prevent repeated menu items, and store counts are updated as a larger menu is completed.

#### Can I export the results?

Yes. Export the default dataset as JSON, CSV or Excel, or read it through the Apify dataset API. Separate stores from menu items by `row_type`, join by `place_id`, and use `fetched_at` when comparing observations from several runs.

# Actor input Schema

## `store_urls` (type: `array`):

Uber Eats store URLs or store UUIDs. Invalid entries in a mixed list are skipped with a warning.

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

City name or city slug, such as Amsterdam or new-york-city.

## `cuisine` (type: `string`):

Cuisine name or category slug. Leave empty to discover all stores in the city.

## `search_query` (type: `string`):

Search term. Requires address or both latitude and longitude.

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

Delivery address. The first matching address supplies the delivery location and ETA.

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

Delivery latitude from -90 to 90. Requires longitude.

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

Delivery longitude from -180 to 180. Requires latitude.

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

Language and country, for example en-US, nl-NL, fr-FR or ja-JP. Menu currency comes from the store.

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

Optional two-letter country code. Defaults to the country in locale.

## `include_menu` (type: `boolean`):

Return flat menu item rows in addition to stores. False returns stores only.

## `max_stores` (type: `integer`):

Maximum number of unique stores across all supplied sources and cursor pages, including closed stores.

## `max_items_per_store` (type: `integer`):

Maximum unique menu items per store. Zero returns all items shown by the store.

## `cursor` (type: `string`):

Continuation returned in next_cursor. Resend the same original input.

## Actor input object example

```json
{
  "store_urls": [
    "https://www.ubereats.com/store/aunt-jakes-upper-east-side/raz2qvtjRmepJ5B5uTLT2w"
  ],
  "city": "new-york-city",
  "cuisine": "pizza",
  "locale": "en-US",
  "include_menu": true,
  "max_stores": 20,
  "max_items_per_store": 0
}
```

# Actor output Schema

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

No description

## `output` (type: `string`):

No description

## `errors` (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 = {
    "store_urls": [
        "https://www.ubereats.com/store/aunt-jakes-upper-east-side/raz2qvtjRmepJ5B5uTLT2w"
    ],
    "city": "new-york-city",
    "cuisine": "pizza"
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/uber-eats-stores").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 = {
    "store_urls": ["https://www.ubereats.com/store/aunt-jakes-upper-east-side/raz2qvtjRmepJ5B5uTLT2w"],
    "city": "new-york-city",
    "cuisine": "pizza",
}

# Run the Actor and wait for it to finish
run = client.actor("s-r/uber-eats-stores").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 '{
  "store_urls": [
    "https://www.ubereats.com/store/aunt-jakes-upper-east-side/raz2qvtjRmepJ5B5uTLT2w"
  ],
  "city": "new-york-city",
  "cuisine": "pizza"
}' |
apify call s-r/uber-eats-stores --silent --output-dataset

```

## MCP server setup

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

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/blteswfVgIovQmv97/builds/YcCqstrp2gtM8s7cI/openapi.json
