# Etsy Listings & Shop Export (Etsy Open API v3) (`cliqtomedia/etsy-listings-api`) Actor

Export active Etsy listings by keyword or by shop with your own approved Etsy app and the Etsy Open API v3: price, views, favorites, tags, materials, photos and shop stats. No scraping, no proxy.

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

## Pricing

from $3.15 / 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

**You need your own approved Etsy app.** Every user of this Actor needs their own app at [etsy.com/developers/your-apps](https://www.etsy.com/developers/your-apps). Etsy must approve it first, then you paste its keystring and shared secret into the input. Without them the Actor saves one free notice row and stops.

This Actor exports active Etsy listings by keyword search or by shop through the Etsy Open API v3, with your own Etsy app key. You get price, views, favorites, tags, materials, photos and shop stats as JSON, CSV or Excel. A typical run, one search with 10 listings, takes a few seconds and costs $0.0465 on the Free plan.

![Etsy Listings & Shop Export: your search or shop goes in, active listings with price, views and favorites come out as JSON or CSV](https://api.apify.com/v2/key-value-stores/iQ58Dj6AEbL4LOzqc/records/hero-v1.png)

### Table of contents

- [What it does](#what-it-does)
- [How it works](#how-it-works)
- [Get your Etsy key](#get-your-etsy-key)
- [Quick start](#quick-start)
- [Use cases](#use-cases)
- [Input](#input)
- [Output](#output)
- [Pricing](#pricing)
- [Limits](#limits)
- [API, export and integrations](#api-export-and-integrations)
- [Troubleshooting](#troubleshooting)
- [FAQ](#faq)
- [Support](#support)

### What it does

You give keyword searches or shop names. The Actor returns one row for each active Etsy listing: title, description, price and currency, stock, views, favorites, tags, materials, all photo links, dates and shop data (name, rating, reviews, sales, country).

It reads Etsy's public developer API with your key. It does not open etsy.com pages, so there is no blocking, no proxy and no browser.

#### Good fit

- Price and demand research for a product idea: compare price, views and favorites across many listings.
- Shop research: export all active listings of shops you want to study.
- Tag and keyword research: see which tags and materials sellers use for a search.

### How it works

1. You choose a mode: search all of Etsy by keywords, or export whole shops by shop name.
2. The Actor asks the Etsy Open API v3 for active listings with your keystring and shared secret. It reads listing pages of up to 100 and adds photos and shop data.
3. It saves one row per listing in the Dataset, in Etsy's order, and a run summary (`RUN_SUMMARY`) in the key-value store.

### Get your Etsy key

1. Sign in to Etsy and open [etsy.com/developers/your-apps](https://www.etsy.com/developers/your-apps).
2. Create a new app and describe how you will use the data.
3. Wait until Etsy approves the app. Etsy decides this; it can take a few days.
4. Copy the **keystring** and the **shared secret** from the app page.

The Actor uses your app's request limit (a new app usually has 5 requests per second and 5,000 per day). It never shares your key with anyone, and it does not save it in the Dataset, logs or run summary. See [Etsy's authentication docs](https://developers.etsy.com/documentation/essentials/authentication) for details.

### Quick start

1. Open the **Input** tab.
2. Paste your keystring into **Etsy API keystring** (`apiKey`) and your shared secret into **Etsy shared secret** (`sharedSecret`).
3. Keep the prefilled search `handmade mug` and **Max listings per search or shop** = 10.
4. Click **Start**.
5. Open the **Output** tab and check `title`, `price`, `views` and `favorites`.

Expected result: 10 listing rows in about 5 seconds, run status `COMPLETE`.

### Use cases

| Buyer job | Input path | Output entity | Key fields | Next step |
| --- | --- | --- | --- | --- |
| Price and demand research | `keywords` | Listing | `price`, `currency`, `views`, `favorites` | Sort or chart in a spreadsheet |
| Shop research | `mode: shop`, `shopNames` | Listing | `title`, `price`, `quantity`, `createdAt` | Export to CSV or Excel |
| Tag research | `keywords` | Listing | `tags`, `materials`, `rank` | Count tags in your own tool |
| Seller comparison | `keywords` | Listing | `shopName`, `shopRating`, `shopSales` | Join with your own data by `shopId` |

### Input

#### Input fields

| Field | Plain name | Type | Required | Default / prefill | Allowed values | Effect |
| --- | --- | --- | --- | --- | --- | --- |
| `apiKey` | Etsy API keystring | secret string | yes | none | your keystring, or `keystring:shared_secret` | Without it the Actor saves one free notice row |
| `sharedSecret` | Etsy shared secret | secret string | yes, unless it is inside `apiKey` | none | your shared secret | Etsy rejects requests without it |
| `mode` | What to export | string | no | `search` | `search`, `shop` | Search all of Etsy, or whole shops |
| `keywords` | Keyword searches | array of strings | in mode `search` | prefill `["handmade mug"]` | up to 50, each under 200 characters | One search for each line |
| `shopNames` | Shop names | array of strings | in mode `shop` | none | up to 200 names or `etsy.com/shop/<name>` links | One export for each shop |
| `maxItems` | Max listings per search or shop | integer | no | default 100, prefill 10 | 1 to 10,000 | Stops each search or shop after this many saved listings |
| `sortBy` | Sort by | string | no | `relevance` | `relevance`, `newest`, `price_low`, `price_high`, `recently_updated` | Order of the listings |
| `minPrice` | Min price | number | no | none | 0 to 1,000,000 | Keyword search only |
| `maxPrice` | Max price | number | no | none | 0 to 1,000,000 | Keyword search only |
| `shopLocation` | Shop location | string | no | none | a place, for example `United States` | Keyword search only |

Repeated searches or shops in one run (also with other letter case, or a shop name and its link) run once. An empty search list with a key is an input error.

#### Interacting settings

| When | Setting A | Setting B | What happens |
| --- | --- | --- | --- |
| Mode `shop` | `keywords` | `shopNames` | Keywords are ignored; the run summary has a warning |
| Mode `shop` | `sortBy: relevance` | — | Shops have no relevance order, so you get newest first |
| Mode `shop` | `minPrice`, `maxPrice`, `shopLocation` | — | These filters work only for keyword search |
| Any mode | `maxItems` | number of searches | `maxItems` is per search or shop, not per run |
| Sort by price | `price_low` / `price_high` | — | Etsy's order; it is almost, but not always strictly, sorted |

#### Input examples

##### One keyword search

```json
{
  "keywords": ["handmade mug"],
  "maxItems": 10
}
```

Add your `apiKey` and `sharedSecret`. Expected: 10 listings for `handmade mug`, status `COMPLETE`. Cost: see [Pricing](#pricing).

##### Whole shops

```json
{
  "mode": "shop",
  "shopNames": ["CaitlynMinimalist", "https://www.etsy.com/shop/SomeShop"],
  "maxItems": 1000,
  "sortBy": "price_low"
}
```

Expected: up to 1,000 active listings of each shop. A shop that does not exist gets `found: false` in the run summary and no rows.

### Output

#### Output fields

| Field | Meaning | Type | Can be empty? | Example |
| --- | --- | --- | --- | --- |
| `status` | Row type | string | no | `listing` or `api_key_required` |
| `mode` | Mode of the run | string | no for listings | `search` |
| `query` | The search or shop name this row came from | string | no for listings | `handmade mug` |
| `rank` | Position in that search or shop, in the sort you chose | integer | no for listings | `1` |
| `listingId` | Etsy listing ID | integer | no for listings | `1389148459` |
| `title` | Listing title | string | no for listings | `Vintage pottery mug...` |
| `description` | Full listing text | string | yes | |
| `price` | Base listing price in the shop's currency | number | yes, when Etsy sends none | `24` |
| `currency` | Currency code of the price | string | yes | `USD` |
| `quantity` | Items in stock | integer | yes | `4` |
| `shopId`, `shopName`, `shopUrl` | Shop | integer, string, string | yes | `msvintagenicole` |
| `shopRating` | Average review score, 1–5 | number | yes | `4.96` |
| `shopReviewCount` | Number of shop reviews | integer | yes | `225` |
| `shopSales` | Shop sales count | integer | yes | `794` |
| `shopCountry` | Shop country code | string | yes | `US` |
| `views` | Listing views | integer | yes | `1670` |
| `favorites` | People who saved the listing | integer | yes | `65` |
| `tags`, `materials` | Seller's tags and materials | array of strings | can be `[]` | `["pottery mug"]` |
| `taxonomyId` | Etsy category ID | integer | yes | `1062` |
| `whoMade`, `whenMade` | Seller's answers about who made it and when | string | yes | `i_did`, `made_to_order` |
| `isCustomizable`, `isPersonalizable`, `hasVariations`, `isDigital` | Listing flags | boolean | yes | `false` |
| `state` | Listing state | string | yes | `active` |
| `url` | Listing link | string | no for listings | `https://www.etsy.com/listing/...` |
| `mainImageUrl`, `images` | First photo and all photos, full size | string, array | yes / `[]` | `https://i.etsystatic.com/...` |
| `createdAt`, `updatedAt` | Listing dates (ISO 8601) | string | yes | `2023-01-08T23:00:19.000Z` |
| `source` | Data source | string | no | `etsy-open-api-v3` |
| `fetchedAt` | When the Actor read this row | string | no | `2026-10-22T11:08:41.815Z` |
| `message` | Text for the notice row | string | null on listings | |

`null` means Etsy did not send the value. The Actor never puts a made-up 0 in its place.

#### Output entities and surfaces

| Situation | Where | Shape | What to do |
| --- | --- | --- | --- |
| Normal run | Dataset (**Listings** view) and `RUN_SUMMARY` | listing rows; status `COMPLETE` | Open, export or use by API |
| No key | Dataset | one free `api_key_required` row; run `SUCCEEDED` | Add your keystring and shared secret |
| Search finds nothing, or unknown shop | `RUN_SUMMARY` | no rows; status `NO_RESULTS`, `found: false` for unknown shops | Check spelling or try a wider search |
| Stopped early | Dataset and `RUN_SUMMARY` | rows saved so far; status `PARTIAL` with `stopReason` | See [Troubleshooting](#troubleshooting) |
| Wrong key | `RUN_SUMMARY` and run log | no rows; run `FAILED`, error code `API_KEY_INVALID` | Check both values in your Etsy app |

`RUN_SUMMARY` also shows, for each search or shop, how many listings were saved and how many Etsy has (`totalAvailable`), plus your app's request limit before and after the run.

#### Output example

```json
{
  "status": "listing",
  "mode": "search",
  "query": "handmade mug",
  "rank": 1,
  "listingId": 1389148459,
  "title": "Vintage pottery mug, handmade mug, ceramic mug, ...",
  "price": 24,
  "currency": "USD",
  "quantity": 4,
  "shopName": "msvintagenicole",
  "shopRating": 4.96,
  "shopReviewCount": 225,
  "shopSales": 794,
  "shopCountry": "US",
  "views": 1670,
  "favorites": 65,
  "tags": ["vintage mugs", "handmade mugs", "pottery mug"],
  "materials": [],
  "whoMade": "someone_else",
  "isDigital": false,
  "url": "https://www.etsy.com/listing/1389148459/vintage-pottery-mug-handmade-mug-ceramic",
  "mainImageUrl": "https://i.etsystatic.com/7160843/r/il/ecdd09/4549836599/il_fullxfull.4549836599_8pxs.jpg",
  "createdAt": "2023-01-08T23:00:19.000Z",
  "source": "etsy-open-api-v3",
  "fetchedAt": "2026-10-22T11:08:41.815Z",
  "message": null
}
```

This example is trimmed: a real row also has `description`, `images`, the shop IDs and links, the other flags and `updatedAt`.

### Pricing

#### Pricing unit

You pay per event. Apify platform usage is included; you do not pay it separately.

| Event | When it is charged | Free plan | Bronze | Silver | Gold |
| --- | --- | ---: | ---: | ---: | ---: |
| Listing | One listing saved to the Dataset | $0.0045 | $0.00405 | $0.0036 | $0.00315 |
| Search or shop | One unique search or shop name sent to Etsy, also when it finds nothing | $0.0005 | $0.00045 | $0.0004 | $0.00035 |
| Actor start | Once per run | $0.001 | $0.001 | $0.001 | $0.001 |

- The start fee is per GB of run memory, at least one event. The default 512 MB run pays one.
- The free `api_key_required` row is not charged. A run without a key pays only the start fee.
- Repeated searches in one run are not charged again. An unknown shop is charged as one shop, because Etsy is still asked.
- If you set a maximum cost per run, the Actor stops before it goes over and ends with `PARTIAL`. Listings that were not saved are never charged.
- Your Etsy app's request limit is your own and free; Etsy does not charge for it.

#### Cost examples

Free plan prices, default 512 MB memory.

| Scenario | Input | Events | Cost |
| --- | --- | --- | ---: |
| No key | any | 1 start | $0.001 |
| Search with no matches | 1 search | 1 start + 1 search | $0.0015 |
| Prefill | 1 search, 10 listings | 1 start + 1 search + 10 listings | $0.0465 |
| Small export | 1 search, 100 listings | 1 start + 1 search + 100 listings | $0.4515 |
| Shop export | 1 shop, 1,000 listings | 1 start + 1 shop + 1,000 listings | $4.5015 |
| Large export | 1 search, 10,000 listings | 1 start + 1 search + 10,000 listings | $45.0015 |

### Limits

- **Your own Etsy app is required.** The Actor has no shared key, no demo mode and no sample data.
- **Active listings only.** Sold, expired, draft and private listings are not in the public API. There are no reviews, sales history, ad slots or "in carts" counts.
- **Price is the base listing price in the shop's currency.** It is not converted to USD. The price on etsy.com can differ when a listing has variations or a sale.
- **Search order is the API's order.** It is not the same as the order on etsy.com search pages, so the top results can differ.
- **Up to 10,000 listings per search or shop, 50 searches or 200 shops per run.** One search of 10,000 listings took about 2 minutes in our tests; it can take longer when Etsy answers slowly, and the default run timeout is 10 minutes. For several large searches, raise the run timeout; when time runs out the run ends with `PARTIAL` and `TIME_LIMIT` and keeps the saved rows.
- **Etsy request limit.** Every 100 listings use 2 requests of your app's daily limit (5,000 per day for a new app). When the limit runs out mid-run, the run ends with `PARTIAL` and `QUOTA_LIMIT`.
- **Not a drop-in replacement** for Etsy scrapers that read etsy.com pages: some field names differ, and the source is the API, not the website.

#### Etsy API Terms

The term 'Etsy' is a trademark of Etsy, Inc. This Application uses Etsy's API, but is not endorsed or certified by Etsy.

You run this Actor with your own Etsy app, so [Etsy's API Terms](https://www.etsy.com/legal/api/) apply to you and your use of the data. Two points matter most for exports: Etsy says listing data you show to others must not be more than 6 hours old, so run the Actor again instead of keeping old exports; and Etsy limits sharing its members' data with third parties. Check the terms before you use the data.

### API, export and integrations

- **API:** start runs and read the Dataset with the [Apify API](https://docs.apify.com/api/v2) or the [Apify clients](https://docs.apify.com/api/client/js). Pass `apiKey` and `sharedSecret` in the run input.
- **Export:** download the Dataset as JSON, CSV, Excel, XML or HTML from the **Output** tab or the API.
- **Scheduling:** run the same input on a [schedule](https://docs.apify.com/platform/schedules) to keep your data fresh.
- **Webhooks and no-code:** send results onward with [integrations](https://docs.apify.com/platform/integrations) such as webhooks, Make or Zapier.

#### Use with AI agents (MCP)

- MCP server with only this Actor: `https://mcp.apify.com?tools=cliqtomedia/etsy-listings-api` ([Apify MCP docs](https://docs.apify.com/platform/integrations/mcp)).
- Smallest useful input: `{"keywords": ["handmade mug"], "maxItems": 10}` plus `apiKey` and `sharedSecret` of the user's own approved Etsy app.
- Key output fields: `title` (listing name), `price` with `currency` (base price in the shop's currency), `views` and `favorites` (demand signals), `tags` (seller keywords), `url` (listing link).
- A 10-listing run takes about 5 seconds and costs $0.0465 on the Free plan. Without a key the run returns one `api_key_required` row and costs $0.001.

### Troubleshooting

#### I get one row with status `api_key_required`

Symptom: one row, no listings, run `SUCCEEDED`.
Reason: the keystring or the shared secret is missing.
Action: paste both from your app page at etsy.com/developers/your-apps and run again.

#### The run failed with `API_KEY_INVALID`

Symptom: run `FAILED`, no rows.
Reason: Etsy rejected the key. Often the app is not approved yet, or the keystring and the shared secret are swapped.
Action: check that the app status is approved, and paste the keystring into `apiKey` and the secret into `sharedSecret`.

#### The run ended with `PARTIAL`

Read `stopReason` in `RUN_SUMMARY`:

- `QUOTA_LIMIT` — your Etsy app used its daily request limit. Wait until it resets, or ask Etsy for a higher limit.
- `TIME_LIMIT` — the run timeout was too short for this many listings. Raise the timeout or split the searches.
- `CHARGE_LIMIT` — the run reached the maximum cost per run you set.
- `SOURCE_ERROR` — Etsy stopped answering. The rows saved before are kept; try again later.

#### A search returns no rows

Status `NO_RESULTS` means Etsy has no active listings for that search with your filters. Check the spelling, remove `minPrice`, `maxPrice` or `shopLocation`, or try a wider search.

### FAQ

#### Do I need my own Etsy app?

Yes. Every user needs their own approved Etsy app. Etsy decides on approval, and the Actor cannot run without your keystring and shared secret.

#### Why are the results different from etsy.com search?

The Actor uses the Etsy Open API, and the API ranks search results in its own way. Prices are base prices in the shop's currency, while the website can show a sale or variation price.

#### How fresh is the data?

Each row is read from Etsy during your run; `fetchedAt` shows when. Nothing is kept between runs. Etsy's API Terms ask you not to show listing data older than 6 hours, so run again for fresh data.

#### Is my key safe?

The key fields are secret inputs, stored encrypted by Apify. The Actor does not write your key to the Dataset, the run log or `RUN_SUMMARY`.

### Support

For a bug, a question or a feature request, open the **Issues** tab of this Actor on Apify. Add the run ID, the mode and the error text. Never post your keystring or shared secret.

# Changelog

This Actor's version history is a separate document: https://apify.com/cliqtomedia/etsy-listings-api/changelog.md

# Actor input Schema

## `apiKey` (type: `string`):

Keystring of your approved Etsy app from etsy.com/developers/your-apps. You can also paste keystring:shared_secret here. Stored encrypted; never written to the dataset, logs or run summary.

## `sharedSecret` (type: `string`):

Shared secret of the same app (shown next to the keystring). Etsy rejects requests without it. Stored encrypted.

## `mode` (type: `string`):

search = active listings matching your keywords across Etsy; shop = all active listings of the shops you name.

## `keywords` (type: `array`):

Searches as you would type them on Etsy, one per line, up to 50. Used in mode search.

## `shopNames` (type: `array`):

Shop names or shop links (etsy.com/shop/<name>), up to 200. Used in mode shop. Unknown shops are listed in the run summary.

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

Stop each search or shop after this many saved listings. Each saved listing is one paid result.

## `sortBy` (type: `string`):

Order of the listings. Relevance works for keyword searches; for shops it means newest first.

## `minPrice` (type: `number`):

Only listings priced at least this much (keyword search only).

## `maxPrice` (type: `number`):

Only listings priced at most this much (keyword search only).

## `shopLocation` (type: `string`):

Only shops in this place, for example United States or Canada (keyword search only).

## Actor input object example

```json
{
  "mode": "search",
  "keywords": [
    "handmade mug",
    "personalized necklace"
  ],
  "shopNames": [
    "CaitlynMinimalist"
  ],
  "maxItems": 10,
  "sortBy": "relevance",
  "shopLocation": "United States"
}
```

# Actor output Schema

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

Active Etsy listings as a table.

## `runSummary` (type: `string`):

Status, stop reason, per-search and per-shop counts, unknown shops and your Etsy app's request limits.

# 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 = {
    "keywords": [
        "handmade mug"
    ],
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("cliqtomedia/etsy-listings-api").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 = {
    "keywords": ["handmade mug"],
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("cliqtomedia/etsy-listings-api").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 '{
  "keywords": [
    "handmade mug"
  ],
  "maxItems": 10
}' |
apify call cliqtomedia/etsy-listings-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,cliqtomedia/etsy-listings-api"
        }
    }
}
```

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/x8N2pDc2Ne4CcxflM/builds/Rx7gBsAfWgNiS5X0i/openapi.json
