# Etsy Scraper: Listings, Etsy Shop Sales, Tags & Reviews (`vant47/etsy-listings-scraper`) Actor

Get Etsy listings for ceramic mugs, custom gifts or digital planners with prices, discounts, ratings, tags, favourites and shop sales. Search, category, shop and listing URLs. Basic listings $0.0032 each: 1,000 cost $3.20. Full enrichment $0.009 each. No login.

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

## Pricing

from $2.56 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Etsy Scraper: Listings, Etsy Shop Sales, Tags & Reviews

For Etsy sellers researching products and keywords, brands checking resellers, and analysts monitoring public listings. A basic listing costs $0.0032: 1,000 listings cost $3.20. Optional enrichment adds $0.0058 once per listing. Full enrichment totals $0.009 each: 20 cost $0.18. No Etsy login, account cookies, developer key or browser extension is needed.

### What you get

Basic runs return storefront titles, prices, discounts, seller IDs, images, ratings and exposed badges. Listing details add descriptions, favourites, tags, materials and variations. Shop research adds displayed lifetime sales, rating, opening year and up to ten public shop review snippets.

The tested prefill, `ceramic mug` with 20 listings, completed in 8.3 seconds on 29 October 2026. A separate one-listing run with both enrichment options completed in 9.8 seconds and returned tags, materials, variation choices, favourites and shop statistics. Larger jobs and retries take longer.

| Field | Meaning and availability |
| --- | --- |
| `verdict` | Short readable result, such as Listing found or 20% off. |
| `recordType` | LISTING for a listing; NOTE for an input correction; SUMMARY for the run summary. |
| `listingId` | Public Etsy listing ID, stored as text. |
| `title` | Listing title. |
| `price` | Price exposed by the selected source. Usually the storefront's displayed starting price. See `priceScope`. |
| `originalPrice` | Struck-through price when the storefront displays one. |
| `currency` | Source currency code, such as USD, GBP, CAD, AUD or EUR. |
| `discountPercent` | Displayed discount, or calculated from the two displayed prices. |
| `shopName`, `shopId` | Public business identity. A shallow search card may expose only the ID. |
| `rating`, `reviewCount` | Rating and review count shown on the card. These are shop-level figures, identified by `ratingScope: SHOP`. |
| `isBestseller` | Bestseller signal when exposed; null when unknown. |
| `isStarSeller` | Star Seller signal when exposed; null when unknown. |
| `isAd` | Whether the listing was observed in an advertising placement. A listing can appear in both advertising and organic positions. |
| `freeShipping` | True when Etsy exposes a free shipping or delivery signal; otherwise null. Destination, variant and order conditions may apply. |
| `favorites` | Public favourite count with listing details enabled. |
| `tags`, `materials` | Public tag and material arrays with listing details enabled. |
| `description` | Full public description with listing details enabled. |
| `variations` | Available property names and choices, with each choice's base price, currency and availability where provided. |
| `shopSales` | Public displayed shop sales count with shop research enabled. |
| `shopSalesDisplay` | Original shop sales display, such as 53.1k. |
| `shopSalesIsApproximate` | True when the shop displays a rounded count. |
| `shopRating`, `shopOpenedYear` | Public shop rating and opening year with shop research enabled. |
| `shopReviews` | Up to ten shop-page review snippets containing rating, text and date only. No reviewer names, IDs, profile links or avatars. These are shop reviews, not a complete listing-review history. |
| `imageUrl`, `url` | Primary listing image and canonical listing URL. |
| `sourceUrl`, `sourceQuery` | Storefront or public listing data source, plus the keyword when applicable. |
| `priceScope`, `basePrice`, `baseCurrency` | Distinguish storefront displayed starting prices from listing API base prices. |
| `detailsStatus`, `shopStatus` | Whether requested enrichment was available, partial or unavailable. |
| `notes` | Relevant source limitations for this record. |
| `scrapedAt` | UTC extraction time. |

Missing data stays null. Counts retain Etsy's precision: 3.5k becomes 3,500. Missing badges stay unknown.

### Three steps to run it

1. Enter one or more short buyer keywords in Search terms, or paste public Etsy URLs into Etsy URLs.
2. Set the total number of listings you need. Leave enrichment off for a quick search, or enable the fields needed for your research.
3. Start the run and export the dataset as JSON, CSV or Excel. The Listings view shows prices and seller signals; the research view shows tags, materials and shop information.

A quick first run:

```json
{
  "searchTerms": ["ceramic mug"],
  "maxItems": 20,
  "country": "US"
}
```

A known listing with its tags and variations:

```json
{
  "startUrls": ["https://www.etsy.com/listing/4296141840"],
  "includeDetails": true,
  "maxItems": 1,
  "country": "US"
}
```

A shop research run:

```json
{
  "startUrls": ["https://www.etsy.com/shop/HereafterLA"],
  "includeShop": true,
  "maxItems": 20,
  "country": "US"
}
```

A price-filtered category:

```json
{
  "startUrls": ["https://www.etsy.com/c/home-and-living"],
  "priceMin": 15,
  "priceMax": 45,
  "sort": "priceAsc",
  "maxItems": 20
}
```

### Example output

Selected fields from a live cloud result on 29 October 2026:

```json
{
  "listingId": "4296141840",
  "title": "Coffee Mug - KJ Pottery",
  "price": 57,
  "currency": "USD",
  "shopName": "KJPottery",
  "favorites": 1701,
  "shopSales": 20900,
  "shopRating": 4.9,
  "shopOpenedYear": 2013
}
```

### Inputs

| Input | Default | What it does |
| --- | --- | --- |
| `searchTerms` | None; prefill is ceramic mug | Array of buyer keywords. Up to 50 terms are processed. Use short, specific phrases rather than whole paragraphs. |
| `startUrls` | Empty | Array of public Etsy URL strings: search, market, category, listing or shop. Up to 100 URLs are processed. |
| `maxItems` | 20 | Maximum unique listings across the complete run, from 1 to 1,000. It is not a separate allowance for each keyword. |
| `sort` | relevance | relevance, newest, mostRecent, priceAsc or priceDesc. Newest and mostRecent both select Etsy's date-descending order. |
| `categoryFallbackToKeywords` | true | When an exact category page is unavailable, search its label and mark rows `KEYWORD_FALLBACK`. Set false for exact-category-only results. |
| `priceMin`, `priceMax` | Unset | Optional bounds on displayed starting prices in the selected storefront currency. |
| `includeDetails` | false | Add public description, tags, materials, favourites and variations. |
| `includeShop` | false | Add public shop statistics and the review snippets on the shop page. |
| `country` | US | US, GB, CA, AU or DE. Selects storefront locale and the default proxy country. |
| `proxyConfiguration` | Residential proxy | Optional standard Apify proxy settings. Public listing JSON tries direct access first. Storefront pages normally need residential access. |

### Prices, sales and variation limits

Storefront prices are starting prices. They can apply to the least expensive variation, a sale, a delivery destination or an order condition. They are not a checkout quote. Tax, postage and personalisation may change the amount paid.

A direct listing URL uses Etsy's public listing JSON. That source exposes the listing's base price and does not expose the storefront's struck-through promotion. Those records have `priceScope: SELLER_BASE_PRICE`; `originalPrice` and `discountPercent` stay null. Use search, category or shop inputs when the displayed discount is the main thing you are monitoring. Enriching a search result preserves its storefront price instead of replacing it with the base price. The independent API value is retained as `basePrice` and `baseCurrency`; a difference without a displayed promotion is noted. Etsy can expose inconsistent prices across its own surfaces.

Variation choice prices are base prices. The Actor does not enumerate every combination or promise that independent choice prices can be added together. Shop sales are lifetime shop sales, not units sold for this product and not estimated revenue. Rounded displays remain explicitly approximate. Review counts on cards describe the shop, unless Etsy explicitly exposes another scope.

### Pricing examples

| Job | Listing fees before tier discounts |
| --- | --- |
| 20 basic listings | $0.064 |
| 100 basic listings | $0.32 |
| 1,000 basic listings | $3.20 |
| 20 listings with details, shop research, or both | $0.18 |
| 100 enriched listings | $0.90 |

The $0.00005 platform start fee is added, at least once and once per GB when applicable. Listing and enrichment discounts are Bronze 5%, Silver 10%, Gold 20%; higher tiers retain Gold pricing. Platform usage is included.

The optional enrichment event is charged once for a listing that receives requested details or shop information. Turning on both options does not double that event. If neither requested enrichment source delivers useful data, that optional event is not charged. Listing retries, duplicates, input notes and summaries do not create listing charges.

Set a maximum charge in Apify. Before another listing, the Actor checks the listing fee plus requested enrichment allowance. If insufficient, it stops and retains saved rows. A $0.01 limit covers one enriched listing and the start fee at standard pricing.

### Monitor prices every day

Save the input as an Apify task. Create an Apify schedule for that task at the time you need the data each day. Export each run's dataset to your own table, key it by `listingId`, and compare the price together with its currency and `priceScope`.

Keep the input and country consistent. Search absence does not prove removal: use a direct listing URL to confirm whether a known listing remains public.

### API examples

Use your Apify token from an environment variable:

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("vant47/etsy-listings-scraper").call(
    run_input={
        "searchTerms": ["ceramic mug", "leather wallet"],
        "maxItems": 100,
        "includeDetails": True,
        "country": "US"
    }
)
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row.get("recordType") == "LISTING":
        print(row["listingId"], row["price"], row["currency"])
```

The dataset also includes a free SUMMARY row. Filter by `recordType` before loading listing rows into a database. A richer summary is available in the default key-value store under `SUMMARY`. It includes per-input outcomes, listing totals, median prices grouped by currency, top returned tags and bestseller share among records with a known signal. It never averages different currencies into a single price.

### Use with AI agents (MCP)

Connect an agent to `https://mcp.apify.com`. Request this Actor, supply keywords or public URLs, country, listing limit, enrichment options and a maximum charge. Connect datasets to Make, n8n, Zapier, spreadsheets or webhooks.

### Honest coverage limits

- Etsy can refuse requests or change its public data calls. The Actor retries with fresh anonymous sessions, reports source failures without charging for missing listings, and preserves delivered data.
- Some exact category storefronts refuse signed-out requests. By default, their last category label becomes a market keyword search. Each such row contains `categoryScope: KEYWORD_FALLBACK`, the requested category and an explanatory note. Keyword results are not an exact category export. Disable `categoryFallbackToKeywords` to receive a free source note instead.
- Pagination is limited to 30 pages per input and 1,000 unique listings for the run. Repeated pages and exhausted result sets stop early.
- A shallow grid may omit shop names, favourites, tags and materials. Use enrichment for those fields.
- Public shop review snippets are a limited sample. The Actor does not paginate every review, collect reviewer identities or estimate product sales from reviews.
- Sold-out or removed listings may not appear in discovery. A missing direct listing is reported as unavailable; the Actor does not manufacture a product record.
- A source may expose some requested details and omit others. Check the status fields and notes before treating null as zero.
- This tool is independent of Etsy. It reads public, signed-out information and does not perform account actions or transactions.

### Frequently asked questions

#### Do I need an Etsy account or an API key?

No. Supply public keywords or URLs. The Actor does not accept account cookies or Etsy credentials.

#### Can I get all thirteen Etsy tags?

Enable `includeDetails`. It returns the public tag array the listing data source exposes. A seller may supply fewer than thirteen; the Actor does not invent the rest.

#### Why is a price different from the amount on a listing page?

Check `priceScope`, country and currency. Search and shop cards show a starting storefront price, while a direct listing data call exposes its base price. Variations, promotions, postage and tax can change the final price.

#### Will I be charged for duplicate keywords or a reboot?

A listing ID is delivered once per run. Repeating the same keyword does not create a second listing charge. Saved dataset rows and durable charge receipts support restart recovery.

# Actor input Schema

## `searchTerms` (type: `array`):

Buyer keywords such as ceramic mug, custom gifts or digital planner. Each term uses Etsy market search. Overlapping listings are delivered and charged once.

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

Optional public Etsy search, market, category, listing or shop URL strings. Example: https://www.etsy.com/shop/HereafterLA

## `sort` (type: `string`):

Etsy storefront sort order. Most recent and newest both use date descending. Ranking may vary for anonymous visitors.

## `priceMin` (type: `number`):

Optional minimum displayed from-price in the selected country currency.

## `priceMax` (type: `number`):

Optional maximum displayed from-price in the selected country currency.

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

Run-wide maximum unique listings across every input. Default 20; up to 1,000. Duplicates, blocked pages and empty results have no listing fee.

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

Fetch public tags, materials, favourites, full description and available variation choices. Slower: up to two extra paced requests per listing. Successful enrichment adds $0.0058 per listing.

## `includeShop` (type: `boolean`):

Read each public shop storefront for displayed sales, shop rating and opening year. Sales may be rounded by Etsy. Successful enrichment adds the same $0.0058 event, once even with includeDetails. Slower; shops are cached within a run.

## `country` (type: `string`):

Anonymous storefront and proxy country. Currency is read from the source. GB, CA, AU and DE use regional storefronts; US shop and category pages use a regional surface with USD.

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

Default: Apify residential in the selected country for storefronts. Listing JSON tries direct first. A supplied proxy is respected; no outside service or login needed.

## `categoryFallbackToKeywords` (type: `boolean`):

Some Etsy department pages refuse signed-out access. If true, search the category label as a market keyword and mark every row KEYWORD_FALLBACK. If false, an inaccessible exact category returns a free source note.

## Actor input object example

```json
{
  "searchTerms": [
    "ceramic mug"
  ],
  "startUrls": [],
  "sort": "relevance",
  "maxItems": 20,
  "includeDetails": false,
  "includeShop": false,
  "country": "US",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  },
  "categoryFallbackToKeywords": true
}
```

# Actor output Schema

## `listings` (type: `string`):

No description

## `summary` (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 = {
    "searchTerms": [
        "ceramic mug"
    ],
    "startUrls": [],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("vant47/etsy-listings-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 = {
    "searchTerms": ["ceramic mug"],
    "startUrls": [],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("vant47/etsy-listings-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 '{
  "searchTerms": [
    "ceramic mug"
  ],
  "startUrls": [],
  "maxItems": 20
}' |
apify call vant47/etsy-listings-scraper --silent --output-dataset

```

## MCP server setup

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