# Citysearch Real-Time Data Scraper (`b2b_leads/citysearch-real-time-data-scraper`) Actor

Live Citysearch business directory data: keyword + city search across US local businesses, full profiles, reviews & ratings, and lead enrichment with phones, websites, emails, and socials. Checkbox features stream structured JSON to your dataset in real time.

- **URL**: https://apify.com/b2b_leads/citysearch-real-time-data-scraper.md
- **Developed by:** [Emmanuel](https://apify.com/b2b_leads) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

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?

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

## Citysearch Real-Time Data

> **Free trial:** free Apify plans get **2 results per run**. Paid plans are uncapped. See [Free-tier trial](#free-tier-trial) below.

Live Citysearch business directory intelligence for agencies, local SEO teams, outreach operations, and CRMs. Search US local businesses by keyword + city, open full business profiles, collect public reviews, and enrich rows with lead details (phones, websites, emails, socials). Every record streams to your dataset as it is collected.

### Who this is for

- **Lead-gen agencies** building outreach lists by service + city (plumbers in New York, dentists in Austin, roofers in Chicago).
- **Local SEO teams** auditing directory presence, categories, hours, and review signals across markets.
- **Sales / RevOps** enriching CRM records with verified phones, websites, emails, and social profiles.
- **Market researchers** tracking service coverage and business density by metro.
- **Data teams** feeding agents and pipelines with fresh, structured local-business rows.

### Features

| Checkbox | What it does |
|---|---|
| 🔎 Business Search (default on) | Keyword + location search across the Citysearch directory. Prefilled with `plumber` / `roofing contractor` in `New York, NY` so first runs return in seconds. |
| Enrich with full business details | Same rows (`detailsFetched: true`) plus full profile: hours, categories, extra phones, coordinates, description. Adds a little extra time per record. |
| 🎯 Add lead details (emails & socials) | Same rows (`leadEnriched: true`) plus public emails and social profiles found on the business's own website. Nothing is ever dropped. |
| 🏢 Business Details | Full profiles for exact Citysearch business URLs you paste (`/profile/<id>`). |
| ⭐ Reviews & Ratings | Public reviews per business URL — reviewer, date, text, source. Capped by `maxReviewsPerBusiness` (default 10). |
| 🔗 Scrape By URL | Paste any Citysearch business URL; returns the structured profile. |
| 🔔 Delivery | Optional webhook (JSON or Slack) fired per record, in addition to the dataset. |
| 🌐 Connection | Residential proxy recommended; US default. |

Every discovered business is exported — enrichment adds fields in place and never filters rows.

### Input reference

- `enableBusinessSearch` (boolean, default `true`) — primary discovery.
- `searchTerms` (string\[], default `["plumber","roofing contractor"]`) — e.g. `"dentist"`, `"auto repair"`, `"med spa"`. Required when search is on. Each term × each location is one task.
- `searchLocations` (string\[], default `["New York, NY"]`) — `"Austin, TX"`, `"Chicago, IL"`, or ZIP `"10001"`. Required when search is on.
- `searchMaxResults` (integer 1–200, default `10`) — max businesses per term + location.
- `searchFetchFullDetails` (boolean, default `false`) — enrich search rows with full profiles in place.
- `enrichLeadDetails` (boolean, default `false`) — add emails/socials from business websites in place.
- `leadDetailsSiteLookups` (integer 1–6, default `3`) — extra pages checked per business website.
- `enableBusinessDetails` + `businessUrls` — e.g. `https://www.citysearch.com/profile/18581644`.
- `enableReviews` + `reviewBusinessUrls` + `maxReviewsPerBusiness` (1–100, default `10`).
- `enableScrapeByUrl` + `scrapeUrls` — any Citysearch business URL.
- `webhookUrl` (string) + `webhookFormat` (`json` | `slack`).
- `proxyConfiguration` — Residential, US default.

Empty input still runs the demo: Business Search on, `plumber` in `New York, NY`, 10 rows.

### Output reference

One row per business (`business_search`, `business_details`, `scrape_by_url`) and one row per review (`business_reviews`). Filter dataset views by `featureType`.

Business fields: `business_id`, `business_name`, `categories`, `primary_category`, `phone`, `extra_phones`, `website`, `website_domain`, `emails`, `email`, `street_address`, `city`, `state`, `postal_code`, `country`, `address_full`, `latitude`, `longitude`, `rating`, `review_count`, `years_in_business`, `claimed`, `open_status`, `hours`, `payments`, `description`, `social_links`, `social_urls`, `sponsored: false`, `position`, `search_term`, `search_location`, `page`, `detailsFetched`, `leadEnriched`, `url`, `scrapedAt`.

Review fields: `review_id`, `author`, `rating`, `date`, `text`, `provider`, `helpful_count`, plus `business_id`, `business_name`, `url`, `position`, `scrapedAt`.

### Webhooks

Set `webhookUrl` to receive each record in real time (dataset writes always happen first):

- **JSON** (`webhookFormat: "json"`) — full record object, ideal for Zapier / Make / n8n / CRM ingestion.
- **Slack** (`webhookFormat: "slack"`) — Slack-friendly message with business name, phone, address, and source link.

Delivery is fire-and-forget: failures are logged and never stop the run.

### MCP / AI-agent usage

Pair with the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp) so agents can call this Actor with natural language:

> "Find 10 plumbers in New York on Citysearch with phones and websites, and enrich the top 5 with emails."

The agent maps that to `searchTerms: ["plumber"]`, `searchLocations: ["New York, NY"]`, `searchMaxResults: 10`, `enrichLeadDetails: true`.

### FAQ

- **Which connection should I use?** Residential US is the default and the most reliable for directory searches at scale.
- **How fresh is the data?** Every run collects live directory results at run time — nothing cached, nothing pre-scraped.
- **What does the free trial include?** Free Apify plans get 2 results per run with an upgrade notice; the run still exits cleanly. Paid plans are uncapped.
- **Do enrich toggles create extra rows?** No — details and lead details merge into the same row (`detailsFetched` / `leadEnriched` flags).
- **Are partial records kept?** Yes — every discovered business is saved, even when a website carries no extra contact details.

### Free-tier trial

Free Apify plans are capped at **2 results per run** (`FREE_TIER_MAX_ITEMS=2`, `FREE_TIER_MODE=limit`). The run finishes with a clean exit and an upgrade notice; the `paywall` block on `OUTPUT` records the cap. Owner env vars (`FREE_TIER_MODE=block`, `PPE_EVENT_NAME=result`) are configured in the Apify Console.

# Actor input Schema

## `enableBusinessSearch` (type: `boolean`):

Live keyword + city search across the US Citysearch directory — local services, contractors, clinics, retail, and more. On by default and prefilled so you can click Start and get results in seconds.

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

What to look for, e.g. "plumber", "roofing contractor", "dentist", "auto repair", "med spa". Required when Business Search is on. Each term is combined with every location below.

## `searchLocations` (type: `array`):

US cities or areas to search, e.g. "New York, NY", "Austin, TX", "Chicago, IL". Required when Business Search is on.

## `searchMaxResults` (type: `integer`):

Maximum businesses collected for each term/location pair (1–200). Default 10 — perfect for instant demo runs.

## `searchFetchFullDetails` (type: `boolean`):

When on, each search result stays ONE row (featureType business_search, detailsFetched=true) but is enriched with the business's full profile: opening hours, payment options, extra phone numbers, social profiles, coordinates, and full categories. Adds a little extra time per record. Every discovered business is always saved — never filtered out.

## `enrichLeadDetails` (type: `boolean`):

When on, each business keeps ONE row (leadEnriched=true) and gains public contact details from the business's own website — email addresses and social profiles (Facebook, Instagram, LinkedIn, X, YouTube, TikTok). Phone and website from the directory are always kept. Adds a little extra time per record. Every business is saved whether or not extra details are found.

## `leadDetailsSiteLookups` (type: `integer`):

How many additional pages (contact, about, team) to check on a business's own website when the homepage carries no email. 1–6, default 3.

## `enableBusinessDetails` (type: `boolean`):

Fetch the full profile for specific Citysearch businesses by URL — description, hours, payment options, extra phones, social profiles, coordinates, and ratings.

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

Full Citysearch business page URLs, e.g. https://www.citysearch.com/profile/18581644

## `enableReviews` (type: `boolean`):

Collect public customer reviews and star ratings for specific businesses — reviewer name, rating, date, review text, and source.

## `reviewBusinessUrls` (type: `array`):

Citysearch business page URLs to collect reviews for, e.g. https://www.citysearch.com/profile/18581644

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

Maximum reviews to collect for each business (1–100). Default 10.

## `enableScrapeByUrl` (type: `boolean`):

Paste any Citysearch URL — a business page, a search results page, or a city/category page.

## `scrapeUrls` (type: `array`):

Any Citysearch business, search, or city/category URL.

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

Optional. Every record is always saved to the run dataset — this webhook is an ADDITIONAL real-time push. Each new row is also POSTed to this URL (Slack, Discord, Zapier, Make, n8n, or your CRM).

## `webhookFormat` (type: `string`):

json = full record object; slack = Slack-friendly message payload.

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

Residential proxy recommended for the most reliable US local-business results.

## Actor input object example

```json
{
  "enableBusinessSearch": true,
  "searchTerms": [
    "plumber",
    "roofing contractor"
  ],
  "searchLocations": [
    "New York, NY"
  ],
  "searchMaxResults": 10,
  "searchFetchFullDetails": false,
  "enrichLeadDetails": false,
  "leadDetailsSiteLookups": 3,
  "enableBusinessDetails": false,
  "businessUrls": [],
  "enableReviews": false,
  "reviewBusinessUrls": [
    "https://www.citysearch.com/profile/18581644"
  ],
  "maxReviewsPerBusiness": 10,
  "enableScrapeByUrl": false,
  "scrapeUrls": [
    "https://www.citysearch.com/profile/18581644"
  ],
  "webhookUrl": "",
  "webhookFormat": "json",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `allResults` (type: `string`):

Full dataset for this run (every featureType).

## `overview` (type: `string`):

Core lead fields across features: name, phone, website, email, address, rating.

## `search` (type: `string`):

featureType=business_search only. One business = one row; full details and lead details merge into the same row when enabled.

## `details` (type: `string`):

featureType=business_details — full profiles for the businesses you listed by URL.

## `business_reviews` (type: `string`):

featureType=business_reviews — one row per review.

## `scrape_by_url` (type: `string`):

featureType=scrape_by_url — one row per business found on the URL you pasted.

# 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 = {
    "enableBusinessSearch": true,
    "searchTerms": [
        "plumber",
        "roofing contractor"
    ],
    "searchLocations": [
        "New York, NY"
    ],
    "searchMaxResults": 10,
    "searchFetchFullDetails": false,
    "enrichLeadDetails": false,
    "leadDetailsSiteLookups": 3,
    "enableBusinessDetails": false,
    "businessUrls": [],
    "enableReviews": false,
    "reviewBusinessUrls": [
        "https://www.citysearch.com/profile/18581644"
    ],
    "maxReviewsPerBusiness": 10,
    "enableScrapeByUrl": false,
    "scrapeUrls": [
        "https://www.citysearch.com/profile/18581644"
    ],
    "webhookFormat": "json",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("b2b_leads/citysearch-real-time-data-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 = {
    "enableBusinessSearch": True,
    "searchTerms": [
        "plumber",
        "roofing contractor",
    ],
    "searchLocations": ["New York, NY"],
    "searchMaxResults": 10,
    "searchFetchFullDetails": False,
    "enrichLeadDetails": False,
    "leadDetailsSiteLookups": 3,
    "enableBusinessDetails": False,
    "businessUrls": [],
    "enableReviews": False,
    "reviewBusinessUrls": ["https://www.citysearch.com/profile/18581644"],
    "maxReviewsPerBusiness": 10,
    "enableScrapeByUrl": False,
    "scrapeUrls": ["https://www.citysearch.com/profile/18581644"],
    "webhookFormat": "json",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("b2b_leads/citysearch-real-time-data-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 '{
  "enableBusinessSearch": true,
  "searchTerms": [
    "plumber",
    "roofing contractor"
  ],
  "searchLocations": [
    "New York, NY"
  ],
  "searchMaxResults": 10,
  "searchFetchFullDetails": false,
  "enrichLeadDetails": false,
  "leadDetailsSiteLookups": 3,
  "enableBusinessDetails": false,
  "businessUrls": [],
  "enableReviews": false,
  "reviewBusinessUrls": [
    "https://www.citysearch.com/profile/18581644"
  ],
  "maxReviewsPerBusiness": 10,
  "enableScrapeByUrl": false,
  "scrapeUrls": [
    "https://www.citysearch.com/profile/18581644"
  ],
  "webhookFormat": "json",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call b2b_leads/citysearch-real-time-data-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,b2b_leads/citysearch-real-time-data-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/qnADKenhhuOggTtw6/builds/CMQIiPQOA8MKtDhPJ/openapi.json
