Website Contacts API avatar

Website Contacts API

Pricing

from $10.50 / 1,000 website with contacts

Go to Apify Store
Website Contacts API

Website Contacts API

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.

Pricing

from $10.50 / 1,000 website with contacts

Rating

0.0

(0)

Developer

Matvey

Matvey

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

7 hours ago

Last modified

Share

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?

FieldExampleWhere it comes from
bestEmail, bestEmailTypehello@apify.com, roleThe 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 7768Best 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, telegramhttps://wa.me/628179677771Messenger links; the WhatsApp number is also added to phones
linkedin, facebook, instagram, x, youtube, tiktok, pinterest, threads, githubhttps://linkedin.com/company/apifyNormalised profile URLs; share buttons, login pages and hashtags are ignored
contactPageUrl, contactFormUrlhttps://apify.com/contactThe contact page that was read and the page with a contact form
addressStreet, addressCity, addressRegion, addressPostalCode, addressCountry2 Canal Park, Cambridge, MA, 02141, USschema.org PostalAddress; addressText falls back to an <address> tag
companyNameHubSpotschema.org Organization, og:site_name or the page title
status, noteok, javascript_rendered_siteok, no_contacts, unreachable, blocked; the note tells you when a site is an empty JavaScript shell
pagesScanned, pagesScannedCount, durationMs, fetchedVia[…], 3, 1497, fetchWhat was read and how long it took
summaryHubSpot: +18884827768 (2 e-mails, 25 phones); linkedin, facebook, instagram, x, youtube, tiktok.One sentence for agents, Slack alerts and spreadsheets
emailChecks[], bestEmailStatusdeliverableOnly 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:

EventPriceWhen 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 addressesOnly 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

Website Contacts API input form: list of websites, domains, max pages per website, default phone country, e-mail check add-on
{
"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
}
FieldDefaultWhat it does
startUrls5 example sitesWebsites 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
maxPagesPerSite6Home page plus the most contact-like pages; 6 finds nearly everything on a normal business site
defaultCountryUSTwo-letter country used for phone numbers without a country code
checkEmailsfalseAdd-on ($): DNS deliverability, provider, disposable / role / free flags per address
onlyOwnDomainEmailsfalseDrop addresses on other domains (an agency, a partner, a gmail.com mailbox)
stopEarlytrueSkip remaining pages once an own-domain e-mail and a phone were found
maxWebsites, concurrency, pageTimeoutSecs, proxyConfiguration1000, 10, 15, offSafety 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

Website Contacts API output table: domain, company, best e-mail, best phone, LinkedIn, Instagram, e-mail and phone counts per website

One row per website:

{
"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:

{ "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 and JavaScript.
  • 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.
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

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

ActorWhat it does
Email & Phone VerifierDeliverability signals, disposable and role flags, US area code, state and time zone for a list of e-mails and phones
US Business LeadsNewly registered US businesses from state registries with owner contacts and a lead score
Website Business EvidenceIs a website a real, active business? Signals from the site itself
Google Flights ScraperFlight prices and itineraries from Google Flights