Website Contact Scraper: Emails, Phones & Social Links
Pricing
Pay per event
Website Contact Scraper: Emails, Phones & Social Links
Website contact scraper and email extractor for lead generation: company emails, phone numbers, social links, address and VAT IDs from a list of websites or a Google Maps dataset. Optional named people with job titles from team and impressum pages. Flat $3 per 1,000 sites.
Pricing
Pay per event
Rating
0.0
(0)
Developer
Rod Services
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
2
Monthly active users
18 days ago
Last modified
Categories
Share
Website contact scraper and email extractor for B2B leads: company emails, phone numbers and social links from any list of websites or a Google Maps dataset. Optional: the named people, such as managing directors and heads of sales, that a company lists on its own team and impressum pages. One clean row per company at a flat $3 per 1,000 websites, up to 5 pages per site included. People are an opt-in extra. No API key, no browser, GDPR-safe defaults.
What you get
- Company emails such as info@, sales@, office@ and support@, with the page they were found on and an MX check.
- Main phone number in E.164 format, ready for any dialer or CRM.
- Social links of the company: LinkedIn, X (Twitter), Facebook, Instagram, YouTube, TikTok and GitHub.
- Postal address, EU VAT IDs and company register numbers from the impressum or legal notice.
- Contact page and contact form URL.
- Named people, opt-in. Name, job title, seniority and the work email or phone printed next to the name, from the company's own team, about, impressum, contact and press pages. Every person carries the page it came from. See Named people.
- One row per website. Contacts from the homepage, contact, impressum, about and legal pages are merged, so there is nothing to deduplicate.
- Google Maps to contacts in 2 steps. Feed the dataset of a Google Maps, Apollo or directory scraper run directly. Rows without a website are skipped for free.
Why it is cheaper
Most contact scrapers charge per page crawled or per contact found. At 5 pages per site that is often $5 to $10 or more per 1,000 websites. This Actor charges one flat price per website: $3 per 1,000 on the Free plan, less on paid plans. The homepage plus up to 4 priority pages are included. You can raise the page limit up to 50 and the price stays the same. Websites that fail, for example DNS errors, timeouts or bot walls, are free.
Quick start
- Open the Input tab.
- Paste websites into Company websites or domains, one per line.
acme.comis fine. - Or pick a dataset in Dataset with websites, for example from a Google Maps Scraper run.
- Press Start. The prefilled example with 3 websites finishes in under 30 seconds.
- Open the Output tab. Pick the Overview, Emails, Social profiles or Company details view and export to CSV, Excel or JSON.
Google Maps to contacts in 2 steps
- Run a Google Maps scraper for your search, for example "dentists in Berlin". Copy the Dataset ID from the run's Storage tab.
- Paste it into Dataset with websites and press Start. The Actor reads the
websitefield of every place, skips Google Maps links and social profiles, and returns emails, phone and socials per company. Chains with many locations share a website, so they are crawled and billed once.
Other datasets work too. The Actor tries website, websiteUrl, website_url, companyWebsite, domain and url. Set Website field in the dataset for another name, for example company.website.
Input example
{"domains": ["apify.com", "https://www.hetzner.com", "pipedrive.com"],"datasetId": "aBcD1234eFgH5678i","urlField": "website","includePeople": false,"includePersonalEmails": false}
| Field | Default | Description |
|---|---|---|
domains | Company websites or domains. Duplicates and www variants are merged. | |
datasetId | Dataset of another run with a website field. Dataset ID or the dataset picker. | |
urlField | auto | Field that holds the website in that dataset. Dot paths work. |
includePeople | false | Return the named people the company lists on its own site. Read Named people first. |
maxPagesPerDomain | 5, or 8 with people | Homepage plus best matching priority pages, 1 to 50. Same price for any number. |
includePersonalEmails | false | Also return addresses of named people in the emails list. Read the GDPR section first. |
suppressionList | Emails, domains or SHA-256 hashes of people who objected. They are never returned. | |
extraCompanyDomains | Other email domains of the same companies, for example acme-group.com. | |
emailFinderHint | false | Add a ready-made Work Email Finder input to people without a named email. Nothing is called. |
includeAllPhones | false | Return every number found, max 20, not only the main company number. |
priorityPages | contact, about, impressum, imprint, kontakt, team, legal | Keywords for links worth following. Built-in ones also match translations. |
checkMx | true | DNS MX lookup for every email domain (mxFound). |
respectRobotsTxt | true | Skip pages disallowed by robots.txt. Always on with people. |
maxConcurrency | 10 | Websites crawled in parallel. |
proxyConfiguration | off | Optional. Apify datacenter proxy or your own proxy URLs. No residential. |
Named people (business roles only)
Turn on Include named people and every company row also carries a people list: the staff the company itself publishes on its own website, with name, job title, seniority and the work email or phone printed next to the name. Typical sources are the legally required impressum (Geschäftsführer, gérant, direktorius, managing director), team and about pages, press pages and schema.org data.
{"domain": "acme-widgets.co.uk","people": [{"fullName": "Tom Archer","jobTitle": "Chief Executive Officer","seniority": "c-level","roleGroup": "leadership","workEmail": "tom.archer@acme-widgets.co.uk","emailKind": "named","workPhone": null,"companyDomain": "acme-widgets.co.uk","sourceUrl": "https://www.acme-widgets.co.uk/team","extractedAt": "2026-10-07T10:00:00.000Z","emailFinderHint": null}],"peopleCount": 1,"peopleTruncatedByBudget": false}
The People view in the Output tab lists one row per person.
The rules this mode follows
- Only the website you gave. Pages of the same company domain, robots.txt always respected, even when you switch the robots setting off. No login, no CAPTCHA or bot-protection bypass, no residential proxies, and no LinkedIn or any other social network. Pages behind a bot wall are skipped.
- Business data only.
fullName,jobTitle,workEmail,workPhone,emailKind,companyDomain,sourceUrlandextractedAt, plusseniorityandroleGroupderived from the title. No photos, no biographies, no birthdays, no private handles, and nothing is inferred about gender, origin, religion, health or union membership. - Work emails only. An address is returned only when it sits on the company's own domain, or on a domain you list in
extraCompanyDomains, and only when it fits the name next to it. Free webmail (Gmail, Outlook, GMX, inbox.lt and dozens more) is never returned. A shared mailbox such as sales@ next to a person is markedemailKind: "role". A phone is kept only when it stands next to that person. sourceUrlon every person. You need it for your GDPR notice, see below.- Suppression. Put every objection into
suppressionList, as an email, a domain or a SHA-256 hash of one. Matching people are removed before output. Plain values are hashed in memory and not kept. - Nothing is stored. The Actor writes only to your own run's dataset. Logs hold counts, never names or addresses. There is no cache and no database across runs. The run summary (
SUMMARYrecord) holds counts and a lawful basis note. - Off by default. Without
includePeoplethe output is as before: role mailboxes only. Personal data stays out unless you ask for it.
People are capped at 50 per company, ranked by seniority and then by named email. The Actor never guesses or builds addresses from name patterns. For people without a named email, the optional emailFinderHint gives you a ready-made input for the Work Email Finder Actor. This Actor never calls it.
Who is responsible: controller and processor
You are the controller of the people data in your dataset. You choose the websites and the purpose. This Actor acts as your processor under Apify's Standard Actor Contract: it processes only on your instruction, keeps no copy and shares nothing. That only holds as long as you pick the targets and use the output yourself. This is not legal advice.
What you need to do as the controller:
- A lawful basis. For B2B outreach this is usually legitimate interest (Art. 6(1)(f) GDPR). Write down a short balancing test. The data is limited to name, role and work contact, taken from a page the company published for that purpose.
- Tell each person (Art. 14 GDPR) at first contact or within one month at the latest. Name the source: use
sourceUrl. A public register or website does not remove this duty. - Honour objections. The right to object to direct marketing is absolute (Art. 21(2)). Add the person to
suppressionListand keep it for every later run. - Do not keep stale people. Re-run and delete people who vanished from the company page. Do not hold the data longer than you need it.
- Respect marketing rules where you send. See the country notes below.
Privacy notice and country notes
Short, practical notes. Check them with your data protection officer.
| Country | What matters for B2B outreach to the people you find |
|---|---|
| Germany | Advertising email needs prior consent, also B2B (UWG section 7(2) no. 2). Do not cold-email German addresses. Impressum names are published to identify the provider, not as an invitation to marketing. |
| France | B2B email is allowed on legitimate interest when the message relates to the person's job. The person must be informed and able to object easily. Generic addresses (info@, contact@) belong to the company and fall outside these rules. |
| Lithuania | After the 2026 change to the Electronic Communications Law (Art. 81), no prior consent is needed for a legal-person subscriber, but an easy opt-out is required. Sole traders are natural persons, so apply the stricter rules to them. |
| Poland | The Art. 14 notice applies even to data from public sources. The regulator reads the "disproportionate effort" exception narrowly. Plan the notice. |
| Other EU countries | Art. 14 and Art. 21 apply everywhere. Marketing rules differ by country, some require consent for B2B email. Check before you send. |
Also: no unsolicited bulk mail. Apify's acceptable use policy and the ePrivacy rules of your country apply to you as the sender.
Run summary. With people on, the SUMMARY record of the run holds counts (peopleReturned, peopleWithNamedEmail, peopleSuppressed, offDomainOrWebmailEmailsDropped) and a lawfulBasisNote that repeats the duties above, so it travels with your export.
Personal emails are off by default
By default the Actor returns only generic role mailboxes such as info@, sales@ and office@, plus the company's main phone. Addresses of named people, such as jane.doe@, are not returned. Each row shows how many were hidden in personalEmailsHidden. Turn on Include personal email addresses to get them too. Then you are the data controller for that personal data, see the GDPR section below.
Output sample
One item per website. The Emails view gives one row per address, handy for a CRM import.
{"domain": "hetzner.com","inputUrl": "hetzner.com","url": "https://www.hetzner.com/","companyName": "Hetzner Online GmbH","emails": [{"email": "info@hetzner.com","type": "role","sourceUrl": "https://www.hetzner.com/unternehmen/ueber-uns/","mxFound": true}],"phones": [{"e164": "+4998315050","raw": "+49 (0)9831 505-0","sourceUrl": "https://www.hetzner.com/unternehmen/ueber-uns/"}],"socials": {"linkedin": "https://www.linkedin.com/company/hetzner-online","x": "https://x.com/hetzner_online","facebook": "https://www.facebook.com/hetzner.de","instagram": "https://www.instagram.com/hetzner.online","youtube": "https://www.youtube.com/user/HetznerOnline","tiktok": null,"github": null},"address": null,"vatIds": ["DE812871812"],"registrationNumbers": ["HRB 6089"],"contactPageUrl": "https://www.hetzner.com/support/","contactFormUrl": null,"personalEmailsHidden": 3,"pagesCrawled": 5,"httpStatus": 200,"error": null,"scrapedAt": "2026-09-27T12:09:22.452Z"}
Data fields
| Field | Description |
|---|---|
domain | Company domain without www. |
companyName | From schema.org Organization, the copyright line, og:site_name or the page title. |
emails | { email, type: role or personal, sourceUrl, mxFound }. Company domains first, third parties removed. |
phones | { e164, raw, sourceUrl }. Main company number by default. Fax numbers are never returned. |
socials | Company profile per network: linkedin, x, facebook, instagram, youtube, tiktok, github. |
address | { street, postalCode, city, region, country, formatted } from schema.org Organization/LocalBusiness. |
vatIds | Validated EU VAT formats (DE123456789, ATU12345678, NL123456789B01...), UK VAT and Swiss UID. |
registrationNumbers | Register entries as printed: HRB 12345, Company No. 01234567, KvK, KRS, SIREN, IČO, CVR and more. |
contactPageUrl | The contact page that was crawled. |
contactFormUrl | Page with a contact form (HTML form with a message field, or HubSpot/Typeform/Jotform embeds). |
personalEmailsHidden | How many personal addresses were seen but not returned. |
people | Only with includePeople: { fullName, jobTitle, seniority, roleGroup, workEmail, emailKind, workPhone, companyDomain, sourceUrl, extractedAt } per person. |
peopleCount | Number of people in people. |
peopleTruncatedByBudget | true when the maximum cost per run cut the list short. |
pagesCrawled | HTML pages read for this domain. |
error | Why a domain failed (DNS, timeout, bot protection, robots.txt). Failed domains are free. |
How the extraction works
- Emails come from
mailto:links, visible text, schema.org and Cloudflare-protected addresses. Obfuscated forms likeinfo [at] acme [dot] com,info(at)acme.deorkontakt (at) firma (punkt) deare decoded. Image names likelogo@2x.pngand tracker IDs are ignored. - Role vs personal: the local part is compared with a multilingual list of shared mailboxes (info, sales, office, support, kontakt, vertrieb, datenschutz, pardavimai, myynti...).
- Phones are normalised with libphonenumber to E.164. The country is guessed from the domain TLD, the schema.org address or the page language. Numbers in national format count only next to a "phone" keyword, so order numbers and dates are not mistaken for phones.
- Social links are only collected from links on the company website. Share buttons, single posts and personal LinkedIn profiles (
/in/) are ignored. When several profiles exist, the one in the header/footer that matches the brand wins.
Pricing
Pay per event. You pay for websites processed, not for compute time or pages. Discounts apply automatically on paid Apify plans.
| Event | Free plan | Bronze | Silver | Gold |
|---|---|---|---|---|
| Website processed, per 1,000 | $3.00 | $2.70 | $2.40 | $2.10 |
| Named person found, per 1,000 | $4.00 | $3.60 | $3.20 | $2.80 |
| Run start, per run | $0.001 | $0.001 | $0.001 | $0.001 |
- 1,000 websites cost about $3.00 on the Free plan, whether the Actor reads 1 page or 5 pages per site.
- Named people cost $0.004 each, only when you turn the option on. A company without a listed person costs nothing extra. The price list with this event takes effect on 2026-10-21. Until then people are returned at no extra charge.
- With people on, the Actor never returns more people than Maximum cost per run pays for. The row is marked
peopleTruncatedByBudget. - Failed websites are free: DNS errors, timeouts, bot walls and robots.txt blocks are listed but not charged.
- Set Maximum cost per run in the run options to cap spend. The Actor stops when the limit is reached.
- The Apify free plan's monthly credit covers over a thousand websites.
Use it from code, Make, Zapier or AI agents
Run it through the Apify API, the JavaScript and Python clients, schedules, webhooks, or integrations such as Make, Zapier, n8n, HubSpot and Google Sheets. AI agents can call it through the Apify MCP server at mcp.apify.com.
curl -X POST "https://api.apify.com/v2/acts/rod_analytics~company-contact-extractor/run-sync-get-dataset-items" \-H "Authorization: Bearer <YOUR_APIFY_TOKEN>" -H "Content-Type: application/json" \-d '{"domains": ["acme.com", "example.org"]}'
To check the emails you found, send the dataset ID to the Email Validator & Verifier. It reads the emails field directly.
GDPR, ePrivacy and responsible use
This Actor is built for B2B use and follows privacy by design:
- Named people are a separate opt-in with their own rules, see Named people.
- Default mode returns only generic role mailboxes (info@, sales@, contact@, hello@, office@, support@ and similar) and the company's main phone number. Addresses and phone numbers of named employees are not returned; only their count is (
personalEmailsHidden). includePersonalEmailsis off by default. If you switch it on, the output can contain personal data under the GDPR (for example jane.doe@company.com). You are the data controller for that data. You need a lawful basis (for example legitimate interest for B2B outreach, documented in a balancing test), must inform the people concerned (Art. 14 GDPR), honour objections and deletion requests, and follow ePrivacy / national marketing rules (in many EU countries cold emails to individuals need prior consent). If you cannot meet these duties, keep the option off.- No guessing. The Actor never generates, permutes or guesses email addresses (no
firstname.lastname@patterns). It only reports what the company itself publishes on its website. - No social network scraping. LinkedIn, Facebook, X, Instagram, TikTok, YouTube and GitHub are never visited. The Actor only reads links that appear on the company's own site. LinkedIn profile links of people are not returned.
- Polite crawling. robots.txt is respected by default and always with people on, at most 2 parallel requests per site, a few pages per domain. Bot walls are skipped, never bypassed.
This is not legal advice. Check your use case with your data protection officer.
FAQ
Does it work on JavaScript-only websites? It reads the server HTML without a browser. Sites that build their menu only with JavaScript may return fewer pages. Contacts in the footer or in schema.org data are usually still found.
Why is an email I can see on the site missing? Addresses on other companies' domains, such as agencies, regulators or partners, are removed on purpose. Personal addresses need Include personal email addresses.
Why is a person missing, or why has a person no email? The Actor reads only what the company prints on its own pages. A person with a Gmail address, an address on another domain, or an address that does not fit the name gets no workEmail. Photos-only team cards, people loaded by JavaScript and PDF org charts are not read. Customers, reviewers and blog authors are skipped on purpose.
How do I remove a person who objected? Add the email or the company domain to suppressionList and re-run. The list works on every run, so keep it. Plain values are hashed at the start of the run, or you can pass SHA-256 hashes.
Some big sites fail with 403. Why? About 10 % of large corporate sites block datacenter IPs. Those rows are free. Try Apify datacenter proxy or your own proxy URLs for them.
Which proxies can I use? No proxy, the default, Apify datacenter proxy or your own proxy URLs. Residential and SERP proxies are not supported. A run that asks for them stops at the start with a clear message.
What happens if my input is wrong? The run ends SUCCEEDED with one free help row: error, errorCode, message and howToFix. Only the start fee is charged. Codes: no-valid-domains, dataset-unreadable, no-websites-in-dataset and unsupported-proxy.
Is scraping company websites legal? Reading publicly available business contact information is generally allowed, but you are responsible for how you store and use the data. Respect the websites' terms, robots.txt and privacy laws.
Found a bug or need a custom field? Open an issue on the Issues tab. Replies usually come within a day.