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
4 days ago
Last modified
Categories
Share
Extract emails and phone numbers from a list of websites. Hand it 5,000 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.
The difference from every other scraper in this category: you are billed per contact delivered, not per page crawled. A page with 0 contacts costs nothing. A page that takes 800 sub-requests to crawl still only bills for the contacts it yields, not the pages it touched to get there.
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.