# Thomson Local Data: UK Business Leads in Real Time (`b2b_leads/thomson-local-real-time-data-scraper`) Actor

Live Thomson Local UK business directory data: keyword + location search, full business profiles, and lead enrichment with websites and emails. Checkbox features stream structured JSON to your dataset in real time. Free plans get a 2-result trial.

- **URL**: https://apify.com/b2b_leads/thomson-local-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 $3.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

## Thomson Local Real-Time Data

> **Free trial:** free Apify plans get a **2-result sample** per run. Upgrade to a paid plan for full, unlimited exports.

Live Thomson Local UK business directory intelligence: keyword + location search, full business profiles, and lead enrichment with websites and emails. Every record streams to your dataset the moment it is collected — no waiting for the run to finish.

### Who is this for?

- **Lead-gen agencies & SDR teams** building UK outreach lists (plumbers, electricians, solicitors, restaurants…)
- **Local SEO tools & rank trackers** that need fresh business listings with phones and addresses
- **CRMs & data enrichment pipelines** that append websites, emails, and socials to company rows
- **Market researchers** sizing local trades (“how many plumbers list in Bristol vs Leeds?”)
- **AI agents** that answer “find me X near Y with a phone number” in real time

### Use cases

1. Build a cold-outreach list: plumbers in Bristol with phone + website + email.
2. Enrich an existing company list with missing websites and contact emails.
3. Monitor new listings per trade/location for sales territory planning.
4. Feed a CRM nightly via webhook (JSON or Slack) as records stream in.
5. Power an AI assistant that looks up local businesses live over MCP.

### Features

| Checkbox | What it does | Default |
|---|---|---|
| 🔍 Business search | Keyword + location rows (e.g. “plumbers” + “Bristol”) | ✅ on |
| 📄 Business details enrich | Full profile merged into the same row (description, hours, extra contacts, photos) | ✅ on |
| 📇 Lead details enrich | Flags lead-ready rows; website/phones/socials added where available | off |
| 📧 Email discovery | Reads each business's own website for a contact email | off |
| 🔗 Scrape By URL | Collect pasted Thomson Local business page links | off |
| 📣 Webhook (JSON/Slack) | POST every record to your URL as it streams | off |
| 🌐 Connection | Apify Residential (GB) by default | GB |

Enrichment works **in place**: the same row gains fields (`businessDetails: true`). No second row, no dropped records — every discovered business lands in the dataset.

### Input reference

- `enableSearch` (boolean, default `true`) — master switch for Business search.
- `searchTasks` (array) — rows of `{ keyword, location, maxResults }`. Example: `{ "keyword": "plumbers", "location": "Bristol", "maxResults": 10 }`.
- `maxResultsPerTask` (int, default `10`) — fallback cap per row.
- `maxPagesPerTask` (int, default `5`) — page cap per row (25 results per page).
- `enableBusinessDetails` (boolean, default `true`) — full-profile enrich.
- `enableContactDiscovery` (boolean, default `false`) — lead-details enrich.
- `fetchEmails` (boolean, default `false`) — website email read.
- `maxReviewsPerBusiness` (int 0–20, default `3`).
- `enableScrapeByUrl` (boolean, default `false`) + `scrapeUrls` (string list) — pasted business page links.
- `maxItems` (int, default `10000`) — global safety cap.
- `delayBetweenRequestsMs` (0–5000, default `800`), `concurrency` (1–8, default `4`).
- `webhookUrl` (string), `webhookFormat` (`json` | `slack`).
- `proxyConfiguration` — defaults to Apify Residential GB.

Legacy flat keys `keyword`/`trade` + `location` still work for single-task runs.

**First run?** Leave the defaults and click Start — you get plumbers in Bristol in seconds.

### Output fields

Each dataset row (`type: "business"`, `platform: "thomsonlocal"`):

`name, profileUrl, businessId, phone, phones, strapline, description, primaryCategory, categories, rating, ratingScale, reviewCount, reviews[], address, streetAddress, town, postcode, latitude, longitude, openingHours[], imageUrl, photos[], website, websiteDomain, email, emails[], socials, facebookUrl, instagramUrl, linkedinUrl, twitterUrl, listingType, sponsored, businessDetails, contactDiscovery, emailDiscovery, searchKeywords, searchLocation, searchTaskIndex, searchTaskLabel, position, featureType, scrapedAt`

The run `OUTPUT` object reports `totalPushed, tasksRequested, tasksCompleted, businessDetailsEnabled, contactDiscoveryEnabled, emailsEnabled, errors[], spendingLimitReached, paywall{...}`.

### Webhooks

Set `webhookUrl` (+ `webhookFormat: json|slack`) and every saved record is POSTed to your endpoint as it streams — ideal for Zapier/Make/n8n/CRM intake. Delivery is fire-and-forget: failures are logged, never fatal, and the dataset write always succeeds.

### MCP / AI-agent usage

Run this Actor through the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp) so your agent can call it as a tool. Example question:

> “Find 10 plumbers in Bristol on Thomson Local with phone numbers and websites, and enrich the first 3 with emails.”

### FAQ

- **Which connection does it use?** Apify Residential (GB default) on the platform — best for this UK directory. Local runs can use an owner-managed residential route via `.env`.
- **How fresh is the data?** Every run reads the live directory — results reflect what is published right now.
- **What does the free trial include?** 2 results per run on free Apify plans (same schema as paid). Upgrade for unlimited exports.
- **Do partial records get dropped?** Never. Every discovered business is exported; enrichment only adds fields.
- **Pay-per-event?** Monetization event `result` (configurable via `PPE_EVENT_NAME`). The run respects the user's spending limit and stops gracefully with a summary.

# Actor input Schema

## `enableSearch` (type: `boolean`):

Live keyword + location search across the Thomson Local UK directory. On by default and prefilled so you can click Start and get results in seconds.

## `searchTasks` (type: `array`):

One row per search: a trade/keyword plus a UK location. Required when Business search is on.

## `maxResultsPerTask` (type: `integer`):

Fallback cap used when a search row has no maxResults. Default 10 — perfect for instant demo runs.

## `maxPagesPerTask` (type: `integer`):

Safety cap on result pages per search row (25 results per page).

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

Enrich every business with its full profile (description, opening hours, extra contacts, photos). Adds a little extra time per business — the same row is enriched, never duplicated or dropped.

## `enableContactDiscovery` (type: `boolean`):

Enrich each business with lead details (website, extra phones, socials) where available. Adds a little extra time per business.

## `fetchEmails` (type: `boolean`):

Read each business's own website for a contact email. Runs last and adds a little extra time per business with a website.

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

Cap on reviews kept per business profile (0–20).

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

Collect specific Thomson Local business pages by pasting their links.

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

Full Thomson Local business page URLs, e.g. https://www.thomsonlocal.com/search/plumbers/bristol-avon/lloyd-s-plumbing/3294904/07968577251. Required when Scrape By URL is on.

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

Global safety cap for this run. Free-trial runs are capped at 2 results.

## `delayBetweenRequestsMs` (type: `integer`):

Politeness pause between page reads (0–5000 ms).

## `concurrency` (type: `integer`):

Parallel detail workers (1–8). Search stays sequential for reliability.

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

Optional https URL — every saved record is also POSTed here (JSON or Slack format). Best-effort: delivery failures never stop the run.

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

Payload shape for webhook posts.

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

Connection settings. Defaults to Apify Residential (GB) — recommended for this UK directory.

## Actor input object example

```json
{
  "enableSearch": true,
  "searchTasks": [
    {
      "keyword": "plumbers",
      "location": "Bristol",
      "maxResults": 10
    }
  ],
  "maxResultsPerTask": 10,
  "maxPagesPerTask": 5,
  "enableBusinessDetails": true,
  "enableContactDiscovery": false,
  "fetchEmails": false,
  "maxReviewsPerBusiness": 3,
  "enableScrapeByUrl": false,
  "scrapeUrls": [],
  "maxItems": 10,
  "delayBetweenRequestsMs": 800,
  "concurrency": 4,
  "webhookUrl": "",
  "webhookFormat": "json",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "GB"
  }
}
```

# Actor output Schema

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

Complete dataset with every business row from all enabled features in this run.

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

Businesses from keyword + location search.

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

Per-run metadata: totals, enabled features, spending-limit status, and the paywall object (detected, isPaying, pricingTier, limited, blocked).

# 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 = {
    "enableSearch": true,
    "searchTasks": [
        {
            "keyword": "plumbers",
            "location": "Bristol",
            "maxResults": 10
        }
    ],
    "maxResultsPerTask": 10,
    "maxPagesPerTask": 5,
    "enableBusinessDetails": true,
    "enableContactDiscovery": false,
    "fetchEmails": false,
    "maxReviewsPerBusiness": 3,
    "enableScrapeByUrl": false,
    "maxItems": 10,
    "delayBetweenRequestsMs": 800,
    "concurrency": 4,
    "webhookUrl": "",
    "webhookFormat": "json"
};

// Run the Actor and wait for it to finish
const run = await client.actor("b2b_leads/thomson-local-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 = {
    "enableSearch": True,
    "searchTasks": [{
            "keyword": "plumbers",
            "location": "Bristol",
            "maxResults": 10,
        }],
    "maxResultsPerTask": 10,
    "maxPagesPerTask": 5,
    "enableBusinessDetails": True,
    "enableContactDiscovery": False,
    "fetchEmails": False,
    "maxReviewsPerBusiness": 3,
    "enableScrapeByUrl": False,
    "maxItems": 10,
    "delayBetweenRequestsMs": 800,
    "concurrency": 4,
    "webhookUrl": "",
    "webhookFormat": "json",
}

# Run the Actor and wait for it to finish
run = client.actor("b2b_leads/thomson-local-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 '{
  "enableSearch": true,
  "searchTasks": [
    {
      "keyword": "plumbers",
      "location": "Bristol",
      "maxResults": 10
    }
  ],
  "maxResultsPerTask": 10,
  "maxPagesPerTask": 5,
  "enableBusinessDetails": true,
  "enableContactDiscovery": false,
  "fetchEmails": false,
  "maxReviewsPerBusiness": 3,
  "enableScrapeByUrl": false,
  "maxItems": 10,
  "delayBetweenRequestsMs": 800,
  "concurrency": 4,
  "webhookUrl": "",
  "webhookFormat": "json"
}' |
apify call b2b_leads/thomson-local-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/thomson-local-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/bgMqNfxeWQgzagh3m/builds/fsOnYB7lq4Agocdb5/openapi.json
