Etsy Listings Scraper - Price, Shop & Badges avatar

Etsy Listings Scraper - Price, Shop & Badges

Pricing

from $1.50 / 1,000 results

Go to Apify Store
Etsy Listings Scraper - Price, Shop & Badges

Etsy Listings Scraper - Price, Shop & Badges

Scrape Etsy search results into structured rows: listing ID and URL, title, numeric price with its currency code, shop name, shop rating and review count, Bestseller and free-shipping flags, and the card image. Feed it search terms, get up to 240 listings per term. No Etsy account or API key.

Pricing

from $1.50 / 1,000 results

Rating

0.0

(0)

Developer

String

String

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

0

Monthly active users

15 days ago

Last modified

Categories

Share

What does the Etsy Listings Scraper do?

It turns Etsy search results into rows. Give it the phrase you would type into Etsy's own search box, such as handmade jewelry, and every listing in that grid comes back as a record: Etsy's listing ID and URL, the title, the price as a number, the shop behind it, and the badges the card carries. Export it as JSON, CSV or Excel, or read it straight from the dataset API.

The Actor reads public search pages the way a logged-out visitor sees them. No Etsy account, no API key, no cookie jar to keep alive.

  • price arrives as 24.99 with the currency code in its own column, so it sorts and averages without any string cleanup
  • listingId is Etsy's own identifier, which makes de-duplication and joins across runs trivial
  • Up to 240 listings per search term: Etsy server-renders 12 per page and stops serving fresh results after its twentieth page
  • The Bestseller badge and the free-shipping promise are booleans, not scraped label text
  • A search page that cannot be read is written into the run's SUMMARY as a failure instead of quietly shrinking the dataset

What data does it extract?

FieldTypeDescription
listingIdstringEtsy's listing ID. Stable across runs, so use it as your key
titlestringThe listing title as it appears on the card
pricenumberNumeric price, e.g. 24.99
currencystringISO code Etsy priced the page in, e.g. USD
shopNamestringThe shop's Etsy handle
shopRatingnumberThe shop's rating out of 5, e.g. 4.8
shopReviewCountnumberReview count for the shop, e.g. 12400
isBestsellerbooleantrue when the card shows Etsy's Bestseller badge
freeShippingbooleantrue when the card advertises free shipping
imageUrlstringThe listing's card image
listingUrlstringDirect link to the listing on Etsy
searchTermstringThe term that produced this row
sourceUrlstringThe Etsy search page the row was read from
collectedAtstringISO timestamp, set once per run

Two notes on the shop columns. shopRating and shopReviewCount describe the shop, not the individual listing, because a shop-level score is what an Etsy search card publishes. And Etsy abbreviates a large review count on the card as "12.4k", which the Actor expands to 12400: counts below a thousand are exact, and above that you get the precision the card printed. Anything the card omits comes back as null rather than an empty string.

Why scrape Etsy?

  • Price a niche before you list in it. Pull 240 listings for the phrase you plan to sell under and you have the real distribution of asking prices, not the handful Etsy chose to show you first.
  • Watch competitors on numbers. price is numeric and listingId is stable, so re-running the same terms weekly gives you a price history per listing with no fuzzy matching.
  • Track who holds the Bestseller badge. The badge moves. isBestseller over time tells you which listings are gaining traction in a category and which are fading.
  • Find shops worth studying. Filter on shopRating and shopReviewCount to pick out the established sellers in a niche, then look at what they charge and how they title their listings.
  • Check whether free shipping is table stakes. In some categories almost every card offers it and in others almost none do, which changes how you price.
  • Feed a dashboard. Schedule the Actor, point a BI tool at the dataset, and keep a keyword-to-price map current without touching it again.

How to use it

  1. Open the Actor and click Try for free.
  2. Put your search terms into Search terms, one per line. These are ordinary Etsy search phrases; 1 to 50 of them per run.
  3. Set Maximum results to the number of rows you want. This also decides how deep each term is paged, so a larger number means more pages per term rather than just a bigger slice of page one.
  4. Leave Concurrency alone unless you have a reason to change it. The default fetches five targets at a time.
  5. Click Start. Watch the log if you like; it names every target that failed.
  6. When the run finishes, open the Storage tab and export the dataset as CSV, JSON or Excel, or pull it over the API with the snippet further down.
  7. To build a time series, put the run on a Schedule and key later joins on listingId.

Input

FieldTypeDefaultDescription
searchesstring[]requiredEtsy search terms, 1 to 50 per run. Duplicates collapse to one fetch
maxItemsinteger1000Cap on dataset rows, 1 to 50000. Also sets paging depth per term
concurrencyinteger5Targets fetched in parallel, 1 to 10
{
"searches": ["handmade jewelry", "leather wallet", "ceramic mug"],
"maxItems": 720,
"concurrency": 5
}

maxItems is split evenly across your search terms and rounded up to whole pages of 12, capped at Etsy's own twentieth page. The example above budgets 240 rows per term, which is 20 pages each, the deepest Etsy will go. Ask for fewer rows and each term is paged more shallowly rather than some terms being dropped, so every phrase you supply is represented in the output.

Output

One row per listing. This is the shape, with plausible values rather than a captured run:

{
"listingId": "1482930571",
"title": "Personalized Birth Flower Necklace, Gold Filled Custom Gift for Her",
"price": 34.5,
"currency": "USD",
"shopName": "MeadowAndOakStudio",
"shopRating": 4.9,
"shopReviewCount": 12400,
"isBestseller": true,
"freeShipping": true,
"imageUrl": "https://i.etsystatic.com/48210933/r/il/9c1f7a/6284915073/il_340x270.6284915073_k8vq.jpg",
"listingUrl": "https://www.etsy.com/listing/1482930571/personalized-birth-flower-necklace-gold",
"searchTerm": "handmade jewelry",
"sourceUrl": "https://www.etsy.com/search?q=handmade+jewelry&page=3",
"collectedAt": "2026-08-19T09:14:02.771Z"
}

The run also writes a SUMMARY record to the key-value store with the item count, the failure count and every target that failed with its error message.

Reliability and limitations

Listings are read from Etsy's server-rendered search grid rather than from the ld+json block on the same page. That block looks like the obvious source and is not: it is a promotional subset, usually six of the twelve rendered cards, and it drops the rating, the review count, the badges and shipping entirely. Each card's markup is isolated before any field is read, so the "Free shipping" option in the filter sidebar is never mistaken for a shipping promise on a listing that makes none.

Etsy also runs two card renderers at once and a session lands in either. They agree on everything but the rating, which one publishes as attributes on a web component and the other folds into an aria-label sentence. Both are handled, so the rating does not depend on which renderer you drew.

Measured yield is 11.67 listings per request after de-duplication, against the 12 a page renders. Promoted listings repeat inside a grid and across a term's pages; those are removed. The same listing found under two different search terms is returned once per term, because that is a row you asked for twice.

Search results only. There are no listing detail pages, so no description, variations, materials, stock level, processing time or per-listing reviews, and no shop pages. Etsy prices a page in the currency it infers for the viewer, so currency reports what it chose rather than a currency you can select.

There are no retries, deliberately. The String Unblocker owns proxy rotation and anti-bot solver selection, so a retry loop here would only re-roll the same block.

How much does it cost?

The Actor uses Apify's pay-per-event pricing and charges once per result row written to the dataset. Rows are what you pay for, not run time, memory or the number of pages it had to fetch to find them. A run that returns nothing charges nothing. The current per-result price is on this Actor's pricing tab, above.

Because charging happens on the push, a spend limit on your account trims the write rather than overrunning it: a row that could not be charged for is never written.

Runs started from an Apify free plan stop at 250 requests and 250 results, and the run reports that it reached the limit. Any paid plan runs the full input and whatever maxItems you set. The limit exists because this Actor fetches through our own infrastructure, which Apify does not cover for free-plan runs, and it binds on requests as well as rows so a large input cannot spend those fetches on rows the run will not return.

Using it with the Apify API

import { ApifyClient } from "apify-client";
const client = new ApifyClient({ token: "YOUR_APIFY_TOKEN" });
const run = await client.actor("usestring/etsy-listings").call({
searches: ["handmade jewelry", "leather wallet"],
maxItems: 480
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, items[0]);

The same call works from the Python client, and any language can hit the Apify REST API directly. To read the failure list, fetch the SUMMARY record from the run's key-value store.

This Actor reads pages that Etsy serves to anyone, with no login and no paywall in the way. It does not sign in, does not touch buyer accounts, order history or messages, and does not collect personal data beyond the shop handle that Etsy itself prints on a public search card.

Scraping public data is broadly lawful in the US and the EU, and courts have repeatedly said so, but what you then do with the data is a separate question governed by copyright, database rights and privacy law. Listing photos and titles belong to the sellers who wrote them. If you plan to republish, retrain on, or otherwise redistribute what you collect, talk to a lawyer first. Nothing here is legal advice.

FAQ

How many listings do I get per search term? 240 at most. Etsy server-renders 12 listings per search page, and past its twentieth page it silently re-serves page 1, so the Actor stops there rather than collecting duplicates. Use narrower terms, or more of them, to cover a category more deeply.

Can I scrape one shop, or a single listing page? No. This Actor works from search terms and reads search results only. It does not open listing detail pages or shop pages, so descriptions, variations, stock levels and per-listing reviews are out of scope.

Which currency are the prices in? Whichever one Etsy picked for the page, reported per row in currency. There is no country input: Etsy infers a currency for the viewer and prices the whole grid in it. Prices are never converted, so compare within a currency or convert them yourself downstream.

How fresh is the data? It is read live when the run starts. Nothing is cached or replayed from an earlier run, and collectedAt records the moment the run began. For a time series, schedule the Actor and join on listingId.

What happens when Etsy blocks a page? That page is recorded under failures in the run's SUMMARY with its URL and error, and the run continues with the rest. If every page failed, the run exits with an error rather than reporting a successful run that produced nothing. The Actor never retries: the String Unblocker behind it already handles proxy rotation and solver selection, so retrying out here would just re-roll the same block.

Do I need an Etsy account, API key or proxies of my own? None of the three. The Actor reads logged-out search pages and brings its own fetching infrastructure, so there is no Apify proxy configuration to set up either.

Feedback

Found a field parsed wrong, a badge missing, or a search term that consistently fails? Open an issue from this Actor's Issues tab on the Store page and include the input you ran. Requests for extra fields are welcome there too.