# Yelp Reviews Scraper: Yelp Reviews API, Every Review, No Key (`hyperbach/yelp-reviews-scraper`) Actor

Scrape every Yelp review of a business by URL, ID or search: text, rating, date, photos, owner reply, reviewer stats, plus Yelp business data: address, phone, website, hours. Every language, sort, star, keyword and date filter, and Yelp's not-recommended reviews. A Yelp Fusion API alternative.

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

## Pricing

from $0.15 / 1,000 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?

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

## Yelp Reviews Scraper: Yelp Reviews API, Every Review, No Key

**Every review of a Yelp business, logged out: Yelp business URLs (any Yelp site), business IDs, aliases, Yelp search URLs or search terms in a place in — one row per review out.** Each row has the review's text, rating, date with the business's own time offset and in UTC, language, Yelp's translation on request, photos and videos, the owner's reply with its date and role, the reactions (helpful, thanks, love this, oh no) and the useful / funny / cool counts, check-ins and the first-review and review-of-the-day flags, expert recognition, the reviewer's earlier review, and the reviewer's public counts, elite year and city — **plus the business's id, name, link, rating, review count, star and language split, address and phone on every row.** One free business row per business carries its record (address, phone, website, coordinates, the week's hours, categories, price range, closed flag), Yelp's own counts and a completeness verdict. Every Yelp sort, stars, one language or all, keywords, a date window, and Yelp's not-recommended and removed reviews on request. No login, no API key, proxies handled for you.

### Why this Yelp reviews scraper

- **Every review, with a verdict.** The walk reads Yelp's own list to its end, and the business row says COMPLETE (Yelp's count is its list plus one on 5 of 5 businesses we walked to the end), CAPPED (your limit stopped it), TRUNCATED or PARTIAL, with the numbers. In our tests a car dealer's 322 English reviews plus its 60 not-recommended and 18 removed ones came in one run of 19 seconds; a Paris café's 591 reviews in 8 languages in a 22-second run.
- **Never blocked by Yelp's bot wall.** The Actor reads the page's own review data, not the walled `yelp.com` pages, and reaches Yelp through its own rotating connections: 0 refusals in the 204 requests of the 26 runs of our build tests on Apify. A business page that renders as an empty shell, a renamed page and Yelp's occasional backend timeout are handled, not failed.
- **The business on every row.** The business's id, name, link, rating, review count, star split, language split, categories, address and phone are on each review row, so a sheet of reviews needs no join; the free business row adds the website, coordinates, the week's hours, the price range and the closed flag.
- **Your filters, applied before the charge.** Yelp's own sorts and star filter, one language or every language, keywords (Yelp's review search, with your stars and sort applied by the Actor because Yelp's search has none), a date window that stops the walk at your first date, and a per-business and a per-run limit: a review outside them is never charged.
- **The Yelp-filtered reviews too.** `includeNotRecommended` adds the reviews Yelp's filter hides and the ones it removed, each marked by `review_status`; every business row carries both counts.
- **Fast.** Several pages of 49 reviews in one request, businesses read side by side: in our tests on Apify the first row came 3.8 to 8.4 seconds after the run started on 22 of 23 runs of builds 0.1.1 to 0.1.6 (the container's start included; one waited 13.5 s), then about 2,800 reviews a minute (1,000 reviews of one restaurant in 21 seconds).

### Who it's for

- **Reputation and customer-experience teams** — every review of your locations and your competitors' with the owner's reply and its date, the star split and the Yelp-filtered reviews; a scheduled run with `onlyNewReviews` delivers only what is new.
- **Market researchers and analysts** — all reviews of a category in a city (a search term and a place), in every language, with the business record on each row and a completeness verdict to report against.
- **Lead generation and local SEO** — the business row per business (address, phone, website, hours, categories, rating, counts) for a search's 240 businesses, with as many reviews per business as you need.
- **Developers and data teams** — typed rows keyed by `review_id` and `business_id`, a free row per business and per search with its status, a run summary to check a pipeline against, every input constrained in the schema.

### Quick start

**The 50 newest reviews of a business**

```json
{
  "businessUrls": [
    "https://www.yelp.com/biz/mcgrath-elmhurst-toyota-elmhurst-2"
  ],
  "maxReviewsPerBusiness": 50
}
```

**Every review in every language, translated to English**

```json
{
  "businessUrls": [
    "Y71NWfl09hSFla7CYd36Jg"
  ],
  "language": "all",
  "translateTo": "en"
}
```

**Ten pizza places in Chicago, 20 reviews each**

```json
{
  "searchTerms": [
    "pizza"
  ],
  "searchLocation": "Chicago, IL",
  "maxBusinessesPerSearch": 10,
  "maxReviewsPerBusiness": 20
}
```

**The 1- and 2-star reviews about service, with Yelp's hidden ones**

```json
{
  "businessUrls": [
    "https://www.yelp.com/biz/gary-danko-san-francisco"
  ],
  "stars": "1,2",
  "keywords": [
    "service"
  ],
  "includeNotRecommended": true
}
```

### Output

One row per review (charged), one free row per business, and one free row per search:

| field | meaning |
|---|---|
| `row_type` | `review` on a review row (charged); `business` on a business's free row; `search` on a search's free row. |
| `input_index` | The position of the input this row answers, from 1 (a search's businesses carry the search's). |
| `input_label` | The value you gave that this row answers: the URL, ID or alias, or the search (`pizza in Chicago, IL`). |
| `status` | `ok`, or why a business or search gave no review: `no_reviews` (none in the asked view), `not_found` (Yelp does not know it, two connections agreeing), `invalid` (the value names no business), `duplicate` (another input of the run reads the same business), `no_results` (a search with no business), `failed` (Yelp would not serve it), `not_read` (a limit or the time limit stopped the run first). Review rows are always `ok`. |
| `status_detail` | Why, in words, when the row is not plainly ok: a renamed page followed, reviews left out by a filter, how Yelp read a search, or what stopped the business. |
| `scraped_at` | When the row was read (ISO 8601, UTC). |
| `business_id` | The business's Yelp ID (22 characters). |
| `business_alias` | The business's Yelp alias, the last part of its page address. |
| `business_name` | The business's name. |
| `business_url` | The business's Yelp page. |
| `business_photo` | The business's main photo. |
| `business_rating` | The business's Yelp rating (1 to 5, one decimal). |
| `business_review_count` | Yelp's count of the business's reviews. |
| `business_star_distribution` | How many reviews carry each rating: `{"1": n, … "5": n}`. |
| `business_language_distribution` | How many reviews Yelp holds in each language: `{"en": n, "fr": n, …}`. |
| `business_categories` | The business's Yelp categories. |
| `business_address` | The business's full address (street, city, region and postal code). |
| `business_city` | The business's city. |
| `business_region` | The business's state, region or department code. |
| `business_postal_code` | The business's postal code. |
| `business_country` | The business's country (ISO 3166 code). |
| `business_phone` | The business's phone number as Yelp shows it. |
| `business_latitude` | The business's latitude (business rows). |
| `business_longitude` | The business's longitude (business rows). |
| `business_hours` | The business's opening hours of the current week, by day: `{"Mon": "9:00 AM - 8:00 PM", …}` (business rows). |
| `business_price_range` | Yelp's price range (`$$`, `€€€`), when the business has one (business rows). |
| `business_website` | The business's own website, from its Yelp page (business rows). |
| `business_is_closed` | Whether Yelp marks the business as closed (business rows). |
| `not_recommended_count` | How many of the business's reviews Yelp's filter does not recommend (business rows). |
| `removed_count` | How many of the business's reviews Yelp removed for a content violation (business rows of a run with `includeNotRecommended`). |
| `review_id` | The review's Yelp ID: stable across runs and sorts. Each review is delivered and charged once a run. |
| `review_url` | The review's own link on Yelp (`…/biz/<alias>?hrid=<id>`). |
| `review_status` | `recommended` (Yelp's public list), `not_recommended` (Yelp's filter hides it) or `removed` (Yelp removed it for a content violation). |
| `rating` | The review's star rating, 1 to 5 (Yelp's scale is 1 to 5). |
| `text` | The review's full text. |
| `language` | The review's language as Yelp reports it (`en`, `fr`…). |
| `text_translated` | Yelp's own translation of the text into `translateTo`, when you asked for one. |
| `date` | When the review was written, in the business's local time with its offset (`2026-10-22T15:40:21-05:00`). |
| `date_utc` | The same moment in UTC (`2026-10-22T20:40:21Z`). |
| `updated_at` | When the reviewer last updated the review, when Yelp shows an update. |
| `experience_date` | The date of the visit the reviewer gave, when they gave one. |
| `photos` | The review's photos: `[{url, caption}]`. |
| `videos` | The review's videos: `[{url, thumbnail_url, caption}]`. |
| `owner_reply` | The business's public reply: `{text, date, role}` (and `name` with `includePersonalData`). Its date can be older than the review: Yelp shows the reply to the reviewer's earlier review. |
| `reactions` | The review's reactions: `{helpful, thanks, love_this, oh_no}` counts. |
| `useful_count` | Yelp's classic 'useful' votes on the review. |
| `funny_count` | Yelp's classic 'funny' votes on the review. |
| `cool_count` | Yelp's classic 'cool' votes on the review. |
| `check_in_count` | How many times the reviewer checked in at the business. |
| `is_first_review` | Whether this was the business's first review on Yelp. |
| `paid_through_yelp` | Whether the reviewer paid through Yelp. |
| `purchased_deal` | Whether the reviewer bought a Yelp deal. |
| `placed_reservation` | Whether the reviewer booked through Yelp. |
| `reservation_provider` | The reservation service the reviewer booked through, when Yelp names one. |
| `review_of_the_day_date` | When Yelp made it its Review of the Day, when it did. |
| `expert_recognition` | The reviewer's Yelp expert recognition shown on the review: `{label, reviews}` (`Cocktail Bar`, 14). |
| `previous_reviews` | The reviewer's earlier review of the same business that Yelp shows beside this one: `[{review_id, rating, text, date}]`. |
| `reviewer_review_count` | How many reviews the reviewer wrote on Yelp. |
| `reviewer_friend_count` | How many Yelp friends the reviewer has. |
| `reviewer_photo_count` | How many business photos the reviewer posted on Yelp. |
| `reviewer_location` | The reviewer's city as their Yelp profile shows it. |
| `reviewer_elite_year` | The reviewer's latest Yelp Elite year, when they are Elite. |
| `reviewer_elite_all_star` | Whether Yelp marks the reviewer as an Elite all-star, when it says. |
| `reviewer_name` | The reviewer's display name (with `includePersonalData` only). |
| `reviewer_photo` | The reviewer's profile photo (with `includePersonalData` only). |
| `reviewer_url` | The reviewer's Yelp profile (with `includePersonalData` only). |
| `keyword` | The keyword whose Yelp review search found the review, when you gave keywords. |
| `search_terms` | The search term that found the business (rows of a search's businesses, and the search row). |
| `search_location` | The search's location as you gave it. |
| `search_rank` | The business's position in its search's results, from 1. |
| `filters` | The view the business was read in: sort, language, stars, keywords, the date window, translation (business rows). |
| `view_count` | Yelp's own count of the asked view (business rows; a keyword view has none), or of a search's businesses (search rows, at most 240). |
| `reviews_found` | The distinct reviews the walk read for the business, filtered ones included (business rows). |
| `reviews_delivered` | The review rows this business or search delivered (charged). |
| `pages_read` | The review pages the walk read (business and search rows). |
| `businesses_found` | The businesses a search took (search rows). |
| `verdict` | How complete the business's or search's read is: `COMPLETE` (to Yelp's own end), `CAPPED` (your limit stopped it), `TRUNCATED` (Yelp's list ended under its own count, or its review search repeated itself) or `PARTIAL` (a page Yelp would not serve, the time limit or an abort). With `includeNotRecommended` the Yelp-filtered lists count too: a limit that stopped them is CAPPED. |
| `verdict_detail` | The verdict's numbers: per view, the reviews read against Yelp's count, the pages, what stopped it. |

Example record:

```json
{
  "row_type": "review",
  "input_index": 1,
  "input_label": "https://www.yelp.com/biz/gary-danko-san-francisco",
  "status": "ok",
  "status_detail": null,
  "scraped_at": "2026-10-28T13:29:55Z",
  "business_id": "WavvLdfdP6g8aZTtbBQHTw",
  "business_alias": "gary-danko-san-francisco",
  "business_name": "Gary Danko",
  "business_url": "https://www.yelp.com/biz/gary-danko-san-francisco",
  "business_photo": "https://s3-media0.fl.yelpcdn.com/bphoto/NjJm1P5NuiltDjbWYB4WFw/o.jpg",
  "business_rating": 4.5,
  "business_review_count": 6153,
  "business_star_distribution": {
    "1": 124,
    "2": 218,
    "3": 484,
    "4": 1098,
    "5": 4234
  },
  "business_language_distribution": {
    "en": 6154,
    "zh": 3,
    "de": 1
  },
  "business_categories": [
    "New American",
    "French",
    "Cocktail Bars"
  ],
  "business_address": "800 N Point St, San Francisco, CA 94109",
  "business_city": "San Francisco",
  "business_region": "CA",
  "business_postal_code": "94109",
  "business_country": "US",
  "business_phone": "(406) 626-8866",
  "business_latitude": null,
  "business_longitude": null,
  "business_hours": null,
  "business_price_range": null,
  "business_website": null,
  "business_is_closed": null,
  "not_recommended_count": null,
  "removed_count": null,
  "review_id": "l9c-8Wjclw3K5gY8Kixk1g",
  "review_url": "https://www.yelp.com/biz/gary-danko-san-francisco?hrid=l9c-8Wjclw3K5gY8Kixk1g",
  "review_status": "recommended",
  "rating": 5,
  "text": "This is an institution for a reason. The food was very well executed and I like how they kept the portions generous and the price is still very reasonable. You can't beat this place for a 3 course meal that costs $135 before tax and tip. The service was top notch and attentive as well.",
  "language": "en",
  "text_translated": null,
  "date": "2026-09-10T20:32:17-07:00",
  "date_utc": "2026-09-11T03:32:17Z",
  "updated_at": null,
  "experience_date": null,
  "photos": [
    {
      "url": "https://s3-media0.fl.yelpcdn.com/bphoto/KKd89NiYno4PP_aJLQ4_Ng/o.jpg",
      "caption": "Lobster risotto. Highly recommend for appetizer"
    },
    {
      "url": "https://s3-media0.fl.yelpcdn.com/bphoto/Pn36nIcJyHN_dWT-r9SWlA/o.jpg",
      "caption": "Perfiterol dessert. Very tasty"
    }
  ],
  "videos": [],
  "owner_reply": null,
  "reactions": {
    "helpful": 0,
    "thanks": 0,
    "love_this": 1,
    "oh_no": 0
  },
  "useful_count": 0,
  "funny_count": 0,
  "cool_count": 0,
  "check_in_count": 0,
  "is_first_review": false,
  "paid_through_yelp": false,
  "purchased_deal": false,
  "placed_reservation": false,
  "reservation_provider": null,
  "review_of_the_day_date": null,
  "expert_recognition": {
    "label": "Cocktail Bar",
    "reviews": 15
  },
  "previous_reviews": [],
  "reviewer_review_count": 177,
  "reviewer_friend_count": 24,
  "reviewer_photo_count": 90,
  "reviewer_location": "[redacted]",
  "reviewer_elite_year": null,
  "reviewer_elite_all_star": null,
  "reviewer_name": null,
  "reviewer_photo": null,
  "reviewer_url": null,
  "keyword": null,
  "search_terms": null,
  "search_location": null,
  "search_rank": null,
  "filters": null,
  "view_count": null,
  "reviews_found": null,
  "reviews_delivered": null,
  "pages_read": null,
  "businesses_found": null,
  "verdict": null,
  "verdict_detail": null
}
```

### Pricing

**Pay for the reviews a run delivers**, plus one run start; no platform usage is billed to you.

| event | unit | Free | Starter | Scale | Business |
|---|---|---|---|---|---|
| Review (`review`) | per 1,000 | $0.30 | $0.255 | $0.21 | $0.15 |
| Run start (`start`) | per run | $0.0018 | $0.0018 | $0.0018 | $0.0018 |

A review is **$0.30 per 1,000** on the Free plan ($0.0003 a review) and $0.255 on Starter, whatever found it (a business link, an ID, an alias, a search) and whatever it carries: the photos and videos, the owner's reply, the reactions, the reviewer's public counts, Yelp's translation and the business on the row are inside the review's price, with no add-on. A Yelp-filtered (not recommended) or removed review asked with `includeNotRecommended` is a review like the others. Each run that delivers a review also pays the **run start, $0.0018 once**; a run that delivers none pays nothing at all. So one review costs $0.0021 on the Free plan and $0.002055 on Starter; 40 reviews $0.0138 and $0.012; 1,000 reviews $0.3018 and $0.2568; every business and search of a run shares one start. Free: every business row and search row, a review a filter (the date window, the stars of a keyword view) or `onlyNewReviews` leaves out, a review another view of the run already delivered (one row, one charge), a business Yelp does not know, a value that names nothing, a rejected input, and the businesses a limit or the time limit left unread. A run that stops early (a timeout, an abort) is charged for the reviews it delivered. `maxItems` counts the charged reviews.

Before the first request the log names the price of a review at your plan, the run start and the most the run can cost: each business is `maxReviewsPerBusiness` reviews, each search `maxBusinessesPerSearch` businesses of that many, and `maxItems` over the whole run. A business with no review cap has no bound but your charge limit: the run reads every review Yelp lists, and the business row carries Yelp's own count. The counts differ by thousands: in our tests ten plumbers in Boise held 261 reviews together (read in 32 s), Café de Flore 591 in eight languages, Gary Danko 6,153 and Bottega Louie 19,668. Set `maxReviewsPerBusiness`, `maxItems` or a charge limit for a lower maximum. Enterprise plans have their own rates — the Actor's Pricing tab shows the price for your plan.

### Usage patterns

- **Businesses** — `businessUrls` takes Yelp business pages of any Yelp site (`yelp.com`, `yelp.de`, `m.yelp.com`…; the `?osq=` and `?hrid=` parts are ignored), 22-character business IDs, bare aliases (`gary-danko-san-francisco`) and Yelp search URLs. A renamed page is followed once. A page Yelp does not know is a free `not_found` row once a second connection agrees.
- **Searches** — `searchTerms` with `searchLocation` (a city, a postcode, an address) read Yelp's search the way its search page shows it: each term takes `maxBusinessesPerSearch` businesses (Yelp lists 240 at most), in Yelp's order, and each business is read like one you named. The search row says how Yelp read the place (`Best pizza Near Chicago, Illinois`) and Yelp's own count. A business found by two inputs is read once.
- **Depth and limits** — A business is read to the end of Yelp's list unless `maxReviewsPerBusiness` stops it first; `maxItems` stops the run. The business row's `verdict` says COMPLETE, CAPPED, TRUNCATED or PARTIAL, `view_count` is Yelp's own count of the asked view and `reviews_found` / `reviews_delivered` what the walk read and delivered.
- **Filters** — `sort` is Yelp's own order (newest, oldest, highest, lowest, recommended, Elite first). `stars` and `language` are Yelp's filters (`all` walks every language the business has). `keywords` use Yelp's review search, one search per keyword; Yelp's search has no order and no star filter, so the Actor applies your stars and your sort to its matches. `dateFrom` / `dateTo` keep the reviews written in that window in the business's own time; with the newest-first sort the walk stops at the first older review. Every filter is applied before the charge.
- **Yelp's not-recommended and removed reviews** — `includeNotRecommended` adds Yelp's not-recommended list and the reviews Yelp removed for a content violation, 10 a page, after the recommended ones; each row's `review_status` says which, and the stars, the date window and the keywords (as words of the text) apply. Those pages carry no language, no photos and no reactions. The business row carries both counts on every run.
- **Monitoring** — `onlyNewReviews` keeps a memory (named by `stateStoreName`) of the reviews delivered; a later run skips them free. With the newest-first sort a business's walk stops at its first review delivered before only when an earlier run of the memory read that business to its end with no stars, keyword or date filter; after a capped or filtered run the next run walks on, skips what it knows and delivers the older reviews it left. A resurrected run reads its own dataset first: no review is delivered or charged twice in one run, and an input that already has its row is not read again.

### Input configuration

| field | type | default | what it does |
|---|---|---|---|
| `businessUrls` | `array` | `[]` | One value per business: a Yelp business page URL on any Yelp site (`https://www.yelp.com/biz/gary-danko-san-francisco`, `yelp.de/biz/…`, `m.yelp.com/biz/…`; its `?osq=` or `?hrid=` part is ignored), a 22-character business id (`WavvLdfdP6g8aZTtbBQHTw`), a bare alias (`gary-danko-san-francisco`), or a Yelp search URL with `find_desc` and `find_loc` (read as a search). Up to 500 values a run. A value that names no business gets a free `invalid` row; a business given twice is read once (a free `duplicate` row). |
| `searchTerms` | `array` | `[]` | What you would type into Yelp's search box (`pizza`, `dentist`, a business name): each term is searched in `searchLocation`, and the businesses it finds are read like the ones above. Needs `searchLocation`. Up to 20 terms. |
| `searchLocation` | `string` | `""` | Where the search terms are searched: a city (`Chicago, IL`), a postcode, a neighbourhood or an address. The search row says how Yelp read it. |
| `maxBusinessesPerSearch` | `integer` | `10` | How many businesses each search term (or search URL) takes, in Yelp's order: 1 to 240 (Yelp lists 240 businesses a search at most). |
| `maxReviewsPerBusiness` | `integer` | `0` | Stop each business after this many review rows. 0 = every review Yelp lists in the asked view (the business row then says COMPLETE when the walk reached Yelp's own end). |
| `sort` | `newest` / `oldest` / `highest` / `lowest` / `recommended` / `elites` | `"newest"` | Yelp's own review order: newest first (the default), oldest first, highest or lowest rated first, Yelp's recommended order, or Elite reviewers first. |
| `language` | `string` | `"en"` | The reviews' language as Yelp's two-letter code (`en`, the default; `fr`, `de`, `es`…), or `all` for every language the business has reviews in (one walk per language). Yelp shows one language at a time; without a language it shows English. |
| `stars` | `string` | `""` | Keep reviews of these star ratings only, comma-separated (`1`, `1,2`, `4,5`). Empty = every rating. |
| `keywords` | `array` | `[]` | Keep reviews that Yelp's own review search matches for these words or phrases (one search per keyword, a review found by two keywords delivered once; each row says its `keyword`). Yelp's review search has no order of its own: with a sort other than `recommended` each business's matches are read whole, then sorted. Up to 20. |
| `dateFrom` | `string` | `""` | Keep reviews written on or after this day in the business's own time (`2026-01-31`), or within the last N days (`30 days`). With the newest-first sort the walk stops at the first older review: nothing older is read or charged. |
| `dateTo` | `string` | `""` | Keep reviews written on or before this day in the business's own time (`2026-06-30`). With the oldest-first sort the walk stops at the first newer review. |
| `translateTo` | `string` | `""` | A two-letter language code (`en`): Yelp's own translation of each review into it, in `text_translated`, beside the original text. Empty = no translation. |
| `includeNotRecommended` | `boolean` | `false` | Also read the reviews Yelp's filter keeps off the business page (its not-recommended list) and the ones Yelp removed for a content violation, each row marked by `review_status`. They are review rows like the others (charged, counted by the limits). The business row always carries both counts. |
| `includePersonalData` | `boolean` | `false` | Off (the default): the reviewer's name, photo and profile link and the replier's name stay empty; the reviewer's public counts, elite year and city are on every row. On: you take the responsibility for processing personal data under the laws that apply to you. |
| `onlyNewReviews` | `boolean` | `false` | Skip the reviews an earlier run with the same memory delivered (free), so a scheduled run delivers only what is new. With the newest-first sort a business's walk stops at its first review delivered before. |
| `stateStoreName` | `string` | `""` | The name of the memory `onlyNewReviews` keeps (letters, digits, `.`, `_`, `~`, `-`). Empty = a name made from the inputs. |
| `maxItems` | `integer` | `0` | Stop the run after this many review rows across every business (0 = no limit). Business and search rows are free and not counted. A business left unread at the limit gets a free `not_read` row. |
| `proxyUrl` | `string` |  | Empty (recommended): Yelp is read through the Actor's own connections at no extra cost to you. Your own proxy URL (scheme://user:pass@host:port) carries every call instead. The word none runs without any proxy, from the Apify worker's own IP (for tests). |

### Errors

**A run does not fail because of your input.** When an input cannot be used — a date that is not a date, an id in the wrong form, two settings that contradict each other — the run ends **Succeeded**, charges nothing, and says what to change:

- the status message starts with `INPUT REJECTED`;
- the dataset holds one row, `{"error": true, "code": "…", "message": "…"}`, and no results;
- the key-value store record `ERROR` holds the same object.

From code, check `error` on the first row before reading results.

A business with no review in the asked view, a page Yelp does not know (checked on a second connection), a search with no result or a value that names nothing is not an error: it gets one free row with its `status` and the reason, and the run goes on with the others. A run that ends **Failed** is a fault on our side, never your input; it charges nothing, and we are alerted.

### FAQ

**Why does a business show more reviews on Yelp than I get?**

Yelp's page counts every language; the Actor reads one language (English by default) unless `language` is `all`. The business row's `business_language_distribution` lists the counts per language, `view_count` is Yelp's count of the view you asked for, and Yelp's own count is one more than its list on every business we walked to the end. The reviews Yelp's filter hides are not in the count either: ask for them with `includeNotRecommended`.

**Why is an owner reply older than its review?**

Yelp shows the reply to the reviewer's earlier review beside their newest one; the reply's own date is in `owner_reply.date`, and the earlier review in `previous_reviews`.

**Do you return the reviewer's name?**

Only with `includePersonalData` on: the name, the photo and the profile link. The reviewer's public review, friend and photo counts, the elite year and the city are always on the row.

**How exact are the keyword results?**

They are Yelp's own review search: in our tests on a car dealer it matched 164 of the 164 reviews that hold the word 'service' and 206 of the 216 that hold 'car'. Yelp matches a phrase word by word: 'oil change' also finds reviews that say only 'changed' (66 matches on that dealer, 37 with the phrase). Yelp's search gives no count of its matches, so the business row counts what it read. On Yelp's not-recommended and removed lists the Actor matches each keyword as written, as whole words.

**Do you return the business's menu, photos gallery or questions?**

No. Each review's own photos and videos are on its row; the business row has the record, the website, the hours and the counts.

**Can I use my own proxy?**

Yes, `proxyUrl`. Leave it empty and the Actor uses its own connections at no extra cost.

### Integration

#### JavaScript

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('hyperbach/yelp-reviews-scraper').call({"businessUrls": ["https://www.yelp.com/biz/mcgrath-elmhurst-toyota-elmhurst-2"], "maxReviewsPerBusiness": 50});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

#### Python

```python
from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')
run = client.actor('hyperbach/yelp-reviews-scraper').call(run_input={'businessUrls': ['https://www.yelp.com/biz/mcgrath-elmhurst-toyota-elmhurst-2'], 'maxReviewsPerBusiness': 50})
items = client.dataset(run['defaultDatasetId']).list_items().items
```

#### CLI

```bash
apify call hyperbach/yelp-reviews-scraper --input '{"businessUrls": ["https://www.yelp.com/biz/mcgrath-elmhurst-toyota-elmhurst-2"], "maxReviewsPerBusiness": 50}'
```

#### REST

```bash
curl -X POST "https://api.apify.com/v2/acts/hyperbach~yelp-reviews-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H 'Content-Type: application/json' -d '{"businessUrls": ["https://www.yelp.com/biz/mcgrath-elmhurst-toyota-elmhurst-2"], "maxReviewsPerBusiness": 50}'
```

### Support

**Disagree with a charge?** Write to apify@hyperbach.com with the run ID. We will ask Apify to compensate you, and the charge comes back to your Apify account as platform credit.

**Did it do the job?** A short [review on the Store](https://apify.com/hyperbach/yelp-reviews-scraper/reviews), at any rating, helps the next buyer choose.

### See also

- **[Trustpilot Reviews Scraper](https://apify.com/hyperbach/trustpilot-reviews-scraper)** — every review of a business on Trustpilot, past the 200-review cap.
- **[App Store Reviews Scraper](https://apify.com/hyperbach/app-store-reviews-scraper)** — Apple App Store reviews by app and country, with the app version each reviewer used.
- **[Google Play Reviews Scraper](https://apify.com/hyperbach/google-play-reviews-scraper)** — Google Play reviews by app, language and country, with the app version each reviewer used.
- **[Goodreads Scraper](https://apify.com/hyperbach/goodreads-scraper)** — books by URL, ISBN or search, with the rating distribution and the readers' reviews.
- **[Yandex Maps Reviews Scraper](https://apify.com/hyperbach/yandex-maps-reviews-scraper)** — the reviews of a Yandex Maps organization, with the rating, the owner's reply and the organization's own rating.

*This page is generated from the Actor's schemas and a live sample — it cannot describe a field the Actor does not have.*

# Actor input Schema

## `businessUrls` (type: `array`):

One value per business: a Yelp business page URL on any Yelp site (`https://www.yelp.com/biz/gary-danko-san-francisco`, `yelp.de/biz/…`, `m.yelp.com/biz/…`; its `?osq=` or `?hrid=` part is ignored), a 22-character business id (`WavvLdfdP6g8aZTtbBQHTw`), a bare alias (`gary-danko-san-francisco`), or a Yelp search URL with `find_desc` and `find_loc` (read as a search). Up to 500 values a run. A value that names no business gets a free `invalid` row; a business given twice is read once (a free `duplicate` row).

## `searchTerms` (type: `array`):

What you would type into Yelp's search box (`pizza`, `dentist`, a business name): each term is searched in `searchLocation`, and the businesses it finds are read like the ones above. Needs `searchLocation`. Up to 20 terms.

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

Where the search terms are searched: a city (`Chicago, IL`), a postcode, a neighbourhood or an address. The search row says how Yelp read it.

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

How many businesses each search term (or search URL) takes, in Yelp's order: 1 to 240 (Yelp lists 240 businesses a search at most).

## `maxReviewsPerBusiness` (type: `integer`):

Stop each business after this many review rows. 0 = every review Yelp lists in the asked view (the business row then says COMPLETE when the walk reached Yelp's own end).

## `sort` (type: `string`):

Yelp's own review order: newest first (the default), oldest first, highest or lowest rated first, Yelp's recommended order, or Elite reviewers first.

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

The reviews' language as Yelp's two-letter code (`en`, the default; `fr`, `de`, `es`…), or `all` for every language the business has reviews in (one walk per language). Yelp shows one language at a time; without a language it shows English.

## `stars` (type: `string`):

Keep reviews of these star ratings only, comma-separated (`1`, `1,2`, `4,5`). Empty = every rating.

## `keywords` (type: `array`):

Keep reviews that Yelp's own review search matches for these words or phrases (one search per keyword, a review found by two keywords delivered once; each row says its `keyword`). Yelp's review search has no order of its own: with a sort other than `recommended` each business's matches are read whole, then sorted. Up to 20.

## `dateFrom` (type: `string`):

Keep reviews written on or after this day in the business's own time (`2026-01-31`), or within the last N days (`30 days`). With the newest-first sort the walk stops at the first older review: nothing older is read or charged.

## `dateTo` (type: `string`):

Keep reviews written on or before this day in the business's own time (`2026-06-30`). With the oldest-first sort the walk stops at the first newer review.

## `translateTo` (type: `string`):

A two-letter language code (`en`): Yelp's own translation of each review into it, in `text_translated`, beside the original text. Empty = no translation.

## `includeNotRecommended` (type: `boolean`):

Also read the reviews Yelp's filter keeps off the business page (its not-recommended list) and the ones Yelp removed for a content violation, each row marked by `review_status`. They are review rows like the others (charged, counted by the limits). The business row always carries both counts.

## `includePersonalData` (type: `boolean`):

Off (the default): the reviewer's name, photo and profile link and the replier's name stay empty; the reviewer's public counts, elite year and city are on every row. On: you take the responsibility for processing personal data under the laws that apply to you.

## `onlyNewReviews` (type: `boolean`):

Skip the reviews an earlier run with the same memory delivered (free), so a scheduled run delivers only what is new. With the newest-first sort a business's walk stops at its first review delivered before.

## `stateStoreName` (type: `string`):

The name of the memory `onlyNewReviews` keeps (letters, digits, `.`, `_`, `~`, `-`). Empty = a name made from the inputs.

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

Stop the run after this many review rows across every business (0 = no limit). Business and search rows are free and not counted. A business left unread at the limit gets a free `not_read` row.

## `proxyUrl` (type: `string`):

Empty (recommended): Yelp is read through the Actor's own connections at no extra cost to you. Your own proxy URL (scheme://user:pass@host:port) carries every call instead. The word none runs without any proxy, from the Apify worker's own IP (for tests).

## Actor input object example

```json
{
  "businessUrls": [
    "https://www.yelp.com/biz/mcgrath-elmhurst-toyota-elmhurst-2"
  ],
  "searchTerms": [],
  "searchLocation": "",
  "maxBusinessesPerSearch": 10,
  "maxReviewsPerBusiness": 50,
  "sort": "newest",
  "language": "en",
  "stars": "",
  "keywords": [],
  "dateFrom": "",
  "dateTo": "",
  "translateTo": "",
  "includeNotRecommended": false,
  "includePersonalData": false,
  "onlyNewReviews": false,
  "stateStoreName": "",
  "maxItems": 0
}
```

# Actor output Schema

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

All scraped records in the default dataset. One row per review (charged), one free row per business, and one free row per search:

## `runSummary` (type: `string`):

How the run went: review rows charged, free rows by type and status, each business's status and verdict, the review-feed document ids in use, the source counters (calls by kind, their slowest answer, exits, walls, rotations, retries, bytes by connection) and the memory watch.

# 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 = {
    "businessUrls": [
        "https://www.yelp.com/biz/mcgrath-elmhurst-toyota-elmhurst-2"
    ],
    "maxReviewsPerBusiness": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("hyperbach/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 = {
    "businessUrls": ["https://www.yelp.com/biz/mcgrath-elmhurst-toyota-elmhurst-2"],
    "maxReviewsPerBusiness": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("hyperbach/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 '{
  "businessUrls": [
    "https://www.yelp.com/biz/mcgrath-elmhurst-toyota-elmhurst-2"
  ],
  "maxReviewsPerBusiness": 50
}' |
apify call hyperbach/yelp-reviews-scraper --silent --output-dataset

```

## MCP server setup

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