Contact Details Scraper — Emails, Phones, Socials from Websites
Pricing
from $6.00 / 1,000 domain with contacts
Contact Details Scraper — Emails, Phones, Socials from Websites
Extract emails, phone numbers and social profiles (Facebook, Instagram, LinkedIn, X, YouTube, TikTok, WhatsApp...) from a list of websites or domains: one merged row per domain.
Pricing
from $6.00 / 1,000 domain with contacts
Rating
0.0
(0)
Developer
Trevor Ortega
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Give it a list of websites or domains and get back one clean row per domain with every email address, phone number and social profile the site publishes: Facebook, Instagram, LinkedIn, X/Twitter, YouTube, TikTok, Pinterest, WhatsApp, Telegram, Discord and GitHub, plus the company name, the postal address (when the site publishes it as structured data) and the URL of the contact page.
The scraper reads the start page and then the pages where contacts usually are: Contact, Impressum/Imprint, About,
Team, Support and legal pages first, other pages after them. It understands mailto: links, plain text, obfuscated
spellings like info (at) acme (dot) com, Cloudflare's email protection and schema.org JSON-LD. Phone numbers come
normalized to international E.164 format (+12122473491) next to the way the site writes them.
You pay only for domains where something was found. Dead domains, blocked sites and sites without any contact details cost nothing.
What data does Contact Details Scraper extract?
| Field | Description |
|---|---|
domain | The domain the row is about (host without www.), e.g. patsys.com |
inputUrl / finalUrl | The URL or domain as you entered it / the start page after redirects |
status | ok, unreachable, blocked (anti-bot page), httpError, notHtml, blockedByRobotsTxt, socialProfileOnly, platformPage, skipped |
error | Why the site could not be read (only when status is not ok) |
companyName | Business name from JSON-LD Organization data, og:site_name or the page title (the one matching the domain wins) |
address | Postal address from JSON-LD: streetAddress, addressLocality, addressRegion, postalCode, addressCountry, full |
emails | Email addresses, the site's own domain first, then other addresses the site shows (gmail.com, agencies) |
phones | Valid phone numbers in E.164 format (+493093931290) |
phonesRaw | The same numbers as written on the site (+49 (0)30 939312-90), in the same order as phones |
phonesUncertain | Numbers from tel: links that could not be validated for any country |
facebooks, instagrams, linkedIns, twitters, youtubes, tiktoks, pinterests, whatsapps, telegrams, discords, githubs | Profile / invite links, normalized (share buttons, single posts and template placeholders are dropped) |
contactPageUrl | The site's contact page |
contactsFound | true when at least one email, phone or social profile was found (only these rows are charged) |
pagesVisited / visitedUrls | How many and which pages were read |
errors | Pages of the site that could not be read (404, timeouts...) |
changeType / previousValues | Only with monitoring on (see below) |
scrapedAt | When the row was made (UTC) |
With Also output one row per page on, every visited page also gets a row (type: "page") with url, depth,
pageKind (contact, imprint, about, team, legal, other...), httpStatus, title and the contacts found on that page,
so you can see where each email was published. Page rows are free.
How to scrape contact details from a list of websites
- Add websites under Websites (one URL per line, or upload / link a text or CSV file), or paste a list or a
whole CSV export into Or paste a list of domains / URLs. Bare domains like
acme.co.ukare fine. - Keep Max pages per domain at 5 (enough for most sites) or raise it for big sites.
- Click Start and download the results as CSV, Excel or JSON from the Output tab, or read them via the API.
Several URLs of the same domain are merged into one row; subdomains (shop.acme.com) get their own row.
Input example
{"startUrls": [{ "url": "https://www.patsys.com/contact.html" }],"urlsText": "joscoffee.com\neinstein-kaffee.de\nhttps://www.zingermansdeli.com","maxPagesPerDomain": 5,"maxDepth": 1,"sameDomainEmailsOnly": false,"proxyConfiguration": { "useApifyProxy": true }}
Output example
{"type": "domain","domain": "patsys.com","inputUrl": "https://www.patsys.com/contact.html","finalUrl": "https://www.patsys.com/contact.html","status": "ok","error": null,"companyName": "Patsys Italian Restaurant","emails": ["anne@patsys.com", "patsysnyc@gmail.com"],"phones": ["+12122473491"],"phonesRaw": ["(212) 247-3491"],"phonesUncertain": [],"facebooks": ["https://www.facebook.com/patsysitalianrestaurant"],"instagrams": ["https://www.instagram.com/patsysitalianrestaurant"],"linkedIns": [],"twitters": ["https://x.com/patsysitalrest"],"youtubes": ["https://www.youtube.com/channel/UCaBjym9W_eD6Svq9vKqX5_w"],"tiktoks": [],"pinterests": ["https://www.pinterest.com/sharonaburch/patsys-italian-restaurant-ny"],"whatsapps": [],"telegrams": [],"discords": [],"githubs": [],"contactPageUrl": "https://www.patsys.com/contact.html","address": null,"contactsFound": true,"pagesVisited": 3,"visitedUrls": ["https://www.patsys.com/contact.html", "https://www.patsys.com/", "https://www.patsys.com/ourstory.html"],"errors": [],"scrapedAt": "2026-10-12T18:54:33Z"}
Which pages does it visit?
The start page, then pages linked from it, best first: contact pages (also Kontakt, Contacto, Contatti,
Nous contacter...), Impressum / imprint / legal notice, About, Team, support, privacy and terms pages, locations,
then any other page of the site. Crawl depth 1 (default) means the start page and the pages it links to; 2 also
follows links found on those pages. Only the website's own domain is crawled (with or without www.); contact,
imprint, about and team pages on other subdomains are read when the site links to them, and Include subdomains
opens the whole subdomain family. robots.txt is respected unless you switch it off. Every site gets at most 3
requests at a time with short pauses, so crawling is polite.
Pricing
| Event | Price | When |
|---|---|---|
| Domain with contacts | $0.006 | A domain where at least one email, phone number or social profile was found. Includes up to 5 pages. |
| Extra page | $0.0012 | Each page beyond the first 5 of a domain with contacts (only if you raise Max pages per domain). |
Domains with nothing found, unreachable or blocked sites, and page rows are free. Platform usage is billed by Apify at cost and is small: a run of 98 domains with the default settings read 4.6 pages per site, took 3 minutes and used $0.007 of platform usage (about $0.07 per 1,000 domains). Example: 1,000 domains, 90% with contacts, default settings: 900 × $0.006 = $5.40 plus about $0.07 usage.
Monitor changes on a schedule
Turn on Only new or changed domains to watch a lead list or your competitors' contact pages. The actor remembers
what earlier runs of the same input found (emails, phones and social profiles per domain) and outputs only domains that
are new or whose contact set changed; unchanged domains are not output and not charged. Save the input as a task and
add a Schedule in Apify Console (Schedules → Create, e.g. weekly). Changed rows carry changeType: "changed" and
previousValues with the old emails/phones/profiles; first-seen domains carry changeType: "new". A site that is down
for one run, or a run where a page fails to load and something disappears, does not count as a change. Use
Monitoring key to keep several watches on the same list apart.
How do I extract emails from a CSV or Google Sheet of domains?
Paste the CSV into Or paste a list of domains / URLs: every column that holds a website or domain is used and the other columns (names, cities, emails) are ignored. For a Google Sheet, use File → Share → Publish to web → CSV and add that link under Websites with the "Link remote text file" option.
Why was no email found for a website?
Common reasons: the site shows a contact form instead of an address, the address is in an image, or the page is
built entirely by JavaScript (single-page apps); this scraper reads the HTML without a browser, which keeps it fast and
cheap. Some sites block datacenter IPs (status: "blocked"): try the residential proxy for those. Rows without
contacts are free, so it costs nothing to try.
Does it find emails hidden by Cloudflare or written as "name (at) domain (dot) com"?
Yes. Cloudflare's email obfuscation is decoded, and the common "(at)" / "[at]" / "(dot)" spellings are read.
Placeholders (you@example.com, Wix and Sentry ids, image names like logo@2x.png) and no-reply addresses are dropped.
Proxy note
The default Apify datacenter proxy works for most business websites and is included in the platform usage. For lists of sites that block datacenter IPs, choose the Residential proxy group; Apify bills residential traffic per GB.
Integrations and API
Run it from Zapier, Make, n8n or Google Sheets, or call it from Python / Node.js with the Apify client (see the
API tab). Use the result to enrich a CRM: the domain field is a stable key.
Is it legal to scrape contact details from websites?
The actor reads only what websites publish openly to anyone, without logging in, and does not guess or verify
addresses. Business contact details are public by intent, but some addresses identify a person (jane.doe@...); if
you are in the EU/UK, data protection law (GDPR) applies to how you store and use them, e.g. for cold outreach. You are
responsible for complying with the applicable law and the sites' terms.
Support
Found a site where a visible email or phone was missed? Open an issue in the Issues tab with the URL; it is usually answered within a day.