# Yelp Scraper (`datascrapers/yelp-scraper`) Actor

Scrape Yelp business listings by search term, category, location, or URL. Optional full business details with phone, hours, website, and reviews.

- **URL**: https://apify.com/datascrapers/yelp-scraper.md
- **Developed by:** [Farhan Ali](https://apify.com/datascrapers) (community)
- **Categories:** E-commerce, Lead generation, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 business scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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

**Yelp Scraper** creates a structured dataset of business listings collected from Yelp. Each dataset item can include business identifiers, ratings, review counts, price range, categories, address and coordinates, and — when business details are enabled — phone, hours, attributes, and review text. Query the source using start URLs, a search term and location, or `searchQueries`, control the result limit with `maxItems`, and retrieve records through the Apify Dataset API or export them as JSON, CSV, Excel, XML, or another supported format.

### Dataset at a glance

| Property | Value |
|---|---|
| Source | Yelp (yelp.com and regional sites such as yelp.de, yelp.co.uk, yelp.com.au) |
| Record unit | One business listing |
| Input methods | `startUrls`, `searchTerm` + `location`, `searchQueries` |
| Main identifiers | `businessId`, `url`, `alias` |
| Delivery | Apify Dataset and API |
| Export formats | JSON, CSV, Excel, XML, HTML |
| Update model | Fresh records per Actor run |
| Pricing | $1.50 per 1,000 listings; $3.00 per 1,000 additional for full business details |

### Coverage and available records

The Actor collects business listings from Yelp search and category pages, and from direct business-page URLs. Supported behavior:

- **Search by term and location** — `searchTerm` plus `location` resolves through Yelp's own search/autocomplete.
- **Search queries** — `searchQueries` accepts strings like `"Pizza in Berlin"` or `"term | location"`.
- **Regional sites** — `countryCode` selects among 31 Yelp sites (US, DE, AT, CH, FR, IT, ES, NL, BE, IE, GB, CA, AU, NZ, SG, JP, MX, BR, SE, NO, DK, FI, PL, CZ, PT, AR, CL, HK, MY, PH, TW). Ignored when a start URL already includes a host.
- **Listing-only vs. details** — `scrapeDetails` (default `false`) returns listing fields only; when enabled, each business is enriched with phone, hours, attributes, full address, and up to a page of review text.
- **Pagination and limits** — `maxItems` caps the number of businesses (0 = unlimited).

Not currently collected: menu data, photos beyond the primary thumbnail, owner responses, and full review history (the Actor returns the review snippet visible on the page, not every review).

### Data dictionary

Listing fields (always present when available):

| Field | Type | Nullable | Description | Example |
|---|---:|---|---|---|
| `businessId` | string | no | Yelp internal business identifier; recommended deduplication key | `_n0Awcf8FFjXBJaCgXXROw` |
| `name` | string | no | Business name | `Café Bondi` |
| `alias` | string | yes | Yelp URL slug | `café-bondi-berlin-2` |
| `url` | string | no | Business page URL | `https://www.yelp.de/biz/café-bondi-berlin-2` |
| `rating` | number | yes | Average star rating | `4.2` |
| `reviewCount` | integer | yes | Number of reviews | `117` |
| `priceRange` | string | yes | Price range symbols | `€€` |
| `categories` | array | yes | Display category names | `["Frühstück & Brunch","Café"]` |
| `categoryAliases` | array | yes | Normalized category slugs | `["breakfast_brunch","cafes"]` |
| `photo` | string | yes | Primary photo URL | `https://s3-media0.fl.yelpcdn.com/...jpg` |
| `isAd` | boolean | yes | Whether the listing is paid placement | `false` |
| `ranking` | integer | yes | Position within the search result set | `1` |
| `searchTerm` | string | yes | Term used for the query | `Lunch` |
| `searchLocation` | string | yes | Resolved location | `Berlin, Deutschland` |
| `sourceQuery` | string | yes | Combined query string | `Lunch in Berlin, Deutschland` |
| `domain` | string | yes | Yelp site host | `www.yelp.de` |
| `snippet` | string | yes | Highlighted review snippet | `...lots of lunch menu items...` |
| `detailsFetched` | boolean | no | Whether detail enrichment succeeded | `true` |

Detail fields (present when `scrapeDetails` is enabled and the page yields them):

| Field | Type | Nullable | Description | Example |
|---|---:|---|---|---|
| `address` | string | yes | Full street address | `Eichendorffstr. 6, Berlin, BE, 10115` |
| `addressLine1` | string | yes | First address line | `Eichendorffstr. 6` |
| `city` | string | yes | City | `Berlin` |
| `region` | string | yes | State/region code | `BE` |
| `postalCode` | string | yes | Postal code | `10115` |
| `country` | string | yes | Country code | `DE` |
| `neighborhoods` | array | yes | Neighborhood names | `["Mitte"]` |
| `latitude` / `longitude` | number | yes | Coordinates | `52.53034262` |
| `phone` | string | yes | Phone number | `030 2411221` |
| `isClosed` | boolean | yes | Whether the business is marked closed | `false` |
| `isOpenNow` | boolean | yes | Whether open at scrape time | `true` |
| `hours` | array | yes | Weekly hours, one object per day | `[{"day":"Mo","hours":["8:00 AM - 6:00 PM"]}]` |
| `attributes` | object | yes | Business attributes (parking, seating, etc.) | `{"OutdoorSeating":true}` |
| `reviews` | array | yes | Review objects from the page | see below |

Each element of `reviews` contains `id`, `rating`, `text`, `language`, `author`, `authorLocation`, `authorReviewCount`, and `date`.

### Example dataset record

```json
{
  "businessId": "vs3J4zfbThn0_5w2Q5Mfuw",
  "name": "Schlögl's",
  "alias": "schlögls-berlin",
  "url": "https://www.yelp.de/biz/schlögls-berlin",
  "rating": 4.3,
  "reviewCount": 114,
  "priceRange": "€€",
  "categories": ["Deutsch", "Biergarten"],
  "categoryAliases": ["german", "beergarden"],
  "photo": "https://s3-media0.fl.yelpcdn.com/bphoto/6J497GlRPS0VMOg3GQTuog/l.jpg",
  "isAd": false,
  "ranking": 2,
  "searchTerm": "Lunch",
  "searchLocation": "Berlin, Deutschland",
  "sourceQuery": "Lunch in Berlin, Deutschland",
  "domain": "www.yelp.de",
  "detailsFetched": true,
  "address": "Karl-Liebknecht-Str. 9, Berlin, BE, 10178",
  "city": "Berlin",
  "country": "DE",
  "latitude": 52.5213,
  "longitude": 13.406281,
  "phone": "030 2411221",
  "isClosed": false,
  "isOpenNow": false,
  "hours": [
    {"day": "Mo", "hours": ["Geschlossen"], "isClosed": null}
  ],
  "reviews": [
    {
      "id": "E6wsKvO9VBU3e6lLjaQx1g",
      "rating": 5,
      "text": "Went here on the limb. While visiting Berlin...",
      "language": "en",
      "author": "Renata R.",
      "authorLocation": "New York, Vereinigte Staaten",
      "authorReviewCount": 607,
      "date": "2026-07-01T21:29:42+02:00"
    }
  ]
}
```

The record above was produced by a run with `searchQueries: ["Lunch in Berlin"]`, `countryCode: "DE"`, and `scrapeDetails: true`.

### Query and input reference

| Input | Type | Required | Default | Accepted values | Description |
|---|---:|---|---|---|---|
| `startUrls` | array | no | — | Yelp search or business URLs | Preferred input; domain is taken from the URL host |
| `searchTerm` | string | no | — | keyword or category | What to find, e.g. `Restaurants`, `Pizza` |
| `location` | string | no | — | city or area | Where to search, e.g. `Berlin`, `New York, NY` |
| `searchQueries` | array | no | — | `"term in location"` or `"term \| location"` | Alternative to `searchTerm` + `location` |
| `countryCode` | string | no | `US` | 31 regional codes | Yelp site used when no start URL host is present |
| `scrapeDetails` | boolean | no | `false` | `true` / `false` | Fetches full business details; adds the `listing-details` charge event |
| `maxItems` | integer | no | `0` | 0 = unlimited | Maximum businesses to scrape |
| `proxyConfiguration` | object | no | residential proxy | proxy settings | Residential proxies are recommended |

Minimal request:

```json
{
  "searchTerm": "Lunch",
  "location": "Berlin",
  "countryCode": "DE",
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

Advanced request (bulk queries with details):

```json
{
  "searchQueries": ["Lunch in Berlin", "Pizza in München"],
  "countryCode": "DE",
  "scrapeDetails": true,
  "maxItems": 0,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

### Retrieve the data through the API

1. Start the Actor with a JSON input (see above).
2. Wait for the run to finish, or call the synchronous endpoint for quick jobs.
3. Retrieve items from the run's default dataset.
4. Paginate or export the dataset in the format you need.

Python example:

```python
import json
import urllib.request

API_TOKEN = "<your Apify API token>"
ACTOR_ID = "datascrapers/yelp-scraper"

payload = {
    "searchTerm": "Lunch",
    "location": "Berlin",
    "countryCode": "DE",
    "maxItems": 20,
    "proxyConfiguration": {"useApifyProxy": True, "apifyProxyGroups": ["RESIDENTIAL"]},
}

req = urllib.request.Request(
    f"https://api.apify.com/v2/acts/{ACTOR_ID}/runs?token={API_TOKEN}",
    data=json.dumps(payload).encode(),
    headers={"Content-Type": "application/json"},
)
with urllib.request.urlopen(req) as resp:
    run = json.loads(resp.read())["data"]

dataset_id = run["defaultDatasetId"]
with urllib.request.urlopen(
    f"https://api.apify.com/v2/datasets/{dataset_id}/items?token={API_TOKEN}"
) as resp:
    items = json.loads(resp.read())
```

For other languages, use the generated API tab on the Actor's page.

### Data quality and record handling

- **Conditional fields** — detail fields (phone, hours, attributes, reviews) are only present when `scrapeDetails` is enabled and Yelp exposes them for that business.
- **Nullable values** — `rating`, `reviewCount`, and address components may be absent for sparse listings; treat them as nullable.
- **Deduplication** — `businessId` is the stable, recommended unique key. `url` also uniquely identifies a business.
- **Retries and errors** — requests are retried with backoff; a business that fails to load is skipped rather than partially written.
- **Raw values** — `priceRange`, `categories`, and `hours` are reported as Yelp displays them; no normalization beyond extracting the fields above.

The Actor does not guarantee a full-site snapshot; results reflect what a given query returns at run time.

### Export and pipeline examples

| Destination | Recommended method | Typical use |
|---|---|---|
| PostgreSQL/Supabase | Dataset API or webhook consumer | Store business records keyed by `businessId` |
| Google Sheets | Apify integration | Review and share a small result set |
| S3/cloud storage | Scheduled export or integration | Archive daily/weekly snapshots |
| BI tools | CSV/JSON export | Analyze ratings and price ranges by city |

### Pricing and cost examples

The Actor uses pay-per-event billing. Two charge events apply:

- **`dataset-item`** — $1.50 per 1,000 business listings returned.
- **`listing-details`** — $3.00 per 1,000 businesses when `scrapeDetails` is enabled (in addition to the listing event).

Apify plan discounts (Bronze/Silver/Gold) reduce these rates.

| Records | Estimated base cost |
|---:|---:|
| 1,000 listings | $1.50 |
| 10,000 listings | $15.00 |
| 10,000 listings + details | $45.00 |

Estimates assume the free-tier rate and no proxy markup; actual cost depends on your Apify plan and selected options.

### Limitations and responsible data use

- The Actor collects publicly accessible listing data only; it does not bypass login or paywalls.
- Results depend on Yelp's current page structure; site changes can require Actor updates.
- Some fields are conditional or nullable (see Data dictionary).
- The Actor does not retain historical snapshots unless you store them yourself.
- You are responsible for complying with Yelp's terms of service and applicable privacy and contractual obligations.

### Dataset questions

#### What does one dataset item represent?

One Yelp business listing, optionally enriched with full business details and a page of reviews.

#### Which field should I use as a unique identifier?

`businessId`. `url` is also unique and useful for joins with other datasets.

#### Are fields nullable or conditional?

Yes. Rating, review count, and address components may be null. Detail fields appear only when `scrapeDetails` is enabled and the page exposes them.

#### Can I retrieve the records as CSV or JSON?

Yes. The default dataset supports JSON, CSV, Excel, and XML exports, and the Dataset API returns JSON.

#### How do I paginate large datasets?

Set `maxItems` to cap the run, or paginate the default dataset via the Dataset API (`offset`/`limit` parameters).

#### What counts as a billable result?

Each business listing returned counts as one `dataset-item`. Enabling `scrapeDetails` adds one `listing-details` event per business.

### Related datasets from Data Scrapers

- **[LinkedIn Company Scraper](https://apify.com/datascrapers/linkedin-company-scraper)** — company-level data (employee count, posts, founders) that can be joined with business listings by company name.
- **[Redfin Scraper](https://apify.com/datascrapers/redfin-scraper)** — real-estate listings with pricing for location-based market research.
- **[Instagram Post Scraper](https://apify.com/datascrapers/instagram-post-scraper)** — social posts that complement local-business brand analysis.
- **[Zoopla Scraper](https://apify.com/datascrapers/zoopla-scraper)** — property listings for adjacent UK location datasets.

### Data Scrapers support

Need an additional field, record type, or export workflow? Contact Data Scrapers at stardustspotlight@gmail.com. Include a sample source URL, required fields, expected record volume, and preferred delivery format.

# Actor input Schema

## `startUrls` (type: `array`):

Preferred input. Paste Yelp search URLs (e.g. https://www.yelp.de/search?find\_desc=Lunch\&find\_loc=Berlin) or business page URLs (e.g. https://www.yelp.com/biz/example-business-name). Domain is taken from the URL host.

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

What to find — a keyword or Yelp category such as Restaurants, Lunch, Pizza, Coffee & Cafes, Contractors & Handymen, etc.

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

City or area to search in (e.g. Berlin, Frankfurt am Main, New York, NY). Uses Yelp location autocomplete when possible.

## `searchQueries` (type: `array`):

Alternative to searchTerm + location. Each item can be "term in location" or "term | location" (e.g. "Pizza in Berlin").

## `countryCode` (type: `string`):

Which Yelp regional site to use for searchTerm/location/searchQueries when startUrls are not provided. Ignored when startUrls include a host.

## `scrapeDetails` (type: `boolean`):

When enabled, fetches full business details (phone, website, hours, attributes, review snippets, photos). Charges an extra listing-details event per successful detail fetch. Disabled by default for faster, cheaper listing-only runs.

## `maxItems` (type: `integer`):

Maximum number of businesses to scrape (0 = unlimited)

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

Proxy settings. Residential proxies are recommended — Yelp uses DataDome bot protection.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.yelp.de/search?find_desc=Lunch&find_loc=Berlin"
    }
  ],
  "searchTerm": "Lunch",
  "location": "Berlin",
  "countryCode": "US",
  "scrapeDetails": false,
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

Dataset containing scraped Yelp businesses

## `runStats` (type: `string`):

Key-value store record with recordsScraped and timestamps

# 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 = {
    "startUrls": [
        {
            "url": "https://www.yelp.de/search?find_desc=Lunch&find_loc=Berlin"
        }
    ],
    "searchTerm": "Lunch",
    "location": "Berlin",
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("datascrapers/yelp-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 = {
    "startUrls": [{ "url": "https://www.yelp.de/search?find_desc=Lunch&find_loc=Berlin" }],
    "searchTerm": "Lunch",
    "location": "Berlin",
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("datascrapers/yelp-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 '{
  "startUrls": [
    {
      "url": "https://www.yelp.de/search?find_desc=Lunch&find_loc=Berlin"
    }
  ],
  "searchTerm": "Lunch",
  "location": "Berlin",
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call datascrapers/yelp-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datascrapers/yelp-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/EE4bkzGsWmqpeDLbv/builds/wahAdZlLmMhFWlqMU/openapi.json
