# Yelp Reviews Scraper (`reviewly/yelp-reviews-scraper`) Actor

Scrapes businesses and their reviews from Yelp search result pages (or a single business page). Extracts ratings, review text, reviewer profiles, and business metadata.

- **URL**: https://apify.com/reviewly/yelp-reviews-scraper.md
- **Developed by:** [Reviewly](https://apify.com/reviewly) (community)
- **Categories:** Developer tools, Social media, Lead generation
- **Stats:** 2 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 and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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 a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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 Reviews Scraper — Extract Yelp Business Data & Reviews Without the Yelp API

**Turn any Yelp search into a clean dataset of businesses and their full review history — ratings, review text, reviewer profiles, owner replies, phone numbers, websites, and opening hours — in just a few clicks.**

- ⭐ Scrape **every review** of a business, sorted newest-first, with full text and reviewer details
- 🏢 Capture **complete business profiles**: address, phone, website, menu, hours, price range, amenities
- 🛡️ **Anti-bot protection handled for you** — the Actor clears Yelp's DataDome protection automatically
- 📅 **Incremental scraping** with a date cutoff, perfect for daily or weekly review monitoring
- 📦 Export to **JSON, CSV, or Excel**, or pull results straight into your app via the Apify API

No Yelp API key, no rate-limit paperwork, no browser extensions. Paste a Yelp URL, press **Start**, get data.

---

### 📌 What This Actor Does

This Apify Actor is a **Yelp scraper** that collects businesses and their reviews from [yelp.com](https://www.yelp.com). Give it either:

- a **Yelp search URL** (e.g. *"grill" in Los Angeles*) — it discovers every business in the results and scrapes each one, or
- a **direct business page URL** (`https://www.yelp.com/biz/...`) — it scrapes just that business.

For every business it returns one structured record combining the listing data, the full business profile, and as many reviews as you ask for.

**Who it's for:**

- **Marketers & agencies** doing reputation management and review monitoring for clients
- **Sales teams** building lead lists of local businesses with phone numbers and websites
- **Data analysts & researchers** studying customer sentiment, pricing, or local markets
- **Developers** who need reliable Yelp data feeds without maintaining their own web scraping infrastructure
- **Business owners** tracking their own reviews and their competitors'

---

### ✨ Key Features

- **Full review extraction** — review text, star rating, date, language, helpful votes, photos, and the owner's public reply
- **Rich reviewer profiles** — name, location, Elite status, review count, friend count, and profile link for every reviewer
- **Complete business details** — street address, phone, website, menu URL, opening hours, price range, categories, neighborhoods, amenities, claimed/closed status
- **Star-rating breakdown** — review counts per star (1★–5★) for instant sentiment overviews
- **Search-to-dataset in one run** — scrape all businesses from a search results page, not just one listing at a time
- **Date-based cutoff** — stop at reviews older than a chosen date, so scheduled runs only fetch what's new
- **Automatic anti-bot bypass** — clears Yelp's DataDome protection with a real fingerprint-hardened browser and rotates IPs when blocked; no configuration needed
- **Cost controls built in** — cap total businesses, cap reviews per business, or skip reviews entirely for a fast listings-only run

---

### 🧠 Why This Actor Is Different

Most Yelp scrapers break the moment Yelp's bot protection (DataDome) challenges them, or silently return the block page instead of data. This Actor was built around that problem, not as an afterthought:

- **It earns real clearance** — a hardened, human-like browser solves Yelp's device check, then a fast HTTP client reuses that trusted session for the actual scraping. You get browser-grade reliability at HTTP-client speed.
- **One clearance, many businesses** — the trusted session is reused across the whole run instead of paying a slow browser check for every single page, so multi-business runs are dramatically faster.
- **Self-healing** — if Yelp rejects a session mid-run, the Actor automatically rotates to a fresh IP and re-clears the protection (up to 8 attempts per item) before giving up.
- **Data from Yelp's own payloads** — business info and reviews are parsed from Yelp's server-rendered JSON and internal GraphQL feed, not from fragile HTML selectors. That means fewer breakages and cleaner fields.
- **Honest failure reporting** — when an attempt is blocked, the Actor stores a debug screenshot and the challenge details in the run's key-value store so issues are diagnosable, not mysterious.

---

### ⚙️ Input Configuration

| Field | Type | Default | Description |
|---|---|---|---|
| `startUrls` | array | — *(required)* | Yelp URLs to scrape. Accepts **search pages** (`https://www.yelp.com/search?find_desc=...&find_loc=...`) and **business pages** (`https://www.yelp.com/biz/...`). |
| `maxItems` | integer | `1000` | Maximum businesses (dataset items) across all start URLs. `0` = no limit. Yelp caps public search at ~240 results per search URL. |
| `fetchBusinessDetails` | boolean | `true` | Load each business's page for full details (address, phone, website, menu, hours, amenities…). Turn off to skip one page load per business. |
| `scrapeReviews` | boolean | `true` | Paginate each business's review feed. Turn off for a fast, listings-only run. |
| `maxReviews` | integer | `1000` | Maximum reviews per business. `0` = all reviews. |
| `targetDate` | string | — | ISO date cutoff (e.g. `2025-01-01`). Reviews are scraped newest-first and collection stops at the first review older than this date — ideal for incremental runs. |
| `proxy` | object | Apify residential (US) | Proxy settings. **Keep residential proxies enabled** — Yelp blocks datacenter IPs. |

#### Example input

```json
{
    "startUrls": [
        { "url": "https://www.yelp.com/search?find_desc=grill&find_loc=Los+Angeles&sortby=review_count" }
    ],
    "maxItems": 20,
    "fetchBusinessDetails": true,
    "scrapeReviews": true,
    "maxReviews": 100,
    "targetDate": "2025-01-01",
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US"
    }
}
````

#### Tips for best results

- **Sort your search on Yelp first** (e.g. by review count or rating) and copy that URL — the Actor scrapes results in the order Yelp returns them.
- A Yelp search maxes out around **240 results**. Need more? Add several narrower searches (by neighborhood, category, or ZIP code) to `startUrls` in one run.
- Scraping **all** reviews of a large restaurant can mean thousands of records. Set `maxReviews` (or `targetDate`) unless you truly need the full history.
- For pure **lead lists** (name, phone, website, address), set `scrapeReviews` to `false` — you'll get the same business fields much faster and cheaper.

***

### 📤 Output Format

The Actor outputs **one dataset record per business**, with the reviews nested inside. Export as JSON, CSV, Excel, or fetch via API.

```json
{
    "encid": "k2dhvRV0gtPoDWLuH2OMTQ",
    "alias": "aca-grill-los-angeles-2",
    "name": "ACA Grill",
    "businessUrl": "https://www.yelp.com/biz/aca-grill-los-angeles-2",
    "rating": 4.5,
    "reviewCount": 289,
    "reviewCountsByRating": { "1": 4, "2": 3, "3": 12, "4": 61, "5": 209 },
    "categories": ["Korean", "Barbeque"],
    "priceRange": "$$",
    "phone": "(213) 674-7708",
    "website": "http://www.acagrill.com",
    "menuUrl": "https://www.yelp.com/menu/aca-grill-los-angeles-2",
    "address": {
        "formatted": "961 S Vermont Ave Ste A Los Angeles, CA 90006",
        "street": "961 S Vermont Ave",
        "city": "Los Angeles",
        "region": "CA",
        "postalCode": "90006",
        "country": "US"
    },
    "neighborhoods": ["Koreatown"],
    "timezone": "America/Los_Angeles",
    "isClosed": false,
    "isClaimed": true,
    "hours": [
        { "day": "Mon", "hours": ["11:00 AM - 10:00 PM"] }
    ],
    "amenities": [
        { "name": "Takes Reservations", "active": true },
        { "name": "Offers Delivery", "active": true }
    ],
    "reviews": [
        {
            "reviewId": "AbCdEfGh123",
            "rating": 5,
            "date": "2026-06-14 19:22:31",
            "text": "The galbi was incredible and the service was fast...",
            "language": "en",
            "helpfulCount": 3,
            "reviewer": {
                "encid": "XyZ987",
                "name": "Sarah K.",
                "location": "Los Angeles, CA",
                "profileUrl": "https://www.yelp.com/user_details?userid=XyZ987",
                "profilePhoto": "https://s3-media0.fl.yelpcdn.com/...",
                "reviewCount": 84,
                "friendCount": 112,
                "isElite": true
            },
            "photos": ["https://s3-media0.fl.yelpcdn.com/bphoto/..."],
            "businessReply": {
                "text": "Thank you so much, Sarah!",
                "date": "2026-06-15 09:10:00"
            }
        }
    ]
}
```

#### Field reference

| Field | Meaning |
|---|---|
| `encid` / `alias` | Yelp's internal business ID and URL slug |
| `rating` / `reviewCount` | Overall star rating and total review count |
| `reviewCountsByRating` | Number of reviews per star level (1–5) |
| `phone`, `website`, `menuUrl`, `hours`, `amenities`, `isClaimed`, `isClosed` | Full-profile fields (require `fetchBusinessDetails: true`) |
| `reviews[]` | Scraped reviews, newest first (requires `scrapeReviews: true`) |
| `reviews[].businessReply` | The owner's public response, if any |
| `reviews[].reviewer.isElite` | Whether the reviewer has Yelp Elite status |

***

### ▶️ How to Use

1. **Open the Actor** in the Apify Store and click **Try for free** — you'll need a free Apify account.
2. **Paste your Yelp URL(s)** into *Start URLs*: a search results page, one or more business pages, or a mix.
3. **Set your limits** — how many businesses (`maxItems`) and reviews per business (`maxReviews`) you want.
4. **Leave the proxy settings as they are** (US residential) unless you have a reason to change them.
5. Click **Start**. The first minute is spent clearing Yelp's bot protection — that's normal. Progress appears in the log.
6. When the run finishes, open the **Dataset** tab to preview results and **Export** them as JSON, CSV, Excel, or HTML — or fetch them programmatically via the [Apify API](https://docs.apify.com/api/v2).

#### Common workflows

- **Weekly review monitoring:** save a task with your business URLs and `targetDate` set to the last run's date, then [schedule it](https://docs.apify.com/platform/schedules) weekly. Each run collects only new reviews.
- **Lead generation:** use a search URL per city/category, `scrapeReviews: false`, and export CSV — you get names, phones, websites, and addresses ready for your CRM.
- **Competitor analysis:** add your competitors' business URLs and compare `reviewCountsByRating`, amenities, and pricing side by side.

***

### 📈 Use Cases

1. **Reputation management** — track every new review (and whether the owner replied) across all client locations, and alert on 1–2★ reviews the same day they appear.
2. **Local lead scraping** — build targeted B2B lead lists of restaurants, salons, contractors, or any local niche, complete with phone numbers and websites for outreach.
3. **Market & sentiment research** — analyze thousands of review texts to find what customers praise or complain about in a category before launching a product or opening a location.
4. **Competitive intelligence** — monitor competitors' ratings trend, review velocity, price range, and amenities to position your own offering.
5. **AI & NLP datasets** — collect clean, labeled review text (rating + text + date) for training sentiment models or powering RAG applications.

***

### 🛠️ Advanced Tips

- **Speed vs. depth:** `fetchBusinessDetails: false` + `scrapeReviews: false` is the fastest mode (search listings only). Each enabled option adds requests per business.
- **Proxies:** the default **US residential** Apify Proxy is the tested configuration. Datacenter proxies will be blocked by Yelp's protection — don't switch unless you know why.
- **Timeouts:** clearing Yelp's bot protection takes ~1–2 minutes per fresh session. For runs with many businesses, keep the Actor's run timeout at **900 seconds or more**; the Actor reuses a cleared session across businesses whenever possible, so later items are much faster than the first.
- **Scaling:** for very large jobs, split cities/categories across multiple parallel runs rather than one giant run — you'll get results sooner and isolate any blocked session to a smaller batch.
- **Incremental pipelines:** combine `targetDate` with Apify [webhooks](https://docs.apify.com/platform/integrations/webhooks) to push only fresh reviews into Slack, Google Sheets, or your database.

***

### ❓ FAQ / Troubleshooting

**Does this Actor use the official Yelp API?**
No. It scrapes publicly visible pages, so you don't need a Yelp API key and you aren't bound by the API's narrow quotas (the official API returns only 3 review excerpts per business — this Actor can return them all).

**Is scraping Yelp legal?**
The Actor only collects **publicly available data** — the same information any visitor sees. That said, how you use the data is your responsibility: consult your legal counsel, respect applicable privacy laws (GDPR/CCPA) when storing personal data such as reviewer names, and don't republish content in ways that violate copyright.

**The run seems stuck at the start / "Launching (Firefox) to clear DataDome…"**
That's the anti-bot bypass working — it takes roughly 1–2 minutes. It's a one-time cost per session, not per page.

**I got "DataDome blocked every IP" for an item.**
Yelp occasionally serves hard blocks to specific IPs. The Actor already rotated through 8 fresh IPs before reporting this. Simply re-run the Actor (or the failed URLs) — a new run draws new IPs. Make sure **residential** proxies are enabled; this error is near-certain with datacenter IPs.

**Why do I get at most ~240 businesses per search?**
Yelp caps public search results at about 240 items regardless of the tool used. Split your search into narrower queries (neighborhoods, ZIP codes, subcategories) and add them all to `startUrls`.

**Some businesses miss the phone/website/hours fields.**
Those fields come from the business's own page — make sure `fetchBusinessDetails` is `true`. If it is, the business may simply not publish that information.

**Reviews stopped at an older date than I expected.**
Check `targetDate` — collection stops at the first review older than it (reviews are processed newest-first). Set it to empty to fetch the full history.

**Can I get reviewer email addresses?**
No. Yelp does not publish reviewer emails, and this Actor only extracts data that is publicly displayed.

***

### 📞 Support

- 🐛 **Found a bug or a field that stopped parsing?** Open an issue on the Actor's **Issues** tab in the Apify Console — please include the run ID.
- 💬 **Questions, feature requests, or custom scraping needs?** Email the developer directly: **<me@ahmedhrid.com>**
- 📚 New to Apify? Start with the [Apify documentation](https://docs.apify.com) to learn about scheduling, integrations, and the API.

If this Actor saves you time, a ⭐ rating in the Apify Store helps others find it — and tells us to keep improving it.

# Actor input Schema

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

Yelp URLs to scrape. Accepts search result pages (e.g. https://www.yelp.com/search?find\_desc=grill\&sortby=review\_count\&find\_loc=Los+Angeles) — every business found is scraped — or a single business page (e.g. https://www.yelp.com/biz/aca-grill-los-angeles-2).

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

Maximum number of businesses (dataset items) to scrape in total, across all start URLs. 0 means no limit (note Yelp caps public search at ~240 results per search URL).

## `fetchBusinessDetails` (type: `boolean`):

Load each business's own page to capture full details: full street address, phone number, website, menu URL, opening hours, price range, amenities, and closed status. Turn off to skip the extra page fetch per business.

## `scrapeReviews` (type: `boolean`):

Paginate each business's review feed. Turn off to collect only business listings/details — much faster and cheaper.

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

Maximum number of reviews to scrape per business (only used when "Scrape reviews" is on). 0 means no limit (all reviews).

## `targetDate` (type: `string`):

Stop scraping reviews older than this date (ISO 8601, e.g. 2025-01-01). Reviews are collected newest-first, so this returns only reviews on or after the date — useful for incremental runs.

## `proxy` (type: `object`):

Residential proxy is strongly recommended — DataDome blocks datacenter IPs. The same session is shared between the bypass browser and all fetch requests so the datadome cookie stays bound to one IP.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.yelp.com/search?find_desc=grill&sortby=review_count&find_loc=Los+Angeles"
    }
  ],
  "maxItems": 1000,
  "fetchBusinessDetails": false,
  "scrapeReviews": false,
  "maxReviews": 1000,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Each record contains business info (encid, alias, name, businessUrl, rating, reviewCount, reviewCountsByRating, categories, address, neighborhoods, phone, priceRange; with fetchBusinessDetails also website, menuUrl, hours, amenities, timezone, isClosed, isClaimed) and a reviews array (when scrapeReviews is on) with reviewId, rating, date, text, language, reviewer profile (name, location, encid, reviewCount, friendCount, isElite, profileUrl, profilePhoto), helpfulCount, businessReply, and photos.

# 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.com/search?find_desc=grill&sortby=review_count&find_loc=Los+Angeles"
        }
    ],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("reviewly/yelp-reviews-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.com/search?find_desc=grill&sortby=review_count&find_loc=Los+Angeles" }],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("reviewly/yelp-reviews-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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.com/search?find_desc=grill&sortby=review_count&find_loc=Los+Angeles"
    }
  ],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call reviewly/yelp-reviews-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=reviewly/yelp-reviews-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Yelp Reviews Scraper",
        "description": "Scrapes businesses and their reviews from Yelp search result pages (or a single business page). Extracts ratings, review text, reviewer profiles, and business metadata.",
        "version": "0.0",
        "x-build-id": "kGCofu1fVRJfdmZtK"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/reviewly~yelp-reviews-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-reviewly-yelp-reviews-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/reviewly~yelp-reviews-scraper/runs": {
            "post": {
                "operationId": "runs-sync-reviewly-yelp-reviews-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/reviewly~yelp-reviews-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-reviewly-yelp-reviews-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "startUrls"
                ],
                "properties": {
                    "startUrls": {
                        "title": "Start URLs",
                        "type": "array",
                        "description": "Yelp URLs to scrape. Accepts search result pages (e.g. https://www.yelp.com/search?find_desc=grill&sortby=review_count&find_loc=Los+Angeles) — every business found is scraped — or a single business page (e.g. https://www.yelp.com/biz/aca-grill-los-angeles-2).",
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "maxItems": {
                        "title": "Max items",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Maximum number of businesses (dataset items) to scrape in total, across all start URLs. 0 means no limit (note Yelp caps public search at ~240 results per search URL).",
                        "default": 1000
                    },
                    "fetchBusinessDetails": {
                        "title": "Fetch business details",
                        "type": "boolean",
                        "description": "Load each business's own page to capture full details: full street address, phone number, website, menu URL, opening hours, price range, amenities, and closed status. Turn off to skip the extra page fetch per business.",
                        "default": false
                    },
                    "scrapeReviews": {
                        "title": "Scrape reviews",
                        "type": "boolean",
                        "description": "Paginate each business's review feed. Turn off to collect only business listings/details — much faster and cheaper.",
                        "default": false
                    },
                    "maxReviews": {
                        "title": "Max reviews per business",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Maximum number of reviews to scrape per business (only used when \"Scrape reviews\" is on). 0 means no limit (all reviews).",
                        "default": 1000
                    },
                    "targetDate": {
                        "title": "Target date (cutoff)",
                        "type": "string",
                        "description": "Stop scraping reviews older than this date (ISO 8601, e.g. 2025-01-01). Reviews are collected newest-first, so this returns only reviews on or after the date — useful for incremental runs."
                    },
                    "proxy": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Residential proxy is strongly recommended — DataDome blocks datacenter IPs. The same session is shared between the bypass browser and all fetch requests so the datadome cookie stays bound to one IP."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
