# Yelp Scraper - Businesses, Ratings and Reviews (`s-r/yelp-scraper`) Actor

Scrape Yelp search results: business name, rating, review count, price range, categories, address and neighbourhood. Search by term and location, or paste a Yelp search URL.

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

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Yelp Scraper

Scrape **Yelp search results**: business name, star rating, review count, price
band, categories, street address and neighbourhood. Search by term and location,
or paste a Yelp search URL with your own filters already applied.

### Yelp was on our "closed" list, and it is not

Measured recently:
**six of six consecutive fetches returned about 1.07 MB of real results.**

The referer is part of it. Reaching a search page from a search engine is the
most ordinary way a person gets there, and it is in the profile that measured
clean.

### Where the data is, and three reasons the obvious parse fails

**Not in the JSON-LD.** The page publishes exactly two structured blocks,
`BreadcrumbList` and `FAQPage`, and **not one business appears in either**. A
scraper that reaches for JSON-LD here comes back empty and concludes the page is
a shell.

The businesses live in the page's **Apollo GraphQL cache**, which is shipped
inside three wrappers, each of which defeats a different parser:

1. inside a `<script type="application/json">` tag,
2. wrapped in an HTML comment, `<!-- ... -->`,
3. HTML-escaped, so every quote arrives as `&quot;`.

Strip all three and it is clean JSON.

**And the cache is normalised.** A `Business` entry holds the name, rating and
review count — but its address is a `__ref` pointer to a separate
`BusinessLocation` entry, and its categories are pointers to `BusinessCategory`
entries. Read only the `Business` entries and every row comes back with a null
address and no categories, which reads as missing data rather than an
unfollowed pointer. This Actor resolves the references, so addresses and
categories are populated.

### Fields

| Field | What it is |
|---|---|
| `alias` | Yelp's own slug, e.g. `queen-anne-coffee-seattle`. Stable, join on it |
| `name` | Business name |
| `rating` | Stars out of 5 |
| `review_count` | Number of reviews |
| `price_range` | `$` to `$$$$` |
| `categories` | Resolved category names, e.g. `["Coffee & Tea", "Bakeries"]` |
| `address`, `city` | Street address and city |
| `neighborhoods` | Neighbourhoods Yelp assigns |
| `timezone` | Business timezone |
| `yelp_guaranteed` | Whether enrolled in Yelp Guaranteed |
| `url` | Yelp business page |

`price_range` is returned as the dollar signs, not as the raw GraphQL object.
Yelp leaves it unset on many businesses, and those come back `null` rather than
being guessed from the category.

Some entries in the cache are landmarks and places rather than businesses, and
they legitimately carry no rating or address. Those fields come back `null`
rather than zero. On a test run of 40 results, 30 carried a rating and 31 an
address, and the run summary reports both counts so you can see the shape of
what you got.

### Input reference

| Field | Type | Default |
|---|---|---|
| `term` | what to search for | `coffee` |
| `location` | where | `Seattle` |
| `search_url` | full Yelp URL, overrides the two above | — |
| `limit` | 1-1000 | 50 |
| `retries` | 1-8 | 4 |

Pagination uses Yelp's own `start` offset in steps of 10.

Passing a `search_url` is the way to use Yelp's own filters. Set price, rating,
open-now, distance or any other facet in your browser, copy the address, and the
Actor paginates through that filtered result set. Filtering on Yelp is cheaper
than filtering the output, because the facet applies before pagination.

### Typical uses

- **Lead generation.** Businesses in a category and city, with address, rating
  and review count. `review_count` is a decent proxy for how established a
  business is.
- **Competitive research.** Rating and review distribution for a category in one
  market, or the same category compared across cities.
- **Market gap analysis.** Categories with high ratings and low review counts
  are usually young businesses; low ratings with high counts are the opposite.
- **Location scouting.** `neighborhoods` groups results the way Yelp's own
  users think about a city.

### Notes on behaviour

Pages are paced with a short
randomised gap. A page that loads but whose cache holds no businesses is
reported as `no_businesses` rather than returned as an empty result.

Yelp returns about 10 businesses per page, so a `limit` of 50 costs roughly five
requests. Results include sponsored placements, exactly as Yelp shows them; they
are not marked separately in the cache and this Actor does not invent a flag it
cannot verify.

This is the US site. Yelp operates elsewhere with a different result structure,
so treat the Actor as yelp.com until measured on another domain.

# Actor input Schema

## `term` (type: `string`):

What to look for, for example coffee, plumber or dentist.

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

Where to search, for example Seattle, Austin, TX or a postcode.

## `search_url` (type: `string`):

Paste a full Yelp search URL instead, including any filters you set in the browser. Overrides term and location.

## `limit` (type: `integer`):

How many businesses to return. Yelp returns about 10 per page.

## `retries` (type: `integer`):

Retries with backoff before a page is reported as an error. Each retry uses a fresh exit IP.

## Actor input object example

```json
{
  "term": "coffee",
  "location": "Seattle",
  "limit": 50,
  "retries": 4
}
```

# Actor output Schema

## `businesses` (type: `string`):

One row per business.

## `summary` (type: `string`):

Counts and how many rows carry a rating, address and categories.

## `errors` (type: `string`):

Failures with a code and a redacted message.

# 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 = {
    "term": "coffee",
    "location": "Seattle",
    "limit": 50,
    "retries": 4
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/yelp-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "term": "coffee",
    "location": "Seattle",
    "limit": 50,
    "retries": 4,
}

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

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "term": "coffee",
  "location": "Seattle",
  "limit": 50,
  "retries": 4
}' |
apify call s-r/yelp-scraper --silent --output-dataset

```

## MCP server setup

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

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/t8TcyeCNtrXjhOSfz/builds/ECuqUKdDEuAPGVHC9/openapi.json
