Contact Details Scraper: Pay Per Site, Not Page
Pricing
from $0.61 / 1,000 site with contacts returneds
Contact Details Scraper: Pay Per Site, Not Page
Extract website emails and contact details, and pay once per site with contacts, not per page read: phones, social profiles, company name, address, contact form and the page each value came from, one row per site. A site with no contacts comes back free and says why.
Pricing
from $0.61 / 1,000 site with contacts returneds
Rating
0.0
(0)
Developer
Pradio Actors
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
1
Monthly active users
9 days ago
Last modified
Categories
Share
What does Contact Details Scraper do?
Contact Details Scraper reads the websites you paste in and returns you one row per site with its emails, phones and social profiles. The row also carries the company name, postal address, contact form and the page behind each value. You pay $1.50 per 1,000 sites that return contacts, not per page read. A site that publishes none costs nothing, and its row says why.
Paste a list, get a contact sheet:
{"startUrls": [{ "url": "https://www.cas.org/contact" }],"proxyConfig": { "useApifyProxy": true }}
Who uses Contact Details Scraper
| Who | What they run it for |
|---|---|
| Lead-list builders | Turn prospect domains into email and phone columns for a campaign. |
| Lead-gen agencies | Hand clients a contact sheet where every miss carries its reason. |
| Sales-ops teams | Add dialable numbers and checked mail domains to account lists. |
| Solo founders | Get a niche contact list without maintaining a script. |
Features
- Priced per site, not per page. One charge for each site that returns contacts, however many of its pages were read.
- Every miss says why. A site with nothing to give still comes back as a row with its verdict and the pages read behind it.
- Contact pages found for you. It follows the site's contact, about, imprint, support and legal links, contact pages first. The sitemap joins in when you ask, common paths otherwise.
- Phones you can dial. Numbers arrive in international form wherever the country is known, including numbers printed in that country's own style.
- A short review pile. Phone-shaped strings that are not plainly the site's own sit in a separate list, at most 10 per row.
- Obfuscation decoded. It also reads addresses a site hides: masked forms, name-at-site spellings and JavaScript-assembled ones.
- Fifteen social networks. LinkedIn, X, Instagram, Facebook, YouTube, TikTok, Pinterest, Discord, Snapchat, Threads, Telegram, Reddit, WhatsApp, GitHub and Medium.
- External links collected. The off-site links a page publishes land in their own column, one per host. Query strings are stripped, and account, login and checkout pages are dropped.
- JavaScript sites rendered. An optional headless-browser pass reads pages that answer with an empty shell.
- Mail domains checked on request. Each email's domain is looked up for mail servers; nothing is sent.
What you can count on
- Every page is fetched the way a logged-out visitor gets it, and only paths the site's robots.txt allows are requested.
- Every entry gets a row: nothing on your list is dropped silently, even an address that cannot be read.
- A row is charged after it is written to your dataset.
- A run that finds nothing returns one row saying so.
- A spending limit ends the run cleanly, with a last row saying how many rows came back and how many did not.
- Every run saves you a summary of what it read, returned and charged, so a short run is easy to tell from a broken one.
- A site that fails to answer becomes its own miss row and the run still completes. A failure the run cannot start from fails it, with the error in the log.
- A value the site leaves unpublished stays null on the row.
Why this one
| Contact Details Scraper | Most-used alternative | |
|---|---|---|
| Rows on the example's first site | 1 | 1 |
| Phone column on that site | ✔️ a dialable phone | ❌ empty, held as an uncertain number |
| Price per 1,000 | $1.50 per site with contacts | $2.00 per page read |
| Start charge per run | $0.00005 | $0.001 |
Run on one of the three sites in the example (2026-10-05). The alternative bills every page it reads. A site answering on five pages costs five reads, while the same site is one charge here. Its row left the phone column empty and held the number as an uncertain one; ours carries it as a phone you can dial.
What data does Contact Details Scraper return?
One row per site. A data row can carry up to 47 fields and a miss row adds a reason field; with Merge contacts off, each fetched page is its own row. A real row, lists shortened:
{"summary": "Found 7 emails and 9 phones and 4 social profiles on /contact.","status": "found","domain": "cas.org","company_name": "CAS","address": "2540 Olentangy River Road, Columbus, Ohio 43202","emails": ["help@cas.org", "cas-pr@cas.org"],"emails_role_based": ["help@cas.org", "cas-pr@cas.org"],"phones": ["+18007534227", "+16144473731", "+6531252705"],"linkedIns": ["https://www.linkedin.com/company/cas"],"form_action_url": "https://www.cas.org/contact","url": "https://www.cas.org/contact","pages_read": 2}
Contact details:
| Field | What it holds |
|---|---|
emails | Addresses found on the site's pages: text, mailto links and decoded obfuscated forms. |
phones | Numbers in international form where the country is known; an unplaced one is kept as published when a tel: link or structured data carries it. |
phonesUncertain | Strings written like a phone that are not plainly the site's own, at most 10 per row. Glance before dialling. |
emails_role_based | The addresses a role answers (info@, sales@, support@), not a named person. |
emails_verified | With Check e-mail domains on: each address and whether it is well formed with mail servers on the domain. Null otherwise. |
form_action_url | Where the site's contact form posts, when it publishes one. |
external_links | Off-site links the pages publish, one per host, query strings stripped, account, login and checkout pages dropped, never followed; field_provenance names the page each came from. |
Social profiles, each link as the site publishes it:
| Field | What it holds |
|---|---|
linkedIns | LinkedIn company or profile links. |
twitters | X (Twitter) links; twitterProfiles carries the canonical form. |
instagrams | Instagram links; instagramProfiles carries the canonical form. |
facebooks | Facebook page links; facebookProfiles carries the canonical form. |
youtubes | YouTube channel links; youtubeProfiles carries the canonical form. |
tiktoks | TikTok profile links; tiktokProfiles carries the canonical form. |
pinterests | Pinterest profile links. |
discords | Discord server invite links. |
snapchats | Snapchat profile links. |
threads | Threads profile links. |
telegrams | Telegram channel or user links. |
reddits | Reddit community or profile links. |
whatsapps | WhatsApp contact links (wa.me). |
githubs | GitHub account links; a repository link is never read as the account. |
mediums | Medium profile or publication links. |
twitterProfiles | Canonical X profile URLs, x.com folded to twitter.com. |
instagramProfiles | Canonical Instagram profile URLs. |
facebookProfiles | Canonical Facebook page URLs. |
youtubeProfiles | Canonical YouTube channel URLs. |
tiktokProfiles | Canonical TikTok profile URLs. |
The site and the read:
| Field | What it holds |
|---|---|
company_name | The name the site gives itself. |
address | The postal address the site publishes, as one line. |
page_title | The title of the page this row was read from. |
url | The page this row's details were read from. |
contact_page_url | The same page; it names a same-site frame when the details sat inside one. |
referrerUrl | Your start page when this row's page was followed from it; null on the start page's own row. |
originalStartUrl | The website you entered that this row came from. |
domain | The site you named, even when it redirects elsewhere. |
depth | The link depth the row was reached at: zero for a URL you gave, one for a page it links to. |
pages_read | How many of the site's pages were read for this row. |
extraction_method | Which readers produced the row: text, links, structured data, frames, decoded obfuscation. |
field_provenance | Per field, the page and carrier each value was read from. |
obfuscated | True when the page hides its contacts behind masking or script assembly. |
summary | One plain sentence: what the read found, or why the row holds none. |
Row kind and counts:
| Field | What it holds |
|---|---|
status | found on a data row; the miss verdict on a miss row, explained under Output. |
row_type | ROW for data, ITEM_STATUS for a per-site miss, NO_CONTACTS_FOUND and STOPPED_EARLY for run-level notes. |
reason | On a miss row, why the site gave no contacts; on a run-level row, why the run ended that way. |
rowsFetched | On a status row: rows the source handed over before deduplication and the cap. |
rowsReturned | On a status row: data rows in the dataset. |
rowsRemaining | On a status row: fetched rows that were not returned. |
A null means the site left that field unpublished, or its page sat outside the read.
How much does it cost?
$1.50 per 1,000 sites that return contacts. One site is a single $0.0015 charge however many of its pages were read. The invoice and the Console name it page-returned. Sites that publish nothing, refused reads, status rows and dropped duplicates are never billed. Your run adds the platform's start charge of $0.00005.
With Merge contacts off, each fetched page is its own row and each page showing contacts is one charge. On paid Apify plans the per-site price drops: $0.001 at Silver, $0.00061 at Gold and above.
At the share measured on the test list, half of sites returned contacts:
| Sites you paste | Expected to answer | You pay | If every site answers |
|---|---|---|---|
| 100 | about 50 | about $0.08 | $0.15 |
| 1,000 | about 500 | about $0.75 | $1.50 |
| 10,000 | about 5,000 | about $7.50 | $15.00 |
Cap a run's spend with the platform's maximum-charge option; a status row reports what was left. The browser option wants 2048 MB of memory or more.
How do I use Contact Details Scraper?
- Open the Actor with Try for free on its Store page.
- Paste your websites into Start URLs, one per site; the three prefilled entries are a working example.
- Turn on what you need: Check e-mail domains (MX), Render JavaScript sites in a browser, Find contact pages in the sitemap, a Default country.
- Press Start, then export the dataset as JSON, CSV or Excel, or read it through the API.
curl -X POST "https://api.apify.com/v2/acts/Pradio~website-email-phone/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"startUrls":[{"url":"https://www.cas.org/contact"}],"proxyConfig":{"useApifyProxy":true}}'
How to scrape emails and phone numbers from websites
Use it to get emails and phones for a lead list, with mail domains checked:
{"startUrls": [{ "url": "https://www.lakelandleather.co.uk/contact-us" },{ "url": "https://www.cas.org/contact" }],"verifyEmails": true,"proxyConfig": { "useApifyProxy": true }}
Use it to read German shop sites and get numbers written in international form:
{"startUrls": [{ "url": "https://www.trigema.de" },{ "url": "https://www.stihl.de" }],"defaultCountry": "DE","proxyConfig": { "useApifyProxy": true }}
Use it to read contact pages that only draw their content in a browser:
{"startUrls": [{ "url": "https://www.dm.de/services/kontakt" }],"useBrowser": true,"proxyConfig": { "useApifyProxy": true }}
Use it to read only the contact, location and imprint pages, skipping careers and blogs:
{"startUrls": [{ "url": "https://www.acxiom.com" }],"includeUrlPatterns": ["/contact", "/locations", "/imprint"],"excludeUrlPatterns": ["/careers", "/blog/"],"useSitemap": true,"maxRequestsPerStartUrl": 12,"proxyConfig": { "useApifyProxy": true }}
Input
| Input | Type | Default | What it does |
|---|---|---|---|
startUrls | array | 3 example sites | The websites to read, one per site. Required. |
defaultCountry | string | empty | Two-letter code for numbers printed without a country code; empty takes it from each site's domain or page language. |
verifyEmails | boolean | off | Check each email's form and its domain's mail servers (MX); answers land in emails_verified. The Console's example ticks it. |
useBrowser | boolean | off | Render app-shell pages in a headless browser; a clean read with no contacts gets one browser pass. Needs 2048 MB or more. |
waitUntil | string | domcontentloaded | The load event the browser pass waits for: domcontentloaded, load or networkidle. Only used with useBrowser on. |
useSitemap | boolean | off | Also read the site's sitemap.xml for contact, about, imprint, support and legal pages, within the per-site request limit. |
includeUrlPatterns | array | empty | Path patterns to visit instead of the automatic page choice; the start URL is always read. |
excludeUrlPatterns | array | empty | Path patterns never to request. |
scrapeSocialMediaProfiles | object | all on | Per-network switches for the social links collected; it never looks the profiles up. |
considerChildFrames | boolean | off | Also read same-host embedded frames. |
mergeContacts | boolean | on | One row per site; off gives one row per fetched page. |
maxDepth | integer | 1 | How many link hops to follow for contact pages, at most 2. |
maxRequestsPerStartUrl | integer | 8 | The most requests to one site, at most 25; the sitemap counts too. |
maxRequests | integer | 100,000 | A request budget shared across the whole run, robots.txt reads included. |
sameDomain | boolean | on | Follow links on the site's own host only; off adds its other subdomains. |
maxItems | integer | 100 | The most rows a run returns, at most 10,000. |
proxyConfig | object | Apify Proxy | Where requests come from. Required. |
An entry that fails to parse as a URL comes back as a status row naming it. A social network's page is marked as bad input on its row. A site that fails to connect gets one retry on its other address form: the bare domain or the www one.
Output
Every site on your list gets a row. A data row has the status found. Any other verdict is a miss row, and its reason field says what happened:
status | What it means |
|---|---|
found | The row carries an email or a phone. The billed verdict. |
armored | The page hides its contacts behind obfuscation that did not decode. |
form_only | The site offers a contact form and nothing else; form_action_url says where it posts. |
none_published | The pages answered but publish no email, phone or form; social links found are still on the row. |
fetch_failed | The site gave no usable answer: a timeout, a failed connection or an error page. |
blocked | The site refused a request (401, 403, 429), showed a challenge page, robots.txt disallows the page, or the site is on the exclusion list. |
bad_url | The entry could not be parsed as a URL. |
bad_input | A repeat of an earlier entry in another spelling, a social network's page, or an input above its maximum. |
js_required | Every page read was a script-drawn shell, so no email or phone was readable; links and structured data still land on the row. |
aborted | The run's request budget ran out before this site. |
not_reached | The run's row cap was spent before this entry's rows could return. |
Rows also carry a type. A row is data, a per-site miss, a run that found nothing, or a run a spending limit stopped. A zero result is an answer too: the dataset holds one row saying the run found no contacts rather than an empty file. A stopped run's last row says how many rows came back and how many did not. Every run saves you a summary record in its key-value store with what it read, returned and charged.
On a test list of 116 business sites, run with the browser option on, 58 returned contact details (half). The rest came back with their reason. Thirty-five refused the visit, 13 failed to answer or returned an error page, and 8 published no email, phone or form. One stayed script-drawn even rendered, and 1 was a social-network page. Of the 58 rows that answered, an email filled 51, a phone 44, a company name 50 and a postal address 39.
What can you do with the data?
A lead-list builder pastes a night's prospect domains and gets back the email and phone columns for the campaign. Every miss arrives already explained, so nobody re-checks the dead ends by hand.
An agency hands a client a contact sheet of their member directory. The directory page's off-site links become the next run's Start URLs, and each member site comes back as its own row.
A sales-ops team cleans a call list. Phones arrive in dialable form, the shaky ones sit in their own column for a glance, and a mail-domain check skips addresses that cannot receive mail.
Use Contact Details Scraper with AI agents
claude mcp add --transport http apify "https://mcp.apify.com?tools=Pradio/website-email-phone"
One line registers this Actor with the Apify MCP server; your agent can then run it and read the rows it returns.
Personal data
You choose the sites, so you are responsible for your right to read them and for a lawful basis for any personal data the rows hold. Each row is the contact details a page itself publishes, read from the page you gave and the contact, about, imprint, support and legal pages it links to. Nothing is looked up or enriched beyond what the page shows. The off-site links it collects lose their query strings, so a token or session key cannot ride along. Those details can identify private individuals. Data-protection law can apply, including the duty to tell people where their details came from. The role-mailbox column helps you keep generic addresses and drop personal ones.
The Actor reads the public pages a logged-out visitor sees, and a site that refuses is left alone. Anyone can ask for a site or an address to be excluded. Open an issue on the Actor's public Issues tab naming the site or the page. A listed site is skipped before any request, and a listed address is removed from every row.
Release notes
- 2026-10-05: A site's channel pages (contact, about, imprint, support, help, privacy, terms, claims and locations) are read contact-first inside its request budget. Contact pages named in Spanish, Portuguese, Italian or German (contacto, contato, telefono, impressum) are found like the English ones.
- 2026-10-04: A thin script-drawn read gets a browser pass with the option on, a dropped connection is tried once more, and a bare-domain address that answers nothing tries its www form.
- 2026-10-03: Miss rows now say how many of the site's pages were read before the verdict. An entry the request budget or the row cap skips gets its own row.
- 2026-09-30: Every row opens with a one-line summary of what was found, and a thin-reading site can get one browser-rescue pass with the option on.
- 2026-09-29: A number printed the way the site's own country writes it now files as a dialable phone. An office mailbox like online@ files as role-based.
- 2026-09-28: Role addresses are read as tokens, and a phone printed with a slash alternative reads as two numbers.
- 2026-09-27: Multi-page reads, more social columns, and the source page carried on every contact.
Limits
- Refusals stop the site. A 401, 403 or 429 answer, a challenge page or a robots.txt disallow ends the site as a blocked row. Once a site refuses it is left alone for the rest of the run, whatever proxy, session or browser is set.
- JavaScript sites need the option on. Without it, script-drawn pages come back marked as needing a browser.
- Social networks are never read. A Facebook, LinkedIn or Instagram URL pasted in comes back as bad input. The Actor collects the links a site publishes to its own profiles.
- The crawl stays shallow. One link hop and 8 requests per site by default, 2 hops and 25 requests at most. A run returns 10,000 rows at most.
- Phones without a known country follow a fixed rule. A plainly published number in the North American shape lands in the phone list. A review-class one stays in the uncertain list. A number carried by a tel: link or structured data is kept as published.
- A mail server on the domain is not a mailbox. The check says the domain accepts mail; the address itself can still be wrong.
- Very large pages are read in part, and one request waits 20 seconds at most.
FAQ
What will a run cost me? $0.0015 for each site that returns contacts (each page with contacts, when Merge contacts is off), plus the platform's start charge per run. A refused, dead or empty site costs nothing.
How many pages does it visit per site? It reads the page you give it, then the contact, about and imprint pages the site links to. It stops at 8 requests per site, 25 at most, and a site's pages are read one at a time.
Can I use integrations with Contact Details Scraper? Yes. Apify integrations, Make and Zapier connect it to your stack, and a webhook can start a run when a new list lands.
Can I use Contact Details Scraper with the Apify API? Yes. The API starts runs and returns the dataset as JSON; the curl line under How do I use is a working call with your API token.
Can I use it through an MCP server? Yes. The AI-agents section above holds the one-line setup; after that your agent runs it like any other tool.
Is it legal to scrape websites for contact details? It reads the public pages the sites publish and follows each host's access rules. Whether collecting the data fits your purpose depends on your jurisdiction and use; the rows can identify private individuals, so read the Personal data section first. You are responsible for having the right to read the pages you give it and for how you use the rows.
What happens when a site blocks the run? The site comes back as a status row naming the refusal (a block page, a 401, 403 or 429). It is left alone for the rest of the run, never retried through another proxy, session, user agent or browser. The Proxy Config input routes the fetches through Apify's proxy pool.
How do I get support or report a problem? Open an issue on the Actor's Issues tab and we answer within two days. Feature requests go there too.
See also
- Imprint Contact: contact details from legal and imprint pages on company websites.
- Broken Link: scans the same sites for dead links and broken pages.
Feedback
A problem or a missing field goes to the Issues tab; we answer within two days. If this Actor saved you time, a review on the Store helps other buyers find it.
Not affiliated
Contact Details Scraper is an independent tool, not affiliated with or endorsed by Apify or by any website it reads.