# Website Contacts API (`lergassy/website-contacts-api`) Actor

Extract e-mails, phone numbers, WhatsApp, Telegram, social profiles, contact page and address from any list of websites. One clean row per website, priced per website, not per page. No API key, no proxy, no browser.

- **URL**: https://apify.com/lergassy/website-contacts-api.md
- **Developed by:** [Matvey](https://apify.com/lergassy) (community)
- **Categories:** Lead generation, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.50 / 1,000 website with contacts

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

### What is Website Contacts API?

**Website Contacts API** turns a list of websites into a **contact list**: one clean row per website with the company's **e-mail addresses, phone numbers, WhatsApp and Telegram links, LinkedIn, Facebook, Instagram, X, YouTube and TikTok profiles, contact page, contact form and postal address** — each contact with the page it was found on and how it was found. Paste domains from Google Maps, a CRM export or a spreadsheet, press Start, and download the contacts as JSON, CSV or Excel, or pull them through the API into n8n, Make, Zapier, Google Sheets or an AI agent.

It reads the home page and the few pages that actually carry contacts (contact, about, team, imprint, legal), decodes Cloudflare-protected addresses and `name [at] domain [dot] com` obfuscation, reads schema.org markup, validates every phone against the international numbering plan, and even reads the hidden search index of Framer sites that show nothing without JavaScript. **No API key, no login, no proxy, no browser.**

**The price is per website, not per page.** You pay one flat event for every website where at least one e-mail or phone was found. Websites with nothing found, unreachable or blocked websites are free, and the number of pages read never changes your bill — so a 1,000-row list costs what the pricing tab says, not twenty times more.

### What data does Website Contacts API extract?

| Field | Example | Where it comes from |
|---|---|---|
| `bestEmail`, `bestEmailType` | `hello@apify.com`, `role` | The best address: the site's own domain first, general inboxes (info@, hello@, contact@) over side mailboxes, mailto links over page text |
| `emails[]` | `{email, type, isOwnDomain, isFree, source, sourceUrl}` | Every distinct address with its type (`role`, `personal`, `generic`), whether it is on the website's own domain, whether it is a free mailbox (gmail.com …), and the source: `mailto`, `schema.org`, `cloudflare` or `text` |
| `bestPhone`, `bestPhoneFormatted` | `+18884827768`, `+1 888 482 7768` | Best number in E.164, tel links first |
| `phones[]` | `{phone, formatted, country, kind, source, sourceUrl}` | Every valid number with country, kind (`mobile`, `fixed_line`, `toll_free` …) and source (`tel`, `schema.org`, `whatsapp`, `text`) |
| `whatsapp`, `telegram` | `https://wa.me/628179677771` | Messenger links; the WhatsApp number is also added to `phones` |
| `linkedin`, `facebook`, `instagram`, `x`, `youtube`, `tiktok`, `pinterest`, `threads`, `github` | `https://linkedin.com/company/apify` | Normalised profile URLs; share buttons, login pages and hashtags are ignored |
| `contactPageUrl`, `contactFormUrl` | `https://apify.com/contact` | The contact page that was read and the page with a contact form |
| `addressStreet`, `addressCity`, `addressRegion`, `addressPostalCode`, `addressCountry` | `2 Canal Park`, `Cambridge`, `MA`, `02141`, `US` | schema.org `PostalAddress`; `addressText` falls back to an `<address>` tag |
| `companyName` | `HubSpot` | schema.org Organization, `og:site_name` or the page title |
| `status`, `note` | `ok`, `javascript_rendered_site` | `ok`, `no_contacts`, `unreachable`, `blocked`; the note tells you when a site is an empty JavaScript shell |
| `pagesScanned`, `pagesScannedCount`, `durationMs`, `fetchedVia` | `[…]`, `3`, `1497`, `fetch` | What was read and how long it took |
| `summary` | `HubSpot: +18884827768 (2 e-mails, 25 phones); linkedin, facebook, instagram, x, youtube, tiktok.` | One sentence for agents, Slack alerts and spreadsheets |
| `emailChecks[]`, `bestEmailStatus` | `deliverable` | Only with the e-mail check add-on: DNS-level deliverability, mail provider, disposable / role / free flags, typo suggestion |

Every row also carries `inputUrl`, `website` (final URL after redirects), `domain`, `language`, `phoneCountryUsed` and `scrapedAt`. Failed websites come back as `type: "error"` rows with `status`, `httpStatus` and `error`, so a batch never silently loses a domain.

### How much does it cost to extract contacts from websites?

Website Contacts API uses **pay-per-event pricing** with two events:

| Event | Price | When it is charged |
|---|---|---|
| 🌐 Website with contacts | **$15.00 per 1,000 websites** ($0.015 each) | Once per website where at least one e-mail or phone number was found |
| ✅ Add-on: e-mail check | $2.00 per 1,000 addresses | Only when you switch the add-on on, once per checked address (up to 20 per website) |

What is **free**: websites with no contacts, unreachable domains, websites behind an anti-bot wall, and every page read. Apify platform usage is included in the price — you do not pay separately for compute, and there is no proxy cost because none is used by default.

For comparison, page-priced contact scrapers charge $1–2 per page and read 20 pages per site by default, which is why their users report bills of $20–70 per 1,000 sites. Here a list of 1,000 websites costs at most **$15**, usually less, because empty sites are not billed. Apify's free plan includes $5 of usage every month, enough to scan roughly 300 websites for free.

### How to extract contacts from a list of websites

1. Open **Website Contacts API** on Apify and click **Try for free** (an Apify account is created in a minute).
2. Paste your websites into **🌐 Websites** — one per line, with or without `https://` — or bare domains into **🌐 Domains**. You can also upload a text file or link a Google Sheet through the ⬇️ Input editor.
3. Optionally set **📞 Default phone country** (used only for numbers written without a country code; a site's own country domain always wins) and switch on the **✅ e-mail check** add-on.
4. Click **Start**. A hundred websites take about a minute.
5. Open the **Contacts** tab to read the results, or **Export** them as CSV, Excel, JSON or XML.

### ⬇️ Input

<a href="https://console.apify.com/actors/s23QhOQ6368qaWx27/input">
<img src="https://raw.githubusercontent.com/lergassy/apify-actor-assets/main/website-contacts-api/website-contacts-api-input-form.png" alt="Website Contacts API input form: list of websites, domains, max pages per website, default phone country, e-mail check add-on" style="width:80%;">
</a>

```json
{
    "startUrls": [
        { "url": "https://www.apify.com" },
        { "url": "https://www.basecamp.com" }
    ],
    "domains": ["hubspot.com", "legalindonesia.id"],
    "maxPagesPerSite": 6,
    "defaultCountry": "US",
    "checkEmails": false,
    "onlyOwnDomainEmails": false,
    "stopEarly": true
}
```

| Field | Default | What it does |
|---|---|---|
| `startUrls` | 5 example sites | Websites as URLs; the Apify editor accepts a pasted list, a file or a Google Sheet |
| `domains` | `[]` | Bare domains, one per line — for lists exported from Google Maps or a CRM |
| `maxPagesPerSite` | `6` | Home page plus the most contact-like pages; 6 finds nearly everything on a normal business site |
| `defaultCountry` | `US` | Two-letter country used for phone numbers without a country code |
| `checkEmails` | `false` | Add-on ($): DNS deliverability, provider, disposable / role / free flags per address |
| `onlyOwnDomainEmails` | `false` | Drop addresses on other domains (an agency, a partner, a gmail.com mailbox) |
| `stopEarly` | `true` | Skip remaining pages once an own-domain e-mail and a phone were found |
| `maxWebsites`, `concurrency`, `pageTimeoutSecs`, `proxyConfiguration` | `1000`, `10`, `15`, off | Safety cap, parallelism, per-page timeout, optional Apify Proxy |

#### 🌐 Which pages are read?

The home page first. Then links whose path or text says **contact, kontakt, contacto, contatti, impressum, imprint, about, team, support, legal, privacy, locations** and their equivalents in a dozen languages, best-scored first. If the navigation is rendered by JavaScript and no such links exist, the well-known paths `/contact`, `/contact-us`, `/about`, `/about-us`, `/impressum` and `/kontakt` are tried. Blog posts, product pages, carts and search pages are never read.

### ⬆️ Output

<a href="https://console.apify.com/actors/s23QhOQ6368qaWx27">
<img src="https://raw.githubusercontent.com/lergassy/apify-actor-assets/main/website-contacts-api/website-contacts-api-output-table.png" alt="Website Contacts API output table: domain, company, best e-mail, best phone, LinkedIn, Instagram, e-mail and phone counts per website" style="width:100%;">
</a>

One row per website:

```json
{
    "type": "website",
    "inputUrl": "https://www.bmw.de",
    "website": "https://www.bmw.de/de/index.html",
    "domain": "bmw.de",
    "companyName": "BMW",
    "status": "ok",
    "bestEmail": "kundenbetreuung@bmw.de",
    "bestEmailType": "generic",
    "bestPhone": "+4989125016000",
    "bestPhoneFormatted": "+49 89 125016000",
    "emailCount": 2,
    "phoneCount": 2,
    "emails": [
        { "email": "kundenbetreuung@bmw.de", "type": "generic", "isOwnDomain": true, "isFree": false, "source": "mailto", "sourceUrl": "https://www.bmw.de/de/footer/metanavigation/legal-notice-pool/imprint.html" },
        { "email": "bmw-connecteddrive@bmw.de", "type": "generic", "isOwnDomain": true, "isFree": false, "source": "mailto", "sourceUrl": "https://www.bmw.de/de/footer/metanavigation/legal-notice-pool/imprint.html" }
    ],
    "phones": [
        { "phone": "+4989125016000", "formatted": "+49 89 125016000", "country": "DE", "kind": "fixed_line", "source": "tel", "sourceUrl": "https://www.bmw.de/de/footer/metanavigation/legal-notice-pool/imprint.html" },
        { "phone": "+4989125016010", "formatted": "+49 89 125016010", "country": "DE", "kind": "fixed_line", "source": "tel", "sourceUrl": "https://www.bmw.de/de/footer/metanavigation/legal-notice-pool/imprint.html" }
    ],
    "whatsapp": null,
    "telegram": null,
    "linkedin": null,
    "facebook": "https://facebook.com/BMWDeutschland",
    "instagram": "https://instagram.com/bmwdeutschland",
    "x": null,
    "youtube": "https://youtube.com/user/BMWDeutschland",
    "tiktok": null,
    "contactPageUrl": "https://www.bmw.de/de/footer/metanavigation/legal-notice-pool/imprint.html",
    "contactFormUrl": null,
    "addressStreet": "Petuelring 130",
    "addressCity": "Munich",
    "addressRegion": null,
    "addressPostalCode": "80788",
    "addressCountry": "DE",
    "language": "de",
    "phoneCountryUsed": "DE",
    "pagesScanned": ["https://www.bmw.de/de/index.html", "https://www.bmw.de/de/footer/metanavigation/legal-notice-pool/imprint.html"],
    "pagesScannedCount": 2,
    "fetchedVia": "fetch",
    "durationMs": 1349,
    "summary": "BMW: kundenbetreuung@bmw.de, +4989125016000 (2 e-mails, 2 phones); facebook, instagram, youtube.",
    "scrapedAt": "2026-09-06T00:58:12.415Z"
}
```

An unreachable or blocked website:

```json
{ "type": "error", "inputUrl": "https://www.zalando.de", "domain": "zalando.de", "status": "blocked", "httpStatus": 403, "error": "anti_bot_challenge", "scrapedAt": "2026-09-06T00:53:27.239Z" }
```

#### 📧 How e-mails are found and cleaned

- `mailto:` links, schema.org `email`, Cloudflare-protected addresses (`data-cfemail` and `/cdn-cgi/l/email-protection` links are decoded), and addresses written in the page text, including `name [at] company [dot] com` and `name (at) company.com`.
- Addresses found only in prose are kept **only when their domain really exists** (a DNS check), which removes the "partner@YC. He…" class of false matches that page-text scrapers produce.
- Placeholders (`example@`, `yourname@`, `test@`), template domains (`example.com`, `yourdomain.com`), error-tracker addresses (`sentry.io`, `wixpress.com`) and image file names that contain an `@` are dropped.
- `type` is `role` for function mailboxes (info@, sales@, support@, privacy@ …), `personal` for `first.last@` shapes, and `generic` for everything else (a country office, a brand word, a first name alone). The distinction is a heuristic, not a promise.

#### 📞 How phones are validated

Every candidate goes through the international numbering plan (`libphonenumber`): the number must be valid for its country, with the country taken from a `+` prefix, else from the site's country domain (`.de`, `.co.uk`, `.id` …), else from **📞 Default phone country**. Numbers in page prose need at least seven national digits, so order numbers and dates are not reported as phones. WhatsApp links (`wa.me/…`) are read as phone numbers as well.

### Use cases for website contact data

#### 🎯 Lead generation and outreach

Export businesses from Google Maps, a directory or a trade-show list, run the domains through Website Contacts API and get the general inbox, a direct phone and the LinkedIn page for each — with the page each contact came from, so an SDR can check it in one click.

#### 🧹 CRM enrichment

Fill the empty e-mail, phone and social columns of an existing account list. `isOwnDomain` and `isFree` tell you whether an address is the company's own or a sole trader's gmail.com mailbox before it enters a sequence.

#### 🤖 AI agents and workflows

One flat row per website with a ready `summary` sentence is what an agent needs: give it a company website, get back who to contact. The Actor is listed for the Apify MCP server, and its input needs nothing but a list of websites.

#### 🔎 Research and due diligence

Registered addresses from schema.org markup, imprint pages and the contact channels a company actually publishes — useful for supplier checks, partnership research and compliance reviews.

### Integrations

- **API** — start a run and read the dataset with any HTTP client, or with the [Apify client for Python](https://docs.apify.com/api/client/python) and [JavaScript](https://docs.apify.com/api/client/js).
- **n8n, Make, Zapier** — use the Apify node/module, pick this Actor, map `startUrls` or `domains` from your sheet, and write `bestEmail`, `bestPhone`, `linkedin` back. Rows are flat, so mappers show every field.
- **Google Sheets** — schedule a run and export the dataset as CSV, or use the Apify Google Sheets integration.
- **MCP server** — call it from Claude, ChatGPT or any MCP-capable agent through the Apify MCP server; `summary` is written for that.
- **Webhooks** — get notified when a run finishes and fetch the dataset in your own code.

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("lergassy/website-contacts-api").call(run_input={
    "domains": ["basecamp.com", "hubspot.com", "legalindonesia.id"],
    "checkEmails": True,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(row["domain"], row["bestEmail"], row["bestPhone"], row["linkedin"])
```

### Limits and honest notes

- **JavaScript-only sites.** A home page that is an empty shell (some Wix apps, single-page apps) yields `status: no_contacts` with `note: javascript_rendered_site`. Framer sites are handled through their search index. A browser mode may be added if enough users ask — open an Issue.
- **Anti-bot walls.** Large sites behind Akamai, DataDome or Cloudflare challenges come back as `status: blocked`, free of charge. Business websites rarely have them; the Chrome-fingerprint fallback clears the simpler ones without a proxy.
- **E-mail check is domain-level.** It tells you whether the domain accepts mail, who hosts it, and whether the address is disposable or a role account. It cannot confirm that a specific mailbox exists — no service can do that reliably without sending mail, and the ones that claim to are guessing for Gmail and Microsoft 365 domains.
- **Public data only.** The Actor reads what the website publishes to any visitor. It never logs in, never guesses addresses and never pulls data from third-party databases.

### ❓ FAQ

#### Is it legal to extract contact details from websites?

The Actor collects only information that the website publishes to every visitor, which is generally lawful to collect. What you may do with it — cold outreach, storage, profiling — is governed by laws such as GDPR, CAN-SPAM and local rules on unsolicited messages. Consult a lawyer for your use case; personal e-mail addresses in particular carry obligations.

#### Why does it cost less than page-priced contact scrapers?

Because it reads only the pages that carry contacts and charges once per website. Reading five pages instead of twenty makes it both faster and cheaper, and empty sites are not billed at all.

#### Can I pass bare domains without https://?

Yes — put them in **🌐 Domains**, one per line. The **🌐 Websites** field needs full URLs because it also accepts files and Google Sheets.

#### Why is `bestEmail` info@ when a personal address was also found?

The general inbox is the address a company chooses to publish as its contact, so it ranks first. Personal addresses are still in `emails[]` with `type: "personal"`. Set your own rule in your workflow if you prefer them.

#### Does it work through the Apify API and the MCP server?

Yes. Every run can be started through the API, and the Actor is listed for the Apify MCP server so AI agents can call it directly.

#### Can I integrate it with Google Sheets, n8n or Make?

Yes — see Integrations above. Rows are flat, so every field maps to a column.

#### Does the run stop when I run out of budget?

Set **Max total charge** on the run (or in the n8n node). The Actor charges only after a website has been written to the dataset, so you always keep what you paid for.

### Your feedback

Found a site where a published address was missed or a wrong number was reported? Open an **Issue** on this page with the URL — every report is answered, and fixes ship within days. Reviews help other buyers find the Actor.

### You might also like

| Actor | What it does |
|---|---|
| [Email & Phone Verifier](https://apify.com/lergassy/email-phone-verifier) | Deliverability signals, disposable and role flags, US area code, state and time zone for a list of e-mails and phones |
| [US Business Leads](https://apify.com/lergassy/us-business-filings) | Newly registered US businesses from state registries with owner contacts and a lead score |
| [Website Business Evidence](https://apify.com/lergassy/website-business-evidence) | Is a website a real, active business? Signals from the site itself |
| [Google Flights Scraper](https://apify.com/lergassy/google-flights-scraper) | Flight prices and itineraries from Google Flights |

# Actor input Schema

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

Websites to scan, one per line: a domain (<code>acme.com</code>), a home page or any page of the site. Paste a list, upload a file, or link a Google Sheet. One dataset row comes back per website.

## `domains` (type: `array`):

Bare domains without https://, e.g. <code>acme.com</code> — handy for lists exported from Google Maps, a CRM or a spreadsheet. Merged with the websites above.

## `maxPagesPerSite` (type: `integer`):

Home page plus the most contact-like pages (contact, about, team, imprint, legal). 6 finds nearly everything on a normal business site; raise it for large sites. The price does not depend on this number.

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

Two-letter country code used to read phone numbers written without a country code. A site's own country domain (<code>.de</code>, <code>.co.uk</code>, <code>.id</code>) always wins over this value.

## `checkEmails` (type: `boolean`):

Adds deliverability signals for every e-mail found: whether the domain accepts mail (DNS MX), the mail provider, disposable and role flags and a typo suggestion. Charged per checked address. This is a domain-level check, not a mailbox probe.

## `onlyOwnDomainEmails` (type: `boolean`):

Drop addresses on other domains (a partner, a web agency, a gmail.com mailbox). Off by default because a sole trader's only address is often on gmail.com.

## `stopEarly` (type: `boolean`):

Faster runs: once a page has yielded both an e-mail on the site's own domain and a valid phone, the remaining pages of that website are skipped. Turn off to collect every address on every page.

## `maxWebsites` (type: `integer`):

Safety cap on how many websites from the list are processed in one run.

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

How many websites are scanned at the same time.

## `pageTimeoutSecs` (type: `integer`):

Give up on a page after this many seconds.

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

Not needed for normal business websites and off by default. Turn on Apify Proxy only if your list is full of sites that block datacenter traffic.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.apify.com"
    },
    {
      "url": "https://www.basecamp.com"
    },
    {
      "url": "https://www.ycombinator.com"
    },
    {
      "url": "https://www.hubspot.com"
    },
    {
      "url": "https://www.zendesk.com"
    }
  ],
  "domains": [],
  "maxPagesPerSite": 6,
  "defaultCountry": "US",
  "checkEmails": false,
  "onlyOwnDomainEmails": false,
  "stopEarly": true,
  "maxWebsites": 1000,
  "concurrency": 10,
  "pageTimeoutSecs": 15,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `websites` (type: `string`):

One flat row per website: company name, best e-mail and phone, every e-mail and phone with its source page, WhatsApp, Telegram, LinkedIn, Facebook, Instagram, X, YouTube, TikTok, contact page, contact form, postal address, pages scanned and a one-sentence summary. Error rows carry the reason.

# 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://www.apify.com"
        },
        {
            "url": "https://www.basecamp.com"
        },
        {
            "url": "https://www.ycombinator.com"
        },
        {
            "url": "https://www.hubspot.com"
        },
        {
            "url": "https://www.zendesk.com"
        }
    ],
    "domains": [],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("lergassy/website-contacts-api").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://www.apify.com" },
        { "url": "https://www.basecamp.com" },
        { "url": "https://www.ycombinator.com" },
        { "url": "https://www.hubspot.com" },
        { "url": "https://www.zendesk.com" },
    ],
    "domains": [],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("lergassy/website-contacts-api").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://www.apify.com"
    },
    {
      "url": "https://www.basecamp.com"
    },
    {
      "url": "https://www.ycombinator.com"
    },
    {
      "url": "https://www.hubspot.com"
    },
    {
      "url": "https://www.zendesk.com"
    }
  ],
  "domains": [],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call lergassy/website-contacts-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,lergassy/website-contacts-api"
        }
    }
}

```

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/s23QhOQ6368qaWx27/builds/xCrb9z273Hhd2Ty2S/openapi.json
