Skip to content
Scrappa Get API key
Etsy API 1 credit/request

Etsy Listing Search API Documentation

GET https://scrappa.co/api/etsy/search?query=leather+wallet&max_price=50&free_shipping=true

Scrappa's GET /api/etsy/search returns Etsy listings for a search query as structured JSON.

What you get

Each listing has listing_id, title, url, image, image_large, price, original_price, discount_percent, currency, rating, review_count, shop_id, shop_name, shop_url and the flags bestseller, popular_now, etsys_pick, star_seller, free_shipping and from_price. pagination.total_results is the number of matches Etsy reports.

Ads are removed

Etsy mixes paid ads into the results. They are removed from data, and pagination.sponsored_removed tells you how many. position counts the remaining listings of the page. A page can hold fewer listings than Etsy shows.

Filters are honoured

min_price, max_price, free_shipping and on_sale are checked on every listing. A listing that breaks a filter is removed, and pagination.filtered_out counts them. Etsy reports the sort and ship_to it applied. If one is missing, the request returns 422 (upstream_rejected) instead of unfiltered listings.

Currency

currency is the currency Etsy shows on the page. Prices are not converted.

Rounded review counts

Search cards show review counts like 12.5k. Then review_count is rounded and review_count_is_rounded is true. The product endpoint returns the exact count.

Pagination

page is 1-20, because Etsy serves 20 result pages at most. The label always equals the page Etsy served. If Etsy served another page, the request fails with 503 and costs nothing. has_more tells you whether a next page exists.

Credits

A successful request costs 10 credits. Etsy needs a full browser for every page, so it costs more than a plain request. Errors, blocks and 404 answers cost nothing. The response shows the charge in meta.credits_charged.

Etsy Listing Search API Documentation 1 credit/request

Endpoint

Request preview
GET
https://scrappa.co/api/etsy/search?query=leather+wallet&max_price=50&free_shipping=true
Auth header
x-api-key
Cost
1 credit/request
query = leather wallet
Response preview
200 OK
{
    "success": true,
    "data": [
        {
            "position": 1,
            "listing_id": "1241528786",
            "title": "Personalized Leather RFID Wallet, Engraved Genuine Leather Custom Wallet",
            "url": "https://www.etsy.com/listing/1241528786/personalized-leather-rfid-wallet",
            "image": "https://i.etsystatic.com/35016605/r/il/a5f633/4007318605/il_255x319.4007318605_mj36.jpg",
            "image_large": "https://i.etsystatic.com/35016605/r/il/a5f633/4007318605/il_794xN.4007318605_mj36.jpg",
            "price": 28,
            "original_price": 70,
            "discount_percent": 60,
            "currency": "USD",
...

Parameters

Start with the required fields, then add optional filters only when your use case needs them.

Runnable path

1 required parameter needed before sending a request.

7 optional filters available.

query string Required

Search words, for example leather wallet.

Example value leather wallet
page integer Optional

Result page, 1-20.

Example value 1
sort string Optional

relevance (default), newest, price_low_to_high, price_high_to_low or top_customer_reviews.

Example value relevance
min_price number Optional

Lowest listing price in the currency of the page. Cheaper listings are removed.

Example value 10
max_price number Optional

Highest listing price in the currency of the page. Dearer listings are removed.

Example value 50
ship_to string Optional

Two-letter country code such as DE or GB. Only listings that ship to that country.

Example value example
free_shipping boolean Optional

true for listings with free shipping only.

Example value true
on_sale boolean Optional

true for listings on sale only.

Example value true

Request Examples

PHP
<?php

$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => "https://scrappa.co/api/etsy/search?query=leather+wallet&max_price=50&free_shipping=true",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "GET",
    CURLOPT_HTTPHEADER => [
        "x-api-key: YOUR_API_KEY_HERE"
    ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
    echo "cURL Error #:" . $err;
} else {
    echo $response;
}
PHP
<?php

use Illuminate\Support\Facades\Http;

$response = Http::timeout(30)
    ->withHeaders(['x-api-key' => 'YOUR_API_KEY_HERE'])
    ->get('https://scrappa.co/api/etsy/search?query=leather+wallet&max_price=50&free_shipping=true');

if ($response->successful()) {
    echo $response->body();
} else {
    echo "Error: " . $response->status();
}
JavaScript
const options = {
    method: 'GET',
    headers: {
        'x-api-key': 'YOUR_API_KEY_HERE'
    }
};

fetch('https://scrappa.co/api/etsy/search?query=leather+wallet&max_price=50&free_shipping=true', options)
    .then(response => {
        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }
        return response.text();
    })
    .then(data => console.log(data))
    .catch(error => console.error('Error:', error));
JavaScript
const axios = require('axios');

const options = {
    method: 'GET',
    url: 'https://scrappa.co/api/etsy/search?query=leather+wallet&max_price=50&free_shipping=true',
    headers: {
        x-api-key: 'YOUR_API_KEY_HERE',
    }
};

try {
    const response = await axios(options);
    console.log(response.data);
} catch (error) {
    console.error('Error:', error.message);
}
Ruby
require 'net/http'
require 'uri'

uri = URI.parse("https://scrappa.co/api/etsy/search?query=leather+wallet&max_price=50&free_shipping=true")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == 'https'

request = Net::HTTP::Get.new(uri.request_uri)
request['x-api-key'] = 'YOUR_API_KEY_HERE'

begin
    response = http.request(request)
    puts response.body
rescue => e
    puts "Error: #{e.message}"
end
Python
import http.client
import json

conn = http.client.HTTPSConnection("scrappa.co")

headers = {
    'x-api-key': 'YOUR_API_KEY_HERE',
}

try:
    conn.request("GET", "/api/etsy/search?query=leather+wallet&max_price=50&free_shipping=true", headers=headers)
    res = conn.getresponse()
    data = res.read()
    print(data.decode("utf-8"))
except Exception as e:
    print(f"Error: {e}")
finally:
    conn.close()
Python
import requests

headers = {
    'x-api-key': 'YOUR_API_KEY_HERE',
}

try:
    response = requests.get('https://scrappa.co/api/etsy/search?query=leather+wallet&max_price=50&free_shipping=true', headers=headers)
    response.raise_for_status()
    print(response.text)
except requests.exceptions.RequestException as e:
    print(f"Error: {e}")
Java
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;

public class ApiExample {
    public static void main(String[] args) {
        OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder()
            .url("https://scrappa.co/api/etsy/search?query=leather+wallet&max_price=50&free_shipping=true")
        .addHeader("x-api-key", "YOUR_API_KEY_HERE")
            .build();

        try (Response response = client.newCall(request).execute()) {
            if (response.isSuccessful()) {
                System.out.println(response.body().string());
            } else {
                System.out.println("Error: " + response.code());
            }
        } catch (IOException e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}
Go
package main

import (
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {
    client := &http.Client{}
    req, err := http.NewRequest("GET", "https://scrappa.co/api/etsy/search?query=leather+wallet&max_price=50&free_shipping=true", nil)
    if err != nil {
        fmt.Println("Error creating request:", err)
        return
    }
    req.Header.Set("x-api-key", "YOUR_API_KEY_HERE")

    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("Error making request:", err)
        return
    }
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println("Error reading response:", err)
        return
    }

    fmt.Println(string(body))
}
Terminal
#!/bin/bash

curl -X GET \
    -H "x-api-key: YOUR_API_KEY_HERE" \
    "https://scrappa.co/api/etsy/search?query=leather+wallet&max_price=50&free_shipping=true"
C#
using System;
using System.Net.Http;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        using var client = new HttpClient();
        client.DefaultRequestHeaders.Add("x-api-key", "YOUR_API_KEY_HERE");

        try
        {
            var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "https://scrappa.co/api/etsy/search?query=leather+wallet&max_price=50&free_shipping=true"));
            var content = await response.Content.ReadAsStringAsync();
            Console.WriteLine(content);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }
}
TypeScript
import axios from 'axios';

async function run(): Promise<void> {
    try {
        const response = await axios({
            method: 'GET',
            url: 'https://scrappa.co/api/etsy/search?query=leather+wallet&max_price=50&free_shipping=true',
            headers: {
        'x-api-key': 'YOUR_API_KEY_HERE',
            },
        });

        console.log(response.data);
    } catch (error) {
        console.error('Error:', error);
    }
}

void run();
RUST
use reqwest::Client;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new();

    let response = client
        .get("https://scrappa.co/api/etsy/search?query=leather+wallet&max_price=50&free_shipping=true")
        .header("x-api-key", "YOUR_API_KEY_HERE")
        .send()
        .await?;

    println!("{}", response.text().await?);

    Ok(())
}

Response Schema

Example response fields are illustrative; inspect the JSON before integrating.

Example response fields

Scan these fields before integrating.

success data pagination applied_filters currency meta

Common data fields

position listing_id title url
JSON Response
200 OK
{
    "success": true,
    "data": [
        {
            "position": 1,
            "listing_id": "1241528786",
            "title": "Personalized Leather RFID Wallet, Engraved Genuine Leather Custom Wallet",
            "url": "https://www.etsy.com/listing/1241528786/personalized-leather-rfid-wallet",
            "image": "https://i.etsystatic.com/35016605/r/il/a5f633/4007318605/il_255x319.4007318605_mj36.jpg",
            "image_large": "https://i.etsystatic.com/35016605/r/il/a5f633/4007318605/il_794xN.4007318605_mj36.jpg",
            "price": 28,
            "original_price": 70,
            "discount_percent": 60,
            "currency": "USD",
            "from_price": false,
            "rating": 4.9,
            "review_count": 12500,
            "review_count_is_rounded": true,
            "shop_id": "35016605",
            "shop_name": "PremiumEngrave",
            "shop_url": "https://www.etsy.com/shop/PremiumEngrave",
            "bestseller": true,
            "popular_now": true,
            "etsys_pick": false,
            "star_seller": true,
            "free_shipping": true
        }
    ],
    "pagination": {
        "page": 1,
        "has_more": true,
        "total_results": 89578,
        "filtered_out": 0,
        "sponsored_removed": 12
    },
    "applied_filters": {
        "query": "leather wallet",
        "max_price": 50,
        "free_shipping": true
    },
    "currency": "USD",
    "meta": {
        "endpoint_family": "etsy-search",
        "billable": true,
        "attempts": 1,
        "credits_charged": 10
    }
}

Errors

Handle these documented responses before retrying or showing customer-facing failures.

422

Filter Not Applied

Etsy did not apply a requested filter such as `ship_to` or `sort` (`upstream_rejected`). The request is rejected instead of returning unfiltered listings. Non-billable.

{
    "meta": {
        "attempts": 1,
        "billable": false,
        "retryable": false,
        "endpoint_family": "etsy-search"
    },
    "error": {
        "code": "upstream_rejected",
        "message": "Etsy did not apply a requested filter. The request is rejected instead of returning unfiltered results."
    },
    "success": false
}
422

Validation Error

A query parameter is missing, unknown or unusable. Unknown parameters are rejected, never ignored. Non-billable.

{
    "errors": {
        "sort": [
            "The selected sort is invalid."
        ]
    },
    "message": "The selected sort is invalid."
}
503

Upstream Unavailable

Etsy could not be reached in time or answered with a block or an unexpected page (`upstream_unavailable`, `upstream_blocked`, `parser_drift`). Retryable and never billed. Clients are never rate limited.

{
    "meta": {
        "attempts": 3,
        "billable": false,
        "retryable": true,
        "endpoint_family": "etsy-search"
    },
    "error": {
        "code": "upstream_unavailable",
        "message": "Etsy is temporarily unavailable. Please retry."
    },
    "success": false
}

Generate Code with AI

Copy a ready-made prompt with all the endpoint details, parameters, and example responses. Paste it into ChatGPT, Claude, or any AI assistant to instantly generate working code.

Try It Live

Test this endpoint in our interactive playground with real data.