Website Contacts Scraper: Emails, Phones, Socials
Pricing
Pay per event
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
Pay per event
Rating
0.0
(0)
Developer
TidyHarvest
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 days ago
Last modified
Categories
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. That means no surprise bills from a runaway crawl on a big site, and dead, parked and blocked domains are free.
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 actor | Contact Details Scraper | |
|---|---|---|
| Sites with an email found | 85% | 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 phone | 92.5% | 90% |
| Postal address | 52% | 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
skipDatasetIdsand 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
| Field | What it does |
|---|---|
domains | Websites, 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. |
datasetIds | Read websites from other Apify datasets (e.g. a Google Maps scraper run). |
skipDatasetIds | Skip domains already processed in earlier runs of this actor. |
maxPagesPerDomain | Homepage + best contact/imprint/about/team pages (default 5, max 20). Price is per domain regardless. |
timeoutSecsPerDomain | Cut off slow sites after this many seconds (default 30). |
country | Default country for local phone numbers and addresses (US, GB, DE...). Empty = the Maps row's country, else guess from the domain. |
retryBlockedWithProxy | Retry sites that refuse cloud servers once through Apify Proxy (on by default; still free if they stay blocked). |
includePersonalEmails | Also return staff emails (jane.doe@, jason@). On by default; off = company mailboxes only. |
checkEmails | Paid add-on: syntax, MX, disposable, role and free-mail checks for each email. |
maxItems | Stop 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). 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), only whencheckEmailsis on.
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.