# Contact Details Scraper (`practicaltools/contact-details-scraper`) Actor

An Apify actor that crawls any website to extract contact details and social media profiles. This tool can extract emails, phone numbers, and profiles from LinkedIn, Twitter, Instagram, Facebook, YouTube, TikTok, Pinterest, Discord, Snapchat, Threads, and Telegram.

- **URL**: https://apify.com/practicaltools/contact-details-scraper.md
- **Developed by:** [Practical Tools](https://apify.com/practicaltools) (community)
- **Categories:** Lead generation, Social media
- **Stats:** 400 total users, 17 monthly users, 99.6% runs succeeded, 6 bookmarks
- **User rating**: 3.11 out of 5 stars

## Pricing

from $4.50 / 1,000 successes

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## Contact Details Scraper

An Apify actor that crawls any website to extract contact details and social media profiles. This tool can extract emails, phone numbers, and profiles from LinkedIn, Twitter, Instagram, Facebook, YouTube, TikTok, Pinterest, Discord, Snapchat, Threads, and Telegram.

### Fair and affordable, pay only for found results

#### Pay-Per-Result Model

- **$0.0045** per successful result (only charge when contact details are found)
- **$4.50** per 1,000 successful results

### Features

- **Comprehensive Contact Extraction**: Extracts emails and phone numbers from both HTML attributes and page text
- **Social Media Profile Detection**: Finds profiles across 11+ social media platforms
- **Smart Crawling**: Respects domain boundaries and crawl depth limits
- **Deduplication**: Automatically removes duplicate contacts across all crawled pages
- **Aggregated Results**: Provides both individual page results and a consolidated summary
- **Configurable**: Flexible input options for different crawling scenarios

### Extracted Data Types

#### Contact Information

- **Email addresses**: From mailto links and text content
- **Phone numbers**: From tel: links (reliable) and text extraction (may include false positives)

#### Social Media Profiles

- LinkedIn profiles
- Twitter/X handles
- Instagram profiles
- Facebook profiles and pages
- YouTube channels
- TikTok profiles
- Pinterest profiles
- Discord servers/invites
- Snapchat profiles
- Threads profiles
- Telegram channels/groups

### Input Configuration

#### Required Parameters

- **startUrls** (array): List of URLs to start crawling from

#### Optional Parameters

- **maxCrawlDepth** (integer, default: 1): How many levels deep to crawl links (conservative)
- **stayWithinDomain** (boolean, default: true): Only follow links within the same domain
- **maxCrawlPages** (integer, default: 40): Maximum number of pages to crawl (conservative limit)
- **extractFromText** (boolean, default: true): Extract phone numbers from text (may have false positives)
- **headless** (boolean, default: true): Run browser in headless mode
- **waitForSelector** (string): CSS selector to wait for before extracting
- **waitForLoadState** (string, default: 'domcontentloaded'): Load state to wait for
- **proxyConfiguration** (object): Proxy settings

#### Example Input

```json
{
  "startUrls": [
    { "url": "https://example.com/" },
    { "url": "https://company.com/about" }
  ],
  "maxCrawlDepth": 1,
  "stayWithinDomain": true,
  "maxCrawlPages": 40,
  "extractFromText": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

### Output Format

The actor provides two types of output:

#### 1. Individual Page Results

Each crawled page generates a result with:

```json
{
  "url": "https://example.com/contact",
  "domain": "example.com", 
  "depth": 1,
  "originalStartUrl": "https://example.com/",
  "referrerUrl": "https://example.com/",
  "emails": ["contact@example.com"],
  "phones": ["+1234567890"],
  "phonesUncertain": ["123.456.7890"],
  "linkedIns": ["https://linkedin.com/company/example"],
  "twitters": ["https://twitter.com/example"],
  "instagrams": ["https://instagram.com/example"],
  "facebooks": ["https://facebook.com/example"],
  "youtubes": [],
  "tiktoks": [],
  "pinterests": [],
  "discords": [],
  "snapchats": [],
  "threads": [],
  "telegrams": []
}
```

#### 2. Aggregated Summary

A deduplicated summary of all found contacts stored in `AGGREGATED_RESULTS`:

```json
{
  "crawlSummary": {
    "totalPages": 25,
    "totalResults": 25,
    "maxDepth": 2,
    "stayWithinDomain": true,
    "startUrls": ["https://example.com/"]
  },
  "aggregatedResults": {
    "emails": ["contact@example.com", "info@example.com"],
    "phones": ["+1234567890"],
    "phonesUncertain": ["123.456.7890"],
    "linkedIns": ["https://linkedin.com/company/example"],
    // ... other social profiles
  },
  "totalContacts": {
    "emails": 2,
    "phones": 1,
    "phonesUncertain": 1,
    "linkedIns": 1,
    // ... counts for each type
  }
}
```

### Usage Tips

1. **Start with key pages**: Include contact pages, about pages, and team pages in your start URLs for best results
2. **Adjust crawl depth**: Use depth 0 for specific pages only, or 2-3 for broader discovery
3. **Domain restrictions**: Keep `stayWithinDomain` true to avoid crawling external sites
4. **Phone extraction**: Set `extractFromText` to false if you're getting too many false positive phone numbers
5. **Performance**: Use appropriate `maxCrawlPages` limits to control execution time and costs

### Technical Notes

- Uses Playwright for robust page rendering and JavaScript execution
- Employs Cheerio for enhanced HTML parsing and extraction
- Implements intelligent URL normalization and deduplication
- Handles failed requests gracefully with error reporting
- Supports proxy rotation for large-scale crawling

### Limitations

- Phone number extraction from text may include false positives
- Some social media profiles may require specific URL patterns to be detected
- JavaScript-heavy sites may need additional wait conditions
- Rate limiting may apply for large crawls

### Legal Considerations

Be aware that extracting contact information may involve personal data protected by GDPR and other privacy regulations. Ensure you have legitimate reasons for collecting this data and comply with applicable laws.

### Pricing

This actor uses a **Pay-per-Result** pricing model - you only pay for pages that successfully extract contact information!

- **$4.50 per 1,000 successful results**
- **Only pages with contact details count** - no payment for empty pages
- **20% cheaper than competitors** who charge per page regardless of results
- **Better value** - you pay for actual data, not failed attempts

#### Cost Examples:

- **40 pages with 25 successful extractions**: $0.11 (25 × $0.0045)
- **100 pages with 60 successful extractions**: $0.27 (60 × $0.0045)
- **1,000 pages with 400 successful extractions**: $1.80 (400 × $0.0045)

The free tier includes $5 in credits, allowing you to extract contact details from approximately 1,111 successful pages.

### Support

For issues, feature requests, or questions about this actor, please refer to the Apify documentation or community forums.

# Actor input Schema

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

List of URLs to start crawling from

## `maxCrawlDepth` (type: `integer`):

How deep should the crawler go? 0 means only start URLs will be crawled.

## `stayWithinDomain` (type: `boolean`):

If enabled, the crawler will only follow links within the same domain as the start URL

## `maxCrawlPages` (type: `integer`):

Maximum number of pages to crawl (0 = unlimited)

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

Proxy settings for the crawler

## `waitForSelector` (type: `string`):

CSS selector to wait for before extracting data

## `waitForLoadState` (type: `string`):

Wait for a specific load state before extracting data

## `includeScriptContent` (type: `boolean`):

Whether to search for contact details in inline JavaScript code (may find additional contacts in JSON data, structured data, etc.)

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://example.com/"
    }
  ],
  "maxCrawlDepth": 1,
  "stayWithinDomain": true,
  "maxCrawlPages": 40,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "waitForLoadState": "domcontentloaded",
  "includeScriptContent": true
}
```

# 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 = {
    "startUrls": [
        {
            "url": "https://example.com/"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("practicaltools/contact-details-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 = { "startUrls": [{ "url": "https://example.com/" }] }

# Run the Actor and wait for it to finish
run = client.actor("practicaltools/contact-details-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 '{
  "startUrls": [
    {
      "url": "https://example.com/"
    }
  ]
}' |
apify call practicaltools/contact-details-scraper --silent --output-dataset

```

## MCP server setup

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