# WhatsApp Scraper — Numbers, Channels & Groups (`crawloop/whatsapp-scraper`) Actor

Scrape public WhatsApp data from phone numbers, channel pages, group invite links, and business catalogs: name, photo, followers, bio, catalog flag, and latest updates. No login, no QR code.

- **URL**: https://apify.com/crawloop/whatsapp-scraper.md
- **Developed by:** [Andrej Kiva](https://apify.com/crawloop) (community)
- **Categories:** Social media, Lead generation, Automation
- **Stats:** 6 total users, 4 monthly users, 96.2% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.99 / 1,000 whatsapp 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?

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

## WhatsApp Scraper — Numbers, Channels & Groups

> **Disclaimer:** Unofficial tool for **publicly accessible** WhatsApp pages (click-to-chat, channel pages, group invite previews, catalog landings). **WhatsApp** and related marks are trademarks of WhatsApp LLC / Meta. Not affiliated with, sponsored by, or endorsed by WhatsApp or Meta. Does not access private chats, messages, or anything behind login. For informational, research, lead-enrichment, and community-intelligence use only. Respect applicable terms of use and law (including GDPR / CCPA when you process phone numbers).

**WhatsApp scraper** for public **numbers**, **channels**, **group invite links**, and **business catalogs** — a practical **WhatsApp API alternative** that needs **no login**, **no QR code**, and **no Business API token**. Look up **wa.me** click-to-chat pages, hydrate **WhatsApp channel** URLs, resolve **group invites**, detect a **WhatsApp Business catalog**, or discover channels by keyword. Export **business name**, **account type**, **profile photo**, **followers**, **bio**, **catalog flag**, and **latest-update reaction counts** as **JSON**, **CSV**, or **Excel**. Scrape WhatsApp with **Python**, **Node.js**, **cURL**, or **Apify MCP** / AI assistants.

This Actor reads the same public Open Graph metadata a logged-out browser sees. It is a **WhatsApp number checker** for *publicly exposed* profiles (typical **WhatsApp Business** pages), a **WhatsApp channel scraper**, a **WhatsApp catalog checker**, and a **WhatsApp group scraper** in one run.

| Actor | Focus |
| :--- | :--- |
| WhatsApp Scraper ◄── you are here | Public WhatsApp numbers, channels, group invites, catalogs |
| [TikTok Trending Hashtags Scraper](https://apify.com/crawloop/tiktok-trending-hashtags-scraper) | TikTok Creative Center trending hashtags |
| [YouTube Comments Scraper](https://apify.com/crawloop/youtube-comments-scraper) | YouTube comments without the Data API |

### When to use this Actor

- You need a **WhatsApp scraper** / **WhatsApp API alternative** that returns structured JSON
- You want to **check if a number exposes a public WhatsApp Business profile** (name, photo, business / official-business flag)
- You want a **WhatsApp channel scraper** (name, follower count, bio, avatar, web join URL, latest updates)
- You want to **check if a WhatsApp Business number has a public catalog** (`hasCatalog`)
- You want a **WhatsApp group scraper** for invite-link previews (name, avatar, invite type)
- You scrape WhatsApp with **Python**, **Node.js**, or **MCP** and export a dataset

### When not to use this Actor

- **Private chats, message history, last seen, or About text** — not published on public pages
- **Guaranteed true/false for personal numbers** — a personal account with locked privacy looks the same as an unregistered number (`status: unresolved`). That is not a “not on WhatsApp” verdict
- **Business email, website, hours, GPS, or catalog product SKUs** — those fields are not on the public click-to-chat / catalog landing pages
- **Joining groups or following channels** — metadata only; the Actor never joins

### Key Features

- **Four public surfaces** — numbers (`wa.me`), channels (`whatsapp.com/channel/…`), group invites (`chat.whatsapp.com/…`), catalogs (`wa.me/c/…` / `whatsapp.com/catalog/…`)
- **WhatsApp number checker (public)** — E.164 normalization, line type, Brazil extra-9 fallback, `public` vs `unresolved` (never a false “not registered”)
- **WhatsApp Business flags** — `business` / `official_business` from the public page
- **WhatsApp Business catalog checker** — `hasCatalog` from the public catalog landing (name + flag; no product grid without login)
- **WhatsApp channel scraper** — parsed follower counts (`29K` → `29000`), bio, avatar, web join URL, optional latest-update strip (time, reactions, text when shown)
- **Keyword channel discovery** — search-engine indexing of public channel pages with extra result pages (not the in-app directory)
- **HTTP only** — Chrome TLS via curl\_cffi, 256–512 MB, no Playwright, no QR
- **MCP / AI ready** — call from assistants via Apify MCP

### Use Cases

| Use case | What you get |
| :--- | :--- |
| **CRM / outreach lists** | Public business name + photo + click-to-chat URL for numbers that expose a profile |
| **Lead qualification** | `isBusiness` / `isOfficialBusiness` to rank WhatsApp Business accounts |
| **Channel research** | Follower counts, bios, web join URL, and latest-update reactions |
| **Catalog qualification** | `hasCatalog` on public business numbers (Twilio-style catalog landing) |
| **Invite-link audit** | Live vs expired group invites (name + avatar when the invite is valid) |
| **Community discovery** | Keyword queries that surface indexed public channels |

### Quick Start

**Business number + catalog:**

```json
{
  "phoneNumbers": ["+14155238886", "+918976859807"],
  "includeCatalog": true,
  "maxItems": 50,
  "proxyConfiguration": { "useApifyProxy": false }
}
```

**Channel page + group invite:**

```json
{
  "startUrls": [
    { "url": "https://www.whatsapp.com/channel/0029Va4K0PZ5a245NkngBA2M" },
    { "url": "https://wa.me/c/14155238886" },
    { "url": "https://chat.whatsapp.com/IJhrKyIsd3aCo3JypCW3KA" }
  ],
  "includeChannelUpdates": true,
  "maxItems": 20
}
```

**Discover channels by keyword:**

```json
{
  "queries": ["crypto trading"],
  "maxChannelsPerQuery": 20,
  "maxItems": 40
}
```

### Input Parameters

| Parameter | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `phoneNumbers` | Array | — | International numbers (E.164 preferred) |
| `numbersText` | String | — | Paste many numbers (lines / commas / semicolons) |
| `startUrls` | Array | — | Channel, group-invite, `wa.me`, or catalog URLs |
| `queries` | Array | — | Channel keyword discovery (paginated search-engine index) |
| `defaultCountry` | String | — | ISO country (US, GB, BR, IN) for numbers without `+` |
| `includeChannelUpdates` | Boolean | `true` | Attach channel latest-update strip when present |
| `includeCatalog` | Boolean | `true` | Check the public catalog landing for each number |
| `maxChannelsPerQuery` | Integer | `20` | Cap on discovered channel URLs per query |
| `maxItems` | Integer | `100` | Hard cap on dataset rows |
| `concurrency` | Integer | `5` | Parallel page fetches (1–20) |
| `proxyConfiguration` | Object | off | Optional; useful for large channel-search batches |

### Output Format

Each dataset item is one number, channel, or group.

| Field | Type | Description |
| :--- | :--- | :--- |
| `type` | String | `number` / `channel` / `group` |
| `status` | String | `public` / `unresolved` / `not_found` / `invalid` / `error` |
| `name` | String | Public display name when the page exposes one |
| `accountType` | String | `business` / `official_business` / `channel` / `group` / `public` |
| `isBusiness` / `isOfficialBusiness` | Boolean | From the public click-to-chat page |
| `onWhatsAppPublic` | Boolean | `true` only when named public metadata was present |
| `description` | String | Channel bio or business label |
| `followers` / `followersRaw` | Integer / String | Channel follower count |
| `avatarUrl` / `profileImageUrl` | String | Public profile / channel / group image |
| `phone` | Object | E.164, country, line type (numbers) |
| `hasCatalog` | Boolean | `true` when the public catalog landing exists |
| `catalogStatus` | String | `ok` / `none` / `skipped` / `error` |
| `catalogName` / `catalogUrl` | String | Business name and catalog landing URL |
| `channelId` / `inviteCode` | String | From the URL |
| `webJoinUrl` | String | `web.whatsapp.com/accept?channel_invite_code=…` |
| `latestUpdates` | Array | Channel time + reactions + text when shown |
| `clickToChatUrl` | String | Canonical `wa.me` URL |
| `matchedQuery` | String | Search query that surfaced a channel |
| `scrapedAt` | String | UTC timestamp |

**Example — public business number:**

```json
{
  "type": "number",
  "status": "public",
  "name": "Twilio",
  "accountType": "business",
  "isBusiness": true,
  "onWhatsAppPublic": true,
  "url": "https://wa.me/14155238886",
  "clickToChatUrl": "https://wa.me/14155238886",
  "hasCatalog": true,
  "catalogStatus": "ok",
  "catalogName": "Twilio",
  "catalogUrl": "https://www.whatsapp.com/catalog/14155238886/"
}
```

**Example — channel:**

```json
{
  "type": "channel",
  "status": "public",
  "name": "WhatsApp",
  "followers": 234000000,
  "followersRaw": "234M",
  "description": "WhatsApp’s official channel. Follow for our latest feature launches, updates, exclusive drops and more.",
  "channelId": "0029Va4K0PZ5a245NkngBA2M",
  "webJoinUrl": "https://web.whatsapp.com/accept?channel_invite_code=0029Va4K0PZ5a245NkngBA2M",
  "hasLatestUpdates": true,
  "url": "https://www.whatsapp.com/channel/0029Va4K0PZ5a245NkngBA2M"
}
```

`unresolved` on a number means the public send page stayed generic. It does **not** prove the number has no personal WhatsApp account.

### Integration examples

#### Node.js

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('crawloop/whatsapp-scraper').call({
  phoneNumbers: ['+14155238886'],
  startUrls: [{ url: 'https://www.whatsapp.com/channel/0029Va4K0PZ5a245NkngBA2M' }],
  maxItems: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.slice(0, 5));
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient(token)
run = client.actor("crawloop/whatsapp-scraper").call(
    run_input={
        "phoneNumbers": ["+14155238886"],
        "startUrls": [{"url": "https://www.whatsapp.com/channel/0029Va4K0PZ5a245NkngBA2M"}],
        "maxItems": 20,
    }
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item.get("type"), item.get("name"), item.get("status"))
```

#### cURL

```bash
curl "https://api.apify.com/v2/acts/crawloop~whatsapp-scraper/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"phoneNumbers":["+14155238886"],"maxItems":20}'
```

### MCP and AI assistants

Use this Actor from AI tools via [Apify MCP](https://docs.apify.com/platform/integrations/mcp). Connect your Apify account, then call `crawloop/whatsapp-scraper`.

Example prompts:

- "Run WhatsApp Scraper for +14155238886 and return name, accountType, hasCatalog, status, clickToChatUrl as JSON"
- "Scrape the official WhatsApp channel and summarize follower count, webJoinUrl, plus latestUpdates"
- "Find public WhatsApp channels for crypto trading (max 20) then scrape each channel page"

### Suite next step

WhatsApp is the messaging layer next to short-video social. For TikTok trend boards, run [TikTok Trending Hashtags Scraper](https://apify.com/crawloop/tiktok-trending-hashtags-scraper). For YouTube comment threads, continue with [YouTube Comments Scraper](https://apify.com/crawloop/youtube-comments-scraper).

### FAQ

**Is this an official WhatsApp API?**\
No. It reads public HTML / Open Graph on click-to-chat, channel, group-invite, and catalog landing pages — a **WhatsApp API alternative** for public metadata only.

**Can it tell me if a personal number is on WhatsApp?**\
Only when that number exposes a **public** profile (typical for WhatsApp Business). Personal accounts with default privacy return `unresolved`. Do not treat that as `false`.

**WhatsApp number checker vs WhatsApp Business lead scraper?**\
Same Actor. Numbers that publish a business page come back with `name`, `isBusiness`, and `avatarUrl`. Channels and groups are separate `type` values in the same dataset.

**Does it scrape channel messages?**\
It captures the public **Latest updates** strip when WhatsApp renders it (time, reaction counts, and post text when the HTML includes it). Full message history stays in the app.

**Does it scrape WhatsApp Business catalog products?**\
The public catalog landing confirms a catalog exists (`hasCatalog: true`) and usually the business name. Product SKUs, prices, and images are not on the logged-out page.

**Do I need a WhatsApp account or QR code?**\
No.

**Python / Node.js / MCP?**\
Yes — use the Apify client examples above or Apify MCP prompts.

**Can I export CSV or Excel?**\
Yes. Download the default dataset from Apify Console, or pull it via the API / MCP.

### Related Actors

| Actor | Focus |
| :--- | :--- |
| WhatsApp Scraper ◄── you are here | Public WhatsApp numbers, channels, groups, catalogs |
| [TikTok Trending Hashtags Scraper](https://apify.com/crawloop/tiktok-trending-hashtags-scraper) | TikTok trending hashtags |
| [YouTube Comments Scraper](https://apify.com/crawloop/youtube-comments-scraper) | YouTube comments |

# Actor input Schema

## `phoneNumbers` (type: `array`):

International numbers to look up on public wa.me pages (E.164 preferred, e.g. +14155238886). Personal accounts with hidden profiles come back as unresolved — that is not a proof the number is unregistered.

## `numbersText` (type: `string`):

Optional. Paste many numbers at once (one per line, or comma/semicolon separated). Merged with Phone numbers and de-duplicated.

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

Public WhatsApp channel pages (whatsapp.com/channel/…), group invite links (chat.whatsapp.com/…), click-to-chat links (wa.me/…), or business catalog links (wa.me/c/… or whatsapp.com/catalog/…).

## `queries` (type: `array`):

Discover public WhatsApp channels via search-engine indexing of whatsapp.com/channel pages (not the in-app directory). Coverage is broad but incomplete; extra result pages are fetched until the cap.

## `defaultCountry` (type: `string`):

ISO 3166 alpha-2 (US, GB, BR, IN, …) used to parse numbers that do not start with +. Leave empty to require an international prefix.

## `includeChannelUpdates` (type: `boolean`):

When a channel page shows a Latest updates strip (time + reaction counts), attach it on the channel row. Off = metadata only.

## `includeCatalog` (type: `boolean`):

For each number, request the public catalog landing (whatsapp.com/catalog/{number}). Returns hasCatalog true/false. Logged-out pages do not list product SKUs — only that a catalog exists, plus the business name on the landing.

## `maxChannelsPerQuery` (type: `integer`):

Cap on channel URLs collected from each search query before hydration.

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

Hard cap on dataset rows for the whole run (numbers + channels + groups).

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

Parallel page fetches (1–20). Lower it if you see rate limits.

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

Public WhatsApp pages usually work without a proxy. Enable Apify proxy if you run large batches or channel search.

## Actor input object example

```json
{
  "phoneNumbers": [
    "+14155238886"
  ],
  "startUrls": [
    {
      "url": "https://www.whatsapp.com/channel/0029Va4K0PZ5a245NkngBA2M"
    }
  ],
  "includeChannelUpdates": true,
  "includeCatalog": true,
  "maxChannelsPerQuery": 20,
  "maxItems": 100,
  "concurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Default dataset items.

# 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 = {
    "phoneNumbers": [
        "+14155238886"
    ],
    "startUrls": [
        {
            "url": "https://www.whatsapp.com/channel/0029Va4K0PZ5a245NkngBA2M"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawloop/whatsapp-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 = {
    "phoneNumbers": ["+14155238886"],
    "startUrls": [{ "url": "https://www.whatsapp.com/channel/0029Va4K0PZ5a245NkngBA2M" }],
}

# Run the Actor and wait for it to finish
run = client.actor("crawloop/whatsapp-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 '{
  "phoneNumbers": [
    "+14155238886"
  ],
  "startUrls": [
    {
      "url": "https://www.whatsapp.com/channel/0029Va4K0PZ5a245NkngBA2M"
    }
  ]
}' |
apify call crawloop/whatsapp-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,crawloop/whatsapp-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/JJVcjMCTlycgFMHHl/builds/k3j80dJk5WksMIkeU/openapi.json
