Nimbryxo Studio

Etsy Product Listings & Shop Research Scraper

Collect Etsy product listings from keyword searches, category pages, and individual shops, with prices, ratings, seller badges, and optional full product detail across ten regional markets.

Input schema

Input fields, types, required flags, descriptions, defaults, and prefills come from the published definition. Prefill examples are distinct from defaults.

FieldTypeRequiredDescription
startUrlsarrayoptionalEtsy market URLs such as https://www.etsy.com/market/handmade_jewelry are the reliable route. Category URLs such as https://www.etsy.com/c/jewelry also work and expose more cards per page. Legacy /search?q= URLs are converted to the matching market URL automatically. Shop and individual listing URLs are usually blocked by Etsy's DataDome protection; they are accepted for backward compatibility and reported as blocked instead of silently returning nothing.
searchQueriesarrayoptionalKeywords to search on Etsy. Each query is mapped to Etsy's market page (https://www.etsy.com/market/<slug>), the route that works without a browser or login. If Etsy redirects a keyword to a category page, the actor follows that category route. Each query is scraped as a separate task.
maxItemsintegeroptionalMaximum number of listings to collect per URL or search query. A keyword market exposes at most 25 pages (about 200 listings); category URLs can expose more pages. Larger values return what Etsy exposes and report a partial result instead of pretending the request was complete.
Show all input fields
FieldTypeRequiredDescription
startUrlsarrayoptionalEtsy market URLs such as https://www.etsy.com/market/handmade_jewelry are the reliable route. Category URLs such as https://www.etsy.com/c/jewelry also work and expose more cards per page. Legacy /search?q= URLs are converted to the matching market URL automatically. Shop and individual listing URLs are usually blocked by Etsy's DataDome protection; they are accepted for backward compatibility and reported as blocked instead of silently returning nothing.
searchQueriesarrayoptionalKeywords to search on Etsy. Each query is mapped to Etsy's market page (https://www.etsy.com/market/<slug>), the route that works without a browser or login. If Etsy redirects a keyword to a category page, the actor follows that category route. Each query is scraped as a separate task.
maxItemsintegeroptionalMaximum number of listings to collect per URL or search query. A keyword market exposes at most 25 pages (about 200 listings); category URLs can expose more pages. Larger values return what Etsy exposes and report a partial result instead of pretending the request was complete.
includeDetailsbooleanoptionalAttempts to open each listing page for description, materials, tags, variations, images, and seller details. Etsy often blocks listing pages with DataDome. When that happens, rows are still returned with detailsStatus set to 'blocked' and the unavailable detail fields omitted; they are never filled with placeholders.
sortBystringoptionalServer-side Etsy ordering for market and category pages.
minPricenumberoptionalDrop listings below this price in the selected market currency. Etsy does not expose a reliable server-side price filter on market pages, so this is applied to fetched cards. 0 disables the lower bound.
maxPricenumberoptionalDrop listings above this price in the selected market currency. 0 disables the upper bound.
freeShippingOnlybooleanoptionalUse Etsy's free-shipping market filter.
starSellerOnlybooleanoptionalUse Etsy's Star Seller market filter.
countrystringoptionalTarget Etsy market. Sets the market URL locale and request language, so prices and ranking match the selected region (for example Germany returns EUR and Japan returns JPY).

Download the published input schema

View complete JSON
{
  "properties": {
    "country": {
      "default": "US",
      "description": "Target Etsy market. Sets the market URL locale and request language, so prices and ranking match the selected region (for example Germany returns EUR and Japan returns JPY).",
      "editor": "select",
      "enum": [
        "US",
        "DE",
        "GB",
        "FR",
        "AU",
        "CA",
        "IT",
        "ES",
        "NL",
        "JP"
      ],
      "enumTitles": [
        "United States (USD)",
        "Germany (EUR)",
        "United Kingdom (GBP)",
        "France (EUR)",
        "Australia (AUD)",
        "Canada (CAD)",
        "Italy (EUR)",
        "Spain (EUR)",
        "Netherlands (EUR)",
        "Japan (JPY)"
      ],
      "prefill": "US",
      "title": "Country / Market",
      "type": "string"
    },
    "freeShippingOnly": {
      "default": false,
      "description": "Use Etsy's free-shipping market filter.",
      "prefill": false,
      "title": "Free shipping only",
      "type": "boolean"
    },
    "includeDetails": {
      "default": false,
      "description": "Attempts to open each listing page for description, materials, tags, variations, images, and seller details. Etsy often blocks listing pages with DataDome. When that happens, rows are still returned with detailsStatus set to 'blocked' and the unavailable detail fields omitted; they are never filled with placeholders.",
      "prefill": false,
      "title": "Include Listing Details",
      "type": "boolean"
    },
    "maxItems": {
      "default": 100,
      "description": "Maximum number of listings to collect per URL or search query. A keyword market exposes at most 25 pages (about 200 listings); category URLs can expose more pages. Larger values return what Etsy exposes and report a partial result instead of pretending the request was complete.",
      "editor": "number",
      "maximum": 1000,
      "minimum": 1,
      "prefill": 1,
      "title": "Max Items",
      "type": "integer"
    },
    "maxPrice": {
      "default": 0,
      "description": "Drop listings above this price in the selected market currency. 0 disables the upper bound.",
      "editor": "number",
      "maximum": 1000000,
      "minimum": 0,
      "prefill": 0,
      "title": "Maximum price",
      "type": "number"
    },
    "minPrice": {
      "default": 0,
      "description": "Drop listings below this price in the selected market currency. Etsy does not expose a reliable server-side price filter on market pages, so this is applied to fetched cards. 0 disables the lower bound.",
      "editor": "number",
      "maximum": 1000000,
      "minimum": 0,
      "prefill": 0,
      "title": "Minimum price",
      "type": "number"
    },
    "searchQueries": {
      "description": "Keywords to search on Etsy. Each query is mapped to Etsy's market page (https://www.etsy.com/market/<slug>), the route that works without a browser or login. If Etsy redirects a keyword to a category page, the actor follows that category route. Each query is scraped as a separate task.",
      "editor": "stringList",
      "prefill": [
        "handmade jewelry"
      ],
      "title": "Search Queries",
      "type": "array"
    },
    "sortBy": {
      "default": "",
      "description": "Server-side Etsy ordering for market and category pages.",
      "editor": "select",
      "enum": [
        "",
        "most_relevant",
        "price_asc",
        "price_desc",
        "date_desc",
        "highest_reviews"
      ],
      "enumTitles": [
        "Most relevant",
        "Price: low to high",
        "Price: high to low",
        "Newest",
        "Most reviewed"
      ],
      "prefill": "",
      "title": "Sort results by",
      "type": "string"
    },
    "starSellerOnly": {
      "default": false,
      "description": "Use Etsy's Star Seller market filter.",
      "prefill": false,
      "title": "Star Seller only",
      "type": "boolean"
    },
    "startUrls": {
      "description": "Etsy market URLs such as https://www.etsy.com/market/handmade_jewelry are the reliable route. Category URLs such as https://www.etsy.com/c/jewelry also work and expose more cards per page. Legacy /search?q= URLs are converted to the matching market URL automatically. Shop and individual listing URLs are usually blocked by Etsy's DataDome protection; they are accepted for backward compatibility and reported as blocked instead of silently returning nothing.",
      "editor": "requestListSources",
      "title": "Etsy URLs",
      "type": "array"
    }
  },
  "required": [],
  "schemaVersion": 1,
  "title": "Etsy Scraper Input",
  "type": "object"
}

Output schema

Published result links and storage locations. This schema is not an exhaustive contract for every field in a dataset record.

FieldTypeRequiredDescription
listingsstringoptionalDataset containing all scraped Etsy product listings.

Download the published output schema

View complete JSON
{
  "actorOutputSchemaVersion": 1,
  "description": "Dataset of Etsy listing records collected from keyword market and category pages, with ISO currency codes, numeric prices, shop-level ratings, badges, provenance fields, and optional listing detail.",
  "properties": {
    "listings": {
      "description": "Dataset containing all scraped Etsy product listings.",
      "template": "{{links.apiDefaultDatasetUrl}}/items",
      "title": "Etsy Listings",
      "type": "string"
    }
  },
  "title": "Etsy Product Listings & Shop Research Scraper Output"
}

Dataset schema

Published dataset views and any declared field definitions. A view can select only a subset of the returned record fields.

Download the published dataset schema

View complete JSON
{
  "actorSpecification": 1,
  "views": {
    "overview": {
      "display": {
        "component": "table",
        "properties": {
          "currencyCode": {
            "format": "text",
            "label": "Currency"
          },
          "isAd": {
            "format": "boolean",
            "label": "Ad"
          },
          "priceValue": {
            "format": "number",
            "label": "Price"
          },
          "rating": {
            "format": "text",
            "label": "Shop rating"
          },
          "reviewCount": {
            "format": "text",
            "label": "Shop reviews"
          },
          "shopName": {
            "format": "text",
            "label": "Shop"
          },
          "title": {
            "format": "text",
            "label": "Title"
          },
          "url": {
            "format": "link",
            "label": "URL"
          }
        }
      },
      "title": "Overview",
      "transformation": {
        "fields": [
          "title",
          "priceValue",
          "currencyCode",
          "shopName",
          "rating",
          "reviewCount",
          "isAd",
          "url"
        ]
      }
    }
  }
}

Key-value schema

Published key-value store definitions, when provided by this build.

This definition is not present in the default published build. See the published README for available documentation.

Published README

Read the full published documentation

Etsy Product Listings & Shop Research Scraper

Collect Etsy listing data from Etsy's keyword market pages without a login, API key, or proxy setup. Give the actor a keyword or a market URL, choose one of ten regional markets, and get structured rows for pricing research, assortment tracking, and shop comparisons.

How it works

Etsy's keyword market pages (https://www.etsy.com/market/<slug>) are the most reliable public route. The actor converts every search query into that route, reads the page's JSON-LD ItemList and listing cards, and follows pages until it reaches your limit or the source ends. When Etsy redirects a keyword to a category page, the actor follows the redirect with a fresh request instead of treating the redirect as a dead end.

Category URLs such as https://www.etsy.com/c/jewelry are also supported directly and normally expose about 64 cards per page. Legacy /search?q= URLs are converted to the equivalent market URL. Shop and individual listing URLs are accepted for backward compatibility, but Etsy protects those with DataDome; the actor reports them as blocked instead of returning an empty result.

What you get per listing

Card-level fields:

  • listingId - numeric Etsy listing ID
  • url - listing page URL
  • title - listing title
  • price, originalPrice - plain decimal strings (no thousands separators)
  • priceValue, originalPriceValue - numeric values for calculations
  • currency - Etsy's display label or symbol (USD, EUR, GBP, JPY, AU$, CA$)
  • currencyCode - ISO 4217 code (USD, EUR, GBP, JPY, AUD, CAD, ...)
  • discountPercent - discount as a string, kept for compatibility
  • discountPercentValue - discount as an integer percentage
  • imageUrl - primary card image
  • imageCount - number of images exposed in the card (usually 1)
  • shopId - Etsy shop ID when the card exposes it
  • shopName, shopUrl - shop name and URL (from the page's brand data or shop link)
  • rating, reviewCount - shop-level rating and review count when the card shows them
  • shopRating, shopReviewCount - numeric shop-level copies of the same values
  • ratingScope - shop when the supplied rating is shop-level
  • listingRating, listingReviewCount - listing-level rating only when the page's structured data supplies aggregateRating (usually it does not)
  • availability - stock status from the page's structured data
  • badges - compatibility object with starSeller, freeShipping, bestseller, etsyChoice, ad
  • isAd - present and true for sponsored cards (omitted for organic cards)
  • freeShipping, starSeller, bestseller, etsyChoice - present and true when the badge is visible
  • hasVariations - present and true when variations are visible
  • page - source market or category page number
  • position - row position within the task's collected results
  • sourceQuery - keyword or slug that produced the row
  • sourceUrl - exact market or category page URL the row came from
  • recordType - listing for card records
  • scrapedAt - ISO 8601 collection timestamp

Fields the page does not expose are omitted rather than emitted as empty strings, nulls, or placeholders. isAd, badge flags, and hasVariations are only present when true; absence means the page did not show that signal. rating is a shop-level rating on market cards, which is why ratingScope is shop.

When includeDetails is enabled

The actor attempts to open each listing page and add:

  • description, category, materials, listedDate, availability
  • images - all listing image URLs
  • variations - selectable options
  • tags - listing tags
  • sellerName, sellerRating, sellerReviewCount, sellerLocation
  • listingRating, listingReviewCount - listing-level rating when the listing page supplies it
  • detailsStatus - enriched, blocked, not_found, partial, or no_url

Etsy frequently blocks listing pages with DataDome. When that happens, the row keeps its card data, detailsStatus is blocked, and no detail fields are invented. A circuit breaker stops detail attempts after three consecutive blocks so a site-wide block cannot stall the run.

Input

At least one of startUrls or searchQueries is required for a normal run. A truly empty input uses the documented handmade jewelry fallback for the scheduled test. Apify's validator cannot express "one of", so the actor enforces it.

Field Type Default Description
startUrls array - Etsy market URLs are reliable; /c/ category URLs work and return more cards per page. Legacy /search?q= URLs are converted to market URLs. Shop URLs use the 10-item public RSS feed; listing URLs are reported as blocked.
searchQueries array - Keywords mapped to Etsy market pages, with automatic category follow when Etsy redirects. Each query is a separate task.
maxItems integer 100 Maximum rows per URL or query (1-1,000). Keyword markets cap at 25 pages; categories can go deeper.
includeDetails boolean false Attempt listing-page enrichment and report detailsStatus honestly.
sortBy select any most_relevant, price_asc, price_desc, date_desc, highest_reviews.
minPrice number - Lower price bound in the market currency. Etsy min is used server-side and a local safeguard follows.
maxPrice number - Upper price bound in the market currency.
freeShippingOnly boolean false Use Etsy's free_shipping=1 market filter.
starSellerOnly boolean false Use Etsy's is_star_seller=1 market filter.
country string US Market locale: US, DE, GB, FR, AU, CA, IT, ES, NL, JP.

If no input is supplied, the actor uses handmade jewelry as a safe fallback so a scheduled test run still produces data. At least one of startUrls or searchQueries is normally provided.

Examples

Keyword search in the default US market:

{
  "searchQueries": ["handmade jewelry"],
  "maxItems": 50
}

Multi-page collection in Germany:

{
  "searchQueries": ["keramik tasse"],
  "country": "DE",
  "maxItems": 120
}

Direct market URL:

{
  "startUrls": [{ "url": "https://www.etsy.com/uk/market/wedding_ring" }],
  "maxItems": 80
}

Category URL with 64 cards per page:

{
  "startUrls": [{ "url": "https://www.etsy.com/c/jewelry/necklaces" }],
  "maxItems": 200
}

Details requested, with honest fallback:

{
  "searchQueries": ["personalized necklace"],
  "includeDetails": true,
  "maxItems": 20
}

Pagination, deduplication, and limits

  • Pages are followed until maxItems is reached, no new listing IDs appear for two consecutive pages, or Etsy's explicit max_page_exceeded marker is hit.
  • A short page is not treated as the end. Etsy market pages normally show about eight cards, and category pages about 64; the old "fewer than 64 cards means stop" shortcut would have stopped after page one.
  • Rows are deduplicated by listing ID across pages and across tasks; sponsored cards can repeat.
  • Etsy serves at most 25 market pages per query (roughly 200 listings). Larger maxItems values return what exists and set a partial status message instead of pretending the request was complete.
  • Category pages can be deeper, but DataDome may rate-limit very deep or rapid page walks. The actor retries, then reports a partial result with the reason.
  • Some keywords have no market page, return 404, or redirect to a category page. The actor tries alternate slug spellings, follows a working category redirect, and reports the specific reason for any task that still fails.

FAQ

Do I need an Etsy account, API key, or proxy? No. The actor reads public market pages and works without credentials or proxy configuration. It chooses its proxy automatically and only after a direct request is blocked.

Why do I sometimes get fewer rows than maxItems? Etsy's market route exposes up to 25 pages per query. The actor reports the ceiling and returns the available rows. Shop RSS is limited to 10 recent items. Category pages can go deeper but may rate-limit.

Which filters and sorts work? sortBy, freeShippingOnly, starSellerOnly, minPrice and maxPrice are supported. Sorting and the two badges are server-side; price bounds use Etsy's min/max parameters and a local safeguard. Views, favorites, carts and bought-in-last-24h are not present on market/category pages; listing pages expose some of them only through a browser, so they are not shipped.

What happens with shop and listing URLs? Shop URLs use Etsy's public shop RSS feed, which returns the 10 most recent listings with title, description, image and price. It is honest about being a recent-items feed and does not paginate. Listing detail pages remain DataDome-blocked for plain HTTP; browser/proxy enrichment is not used in production because it is slow and unreliable. Keyword market pages and /c/ category pages are the reliable bulk routes.

Why is ratingScope set to shop? The rating shown on an Etsy listing card is the shop's aggregate rating. This was verified by finding the same shop's separate listings carrying an identical rating and review count. Listing-level ratings are only claimed through listingRating when structured data on the page supplies them, or through includeDetails when the listing page is readable.

Why are some shop names or ratings missing? Etsy's card markup does not always expose a shop name or rating. The actor fills them from the page's JSON-LD brand and visible rating controls, and omits them when the page genuinely does not show them. Missing fields are never replaced with placeholders.

Are prices strings or numbers? Both are provided. price and originalPrice remain decimal strings for backward compatibility; priceValue and originalPriceValue are numeric for calculations.

Why do output listing/shop URLs return 403? Etsy's DataDome protection blocks clean clients even for URLs the actor collected from public market/RSS pages. The URLs are valid for a browser; this is an Etsy anti-bot caveat, not a broken URL. Image URLs were verified HTTP 200.

Is this affiliated with Etsy? No. This is an independent third-party actor that reads publicly visible pages and is not affiliated with or endorsed by Etsy, Inc.

Python quickstart

Use a schema-derived input and the Python standard library to start a run. An Apify account and token are required for execution.

Open the step-by-step Python guide →

Source build I2vzZsFaC2LGvOXoY. Documentation is regenerated from the default published build; private drafts are not included.