<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: publicrecords</title>
    <description>The latest articles on DEV Community by publicrecords (@publicrecords).</description>
    <link>https://dev.to/publicrecords</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4157345%2Fbb89b543-bdf7-433d-85aa-1b4bfd39ade8.png</url>
      <title>DEV Community: publicrecords</title>
      <link>https://dev.to/publicrecords</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/publicrecords"/>
    <language>en</language>
    <item>
      <title>The MCP servers an Etsy seller can actually use</title>
      <dc:creator>publicrecords</dc:creator>
      <pubDate>Tue, 03 Nov 2026 01:29:52 +0000</pubDate>
      <link>https://dev.to/publicrecords/the-mcp-servers-an-etsy-seller-can-actually-use-21l3</link>
      <guid>https://dev.to/publicrecords/the-mcp-servers-an-etsy-seller-can-actually-use-21l3</guid>
      <description>&lt;p&gt;Search "Etsy MCP" and you'll find a handful of half-finished experiments mixed in with general scraping tools. I wanted a short, honest list of what actually works for an Etsy seller who uses Claude, Cursor or ChatGPT, so I made one: &lt;a href="https://github.com/GeminiGeorge22/awesome-etsy-mcp" rel="noopener noreferrer"&gt;Awesome Etsy MCP&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it's organized
&lt;/h2&gt;

&lt;p&gt;One entry per data source or marketplace. Each one was checked when it was added.&lt;/p&gt;

&lt;h3&gt;
  
  
  Etsy itself
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Etsy Dev MCP Server&lt;/strong&gt; is Etsy's own server. It searches the Open API v3 docs and schemas while you build. It doesn't call the API for you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;etsy-mcp-server&lt;/strong&gt; (community) exposes the Open API v3 for your own shop: listings, inventory, orders, shipping and shop settings, with the OAuth scope each call needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Etsy Search &amp;amp; Shop Sales MCP&lt;/strong&gt; is ours and is marked that way. It returns live Etsy search rows (title, price, shop, badges, rank) and daily sales counters for competitor shops you name.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Scraping platforms that cover Etsy
&lt;/h3&gt;

&lt;p&gt;Apify, Bright Data and Firecrawl all have official MCP servers that can read public Etsy pages alongside other stores. They're the right pick if you need Etsy plus everything else.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other marketplaces
&lt;/h3&gt;

&lt;p&gt;Most sellers aren't only on Etsy, so the list has one entry each for Amazon (the official Selling Partner connector), eBay (Sell APIs) and Shopify (dev docs and schemas).&lt;/p&gt;

&lt;h2&gt;
  
  
  Things you can ask once it's connected
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;"What are the top 20 Etsy results for 'ceramic planter' right now, and which shops show up more than once?"&lt;/li&gt;
&lt;li&gt;"Which of these three competitor shops is growing fastest this month?"&lt;/li&gt;
&lt;li&gt;"Draft a listing title in the style of the best-ranked results for this keyword."&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Connecting
&lt;/h2&gt;

&lt;p&gt;With Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; http etsy-dev &lt;span class="s2"&gt;"https://mcp.api.etsycloud.com/mcp"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The README has Cursor and VS Code snippets for every entry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Suggest one
&lt;/h2&gt;

&lt;p&gt;The list is CC0 and open to pull requests. If something covers a source that isn't listed, or clearly beats a current entry, send it in.&lt;/p&gt;

&lt;p&gt;Disclosure: I maintain the list and one entry on it. The rest are independent. Use these tools only on data you're allowed to access, and follow each marketplace's terms.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>etsy</category>
      <category>ecommerce</category>
    </item>
    <item>
      <title>The sports odds MCP servers worth connecting, one per sportsbook</title>
      <dc:creator>publicrecords</dc:creator>
      <pubDate>Tue, 03 Nov 2026 01:29:32 +0000</pubDate>
      <link>https://dev.to/publicrecords/the-sports-odds-mcp-servers-worth-connecting-one-per-sportsbook-36oi</link>
      <guid>https://dev.to/publicrecords/the-sports-odds-mcp-servers-worth-connecting-one-per-sportsbook-36oi</guid>
      <description>&lt;p&gt;If you've tried giving Claude, Cursor or ChatGPT live betting odds, you've probably noticed that "sports odds MCP" search results are mostly duplicates: several wrappers around the same aggregator, abandoned demos, and a few tools that scrape logged-in sessions. Picking one takes longer than it should.&lt;/p&gt;

&lt;p&gt;So I put together a short curated list: &lt;a href="https://github.com/GeminiGeorge22/awesome-sports-odds-mcp" rel="noopener noreferrer"&gt;Awesome Sports Odds MCP&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one rule: one provider per sportsbook
&lt;/h2&gt;

&lt;p&gt;Each sportsbook, book network, exchange or aggregator gets a single entry, the strongest one I could find. If two servers cover the same source, only the better one is listed. That keeps it short enough to read in a couple of minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's on it
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Multi-book aggregators.&lt;/strong&gt; These normalize many books into one schema: OpticOdds, Odds-API.io, SportsGameOdds, TheRundown and PropLine (for player props).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sportsbook networks and single books.&lt;/strong&gt; These read one source directly. Our own Kambi server (BetRivers, Unibet, Paf, Svenska Spel and ATG) is here, marked as ours, next to PinnWire for Pinnacle and OddiWire for esports.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Regional bookmakers.&lt;/strong&gt; PuntersEdge covers Australian racing and sports.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prediction markets.&lt;/strong&gt; One Polymarket server and one Kalshi server, for anyone pricing event contracts against sportsbook lines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docs MCPs for builders.&lt;/strong&gt; Sportradar and OddsPapi publish MCP servers that serve their API docs and schemas instead of prices. They're useful while you're writing an integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I left out
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Servers with no recent activity&lt;/li&gt;
&lt;li&gt;Near-duplicates of an entry already on the list&lt;/li&gt;
&lt;li&gt;Anything that depends on borrowed cookies or logged-in sessions&lt;/li&gt;
&lt;li&gt;Anything selling win-rate or "guaranteed edge" claims&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Connecting one
&lt;/h2&gt;

&lt;p&gt;Most entries are remote MCP servers, so you just add a URL. With Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; http sports-odds &lt;span class="s2"&gt;"https://mcp.apify.com?tools=publicrecords/sports-odds-api"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or in Cursor (&lt;code&gt;~/.cursor/mcp.json&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pinnacle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://pinnwire.com/mcp"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each provider's own docs explain whether it expects an API key or OAuth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Help keep it current
&lt;/h2&gt;

&lt;p&gt;The list is CC0. If you know a server that covers a book that isn't listed yet, or one that beats a current entry, open a pull request. The contributing guide covers the one-per-sportsbook rule.&lt;/p&gt;

&lt;p&gt;Disclosure: I maintain the list and one of its entries (the Kambi server). Everything else is independent and listed on merit. Odds data only; follow the laws where you live.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>sports</category>
      <category>api</category>
    </item>
    <item>
      <title>Track Etsy Shop Sales Velocity with an Apify Actor (curl + Python)</title>
      <dc:creator>publicrecords</dc:creator>
      <pubDate>Tue, 27 Oct 2026 15:00:22 +0000</pubDate>
      <link>https://dev.to/publicrecords/track-etsy-shop-sales-velocity-with-an-apify-actor-curl-python-33mb</link>
      <guid>https://dev.to/publicrecords/track-etsy-shop-sales-velocity-with-an-apify-actor-curl-python-33mb</guid>
      <description>&lt;h1&gt;
  
  
  Track Etsy Shop Sales Velocity with an Apify Actor (curl + Python)
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Disclosure: I maintain this Actor.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you sell on Etsy (or research niches), you eventually want a simple question answered: &lt;em&gt;how fast is that other shop selling?&lt;/em&gt; Etsy's public shop page shows a lifetime sales counter. Read it twice, with dates, and you can derive a measured sales-per-day rate. This tutorial walks through a real run of the public &lt;a href="https://publicrecords-redirect.publicrecords.workers.dev/r/devto-etsy-1" rel="noopener noreferrer"&gt;Etsy Shop Sales Tracker &amp;amp; Scraper&lt;/a&gt; Actor on Apify — not a mock.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you get back
&lt;/h2&gt;

&lt;p&gt;One dataset row per shop. Useful fields include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;shop&lt;/code&gt;, &lt;code&gt;shop_url&lt;/code&gt;, &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;category&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sales_count&lt;/code&gt; — the public lifetime sales counter as read&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;as_of&lt;/code&gt; / &lt;code&gt;snapshot_date&lt;/code&gt; — when that counter was read&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sales_per_day&lt;/code&gt; — rate derived from consecutive exact reads&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;delta_7d&lt;/code&gt;, &lt;code&gt;delta_last&lt;/code&gt;, &lt;code&gt;history_days&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;public engagement counters: &lt;code&gt;reviews_count&lt;/code&gt;, &lt;code&gt;rating&lt;/code&gt;, &lt;code&gt;admirers&lt;/code&gt;, &lt;code&gt;listings_active&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Actor tracks shops it can read on the public page. It is not limited to Etsy Bestsellers, and this post does not claim an "only Bestsellers" scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;from $0.00005 per run start + $0.003 per shop row (free plan, lower on paid plans)&lt;/strong&gt;, as of Oct 27, 2026. Re-check &lt;a href="https://publicrecords-redirect.publicrecords.workers.dev/r/devto-etsy-1-pricing" rel="noopener noreferrer"&gt;the Store pricing page&lt;/a&gt; before budgeting a large crawl.&lt;/p&gt;

&lt;h2&gt;
  
  
  A tested run
&lt;/h2&gt;

&lt;p&gt;On Oct 27, 2026 I ran the Actor with the Store example input, &lt;code&gt;{"shops": ["OrelCeramics", "Bestickend"]}&lt;/code&gt;. It succeeded in a few seconds and returned 2 shop rows.&lt;/p&gt;

&lt;p&gt;The two rows it returned:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;shop&lt;/th&gt;
&lt;th&gt;sales_count&lt;/th&gt;
&lt;th&gt;sales_per_day&lt;/th&gt;
&lt;th&gt;delta_7d&lt;/th&gt;
&lt;th&gt;delta_last&lt;/th&gt;
&lt;th&gt;as_of&lt;/th&gt;
&lt;th&gt;history_days&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OrelCeramics&lt;/td&gt;
&lt;td&gt;111&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2026-10-26&lt;/td&gt;
&lt;td&gt;27&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bestickend&lt;/td&gt;
&lt;td&gt;11,475&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;2026-10-26&lt;/td&gt;
&lt;td&gt;27&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;Bestickend&lt;/code&gt; shows a clear weekly change (&lt;code&gt;delta_7d&lt;/code&gt; = 10) and a recent step (&lt;code&gt;delta_last&lt;/code&gt; = 6) against a dated counter (&lt;code&gt;as_of&lt;/code&gt; = 2026-10-26). &lt;code&gt;OrelCeramics&lt;/code&gt; is quieter on the same window — useful when you want a side-by-side contrast, not only hot shops.&lt;/p&gt;

&lt;h2&gt;
  
  
  Call it with curl
&lt;/h2&gt;

&lt;p&gt;Replace &lt;code&gt;APIFY_TOKEN&lt;/code&gt; with your Apify API token (Console → Settings → Integrations). Do not commit the real token.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Start a run (Store example input)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sS&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'https://api.apify.com/v2/acts/publicrecords~etsy-shop-velocity/runs?token=APIFY_TOKEN'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "shops": ["OrelCeramics", "Bestickend"]
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful input fields (from the Store input schema):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;shops&lt;/code&gt; — array of shop names (the path after &lt;code&gt;etsy.com/shop/&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;keywords&lt;/code&gt; — match title / headline&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;category&lt;/code&gt; — panel category filter&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;minSales&lt;/code&gt; — lifetime sales floor&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;since&lt;/code&gt; — ISO date; only shops whose counters changed since then&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;maxShops&lt;/code&gt; — upper bound on rows returned (and charged)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Wait for the run, then read the default dataset
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# RUN_ID and DATASET_ID come from the start response:&lt;/span&gt;
&lt;span class="c"&gt;# .data.id and .data.defaultDatasetId&lt;/span&gt;
curl &lt;span class="nt"&gt;-sS&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://api.apify.com/v2/actor-runs/RUN_ID?token=APIFY_TOKEN"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | jq &lt;span class="s1"&gt;'{status: .data.status, datasetId: .data.defaultDatasetId}'&lt;/span&gt;

&lt;span class="c"&gt;# rows, once status is SUCCEEDED&lt;/span&gt;
curl &lt;span class="nt"&gt;-sS&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://api.apify.com/v2/datasets/DATASET_ID/items?token=APIFY_TOKEN&amp;amp;clean=1&amp;amp;limit=10"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | jq &lt;span class="s1"&gt;'.[] | {shop, sales_count, sales_per_day, delta_7d, delta_last, as_of}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Schedule it
&lt;/h3&gt;

&lt;p&gt;In the Apify Console, open the Actor → Schedules, or create a schedule via the Schedules API pointing at the same Actor. Daily or weekly reads are enough to keep &lt;code&gt;sales_per_day&lt;/code&gt; and &lt;code&gt;delta_7d&lt;/code&gt; meaningful; denser schedules mostly burn row events.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to read the numbers
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;sales_count&lt;/code&gt; + &lt;code&gt;as_of&lt;/code&gt;&lt;/strong&gt; — an exact public counter at a known date. Treat it as a measurement, not an Etsy Analytics export.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;sales_per_day&lt;/code&gt;&lt;/strong&gt; — the shop is read a few days apart; sales per day is the average over that gap. If history is short, the rate is noisier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;delta_7d&lt;/code&gt; / &lt;code&gt;delta_last&lt;/code&gt;&lt;/strong&gt; — change across roughly a week, and the most recent step, when the history supports it; otherwise check null-reason fields on the row.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compare shops side-by-side&lt;/strong&gt; on &lt;code&gt;sales_per_day&lt;/code&gt; and &lt;code&gt;delta_7d&lt;/code&gt;, not on lifetime &lt;code&gt;sales_count&lt;/code&gt; alone (a huge shop can grow slowly; a small shop can be accelerating).&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Minimal Python client
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="n"&gt;TOKEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;APIFY_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# never hard-code
&lt;/span&gt;&lt;span class="n"&gt;ACT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;publicrecords~etsy-shop-velocity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.apify.com/v2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/acts/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ACT&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/runs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;token&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TOKEN&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shops&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OrelCeramics&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bestickend&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;
    &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;run_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/actor-runs/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;run_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;token&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TOKEN&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SUCCEEDED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FAILED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ABORTED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TIMED-OUT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}:&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;defaultDatasetId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/datasets/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ds&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/items&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;token&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;clean&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shop&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sales_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sales_per_day&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;delta_7d&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;as_of&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where this fits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Competitor shortlists: pin 10–50 shops, schedule weekly, watch &lt;code&gt;delta_7d&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Niche scans: pass &lt;code&gt;keywords&lt;/code&gt; / &lt;code&gt;category&lt;/code&gt; instead of (or with) explicit shop names.&lt;/li&gt;
&lt;li&gt;Free public slice: &lt;a href="https://www.etsypulse.ca/" rel="noopener noreferrer"&gt;etsypulse.ca&lt;/a&gt; publishes movers/rising from the same family of reads; each shop row there links back to this Actor via "Track this shop's sales".&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limits to say out loud
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Public counters only — not order-level or revenue data.&lt;/li&gt;
&lt;li&gt;A shop can hide sold listings; the lifetime counter may still be readable when listings are not.&lt;/li&gt;
&lt;li&gt;Pricing and field labels can change; re-read the Store page before a large job.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Disclosure: I maintain this Actor.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Store page: &lt;a href="https://publicrecords-redirect.publicrecords.workers.dev/r/devto-etsy-1" rel="noopener noreferrer"&gt;https://publicrecords-redirect.publicrecords.workers.dev/r/devto-etsy-1&lt;/a&gt;&lt;/p&gt;

</description>
      <category>etsy</category>
      <category>apify</category>
      <category>api</category>
      <category>ecommerce</category>
    </item>
    <item>
      <title>Find bestselling Etsy listings in a niche: 10 rows for $0.04</title>
      <dc:creator>publicrecords</dc:creator>
      <pubDate>Mon, 05 Oct 2026 20:16:23 +0000</pubDate>
      <link>https://dev.to/publicrecords/find-bestselling-etsy-listings-in-a-niche-10-rows-for-0065-56ko</link>
      <guid>https://dev.to/publicrecords/find-bestselling-etsy-listings-in-a-niche-10-rows-for-0065-56ko</guid>
      <description>&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt; I maintain these Actors on Apify Store (&lt;a href="https://apify.com/publicrecords" rel="noopener noreferrer"&gt;publicrecords&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Etsy sellers and product researchers keep asking how to &lt;strong&gt;export Etsy search results&lt;/strong&gt; for a niche and see which listings are already marked &lt;strong&gt;Bestseller&lt;/strong&gt;. Today's walkthrough does that with &lt;a href="https://publicrecords-redirect.publicrecords.workers.dev/r/etsy-bestsellers" rel="noopener noreferrer"&gt;Etsy Search Scraper&lt;/a&gt; — a different path from sorting by price.&lt;/p&gt;

&lt;h2&gt;
  
  
  Price (matches the live listing)
&lt;/h2&gt;

&lt;p&gt;Pay-per-event on Apify Store:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Actor start:&lt;/strong&gt; &lt;code&gt;$0.00005&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Listing row:&lt;/strong&gt; &lt;code&gt;$0.004&lt;/code&gt; per delivered listing (free plan; lower on paid plans, down to &lt;code&gt;$0.0034&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;10 rows:&lt;/strong&gt; &lt;code&gt;$0.00005 + 10 × $0.004 = $0.04005&lt;/code&gt; (about $0.04)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Prices as of Oct 27, 2026 — see the &lt;a href="https://apify.com/publicrecords/etsy-search-scraper/pricing" rel="noopener noreferrer"&gt;Store pricing page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Blocked pages are not charged.&lt;/p&gt;

&lt;h2&gt;
  
  
  Paste-ready input (bestsellers in a niche)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"queries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"personalized dog collar"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"relevance"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_best_seller"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxItems"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxPages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fillLazyCards"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"proxyConfiguration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"useApifyProxy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"apifyProxyGroups"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"RESIDENTIAL"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"apifyProxyCountry"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"US"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Swap the keyword for your niche. &lt;code&gt;is_best_seller: true&lt;/code&gt; keeps only listings Etsy marks Bestseller.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open the Actor: &lt;a href="https://publicrecords-redirect.publicrecords.workers.dev/r/etsy-bestsellers" rel="noopener noreferrer"&gt;publicrecords/etsy-search-scraper&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Paste the JSON into Input → Start&lt;/li&gt;
&lt;li&gt;Download the dataset (CSV/JSON)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Or from the CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apify call publicrecords/etsy-search-scraper &lt;span class="nt"&gt;--input&lt;/span&gt; &lt;span class="s1"&gt;'{
  "queries": ["personalized dog collar"],
  "sort": "relevance",
  "is_best_seller": true,
  "maxItems": 10,
  "maxPages": 1,
  "fillLazyCards": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"],
    "apifyProxyCountry": "US"
  }
}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;curl (replace &lt;code&gt;$APIFY_TOKEN&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sS&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://api.apify.com/v2/acts/publicrecords~etsy-search-scraper/runs?token=&lt;/span&gt;&lt;span class="nv"&gt;$APIFY_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "queries": ["personalized dog collar"],
    "sort": "relevance",
    "is_best_seller": true,
    "maxItems": 10,
    "maxPages": 1,
    "fillLazyCards": true,
    "proxyConfiguration": {
      "useApifyProxy": true,
      "apifyProxyGroups": ["RESIDENTIAL"],
      "apifyProxyCountry": "US"
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What you get
&lt;/h2&gt;

&lt;p&gt;Each row is a live search listing: id, title, price, rating, reviews, badges (including Bestseller), shop, and rank in Etsy's order for that query.&lt;/p&gt;

&lt;p&gt;Example repo for the price-sort path: &lt;a href="https://github.com/GeminiGeorge22/etsy-search-example" rel="noopener noreferrer"&gt;GeminiGeorge22/etsy-search-example&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Again: disclosure — I maintain &lt;code&gt;publicrecords/etsy-search-scraper&lt;/code&gt; on Apify Store.&lt;/p&gt;

</description>
      <category>etsy</category>
      <category>scraping</category>
      <category>apify</category>
      <category>ecommerce</category>
    </item>
    <item>
      <title>Scrape Etsy search results sorted by price: 10 rows for $0.04</title>
      <dc:creator>publicrecords</dc:creator>
      <pubDate>Mon, 05 Oct 2026 17:58:37 +0000</pubDate>
      <link>https://dev.to/publicrecords/scrape-etsy-search-results-sorted-by-price-10-rows-for-0065-512i</link>
      <guid>https://dev.to/publicrecords/scrape-etsy-search-results-sorted-by-price-10-rows-for-0065-512i</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure: I publish and maintain the Actor used here (&lt;a href="https://publicrecords-redirect.publicrecords.workers.dev/r/etsy-price-sort" rel="noopener noreferrer"&gt;publicrecords/etsy-search-scraper&lt;/a&gt; on Apify Store). This is the publisher account.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You have an Etsy search query and you want the results as rows you can sort and filter, not a screenshot of page one. Here's the shortest route I know, with a real run as proof.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you get
&lt;/h2&gt;

&lt;p&gt;Each Etsy search result comes back as one row with &lt;code&gt;listing_id&lt;/code&gt;, &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;price&lt;/code&gt;, &lt;code&gt;currency&lt;/code&gt;, &lt;code&gt;shop_name&lt;/code&gt;, &lt;code&gt;shop_url&lt;/code&gt;, &lt;code&gt;rating_value&lt;/code&gt;, &lt;code&gt;review_count&lt;/code&gt;, badges (&lt;code&gt;bestseller&lt;/code&gt;, &lt;code&gt;star_seller&lt;/code&gt;, &lt;code&gt;etsys_pick&lt;/code&gt;, &lt;code&gt;popular_now&lt;/code&gt;, &lt;code&gt;free_shipping&lt;/code&gt;), &lt;code&gt;position&lt;/code&gt; and &lt;code&gt;page&lt;/code&gt;. You can pass a keyword, a market, or a category URL.&lt;/p&gt;

&lt;h2&gt;
  
  
  The input (copy this)
&lt;/h2&gt;

&lt;p&gt;This is the exact input from a Store-page run on 2026-10-03: the 10 cheapest "ceramic mug" listings priced $10–$40.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"queries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"ceramic mug"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"price_asc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"minPrice"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxPrice"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxItems"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxPages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fillLazyCards"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"proxyConfiguration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"useApifyProxy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"apifyProxyGroups"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"RESIDENTIAL"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"apifyProxyCountry"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"US"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sort&lt;/code&gt; takes one of &lt;code&gt;relevance&lt;/code&gt;, &lt;code&gt;newest&lt;/code&gt;, &lt;code&gt;price_asc&lt;/code&gt;, &lt;code&gt;price_desc&lt;/code&gt;, &lt;code&gt;top_reviews&lt;/code&gt;, the same options as Etsy's own sort menu.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;minPrice&lt;/code&gt; / &lt;code&gt;maxPrice&lt;/code&gt; are whole currency units.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;maxItems&lt;/code&gt; and &lt;code&gt;maxPages&lt;/code&gt; cap the run (Etsy itself stops at 20 pages).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Run it
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;In the browser:&lt;/strong&gt; open the &lt;a href="https://console.apify.com/actors/JbNpPvG1Z7YtM9onP/input" rel="noopener noreferrer"&gt;Actor in Apify Console&lt;/a&gt;, switch the input to JSON, paste the block above, and press Start.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From a terminal:&lt;/strong&gt; save the block as &lt;code&gt;input.json&lt;/code&gt; and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://api.apify.com/v2/acts/publicrecords~etsy-search-scraper/run-sync-get-dataset-items?token=&lt;/span&gt;&lt;span class="nv"&gt;$APIFY_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; @input.json &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; rows.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or clone the one-command example repo, which has the same &lt;code&gt;input.json&lt;/code&gt; and the full sample output: &lt;a href="https://github.com/GeminiGeorge22/etsy-search-example" rel="noopener noreferrer"&gt;GeminiGeorge22/etsy-search-example&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Proof run
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Actor&lt;/td&gt;
&lt;td&gt;publicrecords/etsy-search-scraper&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Run&lt;/td&gt;
&lt;td&gt;Started from the Store page, 2026-10-03&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Status&lt;/td&gt;
&lt;td&gt;SUCCEEDED, 10 rows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost (current price)&lt;/td&gt;
&lt;td&gt;actor-start $0.00005 + 10 × listing-row $0.004 = &lt;strong&gt;$0.04005&lt;/strong&gt; (about $0.04), free plan, as of Oct 27, 2026 — &lt;a href="https://apify.com/publicrecords/etsy-search-scraper/pricing" rel="noopener noreferrer"&gt;pricing&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The first 3 of the 10 rows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Title&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Shop&lt;/th&gt;
&lt;th&gt;Rating&lt;/th&gt;
&lt;th&gt;Reviews&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1980's Christmas Coffee Mug&lt;/td&gt;
&lt;td&gt;$10&lt;/td&gt;
&lt;td&gt;TheNostalgiaHunter&lt;/td&gt;
&lt;td&gt;4.9&lt;/td&gt;
&lt;td&gt;~2,200*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Daisy a Day Coffee Mug, 11oz Ceramic Mug&lt;/td&gt;
&lt;td&gt;$10&lt;/td&gt;
&lt;td&gt;SmugMugMugs&lt;/td&gt;
&lt;td&gt;5.0&lt;/td&gt;
&lt;td&gt;51&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;America 250th Birthday Mug, 1776 Bicentennial Style&lt;/td&gt;
&lt;td&gt;$10&lt;/td&gt;
&lt;td&gt;SouthernRoyaltyUS&lt;/td&gt;
&lt;td&gt;5.0&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;*Etsy shows "2.2k", so that row comes back with &lt;code&gt;review_count_approx: true&lt;/code&gt; instead of a made-up exact number.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing, plainly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;$4 per 1,000 listing rows on the free plan (lower on paid plans, down to $3.40), plus a $0.00005 start fee per run — as of Oct 27, 2026; see the &lt;a href="https://apify.com/publicrecords/etsy-search-scraper/pricing" rel="noopener noreferrer"&gt;Store pricing page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Runs on Apify residential proxy by default. That's passthrough: Apify bills proxy usage, and I add no markup.&lt;/li&gt;
&lt;li&gt;A blocked page costs nothing. If a row comes back without a price, title or shop, you still get it, flagged &lt;code&gt;incomplete: true&lt;/code&gt;, and you aren't charged for it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next step: who is selling?
&lt;/h2&gt;

&lt;p&gt;Search rows tell you &lt;em&gt;what&lt;/em&gt; ranks. If you also want to know how fast a shop is selling, feed the &lt;code&gt;shop_name&lt;/code&gt; values into the companion Actor Etsy Shop Sales Tracker. It returns one row per shop with the public lifetime sales counter and the date it was read. The shop is read a few days apart; sales per day is the average over that gap.&lt;/p&gt;

&lt;p&gt;Questions or a query that breaks it? Leave a comment. I maintain both Actors and I read the comments.&lt;/p&gt;

</description>
      <category>etsy</category>
      <category>webscraping</category>
      <category>apify</category>
      <category>ecommerce</category>
    </item>
  </channel>
</rss>
