# Website Contact Extractor (`betterdevsscrape/contact-details-extractor`) Actor

The cheapest contact scraper on Apify. Extract emails, phone numbers, company names, addresses & 25+ social profiles at $0.001/page - 50% less than competitors. Smart crawling auto-finds contact pages, bypasses Cloudflare protection, browser mode for JS sites, sitemap discovery.

- **URL**: https://apify.com/betterdevsscrape/contact-details-extractor.md
- **Developed by:** [Better Devs Scrape](https://apify.com/betterdevsscrape) (community)
- **Categories:** Lead generation, Automation, AI
- **Stats:** 565 total users, 48 monthly users, 99.9% runs succeeded, 14 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $0.69 / 1,000 page scrapeds

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

## 📇 Contact Details Extractor - Extract Emails, Phone Numbers & Social Media From Any Website

**The most affordable contact scraper on Apify.** Extract emails, phone numbers, and 25+ social media profiles from any website at just **$0.001 per page** - 50% cheaper than alternatives.

🚀 **Dead simple:** Paste URLs, click Run, get contacts.

***

### 🏆 Why Use This Contact Scraper?

| Feature | Contact Details Extractor | Alternatives |
|---------|--------------------------|--------------|
| 💰 **Price per page** | $0.001 | $0.002+ |
| 🌐 **Social platforms** | 25+ platforms | Limited |
| 🛡️ **Cloudflare bypass** | ✅ Built-in decoding | ❌ Often fails |
| 🎯 **Smart crawling** | ✅ Auto-prioritizes contact pages | ❌ Basic crawling |
| 🧹 **URL filtering** | ✅ Skips parked domains, social, directories | ❌ Wastes budget |
| ⚡ **Setup complexity** | Paste URL, click Run | Complex configs |

***

### 📊 What Data Can You Extract?

| Category | Data Types |
|----------|------------|
| 📧 **Emails** | All email addresses (mailto: links, text, Cloudflare-protected) |
| 📞 **Phone Numbers** | Phone numbers (tel: links, international formats, validated) |
| 💼 **LinkedIn** | Company pages, personal profiles |
| 🐦 **Twitter / X** | Profiles, handles |
| 📸 **Instagram** | Profiles |
| 👥 **Facebook** | Pages, profiles |
| 🎬 **YouTube** | Channels, custom URLs |
| 🎵 **TikTok** | Profiles |
| 📌 **Pinterest** | Profiles, boards |
| 🎮 **Discord** | Server invites |
| ✈️ **Telegram** | Channels, groups |
| 🤖 **Reddit** | Subreddits, user profiles |
| 💬 **WhatsApp** | Click-to-chat links |
| 👻 **Snapchat** | Profiles |
| 🧵 **Threads** | Profiles |
| 🦋 **Bluesky** | Profiles |
| 🐘 **Mastodon** | Profiles (multiple instances) |
| 🐙 **GitHub** | Profiles, organizations |
| 📝 **Medium** | Author profiles, publications |
| 📰 **Substack** | Newsletter profiles |
| 🎮 **Twitch** | Channels |
| 🎧 **Spotify** | Artists, podcasts, users |
| 🎥 **Vimeo** | Channels, profiles |
| 🏀 **Dribbble** | Designer profiles |
| 🎨 **Behance** | Creative portfolios |
| 🎵 **SoundCloud** | Artist profiles |

***

### 🆕 Contact Scraper Features

#### 🧹 Smart URL Filtering

Your crawl budget goes further with intelligent URL filtering:

- **Parked domains** - Detects 30+ parking services and "domain for sale" pages
- **Social media** - Skips Facebook login walls, LinkedIn gates, and 35+ social platforms
- **Directory sites** - Filters Yelp, Yellow Pages, and other listing sites
- **Parking redirects** - Detects when start URLs redirect to parking pages
- **End-of-run summary** shows exactly what was filtered and why

#### 🏢 Company Name Extraction

Automatically extracts the company/business name from:

- Open Graph meta tags (`og:site_name`)
- Schema.org Organization data
- Page title (cleaned)
- Copyright notices (heuristics mode)

#### 📍 Address Extraction

Extracts physical addresses with parsed components:

- US addresses (ZIP codes)
- UK addresses (postcodes)
- Canadian addresses (postal codes)
- Schema.org PostalAddress data

#### 🤖 Auto Browser Mode

Set `browserMode: "auto"` to let us detect when a page needs JavaScript rendering:

- Detects React, Vue, Angular, Next.js apps
- Auto-retries with browser if no contacts found
- Only charges browser rate when actually used

#### 🗺️ Sitemap Crawling

Enable `useSitemap: true` to discover URLs via sitemap.xml:

- Auto-detects sitemap location
- Supports sitemap index files
- More efficient than link crawling

***

### ⚙️ How to Scrape Contact Details from Any Website

```
1️⃣ Paste your URLs (websites, landing pages, directories)
2️⃣ Set crawl depth (how many pages per site)
3️⃣ Click "Start" and get clean, structured data
```

The scraper automatically:

- 🎯 **Finds contact pages** - Prioritizes /contact, /about, /team, /connect pages
- 🔓 **Decodes protected emails** - Bypasses Cloudflare email obfuscation
- ✅ **Validates phone numbers** - Filters out dates, IPs, and false positives
- 🔄 **Merges contacts per domain** - One clean record per website

***

### 📥 Contact Scraper Input Options

```json
{
  "startUrls": [
    { "url": "https://example.com/" },
    { "url": "https://another-site.com/contact" }
  ],
  "maxPagesPerStartUrl": 10,
  "maxDepth": 2,
  "sameDomain": true,
  "mergeContacts": true,
  "browserMode": "off",
  "useResidentialProxy": false
}
```

#### 📋 Input Parameters Explained

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `startUrls` | array | required | List of websites to scrape |
| `maxPagesPerStartUrl` | number | 20 | Maximum pages to crawl per website |
| `maxDepth` | number | 2 | How deep to follow links (0 = only start URL) |
| `sameDomain` | boolean | true | Stay on the same domain |
| `mergeContacts` | boolean | true | Combine all contacts per domain into one record |
| `useResidentialProxy` | boolean | false | Use residential proxies for blocked sites (adds $0.001/page) |
| `companyNameMethod` | string | "heuristics" | "meta", "heuristics", or "off" |
| `addressExtraction` | boolean | true | Extract physical addresses |
| `browserMode` | string | "off" | "off", "on", or "auto" |
| `useSitemap` | boolean | false | Use sitemap.xml for URL discovery |
| `allowCrossDomainRedirects` | boolean | false | Allow redirects to different domains (disabled by default to save budget) |
| `sitemapUrl` | string | null | Custom sitemap URL (optional) |

> **💡 Tip:** Using `browserMode: "on"` with high `maxPagesPerStartUrl` values? Consider increasing the timeout in Advanced settings to avoid timeouts on large crawls.

***

### 📤 Sample Output

Here's a real example of what the scraper returns for a single domain:

```json
{
  "originalStartUrl": "https://example.com/",
  "domain": "example.com",
  "companyName": "Example Corp",
  "addresses": [
    {
      "full": "123 Main Street, San Francisco, CA 94102",
      "street": "123 Main Street",
      "city": "San Francisco",
      "state": "CA",
      "zip": "94102",
      "country": "USA"
    }
  ],
  "scrapedUrls": [
    "https://example.com/",
    "https://example.com/contact",
    "https://example.com/about"
  ],
  "emails": [
    "hello@example.com",
    "sales@example.com"
  ],
  "phones": [
    "+1-555-123-4567"
  ],
  "phonesUncertain": [
    "555-123-4567"
  ],
  "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": [],
  "reddits": [],
  "whatsapps": [],
  "blueskys": [],
  "mastodons": [],
  "githubs": [],
  "mediums": [],
  "substacks": [],
  "twitchs": [],
  "spotifys": [],
  "vimeos": [],
  "dribbbles": [],
  "behances": [],
  "soundclouds": []
}
```

#### 📖 Understanding the Output

- 📧 **`emails`**: Confirmed email addresses from mailto: links
- 📞 **`phones`**: Confirmed phone numbers from tel: links
- ❓ **`phonesUncertain`**: Phone patterns found in text (may include false positives)
- 🌐 **Social arrays**: Direct links to social media profiles

***

### 💰 How Much Does It Cost to Scrape Contact Details?

This Actor uses **Pay-Per-Event** pricing. You only pay for pages actually scraped.

| Event | Cost |
|-------|------|
| 📄 Page scraped (HTTP) | $0.001 |
| 🌐 Page scraped (Browser) | $0.002 |
| 🏠 Residential proxy used | +$0.001 |
| ⭐ Premium add-ons (SEO/Forms/Business) | +$0.001/page each |

#### 💵 Cost Examples

| Task | Pages | Mode | Total Cost |
|------|-------|------|------------|
| Scrape 100 company websites (1 page each) | 100 | HTTP | **$0.10** |
| Deep crawl 10 sites (20 pages each) | 200 | HTTP | **$0.20** |
| Scrape 50 JS-heavy sites | 50 | Browser | **$0.10** |
| Extract contacts from 1,000 landing pages | 1,000 | HTTP | **$1.00** |

🎉 **Compare:** Competitors charge $0.002+ per page. **You save 50% on every scrape!**

***

### Premium Features

Optional paid add-ons that extract additional data. **You only pay when data is found.**

| Feature | What it extracts | Price |
|---------|-----------------|-------|
| **SEO Data** | Meta tags, Open Graph, Twitter cards, h1 headings, keywords, robots, schema type | +$0.001/page |
| **Contact Forms** | Form URLs, types (contact, quote, newsletter), field names | +$0.001/page |
| **Business Info** | Opening hours, business type, employee count, price range, payment methods, service areas | +$0.001/page |

#### Enable Premium Features

```json
{
  "startUrls": [{ "url": "https://example.com/" }],
  "extractSeo": true,
  "extractForms": true,
  "extractBusinessInfo": true
}
```

#### Premium Output Example

```json
{
  "domain": "example.com",
  "emails": ["hello@example.com"],
  "seo": {
    "title": "Example Corp - Best Widgets",
    "description": "We sell the best widgets",
    "ogImage": "https://example.com/og.jpg",
    "h1": ["Welcome to Example Corp"],
    "schemaType": "Organization"
  },
  "forms": [
    {
      "url": "https://example.com/contact",
      "type": "contact",
      "fields": ["name", "email", "message"]
    }
  ],
  "businessInfo": {
    "type": "LocalBusiness",
    "foundedYear": 2015,
    "employeeCount": "11-50",
    "openingHours": ["Monday, Tuesday 09:00-17:00"]
  }
}
```

***

### 🔌 Integrate With Your Stack

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

run = client.actor("betterdevsscrape/contact-details-extractor").call(
    run_input={
        "startUrls": [{"url": "https://example.com/"}],
        "maxPagesPerStartUrl": 10,
        "browserMode": "auto",
    }
)

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"{item['domain']}: {item['emails']}")
```

#### JavaScript / Node.js

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });

const run = await client.actor('betterdevsscrape/contact-details-extractor').call({
    startUrls: [{ url: 'https://example.com/' }],
    maxPagesPerStartUrl: 10,
    browserMode: 'auto',
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach(item => console.log(`${item.domain}: ${item.emails}`));
```

#### cURL

```bash
## Start a run
curl -X POST "https://api.apify.com/v2/acts/betterdevsscrape~contact-details-extractor/runs?token=YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "startUrls": [{"url": "https://example.com/"}],
    "maxPagesPerStartUrl": 10,
    "browserMode": "auto"
  }'

## Fetch results (replace DATASET_ID from the run response)
curl "https://api.apify.com/v2/datasets/DATASET_ID/items?token=YOUR_API_TOKEN"
```

#### 📦 Export Options

- **JSON** - Full structured data
- **CSV** - Spreadsheet-ready format
- **Excel** - Direct download

#### 🪝 Webhooks

Configure webhooks to receive results automatically when the scrape completes.

#### 🔄 Integrations

Connect via Zapier, Make (Integromat), or any platform that supports REST APIs.

***

### 🎯 Contact Scraping Use Cases

#### 📈 Lead Generation

Scrape business directories, industry listings, or competitor websites to build targeted lead lists with verified contact information.

#### 💼 Sales Prospecting

Extract email addresses and phone numbers from company websites to fuel your outreach campaigns.

#### 🔍 Competitor Analysis

Discover which social platforms your competitors use and how they structure their contact information.

#### 📊 Data Enrichment

Enhance your existing company database with social media links and additional contact methods.

#### 🌍 Market Research

Collect contact data from websites in specific industries or geographic regions.

***

### 💡 Tips for Scraping Contact Information

#### 🧪 Start Small

Begin with `maxPagesPerStartUrl: 5` to test on a few sites before scaling up.

#### 🎯 Target Contact Pages

For single-page extractions, append `/contact` or `/about` to your URLs:

```json
{
  "startUrls": [{ "url": "https://example.com/contact" }],
  "maxPagesPerStartUrl": 1,
  "maxDepth": 0
}
```

#### 🌐 Handle JavaScript Sites

If you're not finding contacts on modern React/Vue/Angular sites, enable browser mode:

```json
{
  "browserMode": "on"
}
```

#### ❓ Check Uncertain Phones

The `phonesUncertain` field contains phone-like patterns found in text. Review these manually as they may include false positives.

#### 🔄 Merge for Clean Data

Keep `mergeContacts: true` (default) to get one record per domain with all contacts combined.

***

### 🧪 Contact Scraping Examples

#### Basic: Scrape one website

```json
{
  "startUrls": [{ "url": "https://example.com/" }]
}
```

#### Extract from contact page only

```json
{
  "startUrls": [{ "url": "https://example.com/contact" }],
  "maxPagesPerStartUrl": 1,
  "maxDepth": 0
}
```

#### Deep crawl with browser for JS sites

```json
{
  "startUrls": [{ "url": "https://react-app.com/" }],
  "maxPagesPerStartUrl": 50,
  "maxDepth": 3,
  "browserMode": "on"
}
```

#### Use sitemap for efficient crawling

```json
{
  "startUrls": [{ "url": "https://example.com/" }],
  "useSitemap": true,
  "maxPagesPerStartUrl": 100
}
```

#### Scrape blocked sites with residential proxy

```json
{
  "startUrls": [{ "url": "https://blocked-site.com/" }],
  "useResidentialProxy": true
}
```

#### Bulk scraping multiple sites

```json
{
  "startUrls": [
    { "url": "https://company1.com/" },
    { "url": "https://company2.com/" },
    { "url": "https://company3.com/" }
  ],
  "maxPagesPerStartUrl": 5,
  "maxDepth": 1
}
```

***

### ❓ Frequently Asked Questions

#### How is this different from other contact scrapers?

We focus on simplicity and value. Paste URLs, click Run, get data. No complex configuration. And at $0.001/page, we're **50% cheaper** than alternatives.

#### Does it work on Cloudflare-protected sites?

Yes! ✅ We automatically decode Cloudflare email obfuscation to extract the real email addresses.

#### What about JavaScript-heavy websites?

Set `browserMode: "on"` to render JavaScript. This uses a real browser and costs $0.002/page total. You can also use `browserMode: "auto"` for automatic detection.

#### Can I scrape thousands of sites?

Absolutely! 🚀 The Actor is designed for scale. Set your `maxPagesPerStartUrl` and let it run. Pay-per-event means you only pay for what you use.

#### Why are some phone numbers in "phonesUncertain"?

Phones from `tel:` links are 100% confirmed and go to `phones`. Phone patterns found in regular text go to `phonesUncertain` since they might be order numbers, dates, or other numeric data.

#### Do you extract personal data?

We only extract publicly visible contact information from websites. No scraping of private data, social media DMs, or protected content.

#### Is it legal to scrape websites for contact information?

Yes, scraping publicly available business contact information is generally legal. See our [Legal & Compliance](#%EF%B8%8F-is-it-legal-to-scrape-contact-details) section for details on responsible use.

#### When am I charged for premium features?

Only when data is found. If you enable SEO extraction but a page has no meta tags, you won't be charged for that page's SEO extraction.

#### My run timed out. What do I do?

Large crawls with `browserMode: "on"` and high `maxPagesPerStartUrl` can exceed the default timeout. Go to **Advanced settings** and increase the timeout (we recommend 600-900 seconds for large browser crawls). You can also reduce `maxPagesPerStartUrl` or switch to `browserMode: "auto"` which only uses the browser when needed.

***

### ⚖️ Is It Legal to Scrape Contact Details?

Web scraping publicly available data is generally legal. This Actor extracts only **publicly visible contact information** that businesses choose to display on their websites.

Our scraper is ethical and does not extract any private user data, such as personal emails from social media profiles, private messages, or data behind login walls. It only extracts what businesses have chosen to share publicly on their websites.

However, you should be aware that your results could contain personal data. Personal data is protected by GDPR in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so.

**Users are responsible for:**

- ✅ Complying with applicable data protection laws (GDPR, CCPA, etc.)
- ✅ Respecting website terms of service
- ✅ Using extracted data ethically and legally
- ✅ Obtaining necessary consents before contacting individuals

If you're unsure whether your use case is legitimate, consult your lawyers. You can also read [Apify's blog post on the legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

***

### 🔗 Related Tools

#### [Google Maps Scraper](https://apify.com/betterdevsscrape/google-maps-scraper)

Need to find businesses first? Our **Google Maps Scraper** extracts business details, reviews, images, and contacts from Google Maps — **50 places in ~4 seconds**.

**Perfect combo:** Use Google Maps Scraper to discover businesses in any location, then feed their websites into the Contact Extractor for deep contact enrichment with 25+ social platforms.

***

### 💬 Support & Feedback

- 🐛 **Issues?** Open a GitHub issue or contact us through Apify
- 💡 **Feature requests?** We'd love to hear what you need
- ❓ **Questions?** Check the FAQ above or reach out
- ⭐ **Happy with the results?** Leave us a review on the Apify Store!

***

**Built with ❤️ by BetterDevsScrape** | [View on Apify Store](https://apify.com/betterdevsscrape/contact-details-extractor)

# Actor input Schema

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

URLs of websites to extract contacts from

## `maxPagesPerStartUrl` (type: `integer`):

Maximum number of pages to crawl per start URL

## `maxDepth` (type: `integer`):

How many links deep to follow from the start URL

## `sameDomain` (type: `boolean`):

Only follow links within the same domain

## `allowCrossDomainRedirects` (type: `boolean`):

If enabled, the scraper will follow redirects to different domains. If disabled (default), redirects to different domains are skipped to prevent wasting budget on unrelated sites.

## `mergeContacts` (type: `boolean`):

Combine all contacts from same domain into one result

## `proxyConfig` (type: `object`):

Proxy settings for bypassing blocks

## `useResidentialProxy` (type: `boolean`):

Use residential proxies for blocked sites. Adds $0.001/page extra cost.

## `companyNameMethod` (type: `string`):

How to extract company names. 'meta' = title/og:site\_name. 'heuristics' = meta + copyright/footer patterns.

## `addressExtraction` (type: `boolean`):

Extract physical addresses using pattern matching

## `browserMode` (type: `string`):

'off' = HTTP only. 'on' = always browser. 'auto' = detect JS-heavy sites or retry if no contacts found.

## `useSitemap` (type: `boolean`):

Parse sitemap.xml to discover URLs instead of crawling links

## `sitemapUrl` (type: `string`):

Optional custom sitemap URL. If empty, auto-detects /sitemap.xml

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://apify.com/"
    }
  ],
  "maxPagesPerStartUrl": 10,
  "maxDepth": 1,
  "sameDomain": true,
  "allowCrossDomainRedirects": false,
  "mergeContacts": true,
  "proxyConfig": {
    "useApifyProxy": true
  },
  "useResidentialProxy": false,
  "companyNameMethod": "heuristics",
  "addressExtraction": true,
  "browserMode": "off",
  "useSitemap": false
}
```

# Actor output Schema

## `contacts` (type: `string`):

No description

## `seo` (type: `string`):

SEO data including meta tags, Open Graph, Twitter cards, h1 headings, keywords

## `forms` (type: `string`):

Detected contact forms with URLs, types (contact, quote, newsletter), and field names

## `businessInfo` (type: `string`):

Business info including type, founded year, employee count, opening hours, payment methods

# 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://apify.com/"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("betterdevsscrape/contact-details-extractor").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://apify.com/" }] }

# Run the Actor and wait for it to finish
run = client.actor("betterdevsscrape/contact-details-extractor").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://apify.com/"
    }
  ]
}' |
apify call betterdevsscrape/contact-details-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,betterdevsscrape/contact-details-extractor"
        }
    }
}

```

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/8CUaIL6Ck8d7gDbck/builds/KQJ1FafOGMI9lctPS/openapi.json
