How do you scrape Etsy listings via API without getting blocked?
Call ReefAPI's etsy listings/search action with a query and read listing ids, titles, prices, shops and images back as JSON, then use listings/detail for the description, favourites, rating and category path. The finding that changes how you use the data: the search card's comparison price and the product page's sale flag disagree.
This guide demonstrates the real Etsy API engine with a captured response from . The example is only published because the engine passed the SEO snapshot gate.
Handmade-market research, price benchmarking, seller analytics and trend discovery.
Call the live endpoint
- 1
Search, then verify the ones you care about
listings/search takes query, sort, min_price, max_price, category and free_shipping, and max_pages controls depth. One page returned eleven items in our run.
- 2
Confirm discounts on the detail call
on_sale and original_price on listings/detail are authoritative. The search card's list_price appeared on all eleven of our results and was contradicted by the product page on the one we checked.
- 3
Read categories for keywords, not tags
tags holds buyer-feedback chips. categories holds the real breadcrumb path down to 'Journals & Notebooks'.
- 4
Use favorites_count for demand
It counts people who saved the listing without buying - 7,533 against 225 reviews on our sample. It is the closest thing Etsy gives you to a wishlist signal.
- 5
Follow shop_id into the shop surfaces
shops/detail, shops/listings and reviews/shop all key on it, which turns one interesting listing into a full competitor profile.
Copy the request
These snippets use the captured request params for etsy/v1/listings/search.
curl -X POST https://api.reefapi.com/etsy/v1/listings/search \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"query":"silver ring"}'import requests
r = requests.post(
"https://api.reefapi.com/etsy/v1/listings/search",
headers={"x-api-key": REEF_KEY},
json={
"query": "silver ring"
},
)
print(r.json()["data"])const res = await fetch("https://api.reefapi.com/etsy/v1/listings/search", {
method: "POST",
headers: {
"x-api-key": process.env.REEF_KEY,
"content-type": "application/json",
},
body: JSON.stringify({
"query": "silver ring"
}),
});
const { ok, data, meta, error } = await res.json();Ask your MCP-connected assistant: call reefapi.etsy.listings/search with {"query":"silver ring"}.Captured output from ReefAPI
Captured on UTC. The response below is the committed snapshot, including the API envelope and metadata.
{
"method": "POST",
"url": "https://api.reefapi.com/etsy/v1/listings/search",
"headers": {
"x-api-key": "$REEF_KEY",
"content-type": "application/json"
},
"body": {
"query": "silver ring"
}
}{
"ok": true,
"meta": {
"api": "etsy",
"endpoint": "listings/search",
"mode": "live",
"latency_ms": 3323.8,
"record_count": 12,
"bytes": 735916,
"cache_hit": false,
"charged_credits": 2,
"version": "2.2.0"
},
"data": {
"query": "silver ring",
"items": [
{
"listing_id": "1548871956",
"title": "Moonstone Ring Soma Moon Ring 925 Sterling Silver Moonstone Engagement ring Witch ring for Her Triple Moon Phase Promise Ring Women Jewelry",
"url": "https://www.etsy.com/listing/1548871956/moonstone-ring-soma-moon-ring-925",
"image_url": "https://i.etsystatic.com/9809064/r/il/b819bc/6560295643/il_fullxfull.6560295643_j3hn.jpg",
"shop_slug": "BlackTreeLab",
"shop_id": "9809064",
"price": "165.00",
"currency": "USD",
"list_price": null,
"is_ad": null
},
{
"listing_id": "4423582517",
"title": "Stacking 925 Sterling Silver Ring Set,Handmade Assorted Patterns, Thin & Thick",
"url": "https://www.etsy.com/listing/4423582517/handmade-925-sterling-silver-stacking",
"image_url": "https://i.etsystatic.com/61195603/r/il/6d1c8d/7552290645/il_fullxfull.7552290645_r8co.jpg",
"shop_slug": "RajputanaJewel",
"shop_id": "61195603",
"price": "14.75",
"currency": "USD",
"list_price": "58.99",
"is_ad": null
},
{
"listing_id": "4537031656",
"title": "Handmade 925 Sterling Silver Stacking Ring Set Floral Design Jewelry For Women",
"url": "https://www.etsy.com/listing/4537031656/handmade-925-sterling-silver-stacking",
"image_url": "https://i.etsystatic.com/61762752/r/il/0d6bc7/8293822771/il_fullxfull.8293822771_j2gi.jpg",
"shop_slug": "ShreeBalajiJewelsIN",
"shop_id": "61762752",
"price": "11.25",
"currency": "USD",
"list_price": "45.00",
"is_ad": null
}
],
"count": 12,
"pages_fetched": 1
}
}Why this is hard manually
Every listing on Etsy looks discounted, and most of them are not. Our 'leather journal' search returned eleven results and all eleven carried a list_price above the price - 66.95 against 103.00, 21.76 against 64.00, 16.83 against 50.99. A 66 percent markdown across an entire result set is not a sale, it is how the shelf is dressed.
We checked one of them against its own product page. Listing 4488906265 showed price 66.95 and list_price 103.00 in search; listings/detail on the same id returned original_price null and on_sale false. The two surfaces contradict each other, and the product page is the one that Etsy treats as authoritative.
The second trap is naming. Etsy has a field called tags on the listing page, and it does not contain product tags.
Why ReefAPI solves it
Verify a discount against listings/detail before you publish it. on_sale is an explicit boolean and original_price is null when there is no genuine former price. If you are building a deal feed, that pair is your filter - the search card's list_price is a merchandising figure and treating it as a former price will make every listing on Etsy look like a bargain.
tags contains review-sentiment chips, not keywords. On our test listing it read ['Love it', 'Looks great', 'Great quality', 'Well packaged', 'Fast shipping', 'As described', 'Attention to detail'] - Etsy's aggregated buyer-feedback labels. They are genuinely useful as a quality signal and completely useless as SEO keyword data, which is what the field name suggests. The keyword-shaped data is in categories, which returns the real breadcrumb: ['Books, Movies & Music', 'Books', 'Blank Books', 'Journals & Notebooks'].
favorites_count is the demand signal Etsy exposes that most marketplaces do not: 7,533 on our test listing against a review_count_display of 225. Favourites accumulate from people who did not buy, which makes the ratio between them a rough read on intent versus conversion - useful when you are deciding whether a niche has demand that nobody is serving well.
Prices are strings, not numbers. price '66.95' and list_price '103.00' arrive as decimal strings with currency in a separate field. We do not cast them, because casting a money value to a float is a decision your accounting code should make, not ours.
One defect worth flagging so it does not surprise you: the variations array on listings/detail can pick up Etsy's own contact-seller dropdown - our sample's first entry was named 'Choose a reason…' with options like 'There is a problem with my order'. That is a parse leak on our side, not a product option, and we are fixing it. Filter on option values that look like product choices until then.
listings/detail also returns schema_product, the JSON-LD block Etsy publishes for search engines, passed through unmodified. When our parsed fields and that block disagree, the JSON-LD is the version Etsy itself asserts to Google, so it is a useful second opinion. Eight actions share the engine: listings/search, listings/detail, listings/category, shops/detail, shops/listings, reviews/shop, reviews/listing and search/suggest. Search answered in about 3.5 seconds, detail in 3.2. shop_slug and shop_id come back on search rows, so a shop's whole catalog is one follow-up call away.
Questions developers ask
Do I need an Etsy developer account?
No. You send a ReefAPI key. There is no Etsy app registration, OAuth scope or per-app quota involved.
Why does every listing look 50 percent off?
Because the search card's list_price is a merchandising figure. All eleven of our results carried one. We checked listing 4488906265 against its product page: search said 66.95 against 103.00, detail said original_price null and on_sale false. Trust the detail call.
What is in the tags field?
Buyer-feedback chips - 'Love it', 'Great quality', 'Fast shipping', 'As described'. They are Etsy's aggregated review sentiment, not seller keywords. For keyword-like data use categories, which returns the breadcrumb path.
Why are prices strings?
Because they arrive as decimal strings and casting money to a float is a decision that belongs in your code, not in ours. currency is a separate field so you never have to parse a symbol.
What is favorites_count good for?
Measuring demand that has not converted. Our test listing had 7,533 favourites against 225 reviews. A high favourite-to-review ratio usually means people want the thing and something - price, shipping, trust - is stopping them.
My variations array contains 'Choose a reason…'. What is that?
Etsy's contact-seller dropdown leaking into our variations parse. It is our defect and we are fixing it. Until then, ignore option groups whose values look like support reasons rather than product choices.
Can I get a whole shop's catalog?
Yes. Search rows carry shop_id and shop_slug; shops/listings paginates that shop's listings and shops/detail returns the profile. reviews/shop gives shop-level reviews with a listing exclusion filter.