Website Contact Scraper — Email & Phone with a Billing Receipt
Pricing
$4.00 / 1,000 contact delivereds
Website Contact Scraper — Email & Phone with a Billing Receipt
Extract contact details — emails and phone numbers — from any website you supply. Priced per contact delivered, not per page crawled, with a full receipt reconciling pages fetched, contacts found, duplicates dropped, and units charged on every run.
Pricing
$4.00 / 1,000 contact delivereds
Rating
0.0
(0)
Developer
Drumlin Labs
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a month ago
Last modified
Categories
Share
Extract emails and phone numbers from a list of websites. Hand it a list of domains; get back every contact found, deduped, and a receipt showing exactly what was charged — so you can verify the bill yourself rather than take it on faith.
You are billed per contact delivered, not per page crawled: a page with 0 contacts costs nothing, and a page that takes many sub-requests to crawl still bills only for the contacts it yields. Per-delivered-item pricing is common in this category — what is not common is being able to check the bill. Every run writes a receipt reconciling what you sent against what you were charged, and your maximum cost per run is enforced as a hard stop before each charge rather than reported after it.
Correction, 2026-09-05. An earlier version of this page said per-contact billing was "the difference from every other scraper in this category". That was wrong: most actors in this category already bill per delivered item, and the claim overstated the difference. The receipt and the enforced ceiling are the actual differentiators, and they are what this page now claims.
Pricing
$0.004 per contact delivered — emails and phone numbers only. Refused URLs, failed fetches, and duplicates are never charged. Your maximum cost per run is a hard ceiling, not an approximation: work stops before the next charge would exceed it.
What it extracts
- Emails — from
mailto:links (highest reliability) and page text. Common false positives (image filenames, file paths) are filtered. - Phone numbers — from
tel:links. Text-extracted phone numbers are not billed because phone patterns in text produce too many false positives;tel:links are authoritative. - Social profile URLs — LinkedIn, X/Twitter, Facebook, Instagram, GitHub, YouTube. Reported for your information; social profiles are not billed.
What it refuses
Some sources use anti-bot measures or prohibit automated access in their terms of service.
URLs on those domains are refused before any fetch is attempted and appear in the dataset
with refused: true and a refusedReason explaining why. Refused URLs are never billed.
You will see in the BILLING_RECEIPT exactly how many URLs were refused and why.
Input
| Field | Type | Default | Description |
|---|---|---|---|
urls | array | — | Websites to crawl. Accepts https://example.com, http://example.com/contact, or bare example.com. Duplicates are removed before any fetch. |
concurrency | integer | 5 | Parallel requests (1–20). Higher is faster; lower is gentler on target sites. |
{"urls": ["https://example.com", "https://company.io/contact"],"concurrency": 5}
Output
One dataset row per input URL:
| Field | Description |
|---|---|
url | The URL that was crawled (or refused) |
hostname | Hostname extracted from the URL |
refused | true if this URL was refused by the denylist before any fetch |
refusedReason | Why the URL was refused, if refused |
fetchedOk | true if the page was fetched and parsed without error |
statusCode | HTTP status code from the server |
error | Error message if the fetch failed |
emails | Unique email addresses found on this page |
phones | Unique phone numbers found on this page (from tel: links) |
socials | Social profile objects: { platform, url } |
contactCount | emails.length + phones.length for this page |
newContacts | Contacts from this page that were new to the run (not already found on another page) |
A SUMMARY key-value record gives aggregate counts for the run.
Check your own bill: the billing receipt
Every run writes a BILLING_RECEIPT to the key-value store. Find it at
Storage → Key-value store → BILLING_RECEIPT or via API:
GET https://api.apify.com/v2/key-value-stores/<runKeyValueStoreId>/records/BILLING_RECEIPT
The same numbers appear at the end of the run log under --- billing receipt ---.
| Field | What it means |
|---|---|
eventName | The charged event — contact-delivered. |
delivered | Unique contacts (emails + phones) extracted and returned to you. |
billedEvents | Unique contacts actually charged. Compare against your invoice. |
duplicatesDropped | Contacts already found earlier in the same run — delivered once, charged once. |
failuresNotCharged | Extraction attempts that failed. Never charged. |
invalidNotCharged | Inputs that produced no billable contact — duplicate URLs, refused hosts and failed fetches. Never charged. |
skipReasons | Breakdown of skipped inputs by reason (e.g. how many URLs were refused and for which domain). |
budgetExhausted | true if your maximum cost per run stopped the work. |
deliveredUnbilled | Contacts already in flight when the cap was reached — delivered to you free. |
billingActive | false when pay-per-event pricing is not in effect — the run was free. |
coverageRatio | null — a URL list has no external denominator, so no coverage ratio is calculated. |
note | One sentence summarising the billing status. |
Reconciling the receipt against what you sent. Every URL you submit ends in exactly one of four places, and the two records together account for all of them:
URLs submitted = urlsCrawled + urlsRefused + urlsFailed + inputDuplicatesSkipped (SUMMARY)delivered = unique contacts returned to you (BILLING_RECEIPT)billedEvents = what you were charged for — never more than delivered
skipReasons in the receipt itemises every URL that produced nothing, by reason and by host, so a
refusal or a dead page is visible rather than merely absent. A URL that vanishes without appearing
in one of those counts is a bug — report it with the run ID and it will be treated as one.
If billedEvents exceeds the number of unique contacts you received, that is a bug — report
the run ID to support@drumlin.dev.
Honest limitations
- One page per URL. The actor fetches the URL as submitted. It does not follow internal links
or crawl a whole site. Submit a
/contactpage directly if that is where the contacts are. - JavaScript-rendered pages. The actor uses standard HTTP fetches. Content loaded dynamically after page load is not captured.
tel:links only for phones. Phone numbers in plain text are omitted because formatted phone patterns in prose produce too many false positives to bill on. Usetel:links for reliable phone extraction.- Results reflect the page at the moment of the run. Pages change.
About
Every result is checkable without trusting us: the receipt reconciles what was fetched, what was found, and what was charged, so an unexpected bill can be traced to a specific URL rather than disputed in the dark.
A Drumlin Labs tool — labs.drumlin.dev.
Support: support@drumlin.dev — the right address for a wrong result, an unexpected charge, or a refused URL you think should be allowed. Charges, invoices and refunds are handled by Apify as merchant of record, not through this address.