Email & Contact Scraper for Websites — Emails, Phones, Socials
Pricing
from $1.05 / 1,000 domain with contacts
Email & Contact Scraper for Websites — Emails, Phones, Socials
Give a list of websites, get one row per domain with public emails, phone numbers, social profiles and contact form. Reads the homepage plus contact, about, impressum and team pages. $1.50 per 1,000 domains with contacts.
Pricing
from $1.05 / 1,000 domain with contacts
Rating
0.0
(0)
Developer
Dottti
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Security
Limited permissionsShare
Website Email & Contact Scraper
Give a list of business websites. Get one row per domain with its public emails, phone numbers, social profiles and contact form.
The actor reads the homepage. Then it reads the pages most likely to list contacts: contact, about, impressum, legal notice, team and locations. It reads 5 pages per site by default.
- Price: $1.50 per 1,000 domains where at least one contact is found ($0.0015 each) on the Apify Free plan, less on paid plans (down to $1.05). Domains without contacts and failed inputs are free. Platform usage is included.
- First run: the form is prefilled with three company websites. Click Start and you get 3 rows of contacts in a few seconds (tested 4 November 2026).
Who it is for
- Sales and lead generation teams who have a list of company websites and need an email and phone for each.
- Agencies who enrich Google Maps results with emails and social profiles.
- Marketplaces and directories who check that listed businesses are reachable.
- Researchers who map the companies in a sector or a city.
What you get for each domain
- Emails, deduplicated and lowercased. The actor reads mailto links, plain text, schema.org data and hidden addresses. It decodes Cloudflare email protection. It also reads written-out forms such as
info [at] acme [dot] comandinfo(at)acme.com. - Best email (
primaryEmail). Addresses on the site's own domain come first. Role addresses such as info@, contact@ and sales@ come next. - Phones in international E.164 format (
+966114555555). The country comes from the country domain (.de, .sa), the Google MapscountryCode, your default country, or the international numbers on the same site. A number whose country stays unclear is returned as digits. - Social profiles, one column each: LinkedIn company page, Facebook, Instagram, X, YouTube, TikTok, WhatsApp and Telegram. When a site links several profiles of one network, the one linked most often is returned. Share buttons and personal LinkedIn profiles are skipped.
- Contact form URL and contact page URL.
- Pages checked, their URLs, and a status for every input.
Junk is removed. Image names such as logo@2x.png, error-tracker addresses, website-builder system addresses and placeholders such as you@example.com never reach your data.
Input examples
A list of websites:
{"websites": ["https://www.hetzner.com", "buffer.com", "https://www.jarir.com/sa-en/"]}
Google Maps results pasted as JSON. The place title, placeId and countryCode are kept, so you can join the rows back:
{"places": [{ "title": "Jarir Bookstore", "placeId": "p1", "countryCode": "SA", "website": "https://www.jarir.com/sa-en/" },{ "title": "Bread Ahead", "placeId": "p2", "countryCode": "GB", "website": "https://www.breadahead.com/" }]}
You can also give the ID of a Google Maps run's dataset in datasetId.
Output example
A real row from a test run (shortened):
{"domain": "hetzner.com","url": "https://www.hetzner.com/","status": "ok","emails": ["info@hetzner.com", "product-feedback@hetzner.com", "tco@hetzner.com"],"primaryEmail": "info@hetzner.com","phones": ["+4998315050", "+49911234226100"],"primaryPhone": "+4998315050","linkedin": "https://www.linkedin.com/company/hetzner-online","facebook": "https://www.facebook.com/hetzner.de","instagram": "https://www.instagram.com/hetzner.online","x": "https://twitter.com/Hetzner_Online","youtube": "https://www.youtube.com/channel/UC5GXP-_6UWl5I9pisIDohUA","tiktok": null,"whatsapp": null,"telegram": null,"contactFormUrl": null,"pagesChecked": 5,"pageUrls": ["https://www.hetzner.com/", "https://www.hetzner.com/support/", "https://www.hetzner.com/legal/legal-notice/"],"phoneCountry": "DE","sourceName": null,"charged": true}
A row from pasted Google Maps data:
{"domain": "jarir.com","status": "ok","primaryEmail": "care@jarir.com","phones": ["+966920000089", "+9668003034444"],"facebook": "https://www.facebook.com/jarirbookstore","phoneCountry": "SA","sourceName": "Jarir Bookstore","sourcePlaceId": "p1","charged": true}
Every row has the same columns, so CSV and Excel exports line up.
Status values
| Status | Meaning | Charged |
|---|---|---|
ok | At least one email, phone or social profile found | Yes |
no_contacts | The site loaded but lists no contacts in its HTML | No |
blocked | The site answers with a bot check on every proxy tried | No |
dns_not_found | The domain does not resolve | No |
timeout, unreachable, http_error | The site is down or answers with an error | No |
parked | Parked or for-sale domain | No |
not_a_website | The input is a Facebook, Instagram or similar page; the link is returned in its column | No |
no_website, invalid_input, duplicate, skipped | Nothing to check, or the same domain was already checked | No |
The run always ends as succeeded. A run summary with counts by status is saved as RUN_SUMMARY in the key-value store.
Pricing
You pay $1.50 per 1,000 domains where at least one contact is found on the Free plan, $1.35 on Bronze, $1.20 on Silver and $1.05 on Gold. Domains without contacts and every failed or skipped input are free. Platform usage is included in the price, so pages read and proxies used do not change what you pay. Set a spending limit on the run and the actor stops before it.
How to schedule
Save your input as a task. Open Schedules, pick the task, and choose how often it runs. Each run returns fresh rows for every domain.
How it works and limits
- Plain HTTP requests, no browser. That keeps it fast: most sites finish in 2 to 5 seconds.
- Sites that block get a second try through a datacenter proxy, then a residential proxy.
- Sites that build their whole page with JavaScript can return
no_contacts. - Only public business contact data that the site itself publishes is read. No logins, no cookies, no CAPTCHA solving.
- Up to 20,000 sites per run. Split larger lists into several runs.
- You are responsible for using the contacts under the privacy and anti-spam laws that apply to you.