Etsy Best Sellers Scraper avatar

Etsy Best Sellers Scraper

Pricing

from $2.99 / 1,000 best sellers

Go to Apify Store
Etsy Best Sellers Scraper

Etsy Best Sellers Scraper

Scrape best-selling product listings from Etsy search or category pages. Extracts title, price, rating, review count, shop name, and listing URL.

Pricing

from $2.99 / 1,000 best sellers

Rating

0.0

(0)

Developer

w3crawler

w3crawler

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

6 hours ago

Last modified

Categories

Share

Collect listing cards from public Etsy best-seller, search, and category pages. Each saved row describes one listing as the page displayed it: identity and URL, title, displayed and parsed price, currency, image, rating and review count, shop details when the card exposes them, visible ad and merchandising badges, and optional detail-page fields such as materials, shipping, seller history, and review snippets.

Get started

  1. Open the Actor Store page and select Try for free, or open the Input tab.
  2. Choose a source: add up to five startUrls, or supply categoryUrl or searchQuery. If all three are empty, the Actor reads https://www.etsy.com/market/best_sellers.
  3. Set maxItems and keep maxPages at 1 for the first run. Leave includeDetails off until you need description, shipping, or seller fields.
  4. Start the Actor, open the dataset, and export rows as JSON, CSV, or Excel. Open Run summary (OUTPUT) to check the row count, filters, duplicates, and detail-page results.

Input

All fields are optional, and the defaults below are ready to use. Unsupported field names and out-of-range values are rejected before requests start. startUrls are used first; otherwise categoryUrl, then searchQuery, then the default best-sellers page.

FieldTypeRequired?DefaultMeaning
startUrlsobject arrayOptional[]Public Etsy search, market, category, or best-sellers URLs, up to five entries. Each entry is an object with a url string. When present, these replace categoryUrl and searchQuery.
searchQuerystringOptionalNot suppliedPublic Etsy search phrase, up to 200 characters. Ignored when startUrls or categoryUrl is supplied.
categoryUrlstringOptionalNot suppliedPublic HTTPS Etsy marketplace or category URL. Used when startUrls is empty and takes precedence over searchQuery.
maxItemsintegerOptional20Maximum listing rows saved across all sources, from 1 to 200.
maxPagesintegerOptional1Maximum result pages visited per source URL, from 1 to 5.
deduplicatebooleanOptionaltrueSkip cards whose Etsy listing ID was already saved from another page or source.
keywordstringOptionalNot suppliedCase-insensitive filter applied to the listing title and shop name, up to 200 characters.
minPricenumberOptionalNot suppliedLower bound for the parsed numeric price. Cards without a parsed price are filtered out when a price bound is set.
maxPricenumberOptionalNot suppliedUpper bound for the parsed numeric price. Cards without a parsed price are filtered out when a price bound is set.
minRatingnumberOptionalNot suppliedMinimum public rating, from 0 to 5. Cards without a rating are filtered out when this is set.
minReviewCountintegerOptionalNot suppliedMinimum public review count, zero or greater. Cards without a review count are filtered out when this is set.
sortBystring enumOptionalrecommendedFinal order after filtering and deduplication: recommended, price_asc, price_desc, rating_desc, or review_count_desc.
includeDetailsbooleanOptionalfalseOpen up to maxDetailItems listing pages to add description, category path, materials, shipping, seller, and popularity fields.
maxDetailItemsintegerOptional0Maximum listing pages opened for detail enrichment, from 0 to 20. Has no effect unless includeDetails is true.
includeReviewsbooleanOptionalfalseKeep a bounded sample of visible reviews from opened detail pages.
maxReviewsintegerOptional5Maximum visible reviews retained per opened detail page, from 0 to 20.
requestDelayMsintegerOptional250Polite pause before page extraction, from 0 to 5,000 ms.
maxConcurrencyintegerOptional1Maximum simultaneous browser pages, from 1 to 2.
maxRequestRetriesintegerOptional1Retries for ordinary request failures, from 0 to 2.
requestTimeoutSecsintegerOptional45Maximum navigation time per page, from 10 to 90 seconds.

Example input used for the saved run:

{
"startUrls": [
{
"url": "https://www.etsy.com/market/best_sellers"
}
],
"maxItems": 3,
"maxPages": 1,
"deduplicate": true,
"sortBy": "recommended",
"includeDetails": false,
"maxDetailItems": 0,
"includeReviews": false,
"maxReviews": 5,
"requestDelayMs": 250,
"maxConcurrency": 1,
"maxRequestRetries": 1,
"requestTimeoutSecs": 45
}

The saved run capped the result at three rows and did not request detail enrichment. The schema defaults are 20 rows, one page per source, and detail enrichment off. The Actor uses ordinary public browser navigation to load each source page and, when enabled, individual listing pages. It does not sign in, call private endpoints, solve CAPTCHAs, spoof a device, or bypass an Etsy access decision. Filters and sorting are applied locally after extraction, so they do not change what Etsy returns.

Other input variations use the same fields:

{
"searchQuery": "handmade mug",
"maxItems": 5,
"sortBy": "rating_desc"
}
{
"categoryUrl": "https://www.etsy.com/market/home_and_living",
"maxItems": 10,
"minPrice": 10,
"maxPrice": 100,
"minRating": 4
}
{
"startUrls": [
{
"url": "https://www.etsy.com/search?q=ceramic+planter"
}
],
"maxPages": 2,
"includeDetails": true,
"maxDetailItems": 2
}

Output

The dataset contains one row per unique listing card saved, in final sorted order. With deduplicate: true, a listing that appears on several pages is kept once. Values that the page did not display are null; optional detail fields stay null when includeDetails is off or the page is not opened. No diagnostic or placeholder rows are written.

FieldTypeAvailabilityMeaning
sourcestring | nullAlwaysSource platform; Etsy.
sourceHoststring | nullAlwaysHostname of the public source.
pageTypestring | nullAlwaysKind of page that produced the card, such as search_results or category.
sourceUrlstring | nullAlwaysSource URL submitted or generated by the Actor.
pageUrlstring | nullAlwaysFinal public page URL after navigation. When the row comes from a public Internet Archive capture, this is the Wayback replay URL that served the archived HTML.
pageNuminteger | nullAlwaysOne-based result page number within its source URL.
positioninteger | nullAlwaysOne-based card position on that result page.
rankinteger | nullAlwaysOne-based position in the final dataset after sorting.
listingIdstring | nullAlwaysEtsy listing identifier.
listingUrlstring | nullAlwaysCanonical public listing URL.
titlestring | nullAlwaysListing title as displayed on the card.
descriptionstring | nullWhen detail enrichment succeedsPublic listing description from the opened listing page.
categorystring | nullWhen publishedCategory label shown by the listing page.
categoryPathstring array | nullWhen detail enrichment succeedsBreadcrumb labels from the public listing page.
pricestring | nullWhen a price is displayedPrice text shown on the card, including its currency symbol.
priceValuenumber | nullWhen a price can be parsedNumeric value parsed from price.
originalPricestring | nullWhen a struck-through price is displayedOriginal price text shown beside the current price.
originalPriceValuenumber | nullWhen an original price can be parsedNumeric value parsed from originalPrice.
discountPercentnumber | nullWhen the page exposes a discountDiscount percentage for the card.
currencystring | nullWhen a price is displayedNormalized currency code such as USD, EUR, GBP, or INR.
currencySymbolstring | nullWhen a price is displayedCurrency symbol or code exactly as displayed.
ratingnumber | nullWhen the card displays a ratingPublic listing rating from 0 to 5.
reviewCountinteger | nullWhen the card displays reviewsPublic listing review count.
shopNamestring | nullWhen the card displays a shopPublic Etsy shop name.
shopUrlstring | nullWhen the card displays a shopPublic Etsy shop URL.
imageUrlstring | nullAlwaysPrimary public listing image URL.
imagesstring array | nullWhen images are displayedBounded list of public listing image URLs.
badgesstring array | nullWhen the card shows badgesVisible merchandising labels, such as free shipping.
isBestsellerboolean | nullWhen the card shows an explicit markerWhether a bestseller marker is visible on the card. null when the page only calls itself a best-seller collection.
isEtsyChoiceboolean | nullWhen Etsy Choice state is observableWhether an Etsy Choice marker is present.
isAdboolean | nullWhen ad state is observableWhether the card carries Etsy's promoted or ad label.
adPositioninteger | nullWhen the card is promotedOne-based position of the promoted slot; null for organic cards.
searchQuerystring | nullWhen a search phrase was usedSearch phrase behind the source page.
categoryUrlstring | nullWhen a category URL was suppliedCategory URL used as the source.
materialsstring array | nullWhen detail enrichment succeedsMaterials listed on the public listing page.
shippingstring | nullWhen detail enrichment succeedsShipping text shown on the listing page.
deliveryEstimatestring | nullWhen detail enrichment succeedsDelivery estimate shown on the listing page.
returnsPolicystring | nullWhen detail enrichment succeedsReturns text shown on the listing page.
sellerLocationstring | nullWhen detail enrichment succeedsPublic seller location.
sellerSalesCountinteger | nullWhen detail enrichment succeedsPublic number of shop sales.
sellerYearsOnEtsyinteger | nullWhen detail enrichment succeedsYears on Etsy derived from the public seller history date.
sellerRatingnumber | nullWhen detail enrichment succeedsPublic seller rating.
sellerReviewCountinteger | nullWhen detail enrichment succeedsPublic seller review count.
sellerResponseTimestring | nullWhen detail enrichment succeedsPublic seller response-time text.
favoritesCountinteger | nullWhen detail enrichment succeedsPublic favorites count for the listing.
listedAtstring | nullWhen detail enrichment succeedsListing date as displayed publicly.
reviewsobject array | nullWhen detail enrichment and includeReviews are enabledBounded visible review snippets; each entry has a text string.
detailEnrichedboolean | nullWhen detail enrichment was requestedWhether the optional listing page was opened successfully. null when no detail page was requested for the row.
detailErrorCodestring | nullWhen detail enrichment failsStable short code for the failure.
detailErrorstring | nullWhen detail enrichment failsBounded explanation of the failure.
scrapedAtstring | nullAlwaysTime the row was saved, in ISO UTC.

categoryPath, images, badges, and materials are string arrays. reviews is an array of objects with a text field. Detail fields are populated only for the first maxDetailItems cards when includeDetails is enabled; the remaining rows keep detailEnriched: null and null detail fields.

The example below is a real saved row from the 2026-10-25 run.

{
"source": "Etsy",
"sourceHost": "www.etsy.com",
"pageType": "search_results",
"sourceUrl": "https://www.etsy.com/market/best_sellers",
"pageUrl": "https://www.etsy.com/market/best_sellers",
"pageNum": 1,
"position": 1,
"rank": 1,
"listingId": "1391093641",
"listingUrl": "https://www.etsy.com/listing/1391093641/personalised-leather-wallet-with-rfid",
"title": "PERSONALISED Leather Wallet With RFID Blocking Technology For Men - Chocolate Brown - HT13 - Gift Boxed - Best Seller - Embossed Wallet",
"description": null,
"category": null,
"categoryPath": null,
"price": "$ 41.97",
"priceValue": 41.97,
"originalPrice": null,
"originalPriceValue": null,
"discountPercent": null,
"currency": "USD",
"currencySymbol": "$",
"rating": null,
"reviewCount": null,
"shopName": null,
"shopUrl": null,
"imageUrl": "https://i.etsystatic.com/13272288/r/il/22cdd2/4558866501/il_600x600.4558866501_kjcm.jpg",
"images": [
"https://i.etsystatic.com/13272288/r/il/22cdd2/4558866501/il_600x600.4558866501_kjcm.jpg"
],
"badges": null,
"isBestseller": null,
"isEtsyChoice": false,
"isAd": true,
"adPosition": 1,
"searchQuery": null,
"categoryUrl": null,
"materials": null,
"shipping": null,
"deliveryEstimate": null,
"returnsPolicy": null,
"sellerLocation": null,
"sellerSalesCount": null,
"sellerYearsOnEtsy": null,
"sellerRating": null,
"sellerReviewCount": null,
"sellerResponseTime": null,
"favoritesCount": null,
"listedAt": null,
"reviews": null,
"detailEnriched": null,
"detailErrorCode": null,
"detailError": null,
"scrapedAt": "2026-10-25T20:41:08.053Z"
}

This row came from a promoted slot on the best-sellers page. Etsy did not expose a shop name, shop URL, rating, review count, badges, or an explicit bestseller marker for that card, so those fields are null; isAd is true and adPosition is 1. Title, price text, parsed price, currency, and image are the values the card displayed. The other two saved rows have the same shape: all three are promoted cards, and only the second and third include a FREE shipping badge.

The row below is a real organic card read from the public Internet Archive capture 20251129182826 of the same best-sellers page when the live page was blocked. The archived card exposed no shop link, so the shop fields are null, and pageUrl is the Wayback replay address that carries the capture timestamp.

{
"source": "Etsy",
"sourceHost": "www.etsy.com",
"pageType": "search_results",
"sourceUrl": "https://www.etsy.com/market/best_sellers",
"pageUrl": "https://web.archive.org/web/20251129182826id_/https://www.etsy.com/market/best_sellers",
"pageNum": 1,
"position": 2,
"rank": 1,
"listingId": "1461506381",
"listingUrl": "https://www.etsy.com/listing/1461506381",
"title": "24 day Elf Kit 2025, Best Seller Christmas Elf Activities Kit, Elf Props, Pre-planned Elf Ideas, 24 Days Elf Scenes, Christmas Elves",
"description": null,
"category": null,
"categoryPath": null,
"price": "75.00",
"priceValue": 75,
"originalPrice": null,
"originalPriceValue": null,
"discountPercent": null,
"currency": "USD",
"currencySymbol": "$",
"rating": 4.8097,
"reviewCount": 3800,
"shopName": null,
"shopUrl": null,
"imageUrl": "https://i.etsystatic.com/31074479/r/il/41ec5d/7401277038/il_300x300.7401277038_84lz.jpg",
"images": [
"https://i.etsystatic.com/31074479/r/il/41ec5d/7401277038/il_300x300.7401277038_84lz.jpg"
],
"badges": null,
"isBestseller": null,
"isEtsyChoice": false,
"isAd": null,
"adPosition": null,
"searchQuery": null,
"categoryUrl": "https://www.etsy.com/market/best_sellers",
"materials": null,
"shipping": null,
"deliveryEstimate": null,
"returnsPolicy": null,
"sellerLocation": null,
"sellerSalesCount": null,
"sellerYearsOnEtsy": null,
"sellerRating": null,
"sellerReviewCount": null,
"sellerResponseTime": null,
"favoritesCount": null,
"listedAt": null,
"reviews": null,
"detailEnriched": null,
"detailErrorCode": null,
"detailError": null,
"scrapedAt": "2026-10-31T19:03:54.935Z"
}

Run summary

Run summary is stored separately from the dataset in the run's key-value store under OUTPUT.

FieldMeaning
statusActor process outcome: SUCCEEDED or FAILED.
runStatusCanonical run status; matches status.
dataStatusCompleteness of the saved listing rows: COMPLETE, PARTIAL, NO_RESULTS, or FAILED.
sourceUrlsPublic source URLs used for the run, in the order they were scheduled.
sourceCountNumber of distinct source URLs.
pagesProcessedResult pages loaded and processed.
scheduledRequestsPage requests queued at the start of the run, before deduplication.
normalRowsWrittenListing rows saved to the dataset.
diagnosticCountOperational issues recorded, such as an access block, empty page, or failed detail request.
diagnosticRowsWrittenDiagnostic dataset rows; always 0.
filteredOutCountCards removed by keyword, minPrice, maxPrice, minRating, or minReviewCount.
duplicateCountRepeated listing IDs skipped after the first occurrence.
detailRequestedNumber of listing pages the run attempted to open.
detailSucceededDetail pages opened and parsed successfully.
detailFailedDetail pages that could not be opened or parsed.
maxItemsRow limit used for the run.
maxPagesPage-per-source limit used for the run.
sortByFinal sort order applied to the rows.
scrapedAtTime the summary was written, in ISO UTC.
StatusData statusMeaning
SUCCEEDEDCOMPLETEAt least one listing row was saved and no operational issue was recorded.
SUCCEEDEDPARTIALListing rows were saved, but a source page or detail request failed afterward. Saved rows remain available.
SUCCEEDEDNO_RESULTSThe page loaded cleanly but no card survived extraction and filtering.
FAILEDFAILEDA fatal error occurred before any usable listing was saved.

Example OUTPUT from the 2026-10-25 run:

{
"status": "SUCCEEDED",
"runStatus": "SUCCEEDED",
"dataStatus": "COMPLETE",
"sourceUrls": [
"https://www.etsy.com/market/best_sellers"
],
"sourceCount": 1,
"pagesProcessed": 1,
"scheduledRequests": 1,
"normalRowsWritten": 3,
"diagnosticCount": 0,
"diagnosticRowsWritten": 0,
"filteredOutCount": 0,
"duplicateCount": 0,
"detailRequested": 0,
"detailSucceeded": 0,
"detailFailed": 0,
"maxItems": 3,
"maxPages": 1,
"sortBy": "recommended",
"scrapedAt": "2026-10-25T20:41:08.946Z"
}

Coverage and limitations

The Actor reports what the public result page rendered during the run. Etsy mixes organic and promoted cards, and a promoted card often omits the shop, rating, review count, and badges that an organic card shows; those gaps stay null instead of being filled from another page. The saved best-sellers run is an example: all three rows came from promoted slots, so shop and rating fields are absent.

priceValue, rating, and reviewCount come from the visible card, and price filters compare only parsed numeric values. A card whose price cannot be parsed is excluded when a price bound is set. Sorting is local and does not change the source order used for pagination. Detail fields such as description, materials, shipping, seller history, and reviews require includeDetails and a positive maxDetailItems; those pages add requests and run time, and a failed detail page yields detailEnriched: false with a bounded error code rather than invented data.

Best-seller and search result sets vary by country, locale, session, and time, so the same input can return a different mix. The Actor does not sign in, use private endpoints, solve CAPTCHAs, or bypass access boundaries. Blocked, empty, and partial pages are counted in OUTPUT and logs rather than written as rows.

When Etsy answers both the browser crawl and a plain HTTP read with a bot-check, the Actor looks for a public Internet Archive capture of the same source URL through the Wayback CDX and availability APIs and reads its raw id_ HTML. Archived HTML goes through the same card and JSON-LD readers, so a row can only contain listings that the archived page displayed. One capture is read per source URL, and pagination links inside an archived page are not followed. That row's pageUrl is the Wayback replay address, which carries the capture timestamp; captures can be old, and a URL with no public capture stays a diagnostic instead of a row.

Usage and support

Cost is driven by browser page loads, page count, concurrency, retries, timeouts, and optional detail enrichment. Start with one source, maxItems of 3 to 20, and details off; then increase pages or enable details after inspecting the dataset and run summary. See the Actor's Pricing tab for current account rates.

Use the Actor Issues page to report a problem. Include the run ID, the input used, and the run summary; do not include tokens, cookies, or private data. This Actor is an independent community tool and is not affiliated with, endorsed by, or sponsored by Etsy, Inc. Use it only for public data and in accordance with Etsy's terms, robots guidance, and applicable law.