Scrape Etsy Product Listings
Search Etsy for a keyword and extract product titles, prices, and links from the results page.
- A Browserless API token from your account dashboard
Steps
- REST API
- Frameworks
- BQL
Use the /scrape REST endpoint to extract product listing data from Etsy search results.
Etsy uses bot detection and loads content dynamically. The /scrape endpoint may return incomplete results. For more reliable extraction, use the BQL tab with stealth mode and residential proxies.
- cURL
- JavaScript
- Python
- Java
- C#
1. Send the request
curl -X POST \
"https://production-sfo.browserless.io/scrape?token=YOUR_API_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{
"url": "https://www.etsy.com/search?q=candles",
"elements": [
{ "selector": ".v2-listing-card h3" },
{ "selector": ".v2-listing-card .currency-value" }
]
}'
2. Check the output
Each selector returns an array of matched elements with text, HTML, and position data:
{
"data": [
{
"selector": ".v2-listing-card h3",
"results": [
{
"text": "Handmade Soy Candle, Vanilla Scent",
"html": "Handmade Soy Candle, Vanilla Scent",
"height": 20,
"left": 32,
"top": 410,
"width": 280
}
]
},
{
"selector": ".v2-listing-card .currency-value",
"results": [
{
"text": "24.99",
"html": "24.99",
"height": 16,
"left": 32,
"top": 440,
"width": 60
}
]
}
]
}
1. Send the request
const response = await fetch(
'https://production-sfo.browserless.io/scrape?token=YOUR_API_TOKEN_HERE',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
url: 'https://www.etsy.com/search?q=candles',
elements: [
{ selector: '.v2-listing-card h3' },
{ selector: '.v2-listing-card .currency-value' },
],
}),
}
);
const { data } = await response.json();
const titles = data[0].results.map((r) => r.text);
const prices = data[1].results.map((r) => r.text);
console.log(titles.map((title, i) => ({ title, price: prices[i] })));
2. Check the output
Run with node scrape-etsy.mjs. The array contains product titles paired with prices.
1. Install dependencies
pip install requests
2. Send the request
import requests
response = requests.post(
'https://production-sfo.browserless.io/scrape?token=YOUR_API_TOKEN_HERE',
json={
'url': 'https://www.etsy.com/search?q=candles',
'elements': [
{'selector': '.v2-listing-card h3'},
{'selector': '.v2-listing-card .currency-value'},
],
},
)
data = response.json()['data']
titles = [item['text'] for item in data[0]['results']]
prices = [item['text'] for item in data[1]['results']]
for title, price in zip(titles, prices):
print(f'{title}: ${price}')
3. Check the output
Run with python scrape_etsy.py. Each line shows a product title and its price.
1. Send the request
import java.net.URI;
import java.net.http.*;
String token = "YOUR_API_TOKEN_HERE";
String endpoint = "https://production-sfo.browserless.io/scrape?token=" + token;
String payload = """
{
"url": "https://www.etsy.com/search?q=candles",
"elements": [
{ "selector": ".v2-listing-card h3" },
{ "selector": ".v2-listing-card .currency-value" }
]
}
""";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(endpoint))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
2. Check the output
Run the class. The response JSON contains product titles and prices.
1. Send the request
using System.Net.Http;
using System.Text;
using System.Text.Json;
string token = "YOUR_API_TOKEN_HERE";
string endpoint = $"https://production-sfo.browserless.io/scrape?token={token}";
var payload = new
{
url = "https://www.etsy.com/search?q=candles",
elements = new[]
{
new { selector = ".v2-listing-card h3" },
new { selector = ".v2-listing-card .currency-value" },
},
};
using (HttpClient httpClient = new HttpClient())
{
var jsonPayload = JsonSerializer.Serialize(payload);
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(endpoint, content);
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseBody);
}
2. Check the output
Run the program. The response JSON contains matched product titles and prices.
Connect a headless browser to search Etsy and extract product data from the rendered DOM.
- Puppeteer
- Playwright
1. Install dependencies
npm install puppeteer-core
2. Connect and scrape
import puppeteer from 'puppeteer-core';
const browser = await puppeteer.connect({
browserWSEndpoint:
'wss://production-sfo.browserless.io/stealth?token=YOUR_API_TOKEN_HERE&proxy=residential&proxyCountry=us',
});
try {
const page = await browser.newPage();
await page.goto('https://www.etsy.com/search?q=candles', {
waitUntil: 'networkidle2',
});
const products = await page.evaluate(() =>
Array.from(document.querySelectorAll('.v2-listing-card')).map((card) => ({
title: card.querySelector('h3')?.innerText?.trim() ?? '',
price: card.querySelector('.currency-value')?.innerText?.trim() ?? '',
link: card.querySelector('a.listing-link')?.href ?? '',
}))
);
console.log(products);
} finally {
await browser.close();
}
3. Check the output
Run with node scrape-etsy.mjs. Each object has title, price, and link fields.
1. Install dependencies
npm install playwright-core
2. Connect and scrape
import { chromium } from 'playwright-core';
const browser = await chromium.connectOverCDP(
'wss://production-sfo.browserless.io?token=YOUR_API_TOKEN_HERE&stealth&proxy=residential&proxyCountry=us'
);
try {
const context = browser.contexts()[0];
const page = await context.newPage();
await page.goto('https://www.etsy.com/search?q=candles', {
waitUntil: 'networkidle',
});
const products = await page.evaluate(() =>
Array.from(document.querySelectorAll('.v2-listing-card')).map((card) => ({
title: card.querySelector('h3')?.innerText?.trim() ?? '',
price: card.querySelector('.currency-value')?.innerText?.trim() ?? '',
link: card.querySelector('a.listing-link')?.href ?? '',
}))
);
console.log(products);
} finally {
await browser.close();
}
3. Check the output
Run with node scrape-etsy.mjs. Each object has title, price, and link fields.
1. Write the mutation
Navigate to Etsy, search for a keyword, then use mapSelector to extract structured data from each product card:
mutation ScrapeEtsy {
goto(url: "https://www.etsy.com", waitUntil: domContentLoaded) {
status
}
fillSearch: type(
selector: "input#global-enhancements-search-query"
text: "candles"
) {
time
}
submitSearch: click(selector: "button.wt-input-btn-group__btn") {
time
}
waitForTimeout(time: 3000) {
time
}
listings: mapSelector(selector: ".v2-listing-card") {
title: mapSelector(selector: "h3", wait: true) {
innerText
}
price: mapSelector(selector: ".currency-value", wait: true) {
innerText
}
link: mapSelector(selector: "a.listing-link") {
href: attribute(name: "href") {
value
}
}
}
}
2. Run it
Paste into the BQL IDE and click Run.
3. Check the output
{
"data": {
"goto": { "status": 200 },
"fillSearch": { "time": 245 },
"submitSearch": { "time": 112 },
"waitForTimeout": { "time": 3000 },
"listings": [
{
"title": [{ "innerText": "Handmade Soy Candle, Vanilla Scent" }],
"price": [{ "innerText": "24.99" }],
"link": [{ "href": { "value": "https://www.etsy.com/listing/123456789/handmade-soy-candle" } }]
},
{
"title": [{ "innerText": "Beeswax Pillar Candle Set" }],
"price": [{ "innerText": "18.50" }],
"link": [{ "href": { "value": "https://www.etsy.com/listing/987654321/beeswax-pillar-candle-set" } }]
}
]
}
}
Next steps
- Scrape Structured Data — extract data from other sites using the
/scrapeendpoint - Solving Cloudflare Challenges — bypass Cloudflare protection on other targets
- Automate Google Search — scrape search engine results with BQL