Monitor Etsy Competitor Listings and Shops at Scale (2026)
Track competitor Etsy shops, new listings, pricing changes, and top-N category share at scale with Thirdwatch's Etsy Scraper, built for ops and growth teams.

Thirdwatch's Etsy Scraper returns Etsy listings filtered by category, keyword, sort order, and price band — production-ready for competitor monitoring, shop tracking, and category-share benchmarking. Built for ops and growth teams running Etsy shops, marketplaces, and competitive-intelligence platforms.
TL;DR
Etsy is a high-churn marketplace: new listings appear daily across 8M+ active shops, pricing shifts weekly, and category share rotates as gift-occasion seasons cycle. Without structured per-shop and per-category monitoring, established Etsy shops cannot detect competitor product-line launches, marketplace operators cannot benchmark competitive supply, and competitive-intelligence platforms cannot ingest the signal. Thirdwatch's Etsy Scraper takes keyword, category, sort, and price-band inputs and returns structured listings. This guide walks through a competitor-monitoring pipeline that diffs daily snapshots to detect new listings, price changes, and shop-level launches.
Why monitor Etsy competitor listings
Etsy is the densest competitive surface in handmade ecommerce. According to Etsy's 2024 Annual Report, the platform has 8M+ active sellers and 90M+ active buyers across 17 top-level categories. The combination of low listing barriers, fast onboarding, and gift-occasion-driven demand means competitive dynamics shift continuously — a category that was 10 dominant shops six months ago can fragment into 50 mid-tier shops over a quarter as a viral product attracts copycats.
The job-to-be-done is structured. An established Etsy shop defending its top-10 share in a category needs daily signal on new competitors entering the category. A marketplace operator benchmarking against Etsy needs weekly snapshots of competitive supply per category. A competitive-intelligence platform sells Etsy shop-tracking as a product and needs structured listing data at scale. A consumer brand evaluating an Etsy entry needs to know which shops dominate which sub-niches before launching. All reduce to: per-shop and per-category listing extraction at recurring cadence, with diffs against a persistent baseline.
How does this compare to alternatives?
| Approach | Reliability | Setup time | Maintenance | Auth required |
|---|---|---|---|---|
| Etsy Open API v3 | No competitor-shop access | Days (OAuth + approval) | Strict TOS | Yes |
| DIY scraper | Brittle, anti-bot churn | 1-2 weeks | High | No |
| Thirdwatch Etsy Scraper | Production-tested | 5 minutes | Thirdwatch tracks Etsy changes | Apify token only |
Etsy's Open API v3 is designed for shop owners managing their own shop, not for cross-shop competitive monitoring. A DIY scraper means owning anti-bot engineering forever as Etsy ships layout changes. The Etsy Scraper actor page delivers public listing data on transparent per-result pricing with no approval workflow.
How to monitor Etsy competitors in 5 steps
Step 1: How do I authenticate against Apify?
export APIFY_TOKEN="apify_api_xxxxxxxxxxxxxxxx"Get the token from apify.com → Settings → Integrations.
Step 2: How do I pull a competitor-shop watchlist?
The cleanest pattern: run keyword queries that match each watchlist shop's primary product line, sort by newest, then filter on the shop field.
import os, requests, pandas as pd
from datetime import date
ACTOR = "thirdwatch~etsy-scraper"
TOKEN = os.environ["APIFY_TOKEN"]
WATCHLIST_SHOPS = {
"HeritageLeatherCo": ["personalized leather wallet", "monogram wallet"],
"RubyAndOakStudio": ["birthstone ring", "personalized ring"],
"WildmeadowPress": ["pressed flower frame", "botanical art"],
"CraftedByAlder": ["minimalist wallet", "leather card holder"],
}
records = []
for shop, keywords in WATCHLIST_SHOPS.items():
for kw in keywords:
resp = requests.post(
f"https://api.apify.com/v2/acts/{ACTOR}/run-sync-get-dataset-items",
params={"token": TOKEN},
json={"queries": [kw], "sortBy": "newest", "maxResults": 60},
timeout=900,
)
records.extend(resp.json())
df = pd.DataFrame(records).drop_duplicates(subset=["product_id"])
df["snapshot_date"] = date.today().isoformat()
# Filter to watchlist shops only
watch = df[df.shop.isin(WATCHLIST_SHOPS.keys())]
print(watch.groupby("shop").size())The actor returns the shop on every listing, so it does not matter which keyword surfaced the listing — the post-filter gives you all watchlist activity in one pass.
Step 3: How do I diff daily snapshots to detect new listings?
Persist snapshots in SQLite keyed on (shop, product_id, snapshot_date).
import sqlite3
conn = sqlite3.connect("etsy_competitors.db")
conn.execute("""
CREATE TABLE IF NOT EXISTS listing_snapshot (
snapshot_date TEXT,
shop TEXT,
product_id TEXT,
product_name TEXT,
price REAL,
rating REAL,
url TEXT,
PRIMARY KEY (snapshot_date, shop, product_id)
)
""")
rows = [
(r["snapshot_date"], r["shop"], r["product_id"], r["product_name"],
r.get("price"), r.get("rating"), r["url"])
for r in watch.to_dict("records") if r.get("product_id")
]
conn.executemany(
"INSERT OR REPLACE INTO listing_snapshot VALUES (?, ?, ?, ?, ?, ?, ?)", rows
)
conn.commit()
# New-listings detector: ids in today's snapshot but not in yesterday's
new_listings = conn.execute("""
SELECT t.shop, t.product_id, t.product_name, t.price, t.url
FROM listing_snapshot t
WHERE t.snapshot_date = (SELECT MAX(snapshot_date) FROM listing_snapshot)
AND NOT EXISTS (
SELECT 1 FROM listing_snapshot y
WHERE y.product_id = t.product_id
AND y.snapshot_date < t.snapshot_date
)
""").fetchall()
print(f"{len(new_listings)} new competitor listings since baseline")After a few weeks of daily snapshots, you get a clean stream of every new listing each competitor publishes.
Step 4: How do I benchmark my shop's category share?
Pull a category sweep sorted by best-reviewed, count listings per shop, and compute share.
resp = requests.post(
f"https://api.apify.com/v2/acts/{ACTOR}/run-sync-get-dataset-items",
params={"token": TOKEN},
json={
"queries": [],
"category": "bags-purses",
"sortBy": "bestReviewed",
"maxResults": 200,
},
timeout=1200,
)
cat = pd.DataFrame(resp.json())
share = (
cat.groupby("shop", as_index=False)
.size()
.rename(columns={"size": "top200_listings"})
.sort_values("top200_listings", ascending=False)
)
share["share_pct"] = (share.top200_listings / share.top200_listings.sum() * 100).round(2)
print(share.head(20))Tracked weekly, the share table shows which shops are gaining and losing top-200 best-reviewed visibility in the category.
Step 5: How do I detect competitor pricing moves?
Combine the per-listing pricing fields with the snapshot history. For each (shop, product_id) pair present in both today's and last-week's snapshot, compute the price-change percent.
diff = conn.execute("""
SELECT a.shop, a.product_id, a.product_name,
b.price AS old_price, a.price AS new_price,
ROUND((a.price - b.price) * 100.0 / b.price, 2) AS pct_change,
a.url
FROM listing_snapshot a
JOIN listing_snapshot b
ON a.shop = b.shop AND a.product_id = b.product_id
WHERE a.snapshot_date = (SELECT MAX(snapshot_date) FROM listing_snapshot)
AND b.snapshot_date = DATE(a.snapshot_date, '-7 day')
AND b.price > 0
AND ABS((a.price - b.price) * 100.0 / b.price) >= 10
ORDER BY pct_change
""").fetchall()
for row in diff[:20]:
print(row)A price drop of 15%+ across multiple listings within a single competitor shop in one week is the textbook margin-defending move. Pair it with the new-listings stream from Step 3 and you have a complete competitor-activity feed.
Sample output
[
{
"product_id": "1685029384",
"product_name": "Handcrafted Leather Bifold Wallet With Coin Pocket",
"shop": "HeritageLeatherCo",
"price": 42.0,
"original_price": 55.0,
"discount_percent": 23.64,
"currency": "USD",
"rating": 4.8,
"image_url": "https://i.etsystatic.com/19283746/r/il/abcd/...",
"url": "https://www.etsy.com/listing/1685029384/handcrafted-leather-bifold-wallet",
"source_query": "personalized leather wallet"
},
{
"product_id": "1623948571",
"product_name": "Slim Front-Pocket Leather Cardholder",
"shop": "CraftedByAlder",
"price": 19.99,
"original_price": null,
"discount_percent": 0,
"currency": "USD",
"rating": 4.9,
"url": "https://www.etsy.com/listing/1623948571/slim-front-pocket-leather-cardholder",
"source_query": "leather card holder"
}
]shop, product_id, price, and url are the four fields a competitor-monitoring pipeline keys on. original_price and discount_percent add sale-event detection on top.
Common pitfalls
Five failure modes recur in Etsy competitor pipelines. Listing-ID churn — Etsy listing IDs are stable across the listing's lifetime, but if a shop deletes and republishes a product, the ID changes; always pair ID-based diffs with title-similarity fallback. Shop-name typos — match shop names case-insensitively and trim whitespace; never key on raw shop strings without normalization. Currency mixing — Etsy auto-displays the viewer's local currency; filter on currency == "USD" before computing price diffs across snapshots. Sort-order bleed — the "newest" sort returns listings created in the last few days; if you only run weekly, you may miss listings created between runs. Sort by relevance plus diff against the persistent baseline for completeness. Top-N saturation — the top 200 best-reviewed listings in a popular category fill up with long-tail shops; for visibility benchmarks, also walk the price-band buckets separately.
Thirdwatch's actor handles the production-grade anti-bot surface, page rendering, listing-card extraction, and the homepage-warmup behaviour Etsy expects. You pay per result and the actor tracks Etsy's listing-DOM changes so your pipeline does not break the next time Etsy ships a layout revision.
Related use cases
Frequently asked questions
Why monitor Etsy competitor listings?
Etsy is a high-churn marketplace — new listings appear daily and pricing shifts weekly. According to Etsy's 2024 Annual Report, there are 8M+ active sellers competing for 90M+ buyers. For established shops defending share, marketplace operators benchmarking competitive supply, and platforms ingesting competitive product data, structured per-shop listing intelligence is essential.
How do I track listings from a specific Etsy shop?
Run keyword queries that match the shop's primary product line, sorted by newest, and filter the returned listings on the shop field. Repeat at daily or weekly cadence and diff against a baseline. The actor returns the shop name on every listing, which makes per-shop aggregation trivial regardless of which keyword surfaced the listing.
How fast does new-listing data arrive?
Run the actor with sortBy=newest in a category and you get the most recently added listings at the top. For high-frequency competitor monitoring (top 10 shops in a category), daily cadence is appropriate. For broader category-level supply monitoring (1000+ listings), weekly cadence keeps cost and signal in balance.
Can I detect when a competitor launches a new product line?
Yes. Persist daily snapshots keyed on (shop, product_id) and compute the set difference. New product_ids appearing under a competitor shop with similar pricing and rating cluster is the textbook signal of a product-line launch. Cross-reference image_url to spot photographic style changes alongside the launch.
How do I benchmark my Etsy shop's category share?
Run a category sweep sorted by bestReviewed at maxResults=200+ and compute each shop's count of listings in the top-N. Your shop's share of the top-N over time is a clean visibility metric. Compare against the 5 highest-ranked competitor shops in the same category for a relative benchmark.
What competitor intelligence cannot the actor capture?
The actor reads public Etsy listing pages and returns the fields visible on listing cards: name, shop, price, rating, image, URL. It does not return per-listing sales counts (Etsy has restricted that field), shop-level revenue, or favorite counts. For order-volume signal, infer from rating count plus review velocity on detail pages over time.
Related
100 free credits, no credit card.
About 30 real searches. Add the MCP to Claude or Cursor in two minutes.