# Yelp Search Scraper (`creation/yelp-search-scraper`) Actor

Extract Yelp business data quickly without API keys. Collects ratings, prices, hours, amenities, and photos. Features advanced anti-bot mitigation (DataDome bypass) and robust cross-run caching for uninterrupted, scalable data extraction.

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

## Pricing

from $0.001 / result

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 Search Scraper

Searches Yelp for businesses matching a description and location, and returns the results as structured data — name, rating, review count, price tier, neighborhood, open/closed status, categories, review snippet, and thumbnail. Optionally visits each business's own page for phone, address, hours, amenities, and photos.

### What you get

For each business found:

| Field | Description |
|---|---|
| `title` | Business name |
| `link` | Yelp business page URL |
| `rating` | Star rating (e.g. `4.5`) |
| `reviews` | Review count |
| `price` | Price tier (`$`–`$$$$`), when Yelp shows one |
| `neighborhoods` | Neighborhood or area |
| `open_state` | e.g. "Open until 9:00 PM" |
| `categories` | Business categories, each with a title and link |
| `snippet` | An excerpt from a featured review |
| `thumbnail` | Listing photo URL |

With **Scrape full detail pages** turned on, each result is enriched with:

| Field | Description |
|---|---|
| `phone`, `address` | Contact details |
| `website` | The business's own site, if listed |
| `status` | e.g. "Permanently closed", when applicable |
| `hours` | Full weekly hours |
| `amenities` | e.g. "Takes reservations; Offers take-out; Accepts credit cards" |
| `people_also_searched` | Related searches Yelp surfaces on the page |
| `photo_urls` | All photo URLs from the business's gallery |

### Input

| Field | Required | Default | Notes |
|---|---|---|---|
| **Search description** (`findDesc`) | Yes | — | What to search for, e.g. `"Indian Veg Restaurants"` |
| **Location** (`findLoc`) | Yes | — | Where to search, e.g. `"Quebec City, Quebec, Canada"` |
| **Scrape full detail pages** (`scrapeDetails`) | No | `true` | Turn off for a faster run using only the search-result summary |
| **Max concurrent detail-page requests** (`maxConcurrency`) | No | `3` | Start low (2–5) — all requests in a run share one identity |
| **Refresh cookie cache only** (`refreshCookieOnly`) | No | `false` | Skips scraping entirely; just warms the shared cookie cache. Meant to be triggered on a Schedule so real runs rarely pay the mint cost live |

### Results per run

Each run returns the top page of Yelp search results for the given query — up to 10 businesses. This is a deliberate design choice, not a current limitation: Yelp's bot protection distinguishes an automated visitor requesting page 2+ of results from one just viewing the first page, and reliably blocks the former regardless of how the request is made. Ten real, verified results per query is the trade-off this Actor makes for consistent reliability instead of an unreliable deeper crawl.

### How it handles Yelp's bot protection

Yelp protects its pages with DataDome, which requires a real browser to solve a JavaScript challenge before serving content. This Actor mints that challenge cookie automatically using a real (non-headless) Chrome browser running against a virtual display — no manual cookie copying required. The resulting cookie is cached across runs, so most runs reuse an already-solved cookie in a few seconds rather than paying the ~70–90s mint cost every time.

If a request is blocked despite a cached cookie, the Actor still returns whatever data it already collected, then refreshes the cookie afterward for the next run — a block never costs you a delayed or empty result if any data was already in hand.

### Tips

- Requests from this Actor use Apify's Residential Proxy automatically when available.
- Running several searches at the exact same moment increases the chance any single one gets blocked (they briefly share one exit IP). Staggering concurrent runs by a few seconds avoids this.
- For scheduled/unattended use, set up an Apify Schedule that runs with **Refresh cookie cache only** enabled every 20–30 minutes, so on-demand runs almost always find a warm cookie waiting.

# Actor input Schema

## `findDesc` (type: `string`):

What to search for.

## `findLoc` (type: `string`):

Where to search.

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

If true, also fetch each business's own detail page (phone, address, hours, amenities, photos, etc). If false, only the search-result summary (rating, snippet, thumbnail, categories) is returned - faster, fewer requests.

## `maxConcurrency` (type: `integer`):

All requests replay the same cookie/identity for a given run, so higher values trade detection risk for speed. Start low (2-5).

## `refreshCookieOnly` (type: `boolean`):

If true, ignores findDesc/findLoc and just checks/refreshes the shared cookie cache, then exits. Meant to be triggered on a schedule (e.g. every 20-30 min via Apify's Schedule feature) so real scrape runs almost always find a warm cookie already cached instead of paying the ~70s mint cost live.

## Actor input object example

```json
{
  "findDesc": "Restaurants",
  "findLoc": "New York, NY, United States",
  "scrapeDetails": true,
  "maxConcurrency": 3,
  "refreshCookieOnly": false
}
```

# Actor output Schema

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

All Yelp businesses returned by the Actor, stored as individual items in the default dataset.

# 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 = {
    "findDesc": "Restaurants",
    "findLoc": "New York, NY, United States"
};

// Run the Actor and wait for it to finish
const run = await client.actor("creation/yelp-search-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 = {
    "findDesc": "Restaurants",
    "findLoc": "New York, NY, United States",
}

# Run the Actor and wait for it to finish
run = client.actor("creation/yelp-search-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 '{
  "findDesc": "Restaurants",
  "findLoc": "New York, NY, United States"
}' |
apify call creation/yelp-search-scraper --silent --output-dataset

```

## MCP server setup

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