---
title: "Etsy scraper"
description: "Scrape Etsy listings, prices, discounts, shop names, ratings and bestseller badges as structured JSON. One API request from Python, Node.js, the CLI or MCP."
canonical: https://www.zenrows.com/scrape/etsy
updated: 2026-10-20
---

# Etsy scraper

The Zenrows Etsy scraper turns an Etsy search or market URL into structured JSON: listing ID, title, price, original price, discount, free shipping, rating, review count, shop name, Star Seller flag and bestseller badge. You send the URL, Fetch in Adaptive Stealth Mode opens the page, and Extract returns the fields. Run it from an API call, the CLI or an AI agent.

- Site: etsy.com
- Returns: Listings, prices, shops, ratings and badges

## Run it: one Etsy search in, JSON out

```json Input
{
  "url": "https://www.etsy.com/search?q=handmade+mug",
  "mode": "auto",
  "extract": "auto"
}
```

```json Output
{
  "listings": [
    {
      "badge": null,
      "currency": null,
      "discount_percent": 25,
      "free_shipping": true,
      "is_ad": null,
      "is_star_seller": null,
      "listing_id": "4491753413",
      "listing_url": "https://www.etsy.com/listing/4491753413/handmade-stoneware-coffee-mug-16oz-large?click_key=…",
      "original_price": 34.99,
      "price": 26.24,
      "review_count": null,
      "review_rating": 4.8,
      "shop_name": "NovaCeramicsCo",
      "shop_url": "https://www.etsy.com/shop/NovaCeramicsCo",
      "thumbnail_url": "https://i.etsystatic.com/36752604/r/il/24186c/7933063958/il_794xN.7933063958_cfzi.jpg",
      "title": "Handmade Stoneware Coffee Mug 16oz, Large Ceramic Mug with Handle, Artisan Pottery Mug, Modern Coffee Cup, Gift for Coffee Lovers"
    }
  ],
  "related_searches": [],
  "search_context": {
    "canonical_url": "https://www.etsy.com/market/handmade_mug",
    "query": "handmade_mug",
    "total_results": null
  }
}
```

Request and output of a live call to an Etsy search page on Oct 20, 2026, trimmed for length. The full response held 60 listings. A field is returned when the card shows it.

## What data can you scrape from Etsy?

An Etsy search returns one record per listing card, in the order Etsy ranks them, plus the search context. These are the fields that come back, with the path where each lives in the JSON.

| Field | What it holds | Example |
|---|---|---|
| `listings[].listing_id` | Etsy's listing ID, the number in every `/listing/` URL | `4491753413` |
| `listings[].title` | Listing title, usually packed with the seller's keywords | `Handmade Stoneware Coffee Mug 16oz…` |
| `listings[].price` | The price a buyer pays today | `26.24` |
| `listings[].original_price` | The price before the sale, when a discount runs | `34.99` |
| `listings[].discount_percent` | Size of the sale | `25` |
| `listings[].currency` | Currency symbol, when the card shows one | `Rp` |
| `listings[].free_shipping` | Whether the card carries the free shipping label | `true` |
| `listings[].review_rating` | Shop rating out of 5 shown on the card | `4.8` |
| `listings[].review_count` | Number of reviews shown next to the rating | `(2.2k)` |
| `listings[].shop_name` | The Etsy shop selling the item | `NovaCeramicsCo` |
| `listings[].shop_url` | The shop's page, ready to request | `https://www.etsy.com/shop/NovaCeramicsCo` |
| `listings[].is_star_seller` | Whether the shop holds Etsy's Star Seller badge | `true` |
| `listings[].badge` | Etsy's ranking badges, such as bestseller or popular now | `bestseller` |
| `listings[].is_ad` | Whether the card is a paid placement | `null` |
| `listings[].thumbnail_url` | The listing's main photo | `https://i.etsystatic.com/…jpg` |
| `search_context.canonical_url` | The `/market/` page Etsy maps the query to | `https://www.etsy.com/market/handmade_mug` |
| `search_context.query` | The query as Etsy normalised it | `handmade_mug` |

## How to scrape Etsy with Zenrows

1. **Create a free Zenrows account** and copy your API key from the dashboard.
2. **Pick the Etsy URL.** A search (`/search?q=…`), a market page (`/market/handmade_mug`), a category (`/c/…`) or a shop (`/shop/ShopName`). Set Etsy's own filters in the browser first, such as price, ship-to country or Star Seller, and copy the URL they produce.
3. **Send it with the default configuration**: Adaptive Stealth Mode to open the page and Extract to return the fields. Add the country when you need prices as a buyer there sees them.
4. **Read `parsed.listings`** from the response. To keep only some fields, list their paths and the response returns just those.
5. **Run every keyword and page in Batch** when one search returns what you need, with the keyword or listing ID as your `external_id`.

```python Python
# pip install requests
import json
import requests

params = {
    "apikey": "YOUR_ZENROWS_API_KEY",
    "url": "https://www.etsy.com/search?q=handmade+mug",
    "mode": "auto",      # Adaptive Stealth Mode
    "extract": "auto",   # structured JSON
}
response = requests.get("https://api.zenrows.com/v1/", params=params, timeout=180)
response.raise_for_status()

data = response.json()["parsed"]
for item in data["listings"]:
    print(item["listing_id"], item["price"], item["shop_name"], item["badge"])
print(json.dumps(data["search_context"], indent=2))
```

```javascript Node.js
// Node 18+ (built-in fetch)
const params = new URLSearchParams({
  apikey: "YOUR_ZENROWS_API_KEY",
  url: "https://www.etsy.com/search?q=handmade+mug",
  mode: "auto",
  extract: "auto",
});

const response = await fetch(`https://api.zenrows.com/v1/?${params}`, {
  signal: AbortSignal.timeout(180_000),
});
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);

const { parsed } = await response.json();
const onSale = parsed.listings.filter((l) => l.discount_percent);
console.log(parsed.listings.length, "listings,", onSale.length, "on sale");
```

```bash cURL
curl "https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fwww.etsy.com%2Fsearch%3Fq%3Dhandmade%2Bmug&mode=auto&extract=auto"

# Only the fields you need
curl "https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fwww.etsy.com%2Fsearch%3Fq%3Dhandmade%2Bmug&mode=auto&extract=auto&extract_fields=listings.listing_id%2Clistings.price%2Clistings.shop_name%2Clistings.review_rating"
```

```python Python SDK
# pip install zenrows
from zenrows import ZenRowsClient

client = ZenRowsClient("YOUR_ZENROWS_API_KEY")
response = client.get(
    "https://www.etsy.com/search?q=handmade+mug&page=2",
    params={"mode": "auto", "extract": "auto"},
)
for item in response.json()["parsed"]["listings"]:
    print(item["title"][:60], item.get("price"), item.get("is_star_seller"))
```

## Input

The scraper takes one Etsy URL per request, plus the options below. A Batch job applies the same options to every task, so tracking 300 keywords is a list of search URLs with these settings.

| Parameter | Type | Default | Description |
|---|---|---|---|
| `url` | string | required | Any Etsy page: search (`/search?q=…`), market (`/market/…`), category, listing (`/listing/ID`) or shop (`/shop/Name`) |
| `mode` | string | `auto` | Adaptive Stealth Mode: starts with the lightest setup and adds rendering and protected-site handling only when the page needs them |
| `extract` | string | `auto` | Returns the page's fields as JSON in `parsed`, next to the raw `html` |
| `extract_fields` | string | all fields | Comma-separated paths to keep, such as `listings.listing_id,listings.price,listings.badge` |
| `proxy_country` | string | any | Two-letter country code. Etsy converts prices to the visitor's local currency and changes shipping labels by location |
| `wait_for` | string | none | A CSS selector to wait for before the page is read |
| `session_id` | integer | none | Keep the same session across several requests, up to 10 minutes, for example while you page through one search |

```json Batch input
{
  "type": "regular",
  "status": "closed",
  "zenrows_params": {
    "mode": "auto",
    "extract": "auto"
  },
  "tasks": [
    { "url": "https://www.etsy.com/search?q=handmade+mug", "external_id": "kw-handmade-mug" },
    { "url": "https://www.etsy.com/search?q=handmade+mug&page=2", "external_id": "kw-handmade-mug-p2" },
    { "url": "https://www.etsy.com/market/handmade_mug", "external_id": "market-handmade-mug" }
  ]
}
```

## Output

Every response is JSON with two keys: `html`, the page as Etsy served it, and `parsed`, the structured record. A search page returns `listings[]`, `related_searches[]` and `search_context`. The sample below shows three more listings from the same live search: a bestseller with free shipping, a discounted item and a popular-now listing.

```json Search results
{
  "listings": [
    {
      "badge": "bestseller",
      "currency": null,
      "discount_percent": null,
      "free_shipping": true,
      "is_ad": null,
      "is_star_seller": true,
      "listing_id": "4296141840",
      "listing_url": "https://www.etsy.com/listing/4296141840/coffee-mug-kj-pottery?click_key=…",
      "original_price": null,
      "price": 57,
      "review_count": null,
      "review_rating": 4.9,
      "shop_name": "KJPottery",
      "shop_url": "https://www.etsy.com/shop/KJPottery",
      "thumbnail_url": "https://i.etsystatic.com/7825028/r/il/553467/6863380541/il_794xN.6863380541_5poq.jpg",
      "title": "Coffee Mug - KJ Pottery"
    },
    {
      "badge": null,
      "currency": null,
      "discount_percent": 10,
      "free_shipping": true,
      "is_ad": null,
      "is_star_seller": true,
      "listing_id": "1179506710",
      "listing_url": "https://www.etsy.com/listing/1179506710/seconds-sale-handmade-pottery-large-mug?click_key=…",
      "original_price": 38,
      "price": 34.2,
      "review_count": null,
      "review_rating": 4.9,
      "shop_name": "JKCreativeWood",
      "shop_url": "https://www.etsy.com/shop/JKCreativeWood",
      "thumbnail_url": "https://i.etsystatic.com/11111774/r/il/dac199/3772432579/il_794xN.3772432579_3grh.jpg",
      "title": "SECONDS SALE | Handmade Pottery | Large Mug (8 colors)"
    },
    {
      "badge": "popular_now",
      "currency": null,
      "discount_percent": null,
      "free_shipping": null,
      "is_ad": null,
      "is_star_seller": true,
      "listing_id": "837615700",
      "listing_url": "https://www.etsy.com/listing/837615700/handmade-ceramic-coffee-mug-large?click_key=…",
      "original_price": null,
      "price": 35.7,
      "review_count": null,
      "review_rating": 4.9,
      "shop_name": "BZceramics",
      "shop_url": "https://www.etsy.com/shop/BZceramics",
      "thumbnail_url": "https://i.etsystatic.com/18265806/r/il/c16dd8/7360466365/il_794xN.7360466365_61zd.jpg",
      "title": "Handmade Ceramic Coffee Mug: Porcelain Espresso Cup"
    }
  ],
  "related_searches": [],
  "search_context": {
    "canonical_url": "https://www.etsy.com/market/handmade_mug",
    "query": "handmade_mug",
    "total_results": null
  }
}
```

Need a spreadsheet? Load `listings` into pandas with `pd.json_normalize(...)` and write CSV or Excel. Need the page for an LLM? Ask for Markdown instead of JSON.

## Scrape Etsy from your coding agent

Claude Code, Cursor, Codex and any MCP client can scrape Etsy from a prompt.

The agent sends the same Fetch and Extract request a developer would and reads the same `listings` array. Connect the Zenrows MCP server once, or install the CLI and let the agent run it in the terminal. No key is needed to try either: the first call creates a free account.

```bash Connect the MCP server (Claude Code)
claude mcp add zenrows -e ZENROWS_API_KEY=YOUR_ZENROWS_API_KEY -- npx -y @zenrows/mcp
```

```json MCP config (Cursor, Claude Desktop, Windsurf)
{
  "mcpServers": {
    "zenrows": {
      "command": "npx",
      "args": ["-y", "@zenrows/mcp"],
      "env": { "ZENROWS_API_KEY": "YOUR_ZENROWS_API_KEY" }
    }
  }
}
```

```bash Or run the CLI
npx -y @zenrows/cli init
zenrows extract "https://www.etsy.com/search?q=handmade+mug"
```

```text Then ask your agent
Use Zenrows to search Etsy for "handmade mug" and "ceramic mug", first two
pages each. Group the listings by shop, and show me the 10 shops with the most
bestseller badges, their price range and whether they are Star Sellers.
```

## Scrape Etsy at scale with Batch and Crawl

**Batch** runs a list of Etsy URLs as one job, in parallel, with your own ID on each result. Use it for weekly keyword research: one task per keyword and results page, so you can see which listings and shops hold the top spots and how their prices move.

**Crawl** finds the URLs for you. Start it on a shop or a market page, keep only links that contain `/listing/`, and it returns every listing page it reaches. Send that list to Batch when you want to track the same items over time.

```bash Batch (cURL)
curl -X POST "https://async.api.zenrows.com/v1/jobs" \
  -H "X-API-Key: YOUR_ZENROWS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "regular",
    "status": "closed",
    "zenrows_params": { "mode": "auto", "extract": "auto" },
    "tasks": [
      { "url": "https://www.etsy.com/search?q=handmade+mug", "external_id": "kw-handmade-mug" },
      { "url": "https://www.etsy.com/search?q=ceramic+planter", "external_id": "kw-ceramic-planter" }
    ]
  }'

# Read the results when the job finishes
curl "https://async.api.zenrows.com/v1/jobs/JOB_ID/results?status=successful" \
  -H "X-API-Key: YOUR_ZENROWS_API_KEY"
```

```bash Batch (CLI)
# etsy.jsonl: one {"url": "...", "external_id": "...", "extract": "auto"} per line
zenrows batch create etsy.jsonl --wait
zenrows batch results <job-id> --out etsy-listings.jsonl
```

```bash Crawl (cURL)
curl -X POST "https://api.zenrows.com/v1/crawls" \
  -H "X-API-Key: YOUR_ZENROWS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://www.etsy.com/shop/KJPottery",
    "depth": 2,
    "max_pages": 200,
    "include_patterns": ["/listing/"]
  }'
```

**Scheduled jobs** run the same Batch job on a timetable, on Zenrows' side: every few hours, once a day, at set times on chosen days, or once at a future date. Each run keeps its own results, a webhook can tell your app when a run finishes, and you can pause or resume the schedule at any time, with no cron server to keep alive.

```bash Scheduled job (cURL)
# Runs every day on Zenrows' side; each run keeps its own results
curl -X POST "https://async.api.zenrows.com/v1/jobs" \
  -H "X-API-Key: YOUR_ZENROWS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
      "type": "scheduled",
      "status": "closed",
      "schedule": {
        "rate": {
          "every": 1,
          "unit": "day"
        }
      },
      "zenrows_params": {
        "mode": "auto",
        "extract": "auto"
      },
      "tasks": [
        {
          "url": "https://www.etsy.com/search?q=handmade+mug",
          "external_id": "etsy"
        }
      ]
    }'

# Or at set times: "schedule": { "calendar": { "times_of_day": ["09:00"],
#   "cadence": { "weekly": { "days": ["mon", "thu"] } } }, "timezone": "Europe/Madrid" }
```

## What teams do with Etsy data

| Use case | Data they pull | Who runs it |
|---|---|---|
| Product and niche research | Listings per keyword, bestseller and popular-now badges, price spread | Etsy sellers and print-on-demand shops |
| Etsy SEO and rank tracking | Position of each listing for a keyword, title wording, ad flag | Sellers and Etsy agencies |
| Competitor shop monitoring | A shop's listings, prices, sales and rating over time | Shop owners and brand teams |
| Pricing and discount analysis | Price, original price and discount percent across a category | Makers, wholesalers and analysts |
| Trend spotting | New listings and badges in a niche week over week | Product designers and buyers |
| Design and IP watch | Titles and photos that copy a protected design, and the shops behind them | Brand protection and legal teams |

## Tips for scraping Etsy

- **Page through search with `page=`.** `/search?q=handmade+mug&page=2` is the second page. Each page returns its own set of listings, so loop until a page comes back with none.
- **Clean the listing URL before you store it.** Search cards carry long tracking parameters (`click_key`, `ref`, `ga_*`). `https://www.etsy.com/listing/LISTING_ID` opens the same item, so keep `listing_id` as your key.
- **Market pages are stable keyword pages.** `search_context.canonical_url` shows the `/market/` page Etsy ties a query to. Track that URL when you want the same keyword page every week.
- **Pin the currency.** Etsy converts prices to the visitor's local currency, and `currency` follows the card. Send every request for a dataset from the same country so prices compare.
- **Read badges as ranking signals.** `bestseller`, `popular_now` and the Star Seller flag are Etsy's own labels. Counting them per shop shows who wins a niche faster than prices do.
- **Parse review counts as text.** Cards show counts like `(173)` or `(2.2k)`. Strip the brackets and expand the `k` before you sort.

## Frequently asked questions

### Is it legal to scrape Etsy?

Collecting public Etsy data, such as listing titles, prices, ratings and shop names shown to every visitor, is common practice for market research and pricing. Shop pages and reviews can name individual makers and buyers, and personal data is protected by laws such as the GDPR and the CCPA, so collect only what you have a legitimate reason to use. Check Etsy's terms of use for your use case and ask your lawyer if you are unsure.

### Is there an official Etsy API?

Yes. The Etsy Open API v3 returns listings, shops and reviews to registered apps. You need an approved API key, sellers' own data needs their OAuth consent, and each app gets a request quota per second and per day. Commercial use needs Etsy's approval. Teams scrape Etsy when they need search rankings, badges and the page exactly as shoppers see it, without waiting on an app review.

### What Etsy pages can I scrape?

Search results, market pages ( /market/… ), category pages, single listings ( /listing/ID ) and shop pages ( /shop/Name ). Send the URL as it appears in your browser, with any filters you set on Etsy.

### Can I scrape an Etsy shop?

Yes. Send the shop URL to see its listings, or start a Crawl on the shop and keep the links that contain /listing/ to collect every item it sells. Run the result in Batch each week to see new listings, price changes and items that sold out.

### Can I scrape Etsy reviews?

Each card carries the shop's rating and review count. For review text, request the listing or shop page, where Etsy shows the reviews, and read them from the response, or ask for the page as Markdown and pass it to an LLM.

### How do I scrape Etsy with Python?

Send a GET request to https://api.zenrows.com/v1/ with your API key, the Etsy URL, Adaptive Stealth Mode and Extract turned on, as in the Python example above. The response's parsed key holds the listings as a Python dictionary. The zenrows package on PyPI wraps the same request.

### How many Etsy listings can I scrape?

Send one URL per request, or a whole list as a Batch job that runs the URLs in parallel and keeps your own ID on each result. One Batch job accepts more than 10,000 URLs, sent inline or as a CSV file.

### Can AI agents scrape Etsy with Zenrows?

Yes. Connect the Zenrows MCP server to Claude, Cursor, Codex or any MCP client, or give your agent the Zenrows CLI. Ask for the searches or shops you want in plain language and the agent calls Fetch and Extract for you.

### Can I scrape Etsy on a schedule?

Yes. Create a scheduled Batch job with your Etsy URLs and the same settings as a single request, and Zenrows runs it on its side: every few hours, once a day, at set times on chosen days, or once at a future date. Each run keeps its own results, a webhook can notify your app when a run finishes, and the schedule can be paused or resumed at any time.

### Which integrations work with the Etsy scraper?

Zenrows works with n8n, Make, Zapier, Clay, Dify, LangChain, LlamaIndex, CrewAI and Mastra, plus the Python, Node.js and Go SDKs and any HTTP client. Send listings to Google Sheets, Airtable or a database from the workflow tool you already use. See the integrations page for the full list.

### What format does the data come in?

JSON by default, with the structured record in parsed and the original page in html . You can also ask for the page as Markdown or plain text, which is what most LLM and RAG pipelines want.

All scrapers: https://www.zenrows.com/scrape. Start free: https://app.zenrows.com/register. Docs: https://docs.zenrows.com
