Find emails from a list of websites in n8n with Apify
Ready-made template: n8n workflow (import JSON) (Google Sheets domains in, emails written back, joined on domain). All three variants are on the templates page.
n8n can reach Apify two ways: the Apify node (run an Actor, then fetch its dataset) and the plain HTTP Request node. For a bulk email lookup the HTTP Request node is the simpler design, because one call runs the Actor and returns the rows, so there is no polling step.
Use your own token. Create an API token in Apify under Settings, Integrations, and put it in the tool's secret or credential store. Never paste it into a shared sheet or a public workflow. The examples say YOUR_APIFY_TOKEN; replace it. Sending the token in the Authorization: Bearer header is safer than putting it in the URL, because URLs end up in logs.
Workflow: three nodes
- Source: any node that outputs one item per company with a
websitefield (Google Sheets, Airtable, a CSV read, a database). - Code node, mode "Run once for all items", to gather the sites into one request body:
return [{ json: { websites: $input.all().map(i => i.json.website), maxPagesPerSite: 4 } }]; - HTTP Request node: method POST, URL
https://api.apify.com/v2/acts/datagleaner~website-contact-details-scraper/run-sync-get-dataset-items, query parametersmaxTotalChargeUsd= 1 andfields=domain,bestEmail,status, a headerAuthorization=Bearer YOUR_APIFY_TOKEN(store the token as an n8n credential of type Header Auth rather than typing it into the node), body type JSON, body = the Code node's output. n8n splits an array response into one item per site.
The equivalent call, verified against the live Actor:
curl -X POST "https://api.apify.com/v2/acts/datagleaner~website-contact-details-scraper/run-sync-get-dataset-items?maxTotalChargeUsd=1&fields=domain,bestEmail,status" \
-H "Authorization: Bearer YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"websites":["basecamp.com","mozilla.org","sitemaps.org"],"maxPagesPerSite":4}'
Using the Apify node instead
The Apify node's Run Actor operation takes the Actor ID datagleaner/website-contact-details-scraper and the same JSON as input, and a Get Dataset Items operation then reads the results. Use it if you want long runs with a wait-for-finish step, or want Apify's own credentials flow. For a list of a few hundred sites the sync HTTP call is simpler. For thousands, split the list into batches of 200 with the Loop Over Items node so each call finishes in a few minutes.
Writing results back
Add a Merge node set to "Combine by matching fields" on domain (strip https:// and www. from your source first), then a Google Sheets or Airtable Update node. Match on domain, not position: the response order differs from the request order.
What comes back
A JSON array with one object per site. Output order is not guaranteed to match input order (in our test, sitemaps.org came back before mozilla.org), so always match rows on domain, never on position. A real response for three sites, with fields=domain,bestEmail,status,failureReason:
[
{"domain": "basecamp.com", "bestEmail": "jason@basecamp.com", "status": "ok", "failureReason": null},
{"domain": "sitemaps.org", "bestEmail": null, "status": "noContacts", "failureReason": "no_contact_found"},
{"domain": "mozilla.org", "bestEmail": "trademark-permissions@mozilla.com", "status": "ok", "failureReason": null}
]
Without fields each object is large (around 60 keys: every email with the page it was found on and a kind, phones, 14 social networks, contact-form URLs, pages crawled). Ask only for what you need. A site that publishes no email still returns a row, with bestEmail: null. Junk input such as "not a site" returns a row with status: "invalidUrl" instead of failing the call.
What it costs
The Actor charges $0.002 for each site where an email is found and nothing for sites without one. 1,000 sites with 600 hits is about $1.20, and a 4-site test is under a cent. Apify's free plan includes monthly credit. The maxTotalChargeUsd query parameter in the examples is a hard cap on what one call can spend: the run stops when it is reached, so a typo cannot cost more than you set. Expect an email on roughly half to two-thirds of small-business sites and less on large brands; in our five-site test three sites gave one.
Try it: Website Contact Details Scraper on Apify. $0.002 per site with an email, nothing for sites without. The Apify free plan includes monthly credit, so a test run costs nothing out of pocket.
Related guides
- Find emails from a website list in Clay with an HTTP API column
- Clay: find a contact email per row with the Run Apify Actor action
- Find emails from a website list in Make (formerly Integromat)
- Find emails from a company website in Zapier with Webhooks
- Find emails from a website list in Google Sheets (Apps Script)
- Find emails from company websites in Airtable (automation script)