# PagesJaunes Scraper \[$0.90/1K💰] | French B2B Leads & Phones (`ahmed_jasarevic/pagesjaunes-fr-scraper`) Actor

Scrape PagesJaunes.fr French business data: name, category, address, phone, website, hours and reviews. Build B2B lead lists and a French company database by profession and city, without the restricted official API.

- **URL**: https://apify.com/ahmed_jasarevic/pagesjaunes-fr-scraper.md
- **Developed by:** [Ahmed Jasarevic](https://apify.com/ahmed_jasarevic) (community)
- **Stats:** 4 total users, 3 monthly users, 91.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.88 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## PagesJaunes Scraper: French Business Directory & B2B Lead Data

Scrape **PagesJaunes.fr** (Yellow Pages France) by profession and location and export **34 fields** per business: name, category, full address, phone numbers, opening hours, services, ratings, reviews, website and quote/booking availability as structured JSON. It reads the public directory with a Chrome-compatible TLS fingerprint, so no API key is needed. **From $0.90 per 1,000 businesses**, with a 10-row free preview.

### Main use cases

- **Prospection B2B / lead generation**: build targeted outreach lists of French businesses by profession and city or department.
- **Base de données entreprises**: assemble a structured French company directory with phone, address, website and activity.
- **Market research and competitor analysis**: measure how many businesses of a given category operate in an area and how they are rated.
- **Review and reputation monitoring**: track ratings and review counts for businesses and categories over time.
- **Directory and enrichment datasets**: fill in missing phone, website or opening-hours data for existing records.
- **Local-services research**: compare service availability (quote/booking) across cities and regions.

### How It Works

![How the PagesJaunes Scraper works: a profession and location search becomes 34-field French business leads.](https://api.apify.com/v2/key-value-stores/oeuA0kLOyhbRM4fzt/records/how-it-works-pagesjaunes-fr-scraper)

This actor queries PagesJaunes search-result pages for a profession plus location, then visits each business profile page and maps it into one dataset row. It uses **no browser**: requests are made with an **impers** (curl-impersonate) HTTP client that reproduces a real Chrome browser's TLS handshake byte-for-byte (exact JA3/JA4 fingerprint, cipher order, extension order and HTTP/2 settings), because PagesJaunes is protected by **Cloudflare Bot Management**, whose plain HTTP requests get a `403` challenge.

The actor warms up the homepage to obtain Cloudflare clearance cookies, reuses the session (cookies plus keep-alive connection pool) for the crawl, and retires the session and retries with a fresh proxy when a challenge appears (up to 3 retries per URL). HTML is parsed with Cheerio.

### Extract French Business Data For B2B Prospecting

For every business found on the search results, the actor visits the profile page and returns a full record: business id, name, primary category plus all activities, schema.org type, street/postal code/city/address/country, phone number(s), public email, website and other external links, quote ("devis") and booking links with availability flags, average rating and review count, recent reviews, services/prestations, description, price range, opening hours by day (French day names), GPS coordinates, photo URLs, the profile URL, the query/location that produced the result, and a scrape timestamp.

### Scrape PagesJaunes Without The Official API

PagesJaunes does publish an official API (developer.pagesjaunes.fr: Reviews API, Business Infos API, Find Businesses API), but it is **restricted**: it is reserved for consumer-facing local-search services and is explicitly **not** available for commercial prospecting, database enrichment or academic research. This actor instead reads the public directory pages directly, so it works for exactly those lead-generation and data-assembly use cases the official API excludes.

**Why residential proxies help:** Cloudflare also fingerprints IP addresses. While Chrome TLS impersonation can sometimes work from datacenter IPs, **residential French proxies significantly improve success rates**. The Console prefills a residential-FR proxy, but the API default is no proxy, so enable one explicitly for production runs.

**Known limitations**

- `latitude`/`longitude` are only present when the profile page embeds them in the JSON-LD `geo` node; not all profiles do.
- Reviews are limited to what the profile page embeds (typically the most recent ones).
- The site is French-only; queries and locations should be in French.

### Input Parameters

| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
| `searchQuery` | string | No | `plombier` | Business type or profession to search for, e.g. `plombier`, `restaurant`, `dentiste`, `electricien`. |
| `location` | string | No | `Paris` | City, department, region or postal code, e.g. `Paris`, `Lyon`, `75011`, `Bordeaux`. |
| `maxResults` | integer | No | `20` | Maximum businesses to return (PagesJaunes lists 20 per page). Hard cap 2,000; free users are capped at 10. |
| `maxPages` | integer | No | `0` | Maximum search pages to crawl (hard max 100). `0` derives it automatically from `maxResults` at 20 businesses per page. |
| `scrapeDetails` | boolean | No | `true` | Visit each business's profile page to extract phone number, opening hours, website, GPS coordinates and reviews. Required for phone/hours, so it is on by default. |
| `startUrls` | array (requestListSources) | No | `[]` | Optional PagesJaunes search-result URLs to scrape directly. When provided, `searchQuery` and `location` are ignored. |
| `proxy` | object (proxy) | No | No proxy (Console prefill: RESIDENTIAL, FR) | Standard Apify proxy picker. **Residential French proxies are strongly recommended** because of Cloudflare Bot Management; enable one explicitly for production. |

### Output Fields

One dataset item per business. The default `overview` view shows Name, Category, Phone, City, Postal code, Rating, Reviews, Website and URL.

| Field | Type | Description |
|---|---|---|
| `businessId` | string | PagesJaunes business id (from `/pros/{id}`). |
| `name` | string / null | Business name. |
| `category` | string / null | Primary business category/activity. |
| `categories` | array | All activities listed for the business. |
| `type` | string / null | schema.org business type, e.g. `Restaurant`, `LocalBusiness`. |
| `street` | string / null | Street address. |
| `postalCode` | string / null | Postal code. |
| `city` | string / null | City. |
| `address` | string / null | Full formatted address. |
| `country` | string / null | Country. |
| `phone` | string / null | Primary phone number. |
| `phones` | array | All phone numbers found for the business. |
| `email` | string / null | Contact email when publicly listed. |
| `website` | string / null | Business website URL. |
| `websites` | array | All external website/social links for the business. |
| `quoteUrl` | string / null | Quote (devis) link. |
| `bookingUrl` | string / null | Online booking/appointment request URL. |
| `hasOnlineQuote` | boolean | Whether the business offers online quotes. |
| `hasOnlineBooking` | boolean | Whether the business offers online booking. |
| `rating` | number / null | Average rating (0-5). |
| `reviewCount` | integer / null | Number of reviews. |
| `services` | array | Services/prestations offered. |
| `description` | string / null | Business description. |
| `priceRange` | string / null | Price range when listed. |
| `openingHours` | object / null | Opening hours by day (French day names). |
| `latitude` | number / null | Latitude. |
| `longitude` | number / null | Longitude. |
| `image` | string / null | Primary image URL. |
| `images` | array | All image URLs for the business. |
| `reviews` | array | Reviews (author, date, rating, text). |
| `url` | string | PagesJaunes profile URL. |
| `searchQuery` | string / null | Search query used (when applicable). |
| `searchLocation` | string / null | Search location used (when applicable). |
| `scrapedAt` | string | ISO timestamp of extraction. |

### Example Input And Output

**Input**

```json
{
  "searchQuery": "plombier",
  "location": "Paris",
  "maxResults": 100,
  "scrapeDetails": true
}
```

**Output (one dataset row)**

```json
{
  "businessId": "123456789",
  "name": "Plomberie Dupont",
  "category": "Plombier",
  "categories": ["Plombier", "Chauffagiste"],
  "type": "LocalBusiness",
  "street": "12 Rue de la Roquette",
  "postalCode": "75011",
  "city": "Paris",
  "address": "12 Rue de la Roquette, 75011 Paris",
  "country": "France",
  "phone": "01 23 45 67 89",
  "phones": ["01 23 45 67 89"],
  "email": null,
  "website": "https://plomberie-dupont.fr",
  "websites": ["https://plomberie-dupont.fr"],
  "quoteUrl": "https://www.pagesjaunes.fr/pros/123456789/devis",
  "bookingUrl": null,
  "hasOnlineQuote": true,
  "hasOnlineBooking": false,
  "rating": 4.6,
  "reviewCount": 38,
  "services": ["Dépannage", "Installation chaudière"],
  "description": "Plombier chauffagiste à Paris 11e ...",
  "priceRange": null,
  "openingHours": { "lundi": "08:00-19:00", "mardi": "08:00-19:00" },
  "latitude": 48.85561,
  "longitude": 2.37201,
  "image": "https://.../image.jpg",
  "images": ["https://.../image.jpg"],
  "reviews": [{ "author": "Marie L.", "date": "2026-08-12", "rating": 5, "text": "Travail soigné ..." }],
  "url": "https://www.pagesjaunes.fr/pros/123456789",
  "searchQuery": "plombier",
  "searchLocation": "Paris",
  "scrapedAt": "2026-10-11T09:00:00.000Z"
}
```

### Pricing

Pay-per-event, charged only for rows written:

| Event | Price |
|---|---|
| Actor start | $0.00005 per started GB (minimum one event) |
| Business row | $0.00090 |

That is **$0.90 per 1,000 businesses**. Free Apify accounts receive a 10-business preview; paid runs are capped at 2,000 businesses by `maxResults`. The actor-start event is charged once per run.

### Integrations & Automation

Every Apify actor is reachable through the **Apify API**, and this one plugs into **webhooks**, **Zapier** and **Make** so results can flow into a Google Sheet, Airtable base, CRM or data warehouse. For prospecting and review monitoring, run it on a **schedule**: a weekly snapshot of your target professions and cities is enough to find new businesses and track rating changes, and recurring runs also improve the actor's Store recommendation signals.

### Related Actors

- [pagesjaunes-scraper](https://apify.com/saswave/pagesjaunes-scraper): the largest PagesJaunes scraper; a reference point for the topic cluster.
- [pagesjaunes-scraper-cheerio](https://apify.com/memo23/pagesjaunes-scraper-cheerio): another lightweight PagesJaunes option.
- [brownbook-scraper](https://apify.com/ahmed_jasarevic/brownbook-scraper): a global business directory with reviews, to widen company coverage beyond France.
- [europages-scraper](https://apify.com/ahmed_jasarevic/europages-scraper): EU B2B company directory data to complement French business records.
- [justdial-scraper](https://apify.com/ahmed_jasarevic/justdial-scraper): a large India business directory for multi-country lead datasets.

### FAQ

#### Is there an official PagesJaunes API?

Yes, there is an official API (developer.pagesjaunes.fr: Reviews API, Business Infos API, Find Businesses API), but it is restricted: it is reserved for consumer-facing local-search services and is explicitly **not** available for commercial prospecting, database enrichment or academic research. This actor reads the public directory pages directly, so it works for the lead-generation and data-assembly use cases the official API excludes.

#### What are the alternatives to this actor / this data source?

For French business data you can combine this with Société.com, SIRENE or other directory scrapers. PagesJaunes is the strongest source for phone numbers, activity categories and customer reviews, so it is worth having alongside registry-based sources that cover SIRET/SIREN identifiers.

#### How do I build a French B2B lead list by profession and city?

Set `searchQuery` to the profession (e.g. `electricien`) and `location` to the city, department or postal code, keep `scrapeDetails` on, and set `maxResults`. The actor returns one row per business with phone, address, website and rating, ready for a spreadsheet or CRM.

#### Why are `latitude` and `longitude` sometimes empty?

GPS coordinates are only returned when the business profile page embeds them in the JSON-LD `geo` node. Not every profile does, so these fields can be `null` for some rows.

#### Does PagesJaunes block scrapers?

PagesJaunes uses Cloudflare Bot Management, which inspects TLS fingerprints and rejects plain HTTP clients. This actor reproduces a real Chrome TLS handshake and works best with residential French proxies; the Console prefills that proxy, but API runs must enable one explicitly.

#### How many businesses does a run return?

PagesJaunes lists 20 businesses per result page. Set `maxResults` to control the total; leave `maxPages` at `0` and the actor derives the page count automatically. Free-plan runs are capped at 10 businesses.

### SEO Keywords

pagesjaunes, pages jaunes, scraper pagesjaunes, pagesjaunes scraper, annuaire entreprises, annuaire professionnel, données entreprises france, prospection b2b, base de données entreprises, extraction données entreprises, scraping pagesjaunes, api annuaire, leads b2b france, avis entreprises, telephone entreprises, entreprises france, pagesjaunes api, pagesjaunes alternative, annuaire des entreprises, donnees entreprises

### For AI Agents & LLM Apps

Purpose: return one structured French business-directory row per PagesJaunes listing for a given profession and location.

Minimal working input:

```json
{ "searchQuery": "plombier", "location": "Paris", "maxResults": 20 }
```

Output fields: `businessId, name, category, categories, type, street, postalCode, city, address, country, phone, phones, email, website, websites, quoteUrl, bookingUrl, hasOnlineQuote, hasOnlineBooking, rating, reviewCount, services, description, priceRange, openingHours, latitude, longitude, image, images, reviews, url, searchQuery, searchLocation, scrapedAt`.

Behaviors an agent should know:

- `searchQuery` and `location` are the normal inputs; if `startUrls` is set, both are ignored and only those URLs are scraped.
- `scrapeDetails` defaults to `true` and is what enables `phone`, `openingHours`, `website` and `reviews`; turning it off returns listing-only rows.
- PagesJaunes lists 20 businesses per page; `maxPages` at `0` is derived automatically from `maxResults`.
- Free-plan runs are capped at 10 businesses regardless of `maxResults`.
- `latitude`/`longitude` may be `null` for some businesses (only present when the profile embeds a `geo` node).
- Queries and locations are French; the site is French-only.

Billing: pay-per-event: **$0.0009 per result** ($0.90 / 1,000 businesses) plus a $0.00005 actor-start event.

### Legal & Compliance Disclaimer

This actor is an independent tool and is **not affiliated with, endorsed by, or sponsored by Solocal or PagesJaunes**. It accesses only publicly available PagesJaunes directory pages; it does not log in, bypass authentication, or solve CAPTCHAs on anyone's behalf. Users are responsible for ensuring their use complies with PagesJaunes' Terms of Service and with applicable data-protection law (including the GDPR, since the data concerns French/EU businesses). Where output includes business contact details such as phone numbers or emails, it must not be used for unsolicited commercial outreach in violation of applicable law.

# Actor input Schema

## `searchQuery` (type: `string`):

Business type or profession to search for on PagesJaunes (e.g. "plombier", "restaurant", "dentiste", "electricien").

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

City, department, region or postal code (e.g. "Paris", "Lyon", "75011", "Bordeaux").

## `maxResults` (type: `integer`):

Maximum number of businesses to return. PagesJaunes lists 20 per page. Free users are capped at 10.

## `maxPages` (type: `integer`):

Maximum number of result pages to crawl. Leave at 0 to derive it automatically from Max results (20 businesses per page).

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

Visit each business's profile page to extract phone number, opening hours, website, GPS coordinates and reviews. Required for phone/hours, so it is on by default.

## `startUrls` (type: `array`):

Optional PagesJaunes search-result URLs to scrape directly. When provided, search query and location are ignored.

## `proxy` (type: `object`):

Select proxies to be used by your crawler. RESIDENTIAL proxies are strongly recommended for PagesJaunes due to Cloudflare Bot Management.

## Actor input object example

```json
{
  "searchQuery": "plombier",
  "location": "Paris",
  "maxResults": 20,
  "maxPages": 0,
  "scrapeDetails": true,
  "startUrls": [],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "FR"
  }
}
```

# 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 = {
    "searchQuery": "plombier",
    "location": "Paris",
    "startUrls": [],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "FR"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ahmed_jasarevic/pagesjaunes-fr-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 = {
    "searchQuery": "plombier",
    "location": "Paris",
    "startUrls": [],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "FR",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("ahmed_jasarevic/pagesjaunes-fr-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 '{
  "searchQuery": "plombier",
  "location": "Paris",
  "startUrls": [],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "FR"
  }
}' |
apify call ahmed_jasarevic/pagesjaunes-fr-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ahmed_jasarevic/pagesjaunes-fr-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/tAqiJdMnZ7eiWaVdx/builds/pChh8LVN9tomnYZoi/openapi.json
