Arcadium Data Scrapers
Home / Guides / Etsy Scraper

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)

  1. Open arcadium/etsy-products and sign in to Apify (a free account works).
  2. Fill in the input form. The fields below are the ones the example uses.
  3. Set a maximum cost per run in the run options if you want a hard cap.
  4. Start the run. Rows appear in the Output tab as they arrive.
  5. Export the dataset as JSON, CSV or Excel, or connect an integration.
Input fieldTypeDescription
searchTermsarrayKeywords 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).
maxResultsPerSearchintegerListings 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
}
FieldWhat it holds
rowTypeKind 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).
platformAlways 'etsy'.
listingIdEtsy listing id (the number in the listing URL). Listing and review rows.
urlListing page URL.
titleListing title as the seller wrote it.
descriptionListing description (first 300 characters by default, full or none on request). Emails and phone numbers removed.
pricePrice before any sale, in 'currency' (the seller's currency). Lowest variation price when prices vary.
currencyCurrency code of price and salePrice, e.g. USD, EUR, GBP.
salePricePrice during a running sale, in 'currency'; null when not on sale.
discountPercentSale discount in percent; null when not on sale.
onSaleTrue when a sale discount is running.
priceUsdThe price converted by Etsy to US dollars.
quantityItems in stock as the listing states.
isAvailableTrue when the listing can be bought now.
isSoldOutTrue when the listing is sold out.
favoritesHow many shoppers saved the listing as a favorite.
ratingAverage star rating of this listing (not the shop), 1 to 5; null without reviews.
reviewCountNumber of reviews of this listing.
ratingCountsReviews of this listing per star, e.g. {'5': 236, '4': 6, '3': 2, '2': 0, '1': 1}.
tagsThe seller's search tags (up to 13).
materialsMaterials the seller lists.
categoryEtsy category of the listing, e.g. Wallets.
categoryPathFull category path, e.g. Bags and purses > Wallets and money clips > Wallets.
taxonomyIdEtsy taxonomy id of the category.
variationsBuyer 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.
hasVariationPricingTrue when the price depends on the chosen option.
imagesFull-size image URLs, main image first.
whenMadeWhen the item was made as Etsy states it, e.g. 'made_to_order', '2020_2026', 'before_2006'.
isDigitalTrue for digital downloads (no shipping).
isCustomizableTrue when the item can be personalized.
isMadeToOrderTrue when the item is made after the order.
isBestsellerTrue when the listing carries Etsy's Bestseller badge.
shipsFromCountryCountry code the item ships from, e.g. US, TR.
shippingShipping as Etsy shows it to a US shopper: {shipsFrom, freeShipping, cost, costText, deliveryEstimate, deliverTo, returns}. Null for digital items or when 'includeShipping' is off.
shopSectionThe shop's own section the listing is in.
shopThe shop as a business: {shopId, shopName, url, sales, rating, reviewCount, location, country, activeListings, favorites, openedAt, isStarSeller}. No owner names.
createdAtListing date Etsy keeps (ISO). A renewal resets it.
updatedAtLast change of the listing (ISO).
isAdTrue for a paid placement (only with includeAds; no searchRank).
searchInputThe search term or URL that found the listing; null for a listing URL input.
searchRank1-based organic position in the results of searchInput.
reviewIdReview rows: Etsy's transaction id of the reviewed purchase, unique per review.
textReview rows: the review text with personal names, emails and phone numbers removed; null for a rating without text.
dateReview rows: review date (YYYY-MM-DD).
sellerResponseReview rows: the shop's public reply, if any.
hasPhotoReview rows: true when the buyer attached a photo (not exported).
inputError rows: the input (term, URL or id) that failed.
codeError rows: invalid_input, not_found, blocked, unavailable, filter_unsupported or no_match.
messageError rows: what went wrong, in plain words.
scrapedAtWhen 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.