How to use Etsy Scraper
Step by step: in the Apify Store, over the API, from JavaScript or Python, in n8n, and from AI agents through MCP or LangChain.
$7.20 per 1,000 listings on the Free plan, down to $5.40 on higher plans (live Apify price on 2026-11-01).
1. In the Apify Store (no code)
- Open arcadium/etsy-products and sign in to Apify (a free account works).
- Fill in the input form. The fields below are the ones the example uses.
- Set a maximum cost per run in the run options if you want a hard cap.
- Start the run. Rows appear in the Output tab as they arrive.
- Export the dataset as JSON, CSV or Excel, or connect an integration.
| Input field | Type | Description |
|---|---|---|
searchTerms | array | Keywords to search Etsy for, for example "ceramic mug" or "personalized necklace". Each term is searched on its own; every listing keeps the term and its position in the results. Also read from queries, searchQueries, searchQuery, search or keywords (other Etsy actors' names). |
maxResultsPerSearch | integer | Listings per search term or search/category URL, e.g. 50 (the default). Each page holds 40 to 64 results; Etsy pages up to about 250 pages deep. Also read from maxResults, maxResultsPerTerm, maxListings or maxPages (x 36). |
Example input:
{
"searchTerms": [
"ceramic mug"
],
"maxResultsPerSearch": 20
}
2. Over the Apify API
The synchronous endpoint runs the actor and returns its rows in one call (for runs up to about five minutes; use the asynchronous run endpoint for longer ones).
curl -X POST "https://api.apify.com/v2/acts/arcadium~etsy-products/run-sync-get-dataset-items" \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"searchTerms":["ceramic mug"],"maxResultsPerSearch":20}'
3. From JavaScript
// npm install apify-client
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('arcadium/etsy-products').call({
"searchTerms": [
"ceramic mug"
],
"maxResultsPerSearch": 20
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
4. From Python
# pip install apify-client
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("arcadium/etsy-products").call(run_input={
"searchTerms": ["ceramic mug"],
"maxResultsPerSearch": 20,
})
items = client.dataset(run.default_dataset_id).list_items().items # apify-client 3.x returns a Run object
print(items)
5. In n8n
Paste this node into a workflow (it is a plain HTTP Request node). Create a Header Auth credential with name Authorization and value Bearer <APIFY_TOKEN>; each returned row becomes one item for the next node.
{
"nodes": [
{
"name": "Run arcadium/etsy-products",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
0,
0
],
"parameters": {
"method": "POST",
"url": "https://api.apify.com/v2/acts/arcadium~etsy-products/run-sync-get-dataset-items",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "{\"searchTerms\":[\"ceramic mug\"],\"maxResultsPerSearch\":20}",
"options": {
"timeout": 300000
}
}
}
],
"connections": {}
}
6. From an AI assistant (MCP)
Add Apify’s MCP server to Claude Desktop, Cursor, VS Code or any MCP client, limited to this actor:
{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com/?tools=arcadium/etsy-products",
"headers": {
"Authorization": "Bearer <APIFY_TOKEN>"
}
}
}
}
More on the MCP page.
7. From LangChain
# pip install langchain-apify (reads APIFY_API_TOKEN from the environment)
from langchain_apify import ApifyActorsTool
tool = ApifyActorsTool("arcadium/etsy-products")
rows = tool.invoke({"run_input": {
"searchTerms": ["ceramic mug"],
"maxResultsPerSearch": 20,
}})
# or give `tool` to an agent: create_react_agent(llm, [tool])
Sample output
One row, from the example in the actor’s README. Long text is shortened and lists are cut to two items.
{
"rowType": "listing",
"platform": "etsy",
"listingId": "962939986",
"title": "Leather Envelope Wallet for Women, Personalized Mini Card Wallet, Full Grain Crazy Horse",
"url": "https://www.etsy.com/listing/962939986",
"price": 64,
"currency": "USD",
"salePrice": 57.6,
"discountPercent": 10,
"onSale": true,
"favorites": 4979,
"rating": 4.95,
"reviewCount": 245,
"tags": [
"Envelope Wallet",
"Women's Leather"
],
"materials": [
"Full Grain Crazy Horse Leather"
],
"category": "Wallets",
"variations": [
{
"name": "Primary color",
"options": [
{
"value": "Tan",
"price": null,
"available": true
}
]
}
],
"whenMade": "2020_2026",
"shipsFromCountry": "TR",
"shipping": {
"shipsFrom": "Türkiye",
"freeShipping": true,
"deliveryEstimate": "Oct 26-Nov 2",
"deliverTo": "United States",
"returns": "Returns & exchanges accepted within 30 days."
},
"shop": {
"shopId": "28165607",
"shopName": "YukonLeatherGoods",
"sales": 6583,
"rating": 4.92,
"reviewCount": 1412,
"location": "Dover, Delaware",
"isStarSeller": true
},
"searchInput": "leather wallet",
"searchRank": 3,
"isAd": false
}
| Field | What it holds |
|---|---|
rowType | Kind of row. Filter on this first. 'listing': one Etsy listing (charged). 'review': one listing review, only when reviews are requested (charged). 'error': an input could not be read; see code and message (free). |
platform | Always 'etsy'. |
listingId | Etsy listing id (the number in the listing URL). Listing and review rows. |
url | Listing page URL. |
title | Listing title as the seller wrote it. |
description | Listing description (first 300 characters by default, full or none on request). Emails and phone numbers removed. |
price | Price before any sale, in 'currency' (the seller's currency). Lowest variation price when prices vary. |
currency | Currency code of price and salePrice, e.g. USD, EUR, GBP. |
salePrice | Price during a running sale, in 'currency'; null when not on sale. |
discountPercent | Sale discount in percent; null when not on sale. |
onSale | True when a sale discount is running. |
priceUsd | The price converted by Etsy to US dollars. |
quantity | Items in stock as the listing states. |
isAvailable | True when the listing can be bought now. |
isSoldOut | True when the listing is sold out. |
favorites | How many shoppers saved the listing as a favorite. |
rating | Average star rating of this listing (not the shop), 1 to 5; null without reviews. |
reviewCount | Number of reviews of this listing. |
ratingCounts | Reviews of this listing per star, e.g. {'5': 236, '4': 6, '3': 2, '2': 0, '1': 1}. |
tags | The seller's search tags (up to 13). |
materials | Materials the seller lists. |
category | Etsy category of the listing, e.g. Wallets. |
categoryPath | Full category path, e.g. Bags and purses > Wallets and money clips > Wallets. |
taxonomyId | Etsy taxonomy id of the category. |
variations | Buyer options, e.g. [{name: 'Primary color', options: [{value: 'Tan', price: 64, available: true}]}]. Option price is null when the option does not change the price. |
hasVariationPricing | True when the price depends on the chosen option. |
images | Full-size image URLs, main image first. |
whenMade | When the item was made as Etsy states it, e.g. 'made_to_order', '2020_2026', 'before_2006'. |
isDigital | True for digital downloads (no shipping). |
isCustomizable | True when the item can be personalized. |
isMadeToOrder | True when the item is made after the order. |
isBestseller | True when the listing carries Etsy's Bestseller badge. |
shipsFromCountry | Country code the item ships from, e.g. US, TR. |
shipping | Shipping as Etsy shows it to a US shopper: {shipsFrom, freeShipping, cost, costText, deliveryEstimate, deliverTo, returns}. Null for digital items or when 'includeShipping' is off. |
shopSection | The shop's own section the listing is in. |
shop | The shop as a business: {shopId, shopName, url, sales, rating, reviewCount, location, country, activeListings, favorites, openedAt, isStarSeller}. No owner names. |
createdAt | Listing date Etsy keeps (ISO). A renewal resets it. |
updatedAt | Last change of the listing (ISO). |
isAd | True for a paid placement (only with includeAds; no searchRank). |
searchInput | The search term or URL that found the listing; null for a listing URL input. |
searchRank | 1-based organic position in the results of searchInput. |
reviewId | Review rows: Etsy's transaction id of the reviewed purchase, unique per review. |
text | Review rows: the review text with personal names, emails and phone numbers removed; null for a rating without text. |
date | Review rows: review date (YYYY-MM-DD). |
sellerResponse | Review rows: the shop's public reply, if any. |
hasPhoto | Review rows: true when the buyer attached a photo (not exported). |
input | Error rows: the input (term, URL or id) that failed. |
code | Error rows: invalid_input, not_found, blocked, unavailable, filter_unsupported or no_match. |
message | Error rows: what went wrong, in plain words. |
scrapedAt | When the row was collected (ISO). |
Schedule it
In Apify Console, create a Task from your input and add a Schedule (for example daily). Each run writes a new dataset; integrations can push the rows to Google Sheets, Slack, a webhook or your database.