Scrape Etsy search listings as clean, structured JSON — title, shop, sale price, original price, discount, listing URL and image — with multi-page collection and CSV export. A small CLI and a Node library.
Powered by ScrapeUnblocker. Etsy renders search results with heavy client-side JavaScript and anti-bot protection. This project uses the ScrapeUnblocker
getPageSourceendpoint withparsed_data, which returns AI-parsed JSON — so there is no HTML parsing to maintain when Etsy changes its markup.
- 🔎 Search any Etsy query and get normalized listing records
- 🏷️ Sale price, original price, currency and discount percent per item
- 🏪 Shop name, listing URL and image for every result
- 📄 Multi-page collection that follows Etsy's own pagination
- 🌍 Country targeting (route the request through a chosen locale)
- 💾 JSON or CSV output, from the CLI or as a library
- 🧩 Built on the official
scrapeunblockerSDK - ✅ Zero runtime dependencies beyond the SDK; tests mock the API (no credits spent)
git clone https://github.com/ScrapeUnblocker/etsy-scraper.git
cd etsy-scraper
npm installSet your API key (get one from the ScrapeUnblocker dashboard):
cp .env.example .env
# then edit .env, or just export it:
export SCRAPEUNBLOCKER_KEY=your_key_hereTo use the command globally, npm link (or npm install -g .).
# Print listings as JSON
etsy-scraper "leather wallet"
# Collect three pages and save a CSV
etsy-scraper "handmade mug" --pages 3 --csv mugs.csv
# Target a country and write JSON to a file, pretty-printed to the terminal
etsy-scraper "vintage lamp" --country GB --json lamps.json
etsy-scraper "vintage lamp" --prettyOptions:
-p, --pages <n> number of result pages to collect (default: 1)
-c, --country <cc> proxy country ISO code (default: US)
--csv <file> write results to a CSV file
--json <file> write results to a JSON file
--pretty pretty-print JSON to stdout
-h, --help show this help
If neither --csv nor --json is given, results are printed as JSON on stdout.
import { EtsyScraper, toCsv } from "etsy-scraper";
const scraper = new EtsyScraper({ country: "US" });
// Collect up to 3 pages of results
const listings = await scraper.search("leather wallet", { pages: 3 });
console.log(listings.length, "listings");
console.log(listings[0]);
// Export to CSV
import { writeFileSync } from "node:fs";
writeFileSync("etsy.csv", toCsv(listings));See examples/ for runnable scripts (search-json.js,
export-csv.js, multi-page.js).
Each listing is normalized to a flat record:
{
"title": "Handmade Leather Bifold Wallet, Personalized Front Pocket Card Holder",
"shop": "NooyaLeather",
"price": 35,
"salePrice": 35,
"originalPrice": null,
"currency": "USD",
"discountPercent": 5,
"url": "https://www.etsy.com/listing/1214703903/handmade-leather-bifold-wallet",
"image": "https://i.etsystatic.com/33293494/r/il/6ad75b/3854048691/il_255x319.jpg"
}Note: Etsy sometimes returns a numeric price with a
nullcurrency.priceis the best available current price (the sale price when present, otherwise the original price);salePriceandoriginalPriceare kept separately.
etsy-scraper/
├── bin/
│ └── etsy-scraper.js # CLI entry point
├── src/
│ ├── index.js # public exports
│ ├── scraper.js # EtsyScraper + URL/pagination logic
│ ├── parse.js # item normalization + price/discount parsing
│ ├── csv.js # CSV serialization
│ └── cli.js # argument parser + runner
├── examples/ # runnable scripts
├── test/ # offline unit tests (SDK mocked)
├── .github/workflows/ci.yml # lint + tests on Node 18 & 20
└── package.json
npm install # install deps
npm test # run the unit tests (offline, no API credits used)
npm run lint # eslint
npm run format # eslint --fixThe tests mock the ScrapeUnblocker client, so they run without an API key and
never spend credits. Pre-commit hooks (ruff-style) are configured in
.pre-commit-config.yaml via pre-commit.
EtsyScraper.search() builds an Etsy search URL, calls client.getParsed(url)
(the SDK's getPageSource + parsed_data wrapper), and normalizes each item in
the returned data.items array. Pagination follows the API-provided
data.next_page link and stops when there are no more pages or the requested
page cap is reached.
MIT © 2026 ScrapeUnblocker
This is an example integration. Please scrape responsibly and in accordance with Etsy's Terms of Service and applicable law.