# Yelp Ad Placement & Business Listings Scraper (`jungle_synthesizer/yelp-local-ad-placement-business-listing-scraper`) Actor

Scrape Yelp search results by category and location. Captures organic business
listings plus paid ad placements — campaign id, ad slot, placement, and showcase
flag — alongside ratings, review counts, categories, and address details.

- **URL**: https://apify.com/jungle\_synthesizer/yelp-local-ad-placement-business-listing-scraper.md
- **Developed by:** [BowTiedRaccoon](https://apify.com/jungle_synthesizer) (community)
- **Categories:** Lead generation, Business
- **Stats:** 2 total users, 1 monthly users, 90.9% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.40 / 1,000 record scrapeds

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/platform/actors/running/actors-in-store#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 Ad Placement & Business Listings Scraper

Scrape [Yelp](https://www.yelp.com) search results by category and location, and get back something no other Yelp scraper returns: which businesses are paying for ad placement. Returns business name, rating, reviews, categories, and contact fields for both organic and sponsored results — plus, for every sponsored card, the campaign ID, ad slot, placement type, and showcase flag behind it.

### Yelp Ad Placement & Business Listings Scraper Features

- Extracts organic AND sponsored ("isAd") result cards from any Yelp search query
- Returns ad campaign ID, opportunity ID, placement type (e.g. `vertical_0`, `carousel_0`), paid slot position, and showcase-ad flag for every sponsored listing — the field family no incumbent Yelp scraper ships
- Tracks organic rank independently of paid rank, so you can measure how much of page one is actually for sale in a given category and metro
- Runs any combination of search categories and locations in one job, not one query at a time
- Paginates automatically up to a per-query page limit you set
- Includes ratings, review counts, categories, service-area text, response time, and photo thumbnails alongside the ad data

### What Can You Do With Yelp Ad Intelligence Data?

- **Ad agencies** — benchmark a client's Yelp Ads spend and slot position against competitors in the same category and city
- **Competing ad platforms** — quantify how much of a market's local search real estate Yelp Ads controls, category by category
- **Local businesses** — see who's outbidding you for your own category before you call Yelp's sales team
- **Sales teams selling into local business** — a business paying for Yelp Ads is a demonstrated marketing spender with an active budget, which makes for a better prospect list than an undifferentiated directory dump
- **Market researchers** — track paid-vs-organic share of page one over time, by category and metro

### How Yelp Ad Placement & Business Listings Scraper Works

1. Give it one or more search categories (`plumbers`, `italian restaurants`) and one or more locations (`Austin, TX`).
2. It runs every category against every location and pages through the results up to your configured page limit.
3. Each result card is classified organic or ad. Ad cards carry the full campaign/placement/slot metadata; every card carries name, rating, reviews, categories, and the rest of the listing fields.
4. Records land in your dataset as they're found — no need to wait for the whole run to finish before you can start reading.

### Input

```json
{
  "categories": ["plumbers"],
  "locations": ["Austin, TX"],
  "maxPagesPerQuery": 2,
  "maxItems": 50
}
```

| Field | Type | Default | Description |
|---|---|---|---|
| `categories` | array of strings | — (required) | One or more Yelp search terms, e.g. `"plumbers"`, `"italian restaurants"`. Every category is crawled against every location. |
| `locations` | array of strings | — (required) | One or more locations in `"City, ST"` form (or a locality name for non-US Yelp markets), e.g. `"Austin, TX"`. |
| `maxPagesPerQuery` | integer | 3 | Maximum result pages (10 businesses/page) fetched per category+location combination. |
| `maxItems` | integer | 50 | Maximum number of business records saved across all queries. |

### Yelp Ad Placement & Business Listings Scraper Output Fields

```json
{
  "biz_id": "dzm1bLeRUuD_BnPr7xeNXg",
  "alias": "avai-contractor-del-valle",
  "biz_url": "https://www.yelp.com/biz/avai-contractor-del-valle",
  "name": "AVAI Contractor",
  "is_ad": true,
  "ad_campaign_id": "x4UWNWA9qmmHo2ZvHW4s8A",
  "ad_opportunity_id": "bf584e7b8053a6f9",
  "ad_placement": "vertical_0",
  "ad_slot": 0,
  "ad_placement_slot": 0,
  "ad_is_showcase": false,
  "ad_themed_name": null,
  "organic_rank": null,
  "rating": 5,
  "review_count": 1,
  "categories": ["Excavation Services", "Plumbing", "Septic Services"],
  "price_range": null,
  "phone": null,
  "formatted_address": "5037 Lexington Meadow Ln",
  "neighborhoods": [],
  "service_area": [],
  "website": null,
  "response_time": "1 day",
  "photo_urls": ["https://s3-media0.fl.yelpcdn.com/bphoto/R7lwqPJcFNlrmf8-vZvYkQ/ls.jpg"],
  "search_category": "plumbers",
  "search_location": "Austin, TX",
  "search_page": 1,
  "scraped_at": "2026-08-10T05:41:28.284Z"
}
```

| Field | Type | Description |
|---|---|---|
| `biz_id` | string | Yelp's internal business ID — the stable primary key |
| `alias` | string | The business's public URL slug |
| `biz_url` | string | Canonical yelp.com/biz/ URL |
| `name` | string | Business name |
| `is_ad` | boolean | True for a paid Yelp Ads placement, false for an organic result |
| `ad_campaign_id` | string | The Yelp Ads campaign behind this placement (ads only) |
| `ad_opportunity_id` | string | The ad auction/opportunity ID tied to this search request (ads only) |
| `ad_placement` | string | Ad slot type, e.g. `vertical_0`, `carousel_0` (ads only) |
| `ad_slot` | integer | Paid rank position within the placement (ads only) |
| `ad_placement_slot` | integer | Sub-slot position within the placement (ads only) |
| `ad_is_showcase` | boolean | True for Yelp's premium showcase ad format (ads only) |
| `ad_themed_name` | string | Themed ad campaign name, when set (ads only, often null) |
| `organic_rank` | integer | 1-based rank among organic results only — independent of `ad_slot` |
| `rating` | number | Star rating (0-5), when shown on the listing |
| `review_count` | integer | Number of reviews, when shown on the listing |
| `categories` | array of strings | Category labels shown on the card |
| `price_range` | string | Yelp price symbol (`$`-`$$$$`), when present |
| `phone` | string | Phone number, when present in the listing (ad listings mostly) |
| `formatted_address` | string | Street address, when present in the listing (ad listings mostly) |
| `neighborhoods` | array of strings | Neighborhood names, when present |
| `service_area` | array of strings | Service-area description, for businesses with no public storefront |
| `website` | string | Business website, when present (rarely surfaced by Yelp search) |
| `response_time` | string | Yelp's displayed typical quote-response time, e.g. `"5 hrs"` |
| `photo_urls` | array of strings | Thumbnail photo URLs from the listing card |
| `search_category` | string | The input category this record was found under |
| `search_location` | string | The input location this record was found under |
| `search_page` | integer | 1-based result-page number |
| `scraped_at` | string | ISO-8601 scrape timestamp |

### Resuming a large crawl

Every run emits a `resumeCursor` in its Output. If a large crawl stops before it finishes — because it hit `maxItems`, your spend cap (`maxTotalChargeUsd`), or was aborted — start a new run with **the same input** plus that `resumeCursor` to continue from where it left off. The crawl resumes from the queued work the previous run didn't reach.

- You are **not re-charged** for records the earlier run already delivered.
- Resume within your account's run-retention window — on the free tier, roughly your 10 most recent runs. Once the source run is pruned, its `resumeCursor` is no longer valid.
- `resumeCursor` is opaque — supply it unmodified.

### FAQ

#### How do I scrape Yelp ad placements?

Give Yelp Ad Placement & Business Listings Scraper a category and a location and run it. Every result card comes back tagged `is_ad: true` or `false`, and every ad card carries its campaign ID and paid slot position — no separate ad-library lookup required.

#### What data can I get from Yelp search results?

Business name, rating, review count, categories, address, price range, and photos for organic and sponsored results alike — plus campaign ID, ad slot, placement type, and showcase status for anything Yelp is running as an ad.

#### Can I run multiple categories and cities in one job?

Yes. `categories` and `locations` both accept arrays, and every category is crawled against every location in the same run.

#### Do I need a Yelp account or API key?

No. Point it at a category and a location and it returns results — no login, no API key.

#### How much does this cost to run?

Priced per business record returned, plus a per-run start fee. Check the Pricing tab on this actor's page for current rates.

### Need More Features?

Need custom fields, filters, or a different target site? [File an issue](https://console.apify.com/actors/issues) or get in touch.

### Why Use Yelp Ad Placement & Business Listings Scraper?

- **Sees what other Yelp scrapers don't** — campaign ID, ad slot, and showcase status for every sponsored card, not just name and rating
- **One job, many queries** — feed it a list of categories and a list of cities and it covers every combination, so you're not scripting a loop around a single-query scraper
- **Built for both sides of the trade** — organic and paid rank land in the same row, so agencies, competitors, and the businesses themselves can all read the same dataset

# Actor input Schema

## `sp_intended_usage` (type: `string`):

What will this data feed? E.g. lead lists, KYB checks, price tracking.

## `sp_improvement_suggestions` (type: `string`):

Provide any feedback or suggestions for improvements.

## `sp_contact` (type: `string`):

We'll personally help with your use case. No spam.

## `resumeCursor` (type: `string`):

Leave empty for a fresh crawl. To CONTINUE a previous run where it stopped — without paying again for records you already received — paste the `resumeCursor` value from that run's Output (the run's OUTPUT key). Resume promptly: the previous run's data expires with your account's retention window (free tier: your ~10 most recent runs).

## `categories` (type: `array`):

One or more Yelp search terms (the same free-text query typed into Yelp's
"find" box, e.g. "plumbers", "italian restaurants"). Every value is crawled
against every location.

## `locations` (type: `array`):

One or more Yelp locations in "City, ST" form (or a locality name for
non-US Yelp markets), e.g. "Austin, TX". Every category is crawled against
every location.

## `maxPagesPerQuery` (type: `integer`):

Maximum number of result pages (10 businesses/page) to fetch per
category+location combination. Each page is one billed Bright Data
Web Unlocker request.

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

Maximum number of business records to save across all queries

## Actor input object example

```json
{
  "sp_intended_usage": "Describe your intended use...",
  "sp_improvement_suggestions": "Share your suggestions here...",
  "sp_contact": "Share your email here...",
  "categories": [
    "plumbers"
  ],
  "locations": [
    "Austin, TX"
  ],
  "maxPagesPerQuery": 2,
  "maxItems": 20
}
```

# Actor output Schema

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

No description

# 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 = {
    "sp_intended_usage": "Describe your intended use...",
    "sp_improvement_suggestions": "Share your suggestions here...",
    "sp_contact": "Share your email here...",
    "categories": [
        "plumbers"
    ],
    "locations": [
        "Austin, TX"
    ],
    "maxPagesPerQuery": 2,
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("jungle_synthesizer/yelp-local-ad-placement-business-listing-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 = {
    "sp_intended_usage": "Describe your intended use...",
    "sp_improvement_suggestions": "Share your suggestions here...",
    "sp_contact": "Share your email here...",
    "categories": ["plumbers"],
    "locations": ["Austin, TX"],
    "maxPagesPerQuery": 2,
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("jungle_synthesizer/yelp-local-ad-placement-business-listing-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 '{
  "sp_intended_usage": "Describe your intended use...",
  "sp_improvement_suggestions": "Share your suggestions here...",
  "sp_contact": "Share your email here...",
  "categories": [
    "plumbers"
  ],
  "locations": [
    "Austin, TX"
  ],
  "maxPagesPerQuery": 2,
  "maxItems": 20
}' |
apify call jungle_synthesizer/yelp-local-ad-placement-business-listing-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jungle_synthesizer/yelp-local-ad-placement-business-listing-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/WHqLLAwiv3buAoXqL/builds/a1hH5jc2YXEs1nWhV/openapi.json
