# Etsy Product & Shop Analyzer (`second_coming/etsy-shop-analyzer`) Actor

Extract product listings, shop info, sales estimates, reviews, and keyword data from Etsy. Marketplace research tool for handmade sellers.

- **URL**: https://apify.com/second\_coming/etsy-shop-analyzer.md
- **Developed by:** [Richard P](https://apify.com/second_coming) (community)
- **Categories:** E-commerce, Marketing
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## 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.md):

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

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.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/platform/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 Product & Shop Analyzer

An [Apify Actor](https://apify.com/actors) for extracting product listings, shop profiles, sales estimates, reviews, and keyword data from Etsy.

### Features

- **Shop scraping** — Extract full shop profiles including sales count, reviews, rating, member since, location, announcement, and social links.
- **Listing scraping** — Extract product details: title, description, price, currency, stock, views, favourites, materials, tags, categories, images, and variations.
- **Review extraction** — Pull customer reviews with author, rating, date, and text.
- **Listing discovery** — Automatically discover and scrape all listings from a shop page.
- **Multi-method parsing** — Uses JSON-LD structured data, meta tags, embedded app-state JSON, and HTML parsing for maximum data coverage.
- **Rate limiting** — Configurable delay between requests to avoid detection.
- **Apify proxy support** — Uses the Apify proxy pool (residential recommended) to bypass Etsy's anti-bot protection.
- **Graceful abort** — Handles platform abort signals cleanly.

### Input

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `shopUrls` | `string[]` | `[]` | List of Etsy shop page URLs (e.g. `https://www.etsy.com/shop/CeramicMugShop`) |
| `listingUrls` | `string[]` | `[]` | List of individual listing URLs (e.g. `https://www.etsy.com/listing/1234567890/...`) |
| `maxListings` | `integer` | `50` | Max listings to scrape per shop. `0` = unlimited. |
| `includeReviews` | `boolean` | `true` | Whether to extract customer reviews from listing pages. |
| `maxReviews` | `integer` | `10` | Max reviews to extract per listing. `0` = all available. |
| `proxy` | `object` | Apify Residential | Proxy configuration for bypassing Etsy's bot protection. |
| `requestDelayMs` | `integer` | `2000` | Delay between requests in milliseconds. |

### Output

Each record in the dataset is either a **`listing`** or **`shop`** type.

#### Listing fields

| Field | Description |
|-------|-------------|
| `listingId` | Etsy numeric listing ID |
| `title` | Product title |
| `description` | Product description |
| `price` | Current price |
| `originalPrice` | Original price (if on sale) |
| `currency` | Currency code (USD, EUR, GBP, etc.) |
| `quantity` | Available stock |
| `views` | View count |
| `favorites` | Heart / favourite count |
| `materials` | Array of materials |
| `tags` | Array of search tags |
| `categories` | Category hierarchy |
| `images` | Array of image URLs |
| `variations` | Product variations (size, colour, etc.) |
| `shopName` | Shop name |
| `shopUrl` | Shop page URL |
| `shopLocation` | Shop location |
| `shopAverageRating` | Shop rating out of 5 |
| `shopTotalReviews` | Total shop reviews |
| `reviews` | Array of review objects |
| `url` | Full listing URL |
| `scrapedAt` | ISO 8601 scrape timestamp |

#### Shop fields

| Field | Description |
|-------|-------------|
| `shopName` | Shop name |
| `shopUrl` | Shop page URL |
| `shopLocation` | Location string |
| `shopTotalSales` | Estimated total sales |
| `shopTotalReviews` | Total review count |
| `shopAverageRating` | Average rating (0–5) |
| `shopMemberSince` | Member join date |
| `numberOfListings` | Number of active listings |
| `shopAnnouncement` | Shop announcement text |
| `socialLinks` | Social media profile URLs |
| `url` | Full shop URL |
| `scrapedAt` | ISO 8601 scrape timestamp |

#### Review object

```json
{
  "author": "CustomerName",
  "rating": 5,
  "review": "Great product!",
  "date": "2024-03-15"
}
````

### Usage

#### Local development

```bash
## Install dependencies
pip install -r requirements.txt

## Run with Apify CLI
apify run --purge
```

#### Configuration

Create or modify `.actor/input_schema.json` to set input defaults. For local runs, Apify reads input from the `INPUT.json` file in the `storage/` directory.

#### Apify platform

1. Push the actor: `apify push`
2. Configure input in the Apify Console web UI
3. Run the actor

### How it works

The actor uses a **multi-strategy parsing pipeline**:

1. **JSON-LD** (`<script type="application/ld+json">`) — Primary source for structured product and shop data from Etsy's Schema.org markup.
2. **Embedded JSON** — Scans `<script>` tags with `data-app-state`, `data-init-state`, `application/json`, and `window.__INITIAL_STATE__` assignments for additional data.
3. **Meta tags** — Open Graph (`og:title`, `og:price:amount`, etc.), Twitter Card, and standard meta tags for fallback data.
4. **HTML parsing** — Visible DOM elements for favourites, stock, materials, tags, reviews, and shop stats.

Requests are sent via `httpx.AsyncClient` with Chrome user-agent headers, automatic retry on 403/429/503 responses, and exponential backoff.

### Notes

- Etsy uses **DataDome** anti-bot protection. For production use, **residential proxies** (available through Apify proxy) are strongly recommended.
- Shop listing discovery depends on the shop page HTML structure. Some listings may not be found if the shop uses pagination (only the first page is scraped).
- Reviews are often loaded dynamically. The actor extracts whatever is in the initial HTML — for full review sets, additional API calls may be needed.
- Sales counts are *estimates* based on what Etsy displays on the shop page, which may be rounded or approximated.

### Limitations

- Does **not** handle shop listing pagination (only the first shop page)
- Review extraction may be incomplete due to Etsy's dynamic loading
- Etsy rate-limits aggressively — keep `requestDelayMs` at 2000+
- Some fields (views, exact stock) may not be available from all pages

### License

MIT

# Actor input Schema

## `shopUrls` (type: `array`):

List of Etsy shop page URLs to scrape (e.g., https://www.etsy.com/shop/CeramicMugShop).

## `listingUrls` (type: `array`):

List of individual Etsy listing/product page URLs to scrape (e.g., https://www.etsy.com/listing/1234567890/...).

## `maxListings` (type: `integer`):

Maximum number of listing pages to scrape per shop. Set to 0 for unlimited.

## `includeReviews` (type: `boolean`):

Whether to extract customer reviews from listing pages.

## `maxReviews` (type: `integer`):

Maximum number of reviews to extract per listing. Set to 0 for all available.

## `requestDelayMs` (type: `integer`):

Delay between requests in milliseconds to avoid rate limiting.

## Actor input object example

```json
{
  "shopUrls": [],
  "listingUrls": [],
  "maxListings": 50,
  "includeReviews": true,
  "maxReviews": 10,
  "requestDelayMs": 2000
}
```

# Actor output Schema

## `results` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("second_coming/etsy-shop-analyzer").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("second_coming/etsy-shop-analyzer").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 '{}' |
apify call second_coming/etsy-shop-analyzer --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Etsy Product & Shop Analyzer",
        "description": "Extract product listings, shop info, sales estimates, reviews, and keyword data from Etsy. Marketplace research tool for handmade sellers.",
        "version": "0.0",
        "x-build-id": "jCtEQPyhs9R5f8JD0"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/second_coming~etsy-shop-analyzer/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-second_coming-etsy-shop-analyzer",
                "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/second_coming~etsy-shop-analyzer/runs": {
            "post": {
                "operationId": "runs-sync-second_coming-etsy-shop-analyzer",
                "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/second_coming~etsy-shop-analyzer/run-sync": {
            "post": {
                "operationId": "run-sync-second_coming-etsy-shop-analyzer",
                "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",
                "properties": {
                    "shopUrls": {
                        "title": "Etsy Shop URLs",
                        "type": "array",
                        "description": "List of Etsy shop page URLs to scrape (e.g., https://www.etsy.com/shop/CeramicMugShop).",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "listingUrls": {
                        "title": "Etsy Listing URLs",
                        "type": "array",
                        "description": "List of individual Etsy listing/product page URLs to scrape (e.g., https://www.etsy.com/listing/1234567890/...).",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxListings": {
                        "title": "Max Listings per Shop",
                        "minimum": 0,
                        "maximum": 1000,
                        "type": "integer",
                        "description": "Maximum number of listing pages to scrape per shop. Set to 0 for unlimited.",
                        "default": 50
                    },
                    "includeReviews": {
                        "title": "Include Reviews",
                        "type": "boolean",
                        "description": "Whether to extract customer reviews from listing pages.",
                        "default": true
                    },
                    "maxReviews": {
                        "title": "Max Reviews per Listing",
                        "minimum": 0,
                        "maximum": 100,
                        "type": "integer",
                        "description": "Maximum number of reviews to extract per listing. Set to 0 for all available.",
                        "default": 10
                    },
                    "requestDelayMs": {
                        "title": "Request Delay (ms)",
                        "minimum": 500,
                        "maximum": 30000,
                        "type": "integer",
                        "description": "Delay between requests in milliseconds to avoid rate limiting.",
                        "default": 2000
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
