Skip to Content
REST APIWebsite contacts (emails)

Website contacts

The websitecontacts endpoint reads a business’s own website and returns the email addresses the business publishes there. One website in, one row out. It is live on production since 12 October 2026.

You call it through the bulk route POST /api/scraper/url-list-run or the MCP tool scrapewise_run_scraper_url_list, with endpointTag set to websitecontacts. There is no portal screen for it yet: you start it over REST or MCP, and read or export the rows like any other group data.

Endpoint tagwebsitecontacts (always send it, it is never detected from the address)
InputUp to 5,000 website addresses per JSON call
OutputExactly one row per website
Price2 credits (€0.0003) per website read, charged only for the statuses EMAIL_FOUND and NO_EMAIL_PUBLISHED
Free requestsNot included. The account needs a topped-up balance
Key scopeLLM_FULL. A read-only key is refused with 403

What it reads

For each website it fetches the home page, then up to two contact-type pages the home page itself links to (contact, imprint, about). The second of those is read only while no address has been found. That is at most 3 fetches and about 15 seconds per website.

The pages are fetched as plain pages. No browser is used, so an address that appears only after JavaScript runs is not found, and an address hidden behind email protection is not decoded. The status column says so, and such a row is not charged.

It returns every address the business publishes: addresses with a person’s name, free-mail addresses and role addresses such as info@. It leaves out addresses that belong to someone else: the web agency, the hosting company or the tax adviser credited on a legal page, cookie-banner vendors, and placeholders such as name@example.com.

Start a run

curl -X POST "https://portal.scrapewise.ai/api/scraper-api/api/scraper/url-list-run" \ -H "Authorization: Bearer $KEY" \ -H "Content-Type: application/json" \ -d '{ "groupId": "65f1c2a9e4b0a1b2c3d4e5f6", "name": "Cafes Tallinn - website emails", "endpointTag": "websitecontacts", "urls": [ "https://www.example.com/", "https://www.example.org/" ] }'
FieldRequiredDescription
groupIdyesThe group (folder) the rows are stored in
nameyesThe name of the list, at most 200 characters. When you retry a failed call, send the exact same name
endpointTagyes, for this endpointwebsitecontacts
urlsyes1 to 5,000 website addresses. Duplicates are collapsed and never charged twice

Each address must start with http:// or https://, use the default port and point at a public domain name. An address that does not (an IP address, a custom port, a name without a public domain ending) refuses the whole call with 400 INVALID_URL, the address is named, and nothing is saved or charged.

The other body fields (scraperId, rerun, force), the JSON Lines upload for more than 5,000 addresses, the response and the retry rules are the same as for every list run. See Create, fill and run in one call.

Response (200) is the usual list-run answer with "tag": "websitecontacts", the scraperId the rows appear under, and linksQueued. Rows arrive while the run goes.

Errors — 400 (INVALID_URL, LIST_TOO_LARGE, TAG_NOT_RESOLVED) / 401 / 402 (WALLET_INSUFFICIENT_BALANCE) / 403 (read-only API key) / 404 (GROUP_NOT_FOUND) / 409 (the list was already run, or is still running) / 429 (too many uploads at once) / 500.

Over MCP the same call is the tool scrapewise_run_scraper_url_list with the arguments { "body": { "groupId", "name", "endpointTag": "websitecontacts", "urls": [ ... ] } }. See Many URLs: one automation, one list.

Read the rows

Read them with GET /api/scraper/data/group/{id}, download Excel with GET /api/scraper/data/group/{id}/download, or open the group in the portal.

Columns

ColumnWhat it holds
websiteThe website address that was read
emailThe best address found: one on the website’s own domain first, one from a contact page before one from the home page
emails_allEvery accepted address, best first, joined with ; . At most 100 addresses
email_source_urlThe page the address in email was found on
domain_matchyes when the address in email is on the website’s own domain, no when it is on another domain (for example a free-mail address), unknown when the page was served from a different domain than the one you sent. Empty when no address was found
statusOne of the statuses below
checked_atWhen the website was read, in UTC

A row with an address looks like this (placeholder values):

{ "website": "https://www.example.com/", "email": "info@example.com", "emails_all": "info@example.com; booking@example.com", "email_source_url": "https://www.example.com/contact", "domain_match": "yes", "status": "EMAIL_FOUND", "checked_at": "2026-10-12T18:04:11Z" }

Statuses and what is charged

You pay for a website only when it was read in full and the answer is final: an address was found, or the business publishes none.

statusMeaningCharged
EMAIL_FOUNDAt least one address of the business was found on the pages readYes, 2 credits
NO_EMAIL_PUBLISHEDThe pages were read and the business publishes no address of its own on themYes, 2 credits
EMAIL_NOT_EXTRACTABLEThe only address on the pages is behind email protectionNo
PAGE_NOT_READABLEThe home page or a contact page could not be read as a page: it needs JavaScript, shows a bot check or a cookie wall, is a parked domain, or is too largeNo
SITE_UNREACHABLEThe website did not answer, or the domain does not existNo
SOCIAL_PROFILE_ONLYThe address is a profile on a social network or a marketplace, not the business’s own website. Nothing is fetchedNo
DAILY_LIMIT_REACHEDOne of the daily limits below was reached. Nothing is fetchedNo

An address that is not a usable public web address never becomes a row: the call is refused with 400 INVALID_URL before anything runs.

Price

2 credits per website read, whatever number of pages (1 to 3) it took. 1 credit is €0.00015, so one charged website is €0.0003 and 1,000 charged websites are €0.30. Only the two charged statuses cost anything.

The endpoint is not part of the free requests of a new account. An account that has never topped up gets no rows from it, only the message “Reading websites for contact details is not part of the free requests. Add funds to use it. Nothing was fetched and nothing was charged.”

Limits

Per account, per UTC day:

LimitValue
Websites read2,000
Reads that end in an uncharged status800
Reads of the same domain3

Above a limit the remaining rows come back as DAILY_LIMIT_REACHED, uncharged. Run them again the next day.

One JSON call takes up to 5,000 addresses. The endpoint works on a list as a run. It has no single-page preview.

What it does not do

  • No guessed addresses. It never builds an address from a pattern such as info@ plus the domain. Every address in a row was read on the page named in email_source_url, or on another of the pages read for emails_all.
  • No social profiles. A Facebook, Instagram or marketplace link is answered SOCIAL_PROFILE_ONLY and not read.
  • No third-party databases. Nothing is looked up in a contact database or bought in. The only source is the business’s own website.
  • No JavaScript rendering. Pages are fetched as plain pages.
  • No check that the mailbox exists. The address is what the website shows. No test mail is sent.
  • No names, job titles or phone numbers. The row holds email addresses only.

How often it finds an address

In our check of 12 October 2026, 14 of 20 small-business websites returned an email address, and the address in email was the right one on all 14. That is one check of 20 websites. Your list will differ.

From a Google Maps search to a leads list with emails

This takes two steps today, two separate runs. There is no single call that does both.

  1. Search Google Maps. Run your Maps searches, either as a scraper in the portal or with the MCP tool find_local_businesses. Each business is one row with name, address, phone and website. Google Maps itself holds no email addresses.
  2. Send the websites here. Take the website column, drop the empty cells, and send the addresses to POST /api/scraper/url-list-run with endpointTag: "websitecontacts". Join the two lists on website in your spreadsheet.

Rows whose website is a social profile cost nothing in step 2. The no-code walk-through is on the local business leads  page.

Using the addresses lawfully

These are addresses a business publishes on its own public website. Scrapewise reads public pages only and nothing behind a login. An address with a person’s name in it, or the address of a one-person business, is personal data, so how you store and use the addresses stays your own responsibility under GDPR. Cold email to businesses has its own rules in each country. This is not legal advice.

See also