# Etsy Scraper: Listings, Prices & Shops (`themineworks/etsy-search-scraper`) Actor

Scrape Etsy search listings: title, price, currency, shop name and image. Handmade and vintage marketplace research. No login, no API key.

- **URL**: https://apify.com/themineworks/etsy-search-scraper.md
- **Developed by:** [The Mine Works](https://apify.com/themineworks) (community)
- **Categories:** E-commerce
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 listings

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Etsy Scraper: Listings, Prices & Shops

🏆 Part of The Mine Works' 149-actor portfolio · 40,000+ runs · 200,000+ results delivered across our full distribution stack · 99.9%+ success rate

💰 $1.50 / 1,000 results.

> ⚡ Reads Etsy's split price markup directly: separate currency-symbol and
> currency-value elements, a screen-reader fallback, and correct original
> versus sale price detection instead of string-mangled numbers.
>
> [Browse all The Mine Works actors](https://apify.com/themineworks)

Scrape Etsy search listings: title, price, currency, sale price, shop name and image. No login, no API key, no browser.

✅ Title, price, currency and shop on 100% of records · ✅ Original price on discounted items · ✅ Around 55 listings per page · ✅ No listings found, no per-listing charge

### Search Etsy by keyword

```json
{
  "queries": ["personalized water bottle"],
  "maxItems": 300
}
```

### Track a niche across several search terms

```json
{
  "queries": ["custom tumbler", "engraved tumbler", "personalized flask"],
  "maxItems": 500,
  "monitorMode": true
}
```

### What you get for each listing

```json
{
  "listing_id": "4321268709",
  "title": "Engraved Water Bottles With Straw, Personalized Insulated Water Bottle",
  "price": 7.11,
  "currency": "USD",
  "original_price": 9.48,
  "on_sale": true,
  "shop_name": "TheSandArtCrafts",
  "shop_id": "53802873",
  "is_ad": false,
  "image": "https://i.etsystatic.com/53802873/r/il/...",
  "listing_url": "https://www.etsy.com/listing/4321268709"
}
```

| Field | Description |
| --- | --- |
| 🏷️ `title` | Listing title |
| 💰 `price`, `currency` | Current price as a sortable number, and its currency |
| 🔻 `original_price`, `on_sale` | Pre-discount price and whether the item is reduced |
| 🏪 `shop_name`, `shop_id` | Seller shop, with Etsy's "Ad ・ By" prefix stripped |
| 📣 `is_ad` | Whether the listing was a promoted result |
| 🖼️ `image` | Listing image URL |
| 🔗 `listing_url` | Clean listing link |

### What this does not return, and why

**Rating and review count are not included.** Etsy's search pages do not contain them: those figures are fetched by the browser after the page loads, so they are absent from the HTML entirely. Four different extraction approaches were tested against live pages and every one returned nothing on every listing.

Rather than ship rating columns that would be null on every row and look like a broken scraper, the fields are left out. If you need ratings, they are on the individual listing pages, not in search results.

**A small fraction of rows may be skipped rather than delivered wrong.** Etsy occasionally serves a card in a markup variant this actor cannot parse cleanly. Measured across two independent test batches (88 listings total), this affected roughly 1 in 90 rows. Rather than deliver a row with a missing title or price, the actor drops it and moves on, so what you receive is correct rather than complete to the last listing.

### How the price is read

Etsy writes each price three different ways in the same card: a screen-reader string, a visible amount split across separate `currency-symbol` and `currency-value` elements, and a struck-through original price in a sibling element. A parser expecting `$45.57` as contiguous text matches none of them, which is a common reason Etsy scrapers return empty prices.

This actor reads the split elements directly, then falls back to the screen-reader copy, and treats the higher of two prices in a card as the pre-discount original. Every run logs a field-coverage line on its first page, so if Etsy changes its markup the run says so immediately instead of quietly returning blank columns.

### Common use cases

**Handmade and print-on-demand market research.** See what a niche actually charges before pricing your own listings.

**Competitor and shop monitoring**, tracking a set of search terms over time with monitor mode.

**Discount tracking**, using `original_price` and `on_sale` to spot genuine markdowns.

**Product and keyword research** for sellers deciding what to list.

### Pricing

| Event | Price | You pay when |
| --- | --- | --- |
| Listing | $0.0015 | An Etsy listing lands in your dataset |
| Actor start | $0.005 per GB of memory, once per run | The actor starts running |

$1.50 per 1,000 listings. Flat pricing, the same on every Apify plan. A search
that returns nothing fires no listing charge.

### Run it on a schedule

1. Run once with the input you want repeated, then click **Save as a task**.
2. Turn on **Monitor mode** so later runs return only newly listed items.
3. In the Apify Console go to **Schedules** and add the saved task.

Nothing is charged just for a schedule existing.

### FAQ

**Do I need an Etsy account or API key?**
No. Everything comes from public search results.

**How many listings does one page give?**
Around 55. The actor pages through results up to your `maxItems`.

**Are sponsored listings included?**
Yes, and they are flagged with `is_ad` so you can filter them out.

**Why is original\_price empty on some rows?**
Because those listings are not discounted. The field is null rather than repeating the current price.

**Is this GDPR compliant?**
It collects public marketplace listings and public shop names, not personal data.

### Use from Claude, ChatGPT and any MCP agent

```
https://mcp.apify.com/?tools=themineworks/etsy-search-scraper
```

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

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });

const run = await client.actor('themineworks/etsy-search-scraper').call({
    queries: ['personalized water bottle'],
    maxItems: 300,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Part of the marketplace research suite

Pair this with [eBay listing data](https://apify.com/themineworks/ebay-search-scraper)
for new and used price comparisons across a wider category, so you can check a
product on both marketplaces before you list or reprice.

Keywords: Etsy scraper, Etsy price tracker, Etsy search API, handmade
marketplace data, Etsy shop monitoring, sale price detection, vintage
marketplace research, reseller price monitoring

# Actor input Schema

## `queries` (type: `array`):

What to search Etsy for. Each search term returns its own set of listings, e.g. "water bottle" or "handmade candle".

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

Maximum listings to return across all queries. Default 50, maximum 2000.

## `monitorMode` (type: `boolean`):

Run on a schedule and get ONLY listings not delivered in a previous run. Keep the input the same across runs.

## Actor input object example

```json
{
  "queries": [
    "water bottle"
  ],
  "maxItems": 60,
  "monitorMode": false
}
```

# Actor output Schema

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

No description

# 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 = {
    "queries": [
        "water bottle"
    ],
    "maxItems": 60
};

// Run the Actor and wait for it to finish
const run = await client.actor("themineworks/etsy-search-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 = {
    "queries": ["water bottle"],
    "maxItems": 60,
}

# Run the Actor and wait for it to finish
run = client.actor("themineworks/etsy-search-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 '{
  "queries": [
    "water bottle"
  ],
  "maxItems": 60
}' |
apify call themineworks/etsy-search-scraper --silent --output-dataset

```

## MCP server setup

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