# Etsy Listings Scraper - Search Results & URLs (`khadinakbar/etsy-listings-scraper`) Actor

Discover publicly indexed Etsy listings from keywords. Returns validated IDs, canonical URLs, titles, snippets, indexed shop/rating metadata, and source context. Use for listing discovery—not live Etsy-page details, carts, ads, inventory, or reviews. $0.003 per listing plus usage.

- **URL**: https://apify.com/khadinakbar/etsy-listings-scraper.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** E-commerce, Automation, SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 etsy listing returneds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## Etsy Listings Scraper

Discover Etsy listings from keyword searches for product research, assortment monitoring, and competitor discovery. This Actor returns a clean dataset of listing IDs, canonical Etsy URLs, titles, indexed snippets, and any indexed shop or rating metadata.

It is a **listing-discovery** Actor. It does not open Etsy listing pages and does not claim live prices, carts, ads, inventory, shipping, seller sales, full descriptions, or review details. That narrow contract is intentional: the data is sourced from public search-index results, so every returned row carries `dataSource: "public-search-index"` and its originating query.

### When to use it

Use this Actor when you need a quick, structured list of Etsy products for a keyword, such as `handmade necklace`, `personalized leather journal`, or `printable wedding invitation`. It is useful for building a candidate set for market research, monitoring which listings are publicly discoverable, and sending stable Etsy listing URLs to another workflow.

Do not use it when you need current listing-page facts such as a product price, stock, variations, delivery terms, photos, shop analytics, customer reviews, promoted placement, or cart activity. Those values are not guaranteed by a public search index and are deliberately not fabricated here.

### Output

Each dataset item is a validated listing-discovery record:

| Field | Meaning |
| --- | --- |
| `listingId` | Etsy listing identifier parsed from the canonical URL. |
| `listingUrl` | Canonical Etsy listing URL. |
| `title` | Title visible in the public search result. |
| `description` | Indexed result snippet in detailed mode, otherwise `null`. |
| `rating`, `reviewCount`, `shopName` | Metadata only when the search index exposes it; otherwise `null`. |
| `sourceQuery`, `sourceSearchUrl` | Query and index request that found the listing. |
| `resultPosition` | One-based position within the parsed index page. |
| `scrapedAt`, `dataSource`, `parseWarnings` | Provenance and safe availability diagnostics. |

The default key-value store also contains `OUTPUT` and `RUN_SUMMARY`. `OUTPUT` is a compact stable machine contract. `RUN_SUMMARY` explains source coverage, duplicate handling, row validation, warnings, and charged events.

### Pricing

- Actor start: **$0.00005** per GB of configured memory
- Etsy listing returned: **$0.003** for each validated record successfully written to the dataset

Platform compute and residential proxy usage are additional under **Pay per event + usage**. `maxResults` is both the dataset and event-cost cap. For example, `maxResults: 50` caps primary listing-event charges at $0.15, plus the small start charge and platform usage.

No event is charged for an invalid, duplicate, or failed dataset row.

### Input

`searchQueries` accepts up to 20 keyword phrases. If omitted, the safe default query is `handmade necklace`, which lets quality checks execute a useful, bounded run. An explicitly empty query list is rejected with an actionable `INVALID_INPUT` outcome.

`maxResults` is the global cap from 1 to 200. `maxPagesPerQuery` controls how many public search-index pages are requested per query, from 1 to 10. `responseFormat: "concise"` returns stable listing-discovery fields with a `null` description; use `"detailed"` only when you want the optional indexed snippet. Set `deduplicateAcrossQueries` to `false` if you want to retain the same listing under multiple search queries.

#### Apify Console input

```json
{
  "searchQueries": ["handmade necklace", "personalized leather journal"],
  "maxResults": 50,
  "maxPagesPerQuery": 2,
  "responseFormat": "concise",
  "deduplicateAcrossQueries": true
}
````

#### JavaScript

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('khadinakbar/etsy-listings-scraper').call({
  searchQueries: ['handmade necklace'],
  maxResults: 20,
  maxPagesPerQuery: 2,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
from apify_client import ApifyClient
import os

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('khadinakbar/etsy-listings-scraper').call(run_input={
    'searchQueries': ['personalized leather journal'],
    'maxResults': 20,
    'responseFormat': 'detailed',
})
for item in client.dataset(run['defaultDatasetId']).iterate_items():
    print(item['listingUrl'], item['title'])
```

### Outcomes and operational behavior

The Actor always writes `OUTPUT` and `RUN_SUMMARY` before its terminal state. `COMPLETE` means every requested source completed with useful persisted rows. `PARTIAL` preserves useful rows but reports exhausted sources, row validation failures, or a charge cap. `VALID_EMPTY` means the public search index processed valid input and exposed no Etsy listing records. `INVALID_INPUT` provides a correction example. `UPSTREAM_FAILED` is used honestly when every required public-index source fails before any useful row can be written.

Rows are normalized, validated, written, and charged in one SDK call. The actor retries a transient source failure up to three times with the same residential session identifier. It never writes diagnostic or placeholder rows into the dataset.

### Tips

- Start with one precise phrase. Add query variations only after checking the first dataset.
- Treat `rating`, `reviewCount`, `shopName`, and `description` as optional fields. A `null` value means the search index did not expose that field.
- Use the canonical `listingUrl` as a join key for your own approved downstream workflows.
- Use scheduled runs for visibility tracking, then compare datasets by `listingId`; search-index ordering and availability may change over time.

### FAQ

**Why is the price missing?** This Actor intentionally does not claim direct listing-page data. Search-index snippets are not a reliable product-price contract.

**Can I pass Etsy URLs?** No. This actor accepts keyword discovery only, which keeps the input small and the output provenance clear.

**Why did the Actor return `VALID_EMPTY`?** The search-index route worked, but it did not expose qualifying Etsy listing links for the supplied query and requested pages.

**Why did the Actor return `UPSTREAM_FAILED`?** The public search-index route failed before any useful listing row could be persisted. Inspect `RUN_SUMMARY.warnings` and retry later with a smaller query set.

### Responsible use

Use this Actor only for lawful, authorized purposes and in accordance with the terms that apply to your use of Etsy and any downstream data source. Do not use it to collect private information, bypass access controls, or make decisions that materially affect people without appropriate review.

# Actor input Schema

## `searchQueries` (type: `array`):

Use this when you need Etsy listing discovery for one or more product keywords. Enter terms such as handmade necklace or personalized leather journal, with one query per item. It defaults to handmade necklace when omitted and accepts at most 20 queries. This is not an Etsy URL field and does not promise direct listing-page enrichment.

## `maxResults` (type: `integer`):

Use this to cap the validated listing records written to the dataset and the primary event cost. Enter an integer such as 50. It defaults to 50 and accepts 1 through 200. This is a global result cap, not a page count or a promise of how many listings the public index contains.

## `maxPagesPerQuery` (type: `integer`):

Use this to limit public search-index pages requested for each query. Enter an integer such as 2. It defaults to 2 and accepts 1 through 10. This is not Etsy pagination and does not guarantee a fixed number of listings per page.

## `responseFormat` (type: `string`):

Use this to choose whether indexed result snippets are included. Select concise for stable discovery fields only or detailed to include an indexed description snippet when available. It defaults to concise. This does not fetch or summarize a listing page.

## `deduplicateAcrossQueries` (type: `boolean`):

Use this to keep the first occurrence of a listing ID when several search queries surface the same listing. Set true for a unique dataset or false to retain query-specific duplicates. It defaults to true. This only deduplicates within the current run and does not compare earlier datasets.

## Actor input object example

```json
{
  "searchQueries": [
    "handmade necklace",
    "personalized leather journal"
  ],
  "maxResults": 50,
  "maxPagesPerQuery": 2,
  "responseFormat": "concise",
  "deduplicateAcrossQueries": true
}
```

# Actor output Schema

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

Validated Etsy listing discovery records.

## `output` (type: `string`):

Compact run outcome and billing counts.

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

Detailed source coverage, warnings, and charge information.

# 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 = {
    "searchQueries": [
        "handmade necklace"
    ],
    "maxResults": 20,
    "maxPagesPerQuery": 2,
    "responseFormat": "concise",
    "deduplicateAcrossQueries": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/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 = {
    "searchQueries": ["handmade necklace"],
    "maxResults": 20,
    "maxPagesPerQuery": 2,
    "responseFormat": "concise",
    "deduplicateAcrossQueries": True,
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/etsy-listings-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "handmade necklace"
  ],
  "maxResults": 20,
  "maxPagesPerQuery": 2,
  "responseFormat": "concise",
  "deduplicateAcrossQueries": true
}' |
apify call khadinakbar/etsy-listings-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=khadinakbar/etsy-listings-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Etsy Listings Scraper - Search Results & URLs",
        "description": "Discover publicly indexed Etsy listings from keywords. Returns validated IDs, canonical URLs, titles, snippets, indexed shop/rating metadata, and source context. Use for listing discovery—not live Etsy-page details, carts, ads, inventory, or reviews. $0.003 per listing plus usage.",
        "version": "1.0",
        "x-build-id": "IXIE5j2FIPjjWW9zK"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/khadinakbar~etsy-listings-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-khadinakbar-etsy-listings-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/khadinakbar~etsy-listings-scraper/runs": {
            "post": {
                "operationId": "runs-sync-khadinakbar-etsy-listings-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/khadinakbar~etsy-listings-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-khadinakbar-etsy-listings-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "searchQueries"
                ],
                "properties": {
                    "searchQueries": {
                        "title": "Etsy search queries",
                        "type": "array",
                        "description": "Use this when you need Etsy listing discovery for one or more product keywords. Enter terms such as handmade necklace or personalized leather journal, with one query per item. It defaults to handmade necklace when omitted and accepts at most 20 queries. This is not an Etsy URL field and does not promise direct listing-page enrichment.",
                        "items": {
                            "type": "string"
                        },
                        "default": [
                            "handmade necklace"
                        ]
                    },
                    "maxResults": {
                        "title": "Maximum listings",
                        "minimum": 1,
                        "maximum": 200,
                        "type": "integer",
                        "description": "Use this to cap the validated listing records written to the dataset and the primary event cost. Enter an integer such as 50. It defaults to 50 and accepts 1 through 200. This is a global result cap, not a page count or a promise of how many listings the public index contains.",
                        "default": 50
                    },
                    "maxPagesPerQuery": {
                        "title": "Maximum index pages per query",
                        "minimum": 1,
                        "maximum": 10,
                        "type": "integer",
                        "description": "Use this to limit public search-index pages requested for each query. Enter an integer such as 2. It defaults to 2 and accepts 1 through 10. This is not Etsy pagination and does not guarantee a fixed number of listings per page.",
                        "default": 2
                    },
                    "responseFormat": {
                        "title": "Response format",
                        "enum": [
                            "concise",
                            "detailed"
                        ],
                        "type": "string",
                        "description": "Use this to choose whether indexed result snippets are included. Select concise for stable discovery fields only or detailed to include an indexed description snippet when available. It defaults to concise. This does not fetch or summarize a listing page.",
                        "default": "concise"
                    },
                    "deduplicateAcrossQueries": {
                        "title": "Deduplicate listings across queries",
                        "type": "boolean",
                        "description": "Use this to keep the first occurrence of a listing ID when several search queries surface the same listing. Set true for a unique dataset or false to retain query-specific duplicates. It defaults to true. This only deduplicates within the current run and does not compare earlier datasets.",
                        "default": true
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
