# Etsy Scraper (`mina_safwat/etsy-scraper`) Actor

Get full Etsy listing data by URL: price, sale price and discount, favorites, tags, images, variations and shop reviews, in any currency. Also pulls a shop's newest listings and finds listings by keyword through web search (not Etsy's own ranking).

- **URL**: https://apify.com/mina_safwat/etsy-scraper.md
- **Developed by:** [Mina](https://apify.com/mina_safwat) (community)
- **Categories:** E-commerce, Marketing, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 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?

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

### What does Etsy Scraper – Listing Details, Prices & Shops do?

**Etsy Scraper – Listing Details, Prices & Shops** collects **Etsy listings** as structured data: **title, price, sale price and discount, shop, bestseller badge, favorites, stock, category, tags and images**, plus optional **descriptions, materials, variations with their prices** and **the shop's newest reviews**. Give it **search keywords**, Etsy **search, category or market links**, **shop links** or **listing links**, and it returns one clean row per listing.

Try it with the prefilled shop: click **Start**, and the shop's 10 newest listings arrive in a few seconds. Because it runs on the Apify platform, you also get API access, scheduled runs, integrations (Google Sheets, Make, Zapier, webhooks), run monitoring and automatic retries through Apify Proxy when [Etsy](https://www.etsy.com) is slow to answer.

### Why scrape Etsy?

- **Product research**: see which handmade and vintage products sell in a niche, at what prices, and how many shoppers favorite them.
- **Price monitoring**: track a competitor's prices, sales and discounts every day with a scheduled run.
- **Shop analysis**: list a shop's newest listings with their tags, categories and stock.
- **SEO and keyword ideas**: collect the tags sellers use for a keyword.
- **Market and trend reports**: export hundreds of listings to a spreadsheet or BI tool.

### How to scrape Etsy listings

1. Type words into **Search keywords**, such as `linen apron`, or paste Etsy links into **Etsy links**: a listing, a shop, or a search, category or market page.
2. Set **Max listings per input** (10 to start with).
3. Turn on **Add listing details** for descriptions and variations, or **Add the shop's newest reviews** for reviews.
4. Optionally pick a **Currency**, such as `EUR`.
5. Click **Start**, then download the results when the run finishes.

### Input

Everything is set on the Input tab. In JSON, the input looks like this:

```json
{
    "searchQueries": ["linen apron"],
    "startUrls": [
        "https://www.etsy.com/shop/CaitlynMinimalist",
        "https://www.etsy.com/listing/1824319193/reversible-linen-apron-no-tie-organic",
        "https://www.etsy.com/c/jewelry/necklaces"
    ],
    "maxListings": 50,
    "skipUnavailable": true,
    "includeDetails": true,
    "includeReviews": true,
    "maxReviewsPerListing": 3,
    "currency": "EUR"
}
```

| Field | What it does |
|---|---|
| `searchQueries` | Words to search for, one search per line. Each search returns listings whose web address contains a word of your search, ranked by a web search of etsy.com. |
| `startUrls` | Etsy links: a listing (`/listing/1824319193/…` or just the number), a shop (`/shop/Linenia` or `linenia.etsy.com`), or a search (`/search?q=…`), category (`/c/…`) or market (`/market/…`) page. Plain strings and `{"url": "…"}` objects both work, with or without `https://`. |
| `maxListings` | Stops after this many listings for each link or keyword. Default: 100. |
| `skipUnavailable` | Leaves out sold-out, expired and other listings that cannot be bought now, so they are not billed. Default: on. |
| `includeDetails` | Adds the full description, materials, shop section and variations (size, colour…) with each option's availability and price. Default: off. |
| `includeReviews` | Adds the newest reviews of each listing's shop (up to 6). Default: off. |
| `maxReviewsPerListing` | How many of those reviews to add, from 0 to 6. Default: 6. |
| `currency` | The currency prices are shown in, such as `USD`, `EUR`, `GBP`, `CAD`, `AUD` or `JPY`. Default: `USD`. |
| `proxyConfiguration` | Optional; leave it empty. The Actor connects directly and falls back to Apify Proxy by itself. |

### Output

Each listing becomes one row. Here is a real row from a keyword search with details, reviews and `"currency": "EUR"` (description, images, variations and reviews shortened):

```json
{
    "id": 753744881,
    "url": "https://www.etsy.com/listing/753744881/wooden-golf-set",
    "title": "Wooden Golf set",
    "price": 200,
    "originalPrice": null,
    "currency": "EUR",
    "discountPercent": null,
    "hasVariationPricing": false,
    "shopName": "WoodNack",
    "shopId": 9634678,
    "shopUrl": "https://www.etsy.com/shop/WoodNack",
    "isBestseller": false,
    "isTopRated": false,
    "favorites": 152,
    "quantityAvailable": 1,
    "isAvailable": true,
    "isSoldOut": false,
    "isDigital": false,
    "isMadeToOrder": true,
    "isCustomizable": true,
    "whenMade": "made_to_order",
    "shipsFrom": "GR",
    "category": "Golf",
    "categoryPath": "toys and games > sports and outdoor games > golf",
    "tags": ["golf", "ball", "outdoor", "game", "set", "play"],
    "images": ["https://i.etsystatic.com/9634678/r/il/4ff779/6521121751/il_fullxfull.6521121751_bnra.jpg"],
    "listedAt": "2026-07-08T13:43:31+00:00",
    "updatedAt": "2026-08-22T06:44:25+00:00",
    "description": "Handmade Wooden Golf Set\nA handmade wooden golf set for indoor or outdoor playing fun …",
    "materials": ["Wood"],
    "shopSection": "TOYS",
    "variations": [],
    "shopReviews": [
        {
            "rating": 5,
            "text": "Product was as described and works well !",
            "language": "en",
            "date": "2026-10-16T17:21:00+00:00",
            "itemId": 1718268394,
            "itemTitle": "Golf set Obstacles-Bright Colours"
        }
    ],
    "source": "wooden golf set",
    "sourceType": "keyword",
    "position": 1,
    "scrapedAt": "2026-10-24T12:55:16.547351+00:00"
}
```

A listing on sale looks like this: `"price": 54.0, "originalPrice": 72.0, "discountPercent": 25`.

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

### Data fields

| Field | Description |
|---|---|
| `id` | Etsy's listing number. |
| `url` | Link to the listing. |
| `title` | The listing title. |
| `price` | The price now, in `currency`. For a listing on sale, this is the sale price. `null` for a sold-out listing (kept only when **Skip listings not for sale** is off). |
| `originalPrice` | The price before the sale; `null` when there is no sale. |
| `currency` | Currency of the prices (the one you chose, converted by Etsy). |
| `discountPercent` | Whole percent off during a sale; `null` otherwise. |
| `hasVariationPricing` | `true` when some variations cost more or less than `price`. |
| `shopName`, `shopId`, `shopUrl` | The shop selling the listing. |
| `isBestseller` | Etsy's Bestseller badge. |
| `isTopRated` | Etsy's top-rated flag for the listing. |
| `favorites` | How many shoppers favorited the listing. |
| `quantityAvailable` | Items in stock. |
| `isAvailable`, `isSoldOut` | Whether it can be bought now. |
| `isDigital`, `isMadeToOrder`, `isCustomizable` | Digital download, made to order, personalisable. |
| `whenMade` | Etsy's "when made" value, such as `made_to_order` or `2020,2026`. |
| `shipsFrom` | Country code the listing ships from. |
| `category`, `categoryPath` | Etsy category and its path from the top. |
| `tags` | The seller's tags. |
| `images` | Full-size image links. |
| `listedAt`, `updatedAt` | When the listing was last listed or renewed, and last edited (UTC, ISO 8601). |
| `description`, `materials`, `shopSection` | With **Add listing details**. |
| `variations` | With **Add listing details**: each variation's `name` and `options` (`value`, `price`, `isAvailable`). `price` is the price before any sale; it is `null` when the listing's price depends on the option (`hasVariationPricing` is `true`), because Etsy's open data does not give per-option prices. |
| `shopReviews` | With **Add the shop's newest reviews**: `rating` (1–5), `text`, `language`, `date`, and the reviewed item's `itemId` and `itemTitle`. |
| `source`, `sourceType`, `position` | The input the listing came from (`keyword`, `shop` or `listing`) and its rank among the rows saved for that input. |
| `scrapedAt` | When the row was saved. |

### How much does it cost to scrape Etsy?

The Actor uses plain HTTP requests, without a browser and usually without a proxy, so runs are fast and light: about 250 listings from one keyword take under 2 minutes, and the prefilled shop takes about 5 seconds. You pay per listing saved; see the **Pricing** tab for the exact price. Inputs that return nothing are never billed.

### Tips and advanced options

- **Search keywords vs. Etsy links**: a keyword and an Etsy search link give the same results. Filters in a search link (price range, sort order, free shipping) are not applied.
- **Shops**: a shop gives its newest listings, 10 per shop section, so a large shop returns its newest few dozen listings rather than its whole catalogue. For a specific listing, paste its link.
- **Keywords** return up to about 250 listings each. Use several narrower keywords for more.
- **Duplicates** are removed: a listing found by two inputs is saved once.
- Leave **Add listing details** off when you only need prices; it adds one request per listing.
- Turn **Skip listings not for sale** off to also get sold-out and expired listings (about 1 in 10 keyword results); they are billed like any other row.

### Why does keyword search work this way?

Etsy protects its own search, category, market and shop pages with a bot wall (DataDome) that refuses cloud servers, even when a real browser loads the page. The listing data itself is open, so the Actor finds the listings for your words through a web search of etsy.com (Yahoo Search) and then reads every listing straight from Etsy. This means:

- Results are ranked by the web search's relevance, not Etsy's own ranking. A listing is kept only when a word of its web address (Etsy builds it from the title) starts with the same 5 letters as a word of your search, or one is the start of the other, which drops off-topic results.
- Etsy's ad flag, free-shipping badge, shop star rating, shop review count and sales count are shown only on the blocked pages, so they are not in the data.

### FAQ, disclaimers, and support

**Is it legal to scrape Etsy?** This Actor reads only public listing data that anyone can see without logging in. Check Etsy's terms and the laws that apply to you before using the data, especially for commercial use. Etsy's robots.txt restricts automated access to some pages.

**Personal data:** the reviews leave out buyers' names and photos. Shop names are business names. If you collect personal data, make sure you have a lawful reason to process it under GDPR and similar laws.

**What happens with links that give nothing?** Removed or sold-out listings, unknown shops, links that are not Etsy links and searches with no matching listings are not billed. They are listed with the reason in the `FAILED_INPUTS` record of the run's key-value store, and the run's status message sums them up.

**Something missing or broken?** Open an issue on the **Issues** tab; we read every one. Need a custom Etsy dataset or a different output format? Get in touch through the same tab.

# Actor input Schema

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

Etsy links, one per line: a listing (https://www.etsy.com/listing/1824319193/…, or just its number), a shop (https://www.etsy.com/shop/Linenia or linenia.etsy.com), or a search, category or market link (https://www.etsy.com/search?q=linen+apron, /c/accessories/aprons, /market/linen_apron). Search, category and market links are searched by their words, like the keywords below; the filters in them (price, sort, shipping) are not applied.

## `searchQueries` (type: `array`):

Words to find listings for, one search per line, such as linen apron. Each search returns up to "Max listings per input" listings whose address contains a word of your search, ranked by a web search of etsy.com (Yahoo Search), not by Etsy, because Etsy's own search pages block cloud servers; see the README.

## `maxListings` (type: `integer`):

Stops after this many listings for each link or keyword. A shop gives its newest listings, 10 per shop section; a keyword gives up to about 250.

## `skipUnavailable` (type: `boolean`):

Leaves out sold-out, expired and other listings that cannot be bought now (no price, or not active), so you are not billed for them. Turn off to keep them; their price is then empty.

## `includeDetails` (type: `boolean`):

Adds the full description, materials, shop section and the variations (size, colour…) with each option's availability and price. When the price depends on the option, Etsy's open data does not give per-option prices, so they are left empty. Costs one extra request per listing.

## `includeReviews` (type: `boolean`):

Adds the newest reviews of each listing's shop (rating, text, date and the item reviewed). Etsy shows at most 6 per shop without the listing page; buyers' names are left out.

## `maxReviewsPerListing` (type: `integer`):

How many of the shop's newest reviews to add to each listing, up to 6.

## `currency` (type: `string`):

Prices are shown in this currency, as Etsy converts them for shoppers: a 3-letter code such as USD, EUR, GBP, CAD, AUD or JPY. Etsy falls back to US dollars for a currency it does not offer, and the log says so.

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

Leave this empty: Etsy's listing data answers the Actor directly, and if it ever refuses, the Actor retries through Apify's datacenter and then residential proxies on its own. A proxy chosen here is used for Etsy only; keyword searches always go direct first and fall back to US residential proxies.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.etsy.com/shop/CaitlynMinimalist"
  ],
  "searchQueries": [],
  "maxListings": 10,
  "skipUnavailable": true,
  "includeDetails": false,
  "includeReviews": false,
  "maxReviewsPerListing": 6,
  "currency": "USD",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `dataset` (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 = {
    "startUrls": [
        "https://www.etsy.com/shop/CaitlynMinimalist"
    ],
    "maxListings": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("mina_safwat/etsy-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/CaitlynMinimalist"],
    "maxListings": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("mina_safwat/etsy-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/CaitlynMinimalist"
  ],
  "maxListings": 10
}' |
apify call mina_safwat/etsy-scraper --silent --output-dataset

```

## MCP server setup

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