Website Contacts Scraper: Emails, Phones, Socials · Apify
Website Contacts Scraper: Emails, Phones, Socials avatar

Website Contacts Scraper: Emails, Phones, Socials

Pricing

from $1.20 / 1,000 domain reads

Go to Apify Store
Website Contacts Scraper: Emails, Phones, Socials

Website Contacts Scraper: Emails, Phones, Socials

Built to beat Contact Details Scraper: on the same 40 sites it found an email on 85% vs 68% and a company mailbox on 75% vs 43%, plus addresses, for 1/6 the cost: a flat $1.50 per 1,000 sites, not $2 per 1,000 pages (~$9.20 per 1,000 sites). Dead sites free.

Pricing

from $1.20 / 1,000 domain reads

Rating

0.0

(0)

Developer

TidyHarvest

TidyHarvest

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

1

Monthly active users

2 days ago

Last modified

Features

Limited permissions

Share

Turn a list of websites or domains into one clean row per company: emails, phone numbers (E.164), social media links (LinkedIn, Facebook, Instagram, X/Twitter, YouTube, TikTok and more), postal address, company name and a tech stack guess, plus a clear status for every domain (ok, dead, parked, blocked).

You pay a flat price per domain, not per page crawled: from $1.50 per 1,000 websites ($1.20 on Gold and above). That means no surprise bills from a runaway crawl on a big site, and dead, parked and blocked domains are free. In our October test on 40 shared websites it found a company email on 75% against 43% for the most-used alternative, at about a sixth of the cost.

Quick start

  1. Click Try for free and paste websites, domains or email addresses into Domains, one per line (a comma-separated list on one line works too).
  2. Press Start. A hundred sites take about a minute.
  3. Open the Output tab, or download JSON, CSV or Excel. Every input gets a row with a status.
{ "domains": ["stripe.com", "https://www.zunicafe.com", "info@tartinebakery.com"] }

It takes Google Maps results directly: paste the dataset id from a Maps scraper run and every place's website gets enriched, with the place name and id carried along so you can join it back.

Compared with Contact Details Scraper

We built this to beat Contact Details Scraper (vdrmota/contact-info-scraper), the most-used contact scraper on Apify Store. In October 2026 we ran both on the same 40 websites (small businesses from Google Maps in 8 countries plus B2B companies), theirs at up to 5 pages per site, and checked 25 of the sites by hand.

This actorContact Details Scraper
Sites with an email found85%68%
Sites with a company mailbox (info@, sales@...)75%43%
Emails on the page that were found (25 hand-checked sites)93%33%
Main phone found (hand-checked)95%90%
Sites with an email or a phone92.5%90%
Postal address52%none (no address field)
What the 40 sites cost$0.06$0.37

Why the price looks different: their Store card says $2.00 per 1,000 pages. A site is several pages (home, contact, about, imprint), so in our test it worked out to about $9.20 per 1,000 sites. This actor charges $1.50 per 1,000 sites, however many pages it reads, and nothing for dead, parked or blocked sites. Higher Apify plans pay less per page there (about $4.80 per 1,000 sites at Gold), still about 3x this price.

Where Contact Details Scraper still does more: it routes every site through a proxy (it read all 40; we read 38), can render JavaScript-only sites in a browser, covers a few more social networks, and sells add-ons we don't (named-lead enrichment with job titles, social-profile enrichment, mailbox-level email verification).

How well it works

Measured in October 2026 on 203 real websites: small businesses drawn from Google Maps in 8 countries (US, UK, Germany, France, Mexico, Australia, Canada, India: plumbers, dentists, accountants, salons, cafés, lawyers) plus 30 B2B/SaaS companies.

  • An email or phone for 87% of sites (176 of 203). A company email for 63% (127 of 203), and an email of any kind, staff included, for 75% (107 of 142). Most sites without one only offer a contact form.
  • The phone Google Maps lists for the business was found on 75% of sites (128 of 170).
  • A postal address for 54%, read from schema.org data or the page text in each country's format.
  • On 25 sites checked by hand: the main phone was right on 95%, and 93% of the emails the site shows were found.
  • 142 sites in under 2 minutes, for about $0.006 of platform compute.
  • Chain location pages (rotorooter.com/columbus/) return that branch's phone and email, not head office's.

What you can do with it

  • Enrich Google Maps leads: run a Maps search, then pass its dataset id here to add emails, phones and socials to every business.
  • Clean up a CRM or lead list: find which domains are dead or parked (free) and get current contact details for the rest.
  • Scheduled refreshes: pass last run's dataset in skipDatasetIds and only new domains are processed and charged.
  • Find a company's social profiles and the platform its website runs on (Shopify, WordPress, Wix, HubSpot...).

Input

FieldWhat it does
domainsWebsites, domains or email addresses, one per line. A URL with a path (a chain's location page) is read first and is its own row.
datasetIdsRead websites from other Apify datasets (e.g. a Google Maps scraper run).
skipDatasetIdsSkip domains already processed in earlier runs of this actor.
maxPagesPerDomainHomepage + best contact/imprint/about/team pages (default 5, max 20). Price is per domain regardless.
timeoutSecsPerDomainCut off slow sites after this many seconds (default 30).
countryDefault country for local phone numbers and addresses (US, GB, DE...). Empty = the Maps row's country, else guess from the domain.
retryBlockedWithProxyRetry sites that refuse cloud servers once through Apify Proxy (on by default; still free if they stay blocked).
includePersonalEmailsAlso return staff emails (jane.doe@, jason@). On by default; off = company mailboxes only.
checkEmailsPaid add-on: syntax, MX, disposable, role and free-mail checks for each email.
maxItemsStop after this many charged domains (caps your cost).

Example:

{ "domains": ["tartinebakery.com", "https://www.zunicafe.com"], "maxPagesPerDomain": 5 }

From a Google Maps run:

{ "datasetIds": ["<your Maps run's dataset id>"] }

Output

One item per domain:

{
"domain": "zunicafe.com",
"status": "ok",
"companyName": "Zuni Café",
"emails": ["jobs@zunicafe.com"],
"emailDetails": [{"email": "jobs@zunicafe.com", "type": "generic", "sameDomain": true, "foundOn": ["https://zunicafe.com/"]}],
"phones": ["+14155522522"],
"socials": {"facebook": "https://facebook.com/zunicafe", "instagram": "https://instagram.com/zunicafe"},
"address": {"street": "1658 Market Street", "city": "San Francisco", "region": "CA", "postalCode": "94102", "country": "US", "source": "text"},
"techStack": ["WordPress", "Google Analytics"],
"url": "https://zunicafe.com/",
"contactPages": ["https://zunicafe.com/contact/"],
"pagesCrawled": 2,
"hiddenEmails": {"personal": 0, "other": 0, "otherDomain": 0},
"statusDetail": null
}

Status values: ok (site read, charged), dead (no DNS, connection refused, timeout), parked (for-sale or parking page), blocked (bot protection answered instead of the site), invalid (not a domain, or a social/listing URL like a Google Maps link). Only ok is charged.

Which emails are returned: company mailboxes such as info@, sales@, hello@, support@, press@, bookings@ (also kontakt@, ventas@, accueil@ and other languages), and free-mail boxes named after the business (room19cafe@gmail.com for room19.com.au, type: "business"), plus staff addresses: named people (jane.doe@, type: "personal") and single-word boxes that may be a first name (jason@, type: "other"). Company mailboxes are listed first. Set includePersonalEmails to false to keep only company mailboxes; the others are then counted in hiddenEmails. Addresses on unrelated domains (the web agency, a regulator listed in the imprint, a software vendor) are dropped too (hiddenEmails.otherDomain). Placeholders such as max@mustermann.de are ignored. This keeps the output to the business's own people and mailboxes.

Is it legal? It returns only what the website itself publishes. Emails of named people are personal data under GDPR (EU/UK) and similar laws: if you email them, you need a lawful basis (usually legitimate interest), and you must follow anti-spam rules such as CAN-SPAM and PECR. If in doubt, turn includePersonalEmails off.

With checkEmails on, each row gets emailChecks: syntaxValid, mxFound, mxHosts, disposable, role, freeMail and a verdict (accepts-mail, risky, invalid, unknown). No SMTP probe is sent, so accepts-mail means the domain receives email, not that the exact mailbox exists.

Pricing

  • $1.50 per 1,000 domains read (domain-processed) on the Free plan; $1.40 Bronze, $1.30 Silver, $1.20 Gold and above. Flat, however many pages it takes. Dead, parked, blocked and invalid domains are free.
  • Email check add-on: $0.30 per 1,000 emails checked (email-checked; $0.24 on Gold and above), only when checkEmails is on.

Use it from n8n, Make, Zapier or code

  • n8n: add the Apify node, operation Run Actor and get dataset items, actor tidyharvest/website-contacts-scraper, input { "domains": ["={{ $json.website }}"] }. Each incoming item becomes one row.
  • Make: the Apify module Run an Actor, then Get Dataset Items; map your sheet's website column into domains.
  • Google Sheets or a CRM export: paste the column straight into Domains; the input field in each row is your original value, so you can join results back.
  • API: one call returns the rows as JSON.
$curl -X POST "https://api.apify.com/v2/acts/tidyharvest~website-contacts-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" -H "Content-Type: application/json" -d '{ "domains": ["stripe.com", "zunicafe.com"] }'

FAQ

How do I get emails for a list of websites? Paste them into Domains (or pass the dataset id of a Google Maps run in datasetIds) and press Start. Each row has emails (company mailboxes first), phones, socials, address and a status.

What counts as a company email? Mailboxes such as info@, sales@, hello@ or support@, business-named free-mail boxes and, if you leave includePersonalEmails on, staff addresses. Each email carries a type so you can filter.

Why did a site come back blocked or dead? blocked means the site's bot protection answered instead of the site; dead means it did not respond (no DNS, refused or timed out). Both are free. Sites that drop our first connection are retried once automatically.

Do I pay twice for the same site? No. Repeated domains in one run are read and charged once, and skipDatasetIds skips domains from earlier runs.

Can it read a chain's location page? Yes: rotorooter.com/columbus/ returns that branch's phone and email, not head office's.

Is it legal to scrape emails from websites? See Is it legal? above: it returns only what each site publishes itself. Named-person emails are personal data under GDPR, so have a lawful basis before emailing them and turn includePersonalEmails off if unsure.

Limits and notes

  • Reads plain HTML. Sites that only render contact details with JavaScript, or sit behind bot protection, come back with fewer fields or blocked (free).
  • Addresses come from schema.org data on the site, or the page text in the site's country format (US, UK, Canada, Australia, Germany, Austria, Switzerland, France, Spain, Italy, Mexico). When a page lists several different addresses (imprints often do), none is guessed.
  • Fax numbers, dates and placeholder numbers (123-456-7890) are not returned as phones.
  • Public business information from each company's own website only. No logins.

Other actors from the same publisher that pair well with this one:

Feedback and requests

We welcome feedback: a field or option you wish this had, a change to how it works, or a scraper you would like us to build. Open an issue in the Issues tab of this page and tell us what you need. We read every one, and we build the requests that come up most. If this actor works well for you, a short review helps other people find it.