# Website Email & Contact Scraper (`maximedupre/website-emails-scraper`) Actor

Find public contact emails on websites from URLs or company details. Get one unique, normalized email per row with its source page, plus phones, social links, and addresses when published.

- **URL**: https://apify.com/maximedupre/website-emails-scraper.md
- **Developed by:** [Maxime Dupré](https://apify.com/maximedupre) (community)
- **Categories:** Lead generation, Automation, Developer tools
- **Features:** Limited permissions
- **Stats:** 1,320 total users, 56 monthly users, 90.1% runs succeeded, 28 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

$8.95 / 1,000 email addresses

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### ✉️ Find public contact emails from website pages

For sales teams, lead researchers, and developers, Website Emails Scraper finds public contact email addresses on websites. You can give it website URLs or company details. It returns one clean row for each unique, normalized email, with the source page and the website it came from. Rows can also include public phone numbers, social profile links, postal addresses, and an optional mail server (MX) check. This helps you build contact lists without opening every page by hand.

- Collect public contact emails from submitted sites with **[website email scraper](https://apify.com/maximedupre/website-emails-scraper/examples/website-email-scraper)**.
- Save each address once with **[website emails: one row per unique email](https://apify.com/maximedupre/website-emails-scraper/examples/website-emails-one-row-per-unique-email)**.
- Check a seed and the pages it links to with **[website emails: shallow by default](https://apify.com/maximedupre/website-emails-scraper/examples/website-emails-shallow-by-default)**.
- Skip repeat addresses and repeat charges with **[website emails with duplicate-safe billing](https://apify.com/maximedupre/website-emails-scraper/examples/website-emails-duplicate-safe-billing)**.
- Test a short seed list before a larger crawl with **[website emails: small seed list first](https://apify.com/maximedupre/website-emails-scraper/examples/website-emails-small-seed-list-first)**.

#### 📬 See clean email rows with their source pages

Each saved row has an email address, the page where it was first found, the page title, and the seed URL that led to it. The email is accepted, normalized, and unique within the run. A row can also include public phone numbers with phone checks, social profile links, and a flag for disposable email domains. Turn on the mail server check to see if MX records were found for the email domain.

When available, rows can also include postal addresses, fax numbers, and company details from published structured contact data, plus published text near the email. This text can help you see what the contact is for. It does not prove mailbox delivery.

#### 🚀 Crawl a small set of pages first

**Quick start**

1. Open the [Input](https://console.apify.com/actors/3C5pf0e2XqFhVcSSj/input) tab. Choose how to supply websites, then add public website URLs or companies.
2. Leave the email limit empty or use `0` to return all available results until the source is exhausted. Set a positive limit when you want a smaller first run.
3. Run the Actor and open the dataset from the Output tab.

**What happens in a run**

The Actor checks each website and follows linked pages allowed by your path and domain settings. By default, it stays within each website. For company details, it first looks for the company website and checks it only when that website publishes the phone number you gave. It can read public contacts shown through JavaScript and common email forms such as `(at)` and `(dot)`. A blocked or unreadable page does not show whether the site has an email, and it does not create a saved email row. Pages blocked by `robots.txt` are skipped. The first eligible occurrence of each normalized email is saved. Later matches are ignored, so they do not create another row.

#### ⚙️ Input

Choose one way to supply websites with `findBy`, then fill in the fields for that choice. This example is copied from the public input of a successful current-beta default-input run.

**Input example**

```json
{
  "maxNbEmailsToScrape": 10,
  "findBy": "websiteUrls",
  "urls": [
    {
      "url": "https://www.w3.org/contact/"
    }
  ],
  "checkMailServer": false,
  "stayWithinWebsite": true
}
```

**Input fields**

| Field | Type | What it does |
| --- | --- | --- |
| `findBy` | string | How you supply websites: `websiteUrls` or `companies`. Only the fields for that choice are used. Defaults to `websiteUrls`. |
| `urls` | array of objects | For `websiteUrls`, a list of one or more public website URLs to check. The form prefills the one URL in the example; this is not a schema default. |
| `urls[].url` | string | A public HTTP or HTTPS website URL. A bare domain is also accepted and uses HTTPS. The Actor checks it and follows linked pages within your path and domain settings. |
| `companies` | array of objects | For `companies`, a list of companies to look up. The Actor checks contacts only when one website publishes the phone number you gave. A missing or unclear match gets a warning. |
| `companies[].name` | string | Required full company name. |
| `companies[].phone` | string | Company phone number. It is needed to confirm the website. Include the country code when known. |
| `companies[].city` | string | Company city. It helps find the website. |
| `companies[].address` | string | Company street address. It is used when no city is given. |
| `companies[].country` | string | Optional two uppercase letters, such as `US` or `GB`, used to read the phone number. Omit it to use `phoneCountryCode`. |
| `maxNbEmailsToScrape` | integer | Optional maximum number of accepted emails for the whole run. Use a positive integer to set a limit. Leave it empty or use `0` to return all available results until the source is exhausted. The form prefills `10`; this is not a schema default. |
| `checkMailServer` | boolean | Set `true` to check each saved email domain for MX records and add `domainReachable`. Each check has its own small charge. Defaults to `false`. |
| `phoneCountryCode` | string | Supported country code with two uppercase ISO letters for local phone numbers, such as `US`, `GB`, `CA`, `AU`, `DE`, `FR`, or `IN`. Omit it to use `US`. Numbers that start with + keep their own country code. |
| `includePaths` | array of strings | Limit linked pages to these path prefixes, such as `/contact`. Empty or omitted allows all paths; submitted URLs are still checked. |
| `excludePaths` | array of strings | Skip linked pages with these path prefixes, such as `/privacy`. Empty or omitted skips none; submitted URLs are still checked. Exclusions take precedence over included paths. |
| `stayWithinWebsite` | boolean | Keep linked pages within each website. Set `false` to also check other websites that these pages link to. Defaults to `true`. |
| `includeSubdomains` | boolean | Set `true` to allow linked pages across the same domain and its subdomains. `false` or omitted stays on each website host, with or without `www`. It applies when `stayWithinWebsite` is on. |

**Input rules**

Set the email limit for the whole run to a positive integer. Leave it empty or use `0` to return all available results until the source is exhausted. The email limit and page settings apply to every input choice. Path filters do not skip submitted URLs.

#### 🧾 Output

**Output fields**

Rows from website URLs and company details use this shape.

| Field | Type | What it does |
| --- | --- | --- |
| `email` | string | One accepted, normalized email address. It appears at most once per run. |
| `url` | string | Page URL where the first accepted match was found. |
| `seedUrl` | string | Website URL that produced the row. For company details, this is the matched website. |
| `pageTitle` | string | Published title of the page where the email was found. |
| `phoneNumbers` | array of strings | Public phone or fax numbers in E.164 format found anywhere on the source page, when available. They are not always marked as phone or fax numbers on the page. |
| `phoneValidation` | array of objects | Phone checks for the numbers found, when the country is known. |
| `phoneValidation[].number` | string | Phone number in international E.164 format. |
| `phoneValidation[].isValid` | boolean | Whether the number is valid for its country. |
| `phoneValidation[].countryCode` | string | Two-letter country code of the number. |
| `socialLinks` | array of strings | Public social profile links found on the source page, when available. Excludes post, reel, story, video, sharing, and intent links. The URL host identifies the platform. |
| `addresses` | array of strings | Postal addresses published in the website's structured contact data, when available. |
| `faxNumbers` | array of strings | Fax numbers in international format from published structured contact data tied to the email, when available. |
| `companies` | array of objects | Company details from published structured data tied to the email, when available. |
| `companies[].name` | string | Published company name. |
| `companies[].legalName` | string | Legal company name stated by the website. |
| `companies[].organizationType` | string | Organization type stated by the website, such as `Organization`. |
| `companies[].logoUrl` | string | Link to the logo published by the organization. |
| `companies[].vatNumbers` | array of strings | Published VAT identification numbers. |
| `companies[].addresses` | array of strings | Complete business addresses as published for the company. |
| `companies[].url` | string | Public page that supports the company details. |
| `contactContext` | array of strings | Published text near the email, such as a contact heading or company name, when available. |
| `isDisposableEmail` | boolean | Whether the email domain is on a list of disposable email domains. Left out when this check is not available. |
| `domainReachable` | boolean | Whether MX records were found for the email domain. Present only when `checkMailServer` is on and the check gives a result. |

**Example website row**

This complete row came from a successful current-beta run with the mail server check on.

```json
{
  "url": "https://novacoastmedia.com/",
  "seedUrl": "https://www.novacoastmedia.com/",
  "email": "contact@novacoastmedia.com",
  "companies": [
    {
      "name": "Nova Coast Media",
      "url": "https://novacoastmedia.com/",
      "organizationType": "Organization",
      "logoUrl": "https://novacoastmedia.com/wp-content/uploads/2025/08/cropped-Web-NOVA-COAST-MEDIA-LOGO-Sample-White-scaled-2.jpg",
      "addresses": [
        "92108, San Diego, CA, US"
      ]
    }
  ],
  "phoneNumbers": [
    "+18189341277"
  ],
  "socialLinks": [
    "https://www.youtube.com/@RickRyanPhotography",
    "https://www.instagram.com/novacoastmedia",
    "https://www.linkedin.com/company/nova-coast-medias"
  ],
  "phoneValidation": [
    {
      "number": "+18189341277",
      "isValid": true,
      "countryCode": "US"
    }
  ],
  "pageTitle": "Nova Coast Media | San Diego Real Estate Media",
  "addresses": [
    "92108, San Diego, CA, US"
  ],
  "isDisposableEmail": false,
  "domainReachable": true
}
```

#### 💳 Pricing

This Actor uses pay-per-event pricing. You are charged one event for each accepted, unique email address saved to the default dataset. When `checkMailServer` is on, each saved email that gets an MX result adds one small domain check event. See the Apify pricing panel for current rates.

**Buyer-facing events**

**Email address**

One accepted, unique email address is saved to your dataset.

**Domain check**

One saved email domain is checked for mail server (MX) records.

Empty searches, failed checks, company lookups, and setup work do not create an event. There is no separate Actor-start event in the pricing configuration. Duplicate addresses do not create another event.

#### 🔌 Integrations

Review rows in the Apify Console, read the default dataset with the Apify API, or export the dataset. This short guide shows a connected Actor workflow:

https://www.youtube.com/watch?v=bNACk1_S_6w\&list=PLObrtcm1Kw6MUrlLNDbK9QRg8VDJg0gOW\&index=4

#### ❓ FAQ

##### Will the Actor return phone numbers or nearby page text?

It saves accepted, normalized email addresses. A row can also include public phone numbers, social profile links, postal addresses, and published text near the email when available on the source page. Phone numbers come from the text, phone links, and structured contact data of the source page. Fax numbers written in page text are included. All rows from the same page get the same phone list, and dates are not read as phone numbers.

##### Can I start from company details instead of a website?

Set `findBy` to `companies` and add the company name with its phone number, plus a city or address. The Actor checks a website only when that website publishes the same phone number. If no website matches, or more than one matches, you get a warning and no rows for that company.

##### What happens when the same email appears on more than one page?

The Actor saves the first eligible occurrence of a normalized address. Later matches are ignored, so the saved row keeps the first source page and seed URL. Later matches do not create another row or charged event.

##### How far does it crawl?

It checks submitted URLs and follows links from each page it reads, within your path and domain settings. There is no fixed link-depth limit. Pages that cannot be read or are blocked by `robots.txt` can limit coverage. Use path filters and an email limit to keep a run focused. If the run gets close to its time limit, it stops early, keeps the saved emails, and logs a warning. Increase the run timeout to check more pages.

##### Can I limit the number of emails?

Yes. Set the email limit for the whole run to a positive integer. Leave it empty or use `0` to return all available results until the source is exhausted.

##### What if a submitted URL has no email or cannot be read?

Only accepted emails from public pages are saved. A blocked or unreadable page does not show whether the site has an email, and a missing row by itself does not explain why no email was saved.

Check the run logs to tell an empty search from a failed check. Other websites can keep running when one website cannot be checked. A run can fail if unresolved access errors prevent all website checks. Confirmed unavailable websites can end with no rows and a warning.

##### Does it access private pages or verify mailboxes?

No. It reads public pages only. Turn on `checkMailServer` to check MX records. MX records show that the email domain can route mail; they do not show that a specific mailbox is active or accepts messages.

##### How does this differ from an email finder?

This Actor starts with websites you supply, from URLs or company details, and finds emails published on those public pages. It does not guess emails from names, and it does not find websites by keyword.

##### What do `url` and `seedUrl` mean?

`url` is the page where the first accepted email match was found. `seedUrl` is the website URL that led to the row. It comes from your URL list or the website matched to your company details.

***

### 📝 Actor Release Notes

**v10.1** (11-11-2026)

- Phone numbers are now also read from the text of the page, not only from phone links and structured contact data. Fax numbers written in page text are included. Dates are not read as phone numbers.
- A number written without a `+` country code is now kept only when it matches a local phone format, including the leading prefix that format needs. Tax IDs, register IDs, and postal codes are no longer returned as phone numbers. Some phone links that leave out the `+` may no longer appear in `phoneNumbers`.

**v10.0** (30-10-2026)

- `spreadsheetUrls`, `datasetIds`, `websiteField`, `emailField`, `idField`, `keepFields`, and `onlyMissingEmail` are removed. `findBy` now offers only `websiteUrls` and `companies`, so the Actor no longer reads CSV or Excel files or Apify datasets. There is no replacement for reading files or datasets. Remove these keys from saved inputs. To keep checking those websites, list them in `urls`.
- `recordId` and `businessFields` are removed from rows, because they only came from the removed spreadsheet and dataset inputs. There is no replacement. Remove these keys from code that reads results.
- `contactFormUrls` is removed from rows, because it could not be filled reliably on every website. There is no replacement field. Remove this key from code that reads results.
- `companies[].legalForm`, `companies[].representatives`, and `companies[].registrations`, with its `court` and `number` fields, are removed, because they worked only on websites with a matching legal notice layout. There is no replacement field. Remove these keys from code that reads results.
- When you submit many websites, each website now gets a turn, so one large website no longer holds up the others.
- If the run stops at its time limit, each website it did not reach gets a warning.
- For company details, you now get a warning when the Actor could not check every possible website, so no match was confirmed.
- Reliability improvements.

**v9.0** (29-10-2026)

- `domainReachable` is no longer added by default. The mail server (MX) check now has its own small charge, so you choose when to pay for it. Set `checkMailServer` to `true` to keep getting `domainReachable`.
- Choose how to supply websites with `findBy`: website URLs, CSV or Excel files with `spreadsheetUrls`, Apify datasets with `datasetIds`, or company details with `companies`.
- For spreadsheet and dataset records, name the website field with `websiteField` and the email field with `emailField`. Keep a record ID with `idField` and other fields with `keepFields`. Turn on `onlyMissingEmail` to check only records with no email. Rows then include `recordId` and `businessFields`.
- For company details, the Actor checks a website only when one website publishes the phone number you supplied. A missing or unclear match gets a warning.
- Turn off `stayWithinWebsite` to also check pages on other websites that your websites link to.
- Rows can now include `pageTitle`, `addresses`, `contactFormUrls`, `isDisposableEmail`, and `phoneValidation`. Company details can include the organization type, legal name, logo URL, and addresses.
- `urls` is no longer required when you use another `findBy` choice.
- A website with a security setup that no browser can connect to is now reported as unavailable with a warning, instead of counting as a failed check.
- Reliability improvements.

**v8.0** (26-10-2026)

- `companies[].legalForm` and `companies[].registrations`, with its `number` and `register` fields, are removed. These fields only covered a narrow set of German company data. There is no replacement field. Remove these keys from code that reads results.
- Phone numbers now come only from phone links and structured contact data on the page. Numbers written only as plain page text are no longer returned.
- Emails are read only from page content that is shown to visitors. Emails in hidden page parts are no longer returned.
- A website that is down for every visitor, such as one that keeps returning a server error or closing the connection, is now reported as unavailable with a warning. It no longer fails the run by itself.
- Linked pages that do not finish loading are skipped, so the run keeps checking other pages.
- If the run gets close to its time limit, it stops early, keeps the saved emails, and logs a warning.
- An unsupported `phoneCountryCode` now gets a clear message that names the problem.
- Reliability improvements.

**v7.0** (26-10-2026)

- `companies[].representatives` is removed. Company details no longer include named representatives. There is no replacement field. Remove this key from code that reads results.
- `companies` and `faxNumbers` now come from structured contact data published on the page. Company details need a published legal name and a matching email. A legal notice alone no longer provides these fields. Handle missing company and fax details in code that reads results.
- Emails from click-to-reveal code and encoded page data are no longer read directly. Emails can still be found in public text, email links, supported structured contact data, or rendered content. Do not rely on encoded data alone to provide an email.
- Linked pages are checked throughout the crawl within your path and domain settings, rather than only from links on the submitted page. Set `includePaths` or `excludePaths` to control which linked pages are checked.
- Find emails written with `[at]` and `[dot]`, including spaces around these parts.
- Published addresses such as `support@yourdomain.com` and `hello@yourdomain.com` are no longer skipped just for their names. Reserved example domains are still excluded.
- Reliability improvements.

**v6.0** (25-10-2026)

- `emailAssessment` and its `role`, `websiteAffiliation`, `confidence`, and `explanation` fields are removed. Rows now use `contactContext` for published text near an email link, when available, instead of contact assessments. Update code that reads assessments to handle this text array. It does not provide assessed roles, website links, or confidence ratings.
- `companies` and `faxNumbers` are now limited to a narrow set of legal notice pages with a supported contact block. This keeps these details tied to a published contact block. Do not expect these fields from most websites; there is no replacement for them on other sites.
- Reading email addresses from click-to-reveal code is now limited to a narrow set of supported pages. Other pages can still return emails from public text, email links, structured page data, or rendered content. Do not rely on click-to-reveal code on other sites.
- Phone numbers can be read across line breaks and in more local formats. Legal reference numbers are no longer read as phone numbers.
- Published email addresses for outside contacts are no longer skipped just because nearby text names an authority or website designer.
- Separate links and lines are no longer joined to make an email address. Federated social handles are no longer read as emails.

**v5.0** (25-10-2026)

- `emailAssessment.confidence` now describes the public page evidence instead of returning `low`, `medium`, or `high`. This gives the basis for the assessment. Update code that reads these ratings to accept text.
- Per-site `urls[].userData.maxNbEmailsToScrape` limits are removed. Email limits now apply to the whole run. Remove this key from saved inputs. Use `maxNbEmailsToScrape` for a run-wide limit; there is no per-site replacement.
- `phoneCountryCode` now requires a supported uppercase country code. Unsupported or lowercase values stop the run without checking websites, so invalid phone settings are not used. Update saved inputs, such as `gb` to `GB`, or omit the field to use `US`.
- Set `maxNbEmailsToScrape` to `0` to leave the run-wide email count unlimited.
- Contact assessments can include roles from a published Inquiry / Contact table and a general inquiry address marked “if in doubt.” These assessments use first-party email addresses.
- Reliability improvements.

**v4.1** (09-10-2026)

- Email rows can include fax numbers and company details from public legal notices.
- Email rows can include a contact role or website link assessment based on public page evidence.
- Social profile links exclude more content and sharing links.
- Find emails written with `(at)` and `(dot)`.
- Linked contact and about pages are no longer limited to the first nine matches.

**v4.0** (08-10-2026)

- Choose a country code to read local phone numbers.
- Filter linked contact and about pages by path and, if needed, include subdomains.
- Find emails in structured page data and some click-to-reveal links.
- Pages blocked by `robots.txt` are skipped.
- `domainReachable` now reports whether MX records were found.
- `emailRole`, which used the email name as a role label, is removed. There is no replacement in this version. Remove this field from code that reads results.
- Runs need at least 2048 MB of memory.

**v3.0** (07-10-2026)

- Runs now need at least 512 MB of memory.
- You can enter a website domain without adding `https://`.

**v2.1** (27-09-2026)

- Email rows can include public phone numbers, social profile links, domain reachability, and email role context when available.
- Reliability improvements.

**v2.0** (10-09-2026)

- The `proxyConfiguration` input is removed because the Actor now manages access to public pages. Remove this key from saved inputs; there is no replacement setting.
- Fixed template addresses such as `support@yourdomain.com` and `hello@yourdomain.com` are not saved or charged.

**v1.0** (05-09-2026)

- You can limit emails for each website. Other valid sites keep running if one site fails.
- Each accepted email includes the page where it was found and the website URL you submitted.

**v0.0**

- Initial release.

***

### 🆘 Support

For issues, questions, or feature requests, [file a ticket](https://console.apify.com/actors/maximedupre~website-emails-scraper/issues) and I'll fix or implement it in less than 24h 🫡

***

### 🔗 Related Actors

- [Website URL Crawler & Link Extractor](https://apify.com/maximedupre/website-url-crawler) to find public page URLs that can become seeds for email crawls.
- [Product Hunt Launches Scraper](https://apify.com/maximedupre/product-hunt-scraper) to collect product websites and launch pages before checking them for public contact emails.
- [Company Domain Finder](https://apify.com/maximedupre/company-domains) to find likely company websites from company names before checking them for public emails.
- [Uneed Scraper](https://apify.com/maximedupre/uneed-scraper) to collect product websites and public contact data before a website email check.
- [Email MX Verifier](https://apify.com/maximedupre/email-mx-verifier) to check syntax and MX records after you collect email addresses.

***

**Made with ❤️ by Maxime Dupré**

# Actor input Schema

## `maxNbEmailsToScrape` (type: `integer`):

Optional maximum number of accepted emails for the whole run. Leave it empty or use 0 to return all available results until the source is exhausted.

## `findBy` (type: `string`):

Choose one way to supply websites. Only the fields for that choice are used. Omit this field to use Website URLs.

## `urls` (type: `array`):

For Website URLs, add one or more complete public URLs that start with http:// or https://. Replace the starter URL with your websites. You can add a country for a website that only opens from that country.

## `companies` (type: `array`):

For Company details, add each company name with its phone number. A city or address helps find the right website. Country is optional. The Actor checks contacts only when one website publishes the supplied phone number. A missing or unclear match is reported in a warning.

## `checkMailServer` (type: `boolean`):

Check whether the domain of each saved email address has mail server (MX) records. The result is saved with each email. Each check has its own small charge. Leave this off or omit it to skip the check.

## `phoneCountryCode` (type: `string`):

Choose a supported two-letter country code for local phone numbers, such as GB. Use uppercase ISO country codes. Omit this field to use US. Phone numbers that start with + keep their own country code.

## `includePaths` (type: `array`):

Limit linked pages to URL paths that start with a prefix you list, such as /contact/. Copy the path from a website link. Leave this empty or omit it to allow all paths. Excluded paths still take priority. Submitted URLs are still checked.

## `excludePaths` (type: `array`):

Skip linked pages with URL paths that start with a prefix you list, such as /privacy/. Copy the path from a website link. Leave this empty or omit it to skip none. These exclusions take priority over included paths. Submitted URLs are still checked.

## `stayWithinWebsite` (type: `boolean`):

Keep linked pages within each submitted or found website. Turn this off to also check pages on other websites that these websites link to. Omit this field to stay within each website.

## `includeSubdomains` (type: `boolean`):

Allow linked pages across the same domain and its subdomains. Leave this off or omit it to stay on each website host, with or without www. This choice applies when Stay within each website is on.

## Actor input object example

```json
{
  "maxNbEmailsToScrape": 10,
  "findBy": "websiteUrls",
  "urls": [
    {
      "url": "https://www.w3.org/contact/"
    }
  ],
  "checkMailServer": false,
  "stayWithinWebsite": true
}
```

# Actor output Schema

## `results` (type: `string`):

Accepted, normalized email addresses with source and seed URLs.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "maxNbEmailsToScrape": 10,
    "urls": [
        {
            "url": "https://www.w3.org/contact/"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("maximedupre/website-emails-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "maxNbEmailsToScrape": 10,
    "urls": [{ "url": "https://www.w3.org/contact/" }],
}

# Run the Actor and wait for it to finish
run = client.actor("maximedupre/website-emails-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "maxNbEmailsToScrape": 10,
  "urls": [
    {
      "url": "https://www.w3.org/contact/"
    }
  ]
}' |
apify call maximedupre/website-emails-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,maximedupre/website-emails-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/3C5pf0e2XqFhVcSSj/builds/fPrxzajGcK0Wf3tA5/openapi.json
