# Yelp Reviews Scraper — Owner Replies & Monitor (`crawloop/yelp-reviews-scraper`) Actor

Scrape Yelp reviews into JSON: star ratings, full text, photos, reactions, and owner replies. Filter unanswered reviews and monitor new reviews with webhooks. A Yelp API alternative for Python, Node.js, and MCP.

- **URL**: https://apify.com/crawloop/yelp-reviews-scraper.md
- **Developed by:** [Andrej Kiva](https://apify.com/crawloop) (community)
- **Categories:** Travel, Lead generation, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.20 / 1,000 yelp reviews

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/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

## Yelp Reviews Scraper — Owner Replies & Reputation Monitor

> Unofficial tool for publicly accessible Yelp data. Yelp and related trademarks belong to their respective owners. Not affiliated with, sponsored by, or endorsed by Yelp Inc. Provided for informational and reputation-monitoring use only; users must comply with applicable terms and laws.

| Actor | Role |
| :--- | :--- |
| Yelp Reviews Scraper | Reviews + owner replies + monitor ◄── you are here |
| [Trustpilot Scraper](https://apify.com/crawloop/trustpilot-scraper) | Company reviews, TrustScore, incremental monitor |
| [Glassdoor Scraper](https://apify.com/crawloop/glassdoor-scraper) | Employer reviews, interviews, salaries, jobs |

**Yelp Reviews Scraper** collects **Yelp reviews and public owner responses** into structured JSON on Apify — star ratings, full review text, photos, reactions, reviewer stats (optional), and business context. Use it as a practical **Yelp API alternative** for Python or Node.js pipelines, agency ORM workflows, and scheduled **reputation monitoring**. Filter **unanswered 1-star reviews**, cap history per location, or run **monitor mode** so daily cron jobs only emit new reviews instead of re-downloading full histories.

**Best for:** Yelp review mining, owner-reply coverage, competitor reputation tracking, local SEO / NAP snapshots, and JSON/CSV datasets for BI or AI assistants via Apify MCP.

### When to use this Actor

- **Yelp reviews scraper** jobs for one or many `/biz/` pages, aliases, or encrypted business IDs
- **Owner reply** audits — keep only answered reviews, or only **unanswered** ones
- **Incremental monitoring** — scheduled runs that stop early once known reviews appear
- Star / date / keyword-filtered exports for sentiment and complaint themes
- Optional search (`pizza` in `San Francisco, CA`) that expands into review scrapes

### When not to use this Actor

- Private Yelp for Business inbox, messaging, or ads manager — this Actor only reads public review pages
- Writing reviews, claiming profiles, or authenticated business-owner actions
- Full restaurant menus, deals, or email-enrichment lead gen (out of scope)
- Sites other than Yelp business / search pages

### Modes

| Mode | What it does |
| :--- | :--- |
| `reviews` | Review rows (optional business profile row). **Default.** |
| `monitor` | Named KV watermarks + early-stop; emit only new reviews / rating deltas |

### Key features

- **Reviews + owner replies** — `hasOwnerReply`, `ownerReplyText`, `ownerReplyDate`, name/role when public
- **Filters the official Actor lacks** — star ratings, sort (newest / elites / highest…), keyword search, `onlyUnanswered` / `onlyWithOwnerReply`
- **Monitor-first ops** — watermark + seen review IDs; webhook / Telegram for new 1–2★ or unanswered reviews
- **Privacy default-off** — reviewer name, location, and counts are `null` unless `includeReviewerProfile` is on
- **Typed dataset rows** — `recordType`: `review`, `business`, `monitor_event`
- **Residential proxies** — recommended (US); datacenter IPs are often blocked

### Input parameters

| Parameter | Description |
|-----------|-------------|
| `mode` | `reviews` / `monitor` |
| `startUrls` / `businessAliases` / `businessIds` | Business pages, slugs, or 22-char enc IDs |
| `searchTerm` + `searchLocation` | Optional discovery, then reviews |
| `maxReviews` | Per-business review cap (`0` = until `maxPages`) |
| `sortOrder` | `newest` (default), `oldest`, `recommended`, `highest`, `lowest`, `elites` |
| `starRatings` / `publishedAfter` / `publishedBefore` / `reviewSearchQuery` | Filters |
| `onlyUnanswered` / `onlyWithOwnerReply` | Owner-reply filters |
| `includeReviewerProfile` | Off by default (GDPR-friendly schema) |
| `includeBusinessProfile` | Push a `business` row in reviews mode |
| `yelpDomain` / `language` | Regional host + review-feed language |
| `monitorStoreName` / `monitorBaselineOnly` / `resetMonitorState` | Monitor KV controls |
| `webhookUrl` / `telegramToken` / `telegramChatId` | Alerts |
| `proxyConfiguration` | Use **Apify Residential** (US) |

#### Example — reviews + unanswered 1-star

```json
{
  "mode": "reviews",
  "startUrls": [{ "url": "https://www.yelp.com/biz/gary-danko-san-francisco" }],
  "maxReviews": 100,
  "sortOrder": "newest",
  "starRatings": ["1", "2"],
  "onlyUnanswered": true,
  "includeBusinessProfile": true,
  "includeReviewerProfile": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "US"
  }
}
```

#### Example — monitor baseline then schedule

```json
{
  "mode": "monitor",
  "businessAliases": ["gary-danko-san-francisco"],
  "monitorStoreName": "yelp-monitor-store",
  "monitorBaselineOnly": true,
  "monitorMaxPages": 3,
  "earlyStopAfterKnown": 5,
  "notifyOnNegativeReviewsOnly": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "US"
  }
}
```

After the baseline run, set `monitorBaselineOnly` to `false` (or omit it). Schedule every 15–60 minutes — later runs emit only deltas and stop early.

### Output

| `recordType` | Fields (highlights) |
| :--- | :--- |
| `review` | `reviewId`, `reviewUrl`, `reviewText`, `reviewRating`, `publishedDate`, `hasOwnerReply`, `ownerReplyText`, photos, reactions, business context |
| `business` | `businessId`, `businessAlias`, `businessName`, `businessRating`, `businessReviewCount`, address, categories |
| `monitor_event` | `changeType` (`new_review`, `rating_drop`, `rating_rise`, `review_count_change`, …) |

#### Output example — review

```json
{
  "recordType": "review",
  "reviewId": "revEncNew111111111111",
  "reviewUrl": "https://www.yelp.com/biz/gary-danko-san-francisco?hrid=revEncNew111111111111",
  "reviewText": "Incredible tasting menu.",
  "reviewRating": 5,
  "reviewLanguage": "en",
  "publishedDate": "2026-08-20T18:00:00.000Z",
  "hasOwnerReply": true,
  "ownerReplyText": "Thank you for dining with us!",
  "ownerReplyDate": "2026-08-21T09:00:00.000Z",
  "ownerReplyName": "Gary Danko",
  "photoUrls": ["https://s3-media0.fl.yelpcdn.com/example.jpg"],
  "reviewerName": null,
  "businessAlias": "gary-danko-san-francisco",
  "businessName": "Gary Danko",
  "businessRating": 4.6,
  "scrapedAt": "2026-08-25T17:40:00+00:00"
}
```

### Use cases

| Use case | What you get |
| :--- | :--- |
| **Restaurant / local ORM** | New Yelp reviews + unanswered 1-star alerts on a schedule |
| **Owner-reply coverage** | Which locations reply, how fast, and which complaints sit unanswered |
| **Competitor research** | Structured review text, stars, photos, and public replies for rivals |
| **Local SEO / NAP** | Business row with rating, review count, address, categories |
| **AI assistant workflows** | Run via Apify API, clients, or MCP and summarize complaint themes |

### Integration examples

#### Node.js

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('crawloop/yelp-reviews-scraper').call({
  mode: 'reviews',
  startUrls: [{ url: 'https://www.yelp.com/biz/gary-danko-san-francisco' }],
  maxReviews: 100,
  sortOrder: 'newest',
  proxyConfiguration: {
    useApifyProxy: true,
    apifyProxyGroups: ['RESIDENTIAL'],
    apifyProxyCountry: 'US',
  },
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.slice(0, 5));
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient(token)
run = client.actor("crawloop/yelp-reviews-scraper").call(
    run_input={
        "mode": "monitor",
        "businessAliases": ["gary-danko-san-francisco"],
        "monitorStoreName": "yelp-monitor-store",
        "monitorBaselineOnly": False,
        "proxyConfiguration": {
            "useApifyProxy": True,
            "apifyProxyGroups": ["RESIDENTIAL"],
            "apifyProxyCountry": "US",
        },
    }
)
items = list(client.dataset(run["defaultDatasetId"]).iterate_items())
print(len(items), items[:3])
```

#### cURL

```bash
curl "https://api.apify.com/v2/acts/crawloop~yelp-reviews-scraper/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "reviews",
    "startUrls": [{"url": "https://www.yelp.com/biz/gary-danko-san-francisco"}],
    "maxReviews": 50,
    "onlyUnanswered": true,
    "proxyConfiguration": {
      "useApifyProxy": true,
      "apifyProxyGroups": ["RESIDENTIAL"],
      "apifyProxyCountry": "US"
    }
  }'
```

### MCP and AI assistants

Use this Actor from AI tools via [Apify MCP](https://docs.apify.com/platform/integrations/mcp). Connect your Apify account, then call `crawloop/yelp-reviews-scraper`.

Example prompts:

- "Run the Yelp Reviews Scraper for https://www.yelp.com/biz/gary-danko-san-francisco, max 50 newest reviews, and return stars plus owner replies as JSON"
- "Scrape unanswered 1-star Yelp reviews for gary-danko-san-francisco and summarize the complaint themes"
- "Chain Yelp Reviews Scraper then Trustpilot Scraper for the same brand and compare reply coverage"

### Suite next step

After you have Yelp location reviews, run [Trustpilot Scraper](https://apify.com/crawloop/trustpilot-scraper) for the same brand’s review-site reputation (TrustScore, company replies, incremental monitor). For employer-side reviews, continue with [Glassdoor Scraper](https://apify.com/crawloop/glassdoor-scraper).

### FAQ

#### Is this a Yelp Fusion API?

No Yelp Fusion API key is required. The Actor reads publicly available business review pages and returns structured dataset rows — a common **Yelp API alternative** for scraping / monitoring use cases. Fusion’s public review cap does not apply here.

#### Why do I need residential proxies?

Yelp rate-limits and challenges many datacenter IPs. Use **Apify Residential** proxies (US for yelp.com) for reliable runs.

#### How does monitor mode save cost?

It stores review watermarks in a named Key-Value Store. Later runs only emit **new** reviews / rating changes and stop pagination early when they hit already-seen content.

#### Can I get owner / manager replies?

Yes. Public owner responses are parsed onto each review (`hasOwnerReply`, `ownerReplyText`, `ownerReplyDate`). Use `onlyUnanswered` to find reviews that still need a response.

#### Does it include reviewer names?

Not by default. Turn on `includeReviewerProfile` if you need display name, location, and public counts. The field names stay in the schema either way (`null` when off).

#### Does it export JSON / CSV?

Yes. Results land in the Apify dataset. Download JSON, CSV, or Excel from the run, or pipe via API / integrations / MCP.

### Tips

- Prefer `monitor` for production schedules; use `reviews` for historical dumps.
- Keep `concurrency` moderate (2–4) on shared residential pools.
- Always enable Residential proxies for Store QA and production.
- `newest` sort + `publishedAfter` stops pagination once older reviews appear.

# Actor input Schema

## `mode` (type: `string`):

reviews = full/filtered scrape (optional business row); monitor = incremental new reviews + rating deltas with early-stop.

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

Yelp business page URLs, e.g. https://www.yelp.com/biz/gary-danko-san-francisco.

## `businessAliases` (type: `array`):

Yelp URL slugs such as gary-danko-san-francisco.

## `businessIds` (type: `array`):

22-character Yelp encBizId values (e.g. cOcFMN\_0nCqHHJ4KZhe5vA).

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

Optional Yelp search query (e.g. pizza). Requires searchLocation. Discovered businesses are then scraped for reviews.

## `searchLocation` (type: `string`):

City, neighborhood, or ZIP for searchTerm (e.g. San Francisco, CA).

## `maxBusinessesPerSearch` (type: `integer`):

Cap businesses expanded from searchTerm + searchLocation.

## `maxSearchPages` (type: `integer`):

Safety cap on Yelp search result pages (10 businesses per page).

## `includeSearchAds` (type: `boolean`):

Keep Yelp ads when expanding searchTerm results.

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

Cap reviews collected per business after filters. 0 = until pages run out (still bounded by maxPages).

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

Hard cap on pushed dataset rows (all types). 0 = unlimited.

## `maxPages` (type: `integer`):

Safety cap on GraphQL review pages per business (10 reviews per page).

## `sortOrder` (type: `string`):

Yelp review sort. newest is best for monitoring and publishedAfter.

## `starRatings` (type: `array`):

Only keep these star ratings (1–5). Empty = all stars.

## `publishedAfter` (type: `string`):

Keep reviews on/after this date (YYYY-MM-DD) or period (7 days, 2 weeks, 1 month). Newest-first pagination stops when older reviews appear.

## `publishedBefore` (type: `string`):

Keep reviews on/before this date (YYYY-MM-DD).

## `reviewSearchQuery` (type: `string`):

Optional keyword passed to Yelp's review search (e.g. wait, parking, gluten).

## `language` (type: `string`):

Language code for the Yelp review feed (e.g. en, de, fr, es, ja). Default en.

## `yelpDomain` (type: `string`):

Regional Yelp host used when you pass aliases or IDs instead of full URLs.

## `includeOwnerReplies` (type: `boolean`):

Always parse public owner responses when present. Kept for compatibility; replies are included in the review row.

## `onlyWithOwnerReply` (type: `boolean`):

Keep reviews that have a public owner / manager response.

## `onlyUnanswered` (type: `boolean`):

Keep reviews with no public owner reply. Overrides onlyWithOwnerReply when both are set.

## `includeReviewerProfile` (type: `boolean`):

If off (default), reviewer name, location, counts, and photo are returned as null.

## `includeBusinessProfile` (type: `boolean`):

In reviews mode, also push a business row (name, rating, review count, address).

## `includePhotos` (type: `boolean`):

Keep photoUrls / videoUrls on review rows.

## `concurrency` (type: `integer`):

Parallel business workers. Keep moderate with residential proxies.

## `requestDelaySecs` (type: `number`):

Throttle between HTML/GraphQL calls on one worker.

## `monitorStoreName` (type: `string`):

Named Key-Value Store for incremental state (per-business watermarks + seen review IDs).

## `monitorBaselineOnly` (type: `boolean`):

First run: seed KV fingerprints and review watermarks without emitting deltas / webhooks.

## `resetMonitorState` (type: `boolean`):

Clear MONITOR\_STATE in the named store before this run.

## `monitorFetchReviews` (type: `boolean`):

In monitor mode, paginate newest reviews until early-stop.

## `monitorMaxPages` (type: `integer`):

Safety cap on review pages scanned per business in monitor mode.

## `earlyStopAfterKnown` (type: `integer`):

In monitor mode, stop pagination after this many consecutive already-seen or older reviews (newest-first).

## `ratingDropThreshold` (type: `number`):

Emit rating\_drop when the business star average falls by at least this amount.

## `webhookUrl` (type: `string`):

Slack / Discord / custom HTTPS endpoint for monitor alerts (JSON POST).

## `telegramToken` (type: `string`):

Optional Telegram bot token for monitor alerts.

## `telegramChatId` (type: `string`):

Telegram chat/user ID for alerts (requires token).

## `notifyOnNewReviews` (type: `boolean`):

Send webhook/Telegram when a new review appears.

## `notifyOnNegativeReviewsOnly` (type: `boolean`):

If enabled, new-review notifications fire only for 1–2 star reviews.

## `notifyOnUnansweredOnly` (type: `boolean`):

If enabled, new-review notifications fire only when there is no owner reply.

## `notifyOnRatingChange` (type: `boolean`):

Send webhook/Telegram when the business star average moves beyond the threshold.

## `notifyOnReviewCountChange` (type: `boolean`):

Send webhook/Telegram when the public review count changes.

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

Yelp blocks many datacenter IPs. Use Apify Residential proxies, preferably US.

## Actor input object example

```json
{
  "mode": "reviews",
  "startUrls": [
    {
      "url": "https://www.yelp.com/biz/gary-danko-san-francisco"
    }
  ],
  "businessAliases": [
    "gary-danko-san-francisco"
  ],
  "maxBusinessesPerSearch": 10,
  "maxSearchPages": 3,
  "includeSearchAds": false,
  "maxReviews": 100,
  "maxItems": 0,
  "maxPages": 200,
  "sortOrder": "newest",
  "language": "en",
  "yelpDomain": "www.yelp.com",
  "includeOwnerReplies": true,
  "onlyWithOwnerReply": false,
  "onlyUnanswered": false,
  "includeReviewerProfile": false,
  "includeBusinessProfile": true,
  "includePhotos": true,
  "concurrency": 4,
  "requestDelaySecs": 0.6,
  "monitorStoreName": "yelp-monitor-store",
  "monitorBaselineOnly": false,
  "resetMonitorState": false,
  "monitorFetchReviews": true,
  "monitorMaxPages": 5,
  "earlyStopAfterKnown": 5,
  "ratingDropThreshold": 0.1,
  "notifyOnNewReviews": true,
  "notifyOnNegativeReviewsOnly": false,
  "notifyOnUnansweredOnly": false,
  "notifyOnRatingChange": true,
  "notifyOnReviewCountChange": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

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

Default dataset items (review, business, monitor\_event).

# 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/biz/gary-danko-san-francisco"
        }
    ],
    "businessAliases": [
        "gary-danko-san-francisco"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawloop/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/biz/gary-danko-san-francisco" }],
    "businessAliases": ["gary-danko-san-francisco"],
}

# Run the Actor and wait for it to finish
run = client.actor("crawloop/yelp-reviews-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.com/biz/gary-danko-san-francisco"
    }
  ],
  "businessAliases": [
    "gary-danko-san-francisco"
  ]
}' |
apify call crawloop/yelp-reviews-scraper --silent --output-dataset

```

## MCP server setup

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