Website Contact Extractor — Emails, Phones & Socials
Pricing
from $0.80 / 1,000 domain with contacts founds
Website Contact Extractor — Emails, Phones & Socials
Give it a list of website domains and get back business emails, phone numbers, LinkedIn and social profiles, the contact page URL and postal address, one row per domain. HTTP only, no browser, no login. You only pay for domains where something is found.
Pricing
from $0.80 / 1,000 domain with contacts founds
Rating
0.0
(0)
Developer
Insight Solutions
Maintained by CommunityActor stats
0
Bookmarked
18
Total users
9
Monthly active users
9 hours ago
Last modified
Categories
Share
Extract emails from a list of websites. Give this Actor a list of domains and get back the business email addresses, phone numbers, LinkedIn and social profiles, contact-page URL and postal address for each one — one row per domain, as JSON, CSV or Excel.
It reads the sites' own public pages over plain HTTP: no browser, no proxy, no login, and no email verification pings of any kind. A typical domain costs one to four page fetches and finishes in a couple of seconds; 1,000 domains typically finish in a few minutes.
You are only charged for domains where we actually find something, plus a flat $0.0005 per run that finds any. Blocked sites, dead domains and sites with no published contact details cost you nothing.
Try it in 30 seconds
This is the Store prefill; paste it and run:
{ "domains": ["apify.com", "mozilla.org"], "maxPagesPerDomain": 4, "extractPhones": true, "extractSocials": true, "includePersonalEmails": false }
Bare domains, www. hosts and full URLs all work. A bare domain is resolved automatically across four permutations — https://, https://www., http://, http://www. — so a site that only answers on one of them is still found.
Output — one row per input domain, always, including the failures; the fields you will use most are domain, emails[], phones[], socials, contactPageUrl and found (full list under Output reference). A domain that could not be used comes back as a free row with found: false and a machine-readable error (blocked, dns, robots_disallowed, no_contacts, timeout, …) instead of a charge.
Price — ≈$1.50 per 1,000 domains with contacts on the FREE tier ($0.0015 each, + $0.0005 per run with a hit); blocked, dead, disallowed, timed-out and contact-less domains are free. Pay-per-event, no API key, no browser, no login, limited permissions — works over the Apify MCP server (mcp.apify.com) and with agentic (x402) payments.
From code — client.actor("insight.solutions/website-contact-extractor").call(run_input={"domains": ["apify.com", "mozilla.org"]}) with apify-client, or POST https://api.apify.com/v2/acts/insight.solutions~website-contact-extractor/run-sync-get-dataset-items.
Digging harder on sites that bury their details:
{"domains": ["example-manufacturer.de", "example-agency.co.uk"],"maxPagesPerDomain": 8,"contactPathHints": ["/contact", "/kontakt", "/impressum", "/about", "/legal"]}
What we extract from each website (and what we never touch)
This is the important section, so it is near the top.
We extract
- Role-based business addresses —
info@,contact@,sales@,support@,hello@,careers@,press@,office@,admin@, and their equivalents in German, French, Spanish, Italian, Portuguese and Polish (kontakt@,vertrieb@,ventas@, …). - Officer and owner mailboxes —
owner@,founder@,ceo@,cto@,director@,manager@,geschaeftsfuehrer@. These name a post, not a person: for an SMB list,owner@plumbingco.exampleis usually the address you wanted. - Non-personal generic addresses —
team@,bookings@,orders@,enquiries@. Business functions, not people. - Published business phone numbers, normalised to E.164.
- Company social profiles — LinkedIn, X/Twitter, Facebook, Instagram, YouTube, GitHub.
- The contact page URL, the postal address, and whether the site has a contact form.
We do not extract, by default
- Anything that is not a recognised business function. The filter is an allowlist, not a name detector: an address survives only if its local part matches a known role or generic business word (trailing digits ignored, so
sales2@andshop2024@still match). Everything else —jane.doe@,anna.k@,sarah_jones88@,wolfgang@— is classifiedpersonaland dropped before the row is written, and a given name anywhere in the local part beats a role word, soanna.sales@is personal too. Opt in withincludePersonalEmails. The cost is deliberate: an unusual but genuine business mailbox (kundenbetreuung@) can be dropped too. Losing a business address costs you recall; emitting a natural person's address costs you a GDPR problem. - Contact details attached to a person in structured data. If a page's JSON-LD marks an email as belonging to a
Person— a blog author, a quoted employee — we never read it, even whenincludePersonalEmailsis on. There is no switch for that one. - Names, in any field, ever. And
noreply@,donotreply@,bounce@and other addresses nobody can be reached at.
We never log in to anything, never ping SMTP or call any email-verification API, never ignore robots.txt (a site that disallows us gets found: false, error: "robots_disallowed" and is not charged), and never resell or retain your results.
Use cases
- Enrich a B2B lead list with contact details — feed the domains from your CRM and get emails, phones and LinkedIn back, one row per company.
- Get emails from a list of websites you already have — a scraped directory, a conference exhibitor list, a Google Maps export.
- Build an outbound list for an SMB vertical —
owner@,info@and a phone number is usually all a local-business campaign needs. - Find the LinkedIn and social profiles for a set of companies — attributed to the company, not scraped from a share button.
- Fill in missing phone numbers and postal addresses for records you already hold, normalised to E.164.
- Verify a supplier or partner list is still live — dead, parked and blocked domains come back labelled, free of charge.
How it compares
- You pay per domain where contacts were found, not per input row and not per page crawled. On a 1,000-domain list with an 85% hit rate that is 850 billable rows — the other 150 are in your dataset with a reason, at $0.00.
- ≈$1.50 per 1,000 domains with contacts, where listings in this category run to $25 per 1,000 results.
- GDPR posture by default, not as an afterthought. Role-based allowlist, no names in any field,
Person-marked JSON-LD never read, no SMTP probing,robots.txthonoured and reported. - One row per input domain, always — including failures, with a machine-readable
error. You can tell "we could not reach it" apart from "there was nothing there". - No headless browser. That is a deliberate trade: sites that assemble an address in JavaScript are a miss, and in exchange the Actor costs a fraction of a browser-based crawler and runs in seconds.
Input reference
| Field | Type | Default | What it does |
|---|---|---|---|
domains | array of strings | — (required) | Domains or URLs, one per line. Email addresses and bare IPs are rejected with a diagnostic row and never charged |
maxPagesPerDomain | integer 1–10 | 4 | Total pages fetched per domain, including the home page. The rest of the budget goes to the best-scoring contact/about/imprint links. Costs nothing extra — pricing is per domain, not per page |
contactPathHints | array of strings | /contact, /contact-us, /about, /imprint, /impressum, /legal | Paths we prefer to follow. Prefix matching, case-insensitive. Anchor text mentioning contact/about/imprint/kontakt is followed regardless |
includePersonalEmails | boolean | false | Also return person-shaped addresses. Read the GDPR note below before enabling |
extractPhones | boolean | true | Parse tel: links, JSON-LD telephone and visible text; normalise to E.164 |
extractSocials | boolean | true | Detect the six social platforms, normalised to the profile root |
requestTimeoutSecs | integer 5–120 | 20 | Per-request timeout. Lower it to move faster through lists with many dead domains |
maxRunSecs | integer 30–3600 | 240 | Wall-clock budget for the run. When reached, no further domains are started; the status message says how many were skipped, and skipped domains are never charged |
Output reference
One row per input domain — always, including failures. The dataset is never empty.
{"domain": "alpha-robotics.example","inputUrl": "alpha-robotics.example","resolvedUrl": "https://www.alpha-robotics.example/","redirectChain": ["https://www.alpha-robotics.example/"],"httpStatus": 200,"pageTitle": "Alpha Robotics — Industrial automation","emails": [{ "address": "info@alpha-robotics.example", "type": "role", "foundOn": "https://www.alpha-robotics.example/" },{ "address": "bookings@alpha-robotics.example", "type": "generic", "foundOn": "https://www.alpha-robotics.example/contact" }],"phones": [{ "raw": "+44 20 7946 0958", "e164": "+442079460958", "foundOn": "https://www.alpha-robotics.example/" }],"socials": {"linkedin": "https://linkedin.com/company/alpha-robotics","twitter": "https://twitter.com/alpharobotics","facebook": null, "instagram": null, "youtube": null,"github": "https://github.com/alpha-robotics"},"contactPageUrl": "https://www.alpha-robotics.example/contact","contactPageConfirmed": true,"addressText": "12 Kingsway, London, WC2B 6UN, GB","hasContactForm": true,"pagesFetched": ["https://www.alpha-robotics.example/", "https://www.alpha-robotics.example/contact"],"found": true, "error": null,"source": "www.alpha-robotics.example","sourceUrl": "https://www.alpha-robotics.example/","scrapedAt": "2026-09-08T09:14:02.117Z"}
Field notes
emails[].type—role(a named business function),generic(business-flavoured but off the canonical role list), orpersonal(only when you opted in). Sorted role first. Page text is read the way a browser lays it out, so an address at the end of a link never fuses with the next label.phones[].e164—nullwhen the number could not be validated. Numbers from atel:link are kept even when they do not validate, because the site declared them; numbers from body text are kept only when they validate, so prices, years and postcodes do not end up in your CRM.socials— always all six keys,nullwhere nothing was found. Share buttons, tweet-intent links and embedded videos are ignored. A profile is reported only with evidence the company owns it: JSON-LDsameAs, a handle matching the site's domain, or the same profile root on two pages. For LinkedIn, X/Twitter, YouTube and GitHub a link in the site's own header, footer or nav counts too; Facebook and Instagram keep the stricter rule.contactPageUrl/contactPageConfirmed— the best contact/imprint page identified, and whether we fetched it. Only a confirmed page counts as a hit, so a "Contact us" anchor that 404s never makes a domain billable.found—truewhen we found at least one email, phone, attributable social profile or a contact page we fetched. This is the flag that decides whether you are charged.error—nullon success, otherwiseno_contacts,blocked,robots_disallowed,dns,timeout,tls,connection,not_html,too_large,invalid_input, orhttp_<status>.
Accuracy and coverage
Roughly 85% of ordinary business websites yield at least one contact. That is an estimate derived from the failure modes below, not a published benchmark — your hit rate depends on the list you feed in. SMB service businesses do better than enterprise SaaS companies that route everything through a form.
| What stops us | Roughly | What you see |
|---|---|---|
| Site publishes no address at all — contact form only | 5–10% | hasContactForm: true, contactPageUrl set; billable only if that page was fetched |
| Cloudflare / bot wall / WAF blocking datacenter IPs | 10–15% | error: "blocked" |
| Email assembled by JavaScript at runtime | a few % | address simply absent |
| Dead, parked or expired domain | varies by list | error: "dns" |
robots.txt disallows us | rare | error: "robots_disallowed" |
What we handle that simpler extractors miss: Cloudflare data-cfemail encoding is decoded (arithmetic on served markup — we execute no JavaScript); name [at] example [dot] com and its (at) / {at} variants are de-obfuscated; JSON-LD Organization and ContactPoint blocks are parsed, including @graph and nested publisher; mailto: links with ?subject=, display names and multiple recipients parse correctly; contact pages are followed by path and anchor text in six languages; non-Latin imprint pages work, with no ASCII assumptions.
When a run reports FAILED. A run whose domains were all usable but produced nothing — a domain that does not resolve, a site behind a bot wall, a site that simply publishes no contact details — finishes SUCCEEDED with zero results, a status message that says so (0 domains with contacts. N diagnostic row(s) explain why — …), and a free row per domain telling you why in error; nothing is charged at all, start fee included (… Nothing was charged.). An input with no usable domain at all is reported in the status message and charged nothing. A run finishes FAILED only when the Actor itself hit an error.
Pricing
| Event | Free | Bronze | Silver | Gold |
|---|---|---|---|---|
actor-start — once per run, only after the first domain with contacts is delivered | $0.0005 | $0.0005 | $0.0005 | $0.0005 |
domain-with-contacts — per domain, only when contacts are found | $0.0015 | $0.0015 | $0.0011 | $0.0008 |
≈ $1.50 per 1,000 domains with contacts. Nothing for the misses.
Worked example. One run over 1,000 domains on the Free or Bronze tier, of which 850 yield at least one contact:
actor-start 1 × $0.0005 = $0.0005domain-with-contacts 850 × $0.0015 = $1.2750───────$1.2755
The 150 domains that were blocked, dead or empty are in your dataset, and cost $0.00.
You are not charged when the site is behind a bot wall (blocked), the domain does not resolve (dns), robots.txt tells us not to, the request times out or TLS fails, the input was an email address or an IP (invalid_input), the site loaded fine and simply publishes no contact details (no_contacts), we saw a "Contact us" link but the page budget ran out before fetching it, or the run hit maxRunSecs or your run-cost limit before reaching that domain. The one flat charge is actor-start, billed once per run and only after the first domain with contacts has been delivered to your dataset — a run that finds no contacts, or has no usable domain in it, costs nothing at all.
Use it from an AI agent, or from code
One JSON object in, one flat array out — the shape agent runtimes want. The Actor runs with limited permissions, uses pay-per-event pricing and never enters Standby, so it works over the Apify MCP server and with x402 agentic payments. The Integrations tab pushes results straight to Slack, a webhook, Zapier, Make, Google Sheets, Snowflake or BigQuery, and Apify Schedules run it unattended — contact details change slowly, so monthly is usually plenty.
curl -X POST "https://api.apify.com/v2/acts/insight.solutions~website-contact-extractor/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"domains":["apify.com","mozilla.org"],"maxPagesPerDomain":4}'
# pip install apify-clientfrom apify_client import ApifyClientclient = ApifyClient("<APIFY_TOKEN>")run = client.actor("insight.solutions/website-contact-extractor").call(run_input={"domains": ["apify.com", "mozilla.org", "example-agency.co.uk"],"maxPagesPerDomain": 6,})for row in client.dataset(run["defaultDatasetId"]).iterate_items():if row["found"]:emails = ", ".join(e["address"] for e in row["emails"])print(row["domain"], emails, row.get("socials", {}).get("linkedin"), sep=" | ")
GDPR / CCPA notes for operators
Read this before you switch includePersonalEmails on.
- The default output is business contact data. Role-based addresses like
info@andsales@identify a function, not a person — the least contentious category of contact data there is, and most EU regulators treat them as such. includePersonalEmailschanges that.jane.doe@company.comidentifies a natural person and is personal data under the GDPR and the CCPA/CPRA, regardless of having been published on a public web page.- If you enable it, you are the controller — not Apify, and not this Actor's developer. You need a lawful basis (usually legitimate interest, with a balancing test you can produce on request), you owe the Article 13/14 notice at first contact, and you must honour access, rectification, erasure and objection requests.
- Marketing to these addresses is a separate question. The GDPR governs whether you may hold the data; ePrivacy and national law govern whether you may email it, and several member states require prior consent for B2B email marketing regardless of your GDPR basis. CAN-SPAM is more permissive but still requires accurate headers and a working opt-out.
- We do not verify deliverability, so treat every address as unconfirmed.
Nothing here is legal advice. If you are running outbound at scale into the EU, get some.
FAQ
Do you check whether the email address actually works? No, and we will not add it. Verification means connecting to the recipient's mail server and probing for a mailbox — a different legal and technical posture, and what gets IP ranges blacklisted. We report exactly what the website publishes.
Why did a site come back blocked?
Its WAF refused a datacenter IP, or served a bot-check interstitial instead of the page. We detect both — including the awkward case where the interstitial is served with HTTP 200 — and report blocked rather than a row full of Cloudflare boilerplate. You are not charged.
Why is found true when emails is empty?
We found a phone number, a social profile attributable to the company, or a contact page we actually fetched. Any one is a usable route to the company. Filter on emails.length > 0 if you only want rows with an email.
My run SUCCEEDED but no domain has contacts.
Every domain either failed to load — DNS, timeout, TLS, refused connection or a bot wall — or answered and published nothing. The status message counts them (0 domains with contacts. N diagnostic row(s) explain why — 2 blocked, 1 dns …), and the rows are the diagnostics, with the reason in error. No domain was charged. If a big, varied list comes back all blocked or timeout, something upstream is wrong.
Can I feed it URLs from a sitemap or a crawl? Yes. Full URLs are used as given, fetched directly rather than through the permutation ladder. Duplicates are not merged, so de-duplicate your list first if you do not want to pay twice for the same company.
Does it follow links beyond the pages I allowed?
No. maxPagesPerDomain is a hard cap on total fetches per domain, home page included, and we follow only same-registrable-domain links that score as contact-ish. There is no recursive crawl.
Legal
- Public pages only. Everything this Actor reads is served to any anonymous visitor. We never authenticate, never supply cookies or session tokens, and never accept credentials as input.
- We honour
robots.txton every host we touch, and report a refusal as a result rather than working around it. No SMTP probing, no verification APIs. - We are not a data broker. This Actor holds no database and sells no list. It reads pages on demand and writes the result to your dataset on your account. We retain nothing.
- Not affiliated with, endorsed by or sponsored by any website you point it at, nor by Cloudflare, LinkedIn, X/Twitter, Meta, Google, YouTube or GitHub. Platform names are used descriptively, to say which link we detected.
- You are responsible for how you use the output. Compliance with the GDPR, the CCPA, ePrivacy, CAN-SPAM and applicable marketing law sits with you as the operator.
Our other Actors
Every Insight Solutions Actor is pay-per-result with no browser, no login and no API key, and every one of them returns free diagnostic rows instead of billing for failures. Prices are per 1,000 results.
Video, audio & social
- YouTube Transcript API — captions as timed segments, text, SRT or VTT, with language fallback and translation.
- YouTube Comments API — comments and replies with likes, pinned and hearted flags, newest or top sort.
- YouTube Channel API — a channel's videos, Shorts and live streams, plus YouTube search.
- Podcast Search, Episodes & Charts API — Apple Podcasts search, charts and full episode feeds.
- Bluesky Scraper — profiles, posts, followers and follows from the public AT Protocol API.
- Telegram Channel Scraper — posts, views and channel stats from public Telegram channels.
- Substack Scraper — posts with full free text, comments and publication profiles.
- Hacker News API — stories, comments, users, front page and a structured "Who is hiring?" parser from the official HN APIs.
- Discourse Forum API — topics, posts and categories from any Discourse community via its own JSON endpoints, usernames only.
News, documents & the web
- Google News Search, Topics & Real Article URLs — news search and topic feeds with the publisher's real URL decoded.
- Website to Markdown — Content Extractor for LLMs & RAG — any site as clean Markdown, text and heading-aware chunks.
- Internet Archive API — archive.org search, item metadata, files and reviews.
- Wayback Machine Toolkit — archived URL inventories, snapshots and text diffs between dates.
- Website Technology Detector — the tech stack behind any site, with the evidence for each detection.
- Domain Intelligence API — DNS, RDAP registration, TLS certificate and HTTP facts in one row per domain.
- SEO Page Audit — sitemap crawl with on-page checks, structured data and broken-link reports.
- Keyword Suggestions API — Google, YouTube, Bing, Amazon and eBay autocomplete with alphabet and question expansions.
- Web Search Results API — Bing and DuckDuckGo organic results with snippets, no key, no browser.
- Company Enrichment API — a domain in, a company profile out: firmographics, contacts, tech stack, DNS and hiring signal.
- Company Dossier API — one company in, twelve sections out: profile, tech, contacts, DNS, open roles, news, SEC filings, federal awards, recalls, YC batch and apps.
- Press Releases API — GlobeNewswire and PR Newswire releases plus any newsroom feed, by keyword, company, ticker or subject.
- Federal Register API — rules, proposed rules, notices and the Public Inspection desk with dockets, comment deadlines and CFR references.
- Academic Papers Search API — OpenAlex, Crossref, arXiv and PubMed in one row per paper: abstract, citations, open-access PDF, authors and venue.
- RSS & Atom Feed Monitor — any RSS, Atom or JSON feed (or an OPML file) in, only the new items out, with keyword filters and a webhook.
- Website Change Monitor — watch any pages, diff the text between runs, get change rows with added/removed lines, keyword alerts and a webhook.
- Wikipedia & Wikidata API — article text, search, daily pageviews and Wikidata entity facts, any language edition.
Business, finance & jobs
- Congress & Insider Trades API — STOCK Act periodic transaction reports and SEC Form 4 insider trades in one schema.
- Federal Contracts, Grants & Lobbying API — SAM.gov opportunities, USAspending awards, Grants.gov notices and Senate lobbying filings in one schema.
- SEC EDGAR API — filings, XBRL financials and full-text search by ticker or CIK.
- Clinical Trials & FDA API — ClinicalTrials.gov studies plus openFDA recalls, labels, approvals, 510(k)s and adverse-event reports.
- Product & Vehicle Recalls API — CPSC, NHTSA, FDA and USDA recalls, vehicle complaints and ratings, plus a VIN decoder.
- Y Combinator Companies, Batches & Founders — the YC directory with founders and social links, filterable by batch, industry and hiring status.
- Career Site Jobs API — jobs straight from Greenhouse, Lever, Ashby, Workable and 10+ other ATS career sites.
- New Job Postings Monitor — new, closed and changed postings on the career sites you watch.
- Hiring Signals API — Open Roles & Hiring Surge by Company — one row per company per run: open roles, what opened and closed, department and seniority breakdowns, and a hiring-surge flag.
- Remote Jobs API — RemoteOK, Remotive, We Work Remotely, Himalayas, Jobicy and more in one schema, deduplicated.
- Shopify Products API — any Shopify store's catalogue, variants, prices and stock signals.
- Shopify Store Monitor — price drops, sales, restocks, sell-outs and new products on any Shopify store, one row per change.
- Public Tenders API — EU TED, UK Find a Tender and Contracts Finder notices by keyword, CPV code, country, stage and deadline.
- Nonprofit & IRS 990 Lookup API — search US nonprofits and get EIN, NTEE code and multi-year Form 990 financials.
- OpenStreetMap Places API — businesses and points of interest by category and area from OpenStreetMap: name, address, coordinates, website, phone, opening hours.
Apps & games
- App Store & Google Play Reviews API — reviews from both stores with ratings, versions and developer replies.
- App Store Top Charts & App Search API — Apple top charts by country and genre, plus app search and details.
- App Store Keyword Rank Tracker — where any app ranks for any keyword on the App Store and Google Play, with rank changes and ASO suggestions.
- Steam Reviews API — Steam reviews with playtime, helpfulness and game details.
- Steam Game Data API — prices, tags, review scores, live player counts and top charts.