# Etsy Email Scraper (`w3crawler/etsy-email-scraper`) Actor

Read bounded public Etsy pages and return publicly visible contact evidence, shop links, and listing links without inferring or fabricating seller emails.

- **URL**: https://apify.com/w3crawler/etsy-email-scraper.md
- **Developed by:** [w3crawler](https://apify.com/w3crawler) (community)
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.99 / 1,000 emails

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## Etsy Email Scraper

Inspect bounded [public Etsy pages](https://www.etsy.com/shop/GeekTropicalOfficial) for email addresses that are explicitly visible in the page text or in a `mailto:` link. Each saved row also returns the public page title, unique shop and listing links found on the page, and a short evidence excerpt for every email. The Actor does not infer an address from a shop name, a domain, or an account record.

### Get started

1. Open the [Actor Store page](https://apify.com/w3crawler/etsy-email-scraper) and select **Try for free**, or open the **Input** tab.
2. Add public Etsy shop, listing, search, market, or homepage URLs to `startUrls`.
3. Keep `maxItems` small: it caps how many of those URLs are inspected, and each URL costs one request plus limited retries.
4. Start the Actor, inspect the dataset, and open **Run summary** (`OUTPUT`) to see how many pages were verified, how many emails were found, and whether any page failed. You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

### Input

All fields are optional, and the defaults below are ready to use. Unsupported field names and out-of-range values are rejected before requests start.

| Field | Type | Required? | Default | Meaning |
| --- | --- | --- | --- | --- |
| `startUrls` | string array | Optional | `["https://www.etsy.com/shop/GeekTropicalOfficial"]` | Public HTTPS Etsy shop, listing, search, market, or homepage URLs. Duplicate strings are ignored. |
| `maxItems` | integer | Optional | `10` | Maximum number of source URLs inspected, from 1 to 100. URLs beyond this cap are not requested. |
| `timeoutSecs` | integer | Optional | `30` | Per-URL request timeout, from 5 to 120 seconds. |
| `requestDelayMs` | integer | Optional | `500` | Polite pause between consecutive Etsy requests, from 0 to 5,000 ms. |
| `maxRequestRetries` | integer | Optional | `1` | Retries for ordinary request failures, from 0 to 2. |
| `proxyConfiguration` | object | Optional | `{"useApifyProxy":true}` | Standard Apify Proxy configuration. Direct access is attempted when the object is omitted; no challenge bypass is attempted. |

Example input used for the saved run:

```json
{
  "startUrls": [
    "https://www.etsy.com/shop/GeekTropicalOfficial"
  ],
  "maxItems": 1,
  "timeoutSecs": 30,
  "requestDelayMs": 0,
  "maxRequestRetries": 1,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

The saved run inspected one shop page; the schema default is ten pages. Requests are serialized and separated by `requestDelayMs`, with retries limited to transient failures. The Actor reads public HTTPS Etsy HTML only. It does not sign in, submit contact forms, follow external links, call private endpoints, solve CAPTCHAs, or bypass an access decision. Optional Apify Proxy settings are used when supplied. Diagnostic detail for blocked or failed pages is kept in the run logs and summary, never in a dataset row.

Shorter variations use the same fields:

```json
{
  "startUrls": [
    "https://www.etsy.com/shop/GeekTropicalOfficial",
    "https://www.etsy.com/market/best_sellers"
  ],
  "maxItems": 2
}
```

```json
{
  "startUrls": [
    "https://www.etsy.com/listing/1461506381/24-day-elf-kit-2025-best-seller"
  ],
  "maxItems": 1,
  "includeDiagnostics": true
}
```

```json
{
  "startUrls": [
    "https://www.etsy.com/shop/GeekTropicalOfficial"
  ],
  "maxItems": 1,
  "timeoutSecs": 45,
  "maxRequestRetries": 0
}
```

### Output

The dataset contains one row per verified public page that was successfully fetched. A page with no visible email still produces a row, with `emails` and `emailEvidence` set to `null`, `emailCount` set to `0`, and `publicContactFound` set to `false`. A page that cannot be verified produces no row and is counted in `diagnosticCount`.

| Field | Type | Availability | Meaning |
| --- | --- | --- | --- |
| `platform` | string | null | Always | Source platform; `Etsy`. |
| `pageType` | string | null | Always | Verified page kind; `public_contact_page` for saved rows. |
| `sourceUrl` | string | null | Always | Exact public Etsy URL submitted in `startUrls`. |
| `pageUrl` | string | null | Always | Final public URL after ordinary redirects, such as a regional Etsy host. When the URL was read from a public Internet Archive capture, this is the Wayback replay address. |
| `pageTitle` | string | null | When the page has a title | Public HTML title, trimmed to a readable length. |
| `emails` | string array | null | When a visible email is found | Unique lowercased email addresses found in visible text or `mailto:` links, up to 50 per page. |
| `emailCount` | integer | null | Always | Number of addresses in `emails`; `0` when the page exposes none. |
| `publicContactFound` | boolean | null | Always | Whether at least one visible public email was found on the page. |
| `emailEvidence` | object array | null | When a visible email is found | One evidence record per unique address, with the location and surrounding text. |
| `shopLinks` | string array | null | When shop links are present | Unique public Etsy shop links found in the page HTML, capped at 100. |
| `shopLinkCount` | integer | null | Always | Number of entries in `shopLinks`; `0` when none were found. |
| `listingLinks` | string array | null | When listing links are present | Unique public Etsy listing links found in the page HTML, capped at 100. |
| `listingLinkCount` | integer | null | Always | Number of entries in `listingLinks`; `0` when none were found. |
| `scrapedAt` | string | null | Always | Time the row was saved, in ISO UTC. |

Each `emailEvidence` entry contains `email`, `evidenceType`, `sourceUrl`, and `context`. `evidenceType` is `mailto` when the address came from a link target or `visible_text` when it appeared as plain text. `context` is a bounded excerpt around the first occurrence, or `null` when the visible excerpt could not be located. `emails`, `shopLinks`, and `listingLinks` are plain string arrays.

The example below is a real saved row from the 2026-10-25 run. The shop-link and listing-link arrays are shortened to three entries each for readability; `shopLinkCount` and `listingLinkCount` reflect the complete arrays.

```json
{
  "platform": "Etsy",
  "pageType": "public_contact_page",
  "sourceUrl": "https://www.etsy.com/shop/GeekTropicalOfficial",
  "pageUrl": "https://www.etsy.com/in-en/shop/GeekTropicalOfficial",
  "pageTitle": "GeekTropicalOfficial - Etsy India",
  "emails": [
    "aloha@geektropical.com"
  ],
  "emailCount": 1,
  "publicContactFound": true,
  "emailEvidence": [
    {
      "email": "aloha@geektropical.com",
      "evidenceType": "visible_text",
      "sourceUrl": "https://www.etsy.com/shop/GeekTropicalOfficial",
      "context": "a protection authority. How to Contact Me You may reach me with any concerns relating to privacy at aloha@geektropical.com , or by mail at my physical address 4535 E. McKellips Rd #1016, Mesa, AZ 85215 addressed to Geek Tropical. For purposes of EU data protection law, I, GeekTropi"
    }
  ],
  "shopLinks": [
    "https://www.etsy.com/in-en/shop/GeekTropicalOfficial",
    "https://www.etsy.com/shop/GeekTropicalOfficial",
    "https://www.etsy.com/in-en/shop/GeekTropicalOfficial/reviews?ref=pagination&page=1"
  ],
  "shopLinkCount": 7,
  "listingLinks": [
    "https://www.etsy.com/in-en/listing/1433538267/dinosaur-chicken-nuggets-blue-button-up?ref=shop_review",
    "https://www.etsy.com/in-en/listing/1173516903/astronaut-pixels-outer-space-purple-blue?ref=shop_review",
    "https://www.etsy.com/in-en/listing/1419395394/dnd-dice-critters-colors-button-up?ref=shop_review"
  ],
  "listingLinkCount": 10,
  "scrapedAt": "2026-10-25T20:41:26.016Z"
}
```

The email in this row appeared in the shop's visible privacy text and was lowercased; the evidence excerpt still shows its original casing and surrounding wording. The shop links include regional and review-page variants, and the listing links point to products shown on the page.

The row below was produced from the public Internet Archive capture `20221001023956` of the same shop page when the live request was blocked; link arrays are omitted for brevity. `pageUrl` is the Wayback replay address, so the capture timestamp is visible in the row.

```json
{
  "platform": "Etsy",
  "pageType": "public_contact_page",
  "sourceUrl": "https://www.etsy.com/shop/GeekTropicalOfficial",
  "pageUrl": "https://web.archive.org/web/20221001023956id_/https://www.etsy.com/shop/GeekTropicalOfficial",
  "pageTitle": "GeekTropicalOfficial - Etsy",
  "emails": [
    "aloha@geektropical.com"
  ],
  "emailCount": 1,
  "publicContactFound": true,
  "emailEvidence": [
    {
      "email": "aloha@geektropical.com",
      "evidenceType": "visible_text",
      "sourceUrl": "https://www.etsy.com/shop/GeekTropicalOfficial",
      "context": "a protection authority. How to Contact Me You may reach me with any concerns relating to privacy at aloha@geektropical.com , or by mail at my physical address 4535 E. McKellips Rd #1016, Mesa, AZ 85215 addressed to Geek Tropical. For purposes of EU data protection law, I, GeekTropi"
    }
  ],
  "shopLinkCount": 46,
  "listingLinkCount": 47,
  "scrapedAt": "2026-10-31T19:02:07.497Z"
}
```

### Run summary

**Run summary** is stored separately from the dataset in the run's key-value store under `OUTPUT`.

| Field | Meaning |
| --- | --- |
| `status` | Actor process outcome: `SUCCEEDED` or `FAILED`. |
| `runStatus` | Canonical run status; matches `status`. |
| `dataStatus` | Completeness of the saved rows: `COMPLETE`, `PARTIAL`, `NO_RESULTS`, or `FAILED`. |
| `sourceUrls` | Public Etsy URLs selected for the run after deduplication and the `maxItems` cap. |
| `pagesRequested` | Number of source URLs the run selected to inspect. |
| `pagesProcessed` | Pages fetched and verified into dataset rows. |
| `datasetItems` | Rows present in the dataset. |
| `normalRowsWritten` | Source-backed rows written; equals `datasetItems`. |
| `diagnosticCount` | Operational issues recorded, including blocked, failed, unverifiable, or unsaveable pages. |
| `diagnosticItems` | Diagnostic dataset rows; always `0`. |
| `diagnosticRowsWritten` | Diagnostic rows written; always `0`. |
| `emailsFound` | Total email addresses across all saved rows. |
| `shopLinks` | Total shop links across all saved rows, as a count rather than a list. |
| `listingLinks` | Total listing links across all saved rows, as a count rather than a list. |
| `includeDiagnostics` | Whether diagnostic detail was retained for the run; `true` for the saved run and for runs that do not set the internal compatibility field. |
| `finishedAt` | Time the summary was written, in ISO UTC. |

| Status | Data status | Meaning |
| --- | --- | --- |
| `SUCCEEDED` | `COMPLETE` | At least one page was verified and no operational issue was recorded. |
| `SUCCEEDED` | `PARTIAL` | At least one page was saved, but another page was blocked, failed, or could not be saved. |
| `SUCCEEDED` | `NO_RESULTS` | No page produced a row and no diagnostic was recorded, for example when no URL was supplied. |
| `FAILED` | `FAILED` | No page produced a row and at least one diagnostic was recorded. |

Example `OUTPUT` from the 2026-10-25 run:

```json
{
  "status": "SUCCEEDED",
  "runStatus": "SUCCEEDED",
  "dataStatus": "COMPLETE",
  "sourceUrls": [
    "https://www.etsy.com/shop/GeekTropicalOfficial"
  ],
  "pagesRequested": 1,
  "pagesProcessed": 1,
  "datasetItems": 1,
  "normalRowsWritten": 1,
  "diagnosticCount": 0,
  "diagnosticItems": 0,
  "diagnosticRowsWritten": 0,
  "emailsFound": 1,
  "shopLinks": 7,
  "listingLinks": 10,
  "includeDiagnostics": true,
  "finishedAt": "2026-10-25T20:41:26.127Z"
}
```

### Coverage and limitations

The Actor reports only addresses that the fetched public page shows in visible text or in a `mailto:` link. It does not click through to contact forms, seller profiles, or external websites, and it does not decode deliberately obfuscated addresses, images, or script-only values. Addresses on platform domains and obvious placeholder domains are excluded. The visible-text scan is bounded, so an address far down a very long page may be missed; at most 50 unique emails and 100 shop links and 100 listing links are retained per page.

A saved row means the page was fetched and verified, not that an email exists. When `publicContactFound` is `false`, the page simply exposed no qualifying address during the run. Addresses can be stale, role-based, or shared, and the Actor does not send mail or verify deliverability. Regional redirects, locale, and generated markup can change the page URL and link set between runs.

Blocked or failed pages are counted in `diagnosticCount` and described in logs; they are never converted into rows or placeholder values. When Etsy answers a live request with a bot-check, the Actor also checks the public Internet Archive for a capture of the same URL through the Wayback CDX and availability APIs and, if one exists, reads its raw `id_` HTML with the same parser. The row's `pageUrl` is then the Wayback replay address, which carries the capture timestamp, so archived addresses can be older than the run. A URL with no public capture remains a diagnostic. Optional Apify Proxy settings are supported when supplied. Use the data only for lawful contact where you have a documented basis, and honor consent, anti-spam, and privacy rules that apply to your jurisdiction.

### Usage and support

Cost depends on the number of source URLs, timeout and delay settings, retries, response size, and any proxy usage. One request is made per selected URL, so start with a handful of URLs and `maxItems` below the default when testing. See the Actor's Pricing tab for current account rates.

Use the [Actor Issues page](https://apify.com/w3crawler/etsy-email-scraper/issues) to report a problem. Include the run ID, the input used (with private addresses or tokens removed), and the run summary. This Actor is an independent community tool and is not affiliated with, endorsed by, or sponsored by Etsy, Inc. Use it only for public data and in accordance with Etsy's terms, robots guidance, and applicable law.

# Actor input Schema

## `startUrls` (type: `array`):

Public HTTPS Etsy shop, listing, search, market, or homepage URLs.

## `maxItems` (type: `integer`):

Maximum source URLs to inspect.

## `timeoutSecs` (type: `integer`):

Per-URL public request timeout.

## `requestDelayMs` (type: `integer`):

Polite delay between consecutive public Etsy requests.

## `maxRequestRetries` (type: `integer`):

Bounded retries for ordinary request failures.

## `proxyConfiguration` (type: `object`):

Optional Apify Proxy configuration. No challenge bypass is attempted.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.etsy.com/shop/GeekTropicalOfficial"
  ],
  "maxItems": 10,
  "timeoutSecs": 30,
  "requestDelayMs": 500,
  "maxRequestRetries": 1,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing only source-backed public-page contact observations.

## `keyValueStore` (type: `string`):

Key-value store containing the OUTPUT run summary.

## `runSummary` (type: `string`):

Run status and counters stored by the Actor.

# 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 = {
    "startUrls": [
        "https://www.etsy.com/shop/GeekTropicalOfficial"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("w3crawler/etsy-email-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 = { "startUrls": ["https://www.etsy.com/shop/GeekTropicalOfficial"] }

# Run the Actor and wait for it to finish
run = client.actor("w3crawler/etsy-email-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 '{
  "startUrls": [
    "https://www.etsy.com/shop/GeekTropicalOfficial"
  ]
}' |
apify call w3crawler/etsy-email-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,w3crawler/etsy-email-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/ULaClYEsqbju4ChYF/builds/NF4jR2O2e3xU5sEh2/openapi.json
