Skip to main content

trawl-api: Python eBay scraper API for sold listings and prices

PyPI Python

The official Python client for trawl, a data API for eBay. Search 300+ million completed eBay sales on the US and UK marketplaces and get each one back as typed Python objects: final price, sale date, condition, shipping, seller, item specifics, images and description. One API key, no proxies, no HTML parsing, no browser to run.

pip install trawl-api

Requires Python 3.10 or newer. Create a free account to get an API key; the free plan needs no card.

Quickstart

from trawl_api import Trawl

client = Trawl()  # reads the TRAWL_API_KEY environment variable

sold = client.ebay.sold("iphone 15 pro 256gb", condition="used")

for listing in sold.results[:5]:
    print(listing.date_sold.date(), listing.sale_price, listing.title)

print(f"{sold.count} results, {sold.credits_charged} credit(s) charged")

The key can also be passed directly: Trawl(api_key="sk_live_..."). Keep it on your server and out of source control.

What you can ask

Method Answers Costs
client.ebay.sold(query, ...) Sold listings matching a query, newest first, up to 2,000 in one response 1 credit per page of 100 results (2 with details=True); free when nothing matches
client.ebay.item(item_id) One sold listing in full: specifics, seller, every image, description, recorded sales 1 credit
client.ebay.categories(query) eBay categories by name or id, for the category filter 1 credit; free when nothing matches

The full parameter and field reference is at trawl.dev/docs.

Tutorials

Each of these is a complete script in examples/.

Get the sold prices of a product

from trawl_api import Trawl

client = Trawl()
sold = client.ebay.sold(
    "iphone 15 pro 256gb",
    condition="used",
    exclude=["case", "cracked"],  # words that must not be in the title
)

for listing in sold.results:
    print(
        f"{listing.date_sold:%Y-%m-%d}  {listing.currency}{listing.sale_price:.2f}  {listing.title}"
    )

Average sold price over the last 90 days

max_pages sets how many pages of 100 results come back in the one response, and is also the most credits the call can cost.

from datetime import date, timedelta
from statistics import mean, median

from trawl_api import Trawl

client = Trawl()
sold = client.ebay.sold(
    "nintendo switch oled",
    condition="used",
    date_from=date.today() - timedelta(days=90),
    max_pages=5,
)

prices = [listing.sale_price for listing in sold.results]
print(
    f"{len(prices)} sales, average {mean(prices):.2f}, median {median(prices):.2f} {sold.currency}"
)

Filter by price, marketplace and item specifics

sold = client.ebay.sold(
    "charizard",
    site="EBAY_GB",  # ebay.co.uk; prices are then in GBP
    min_price=100,
    max_price=2000,
    attr={"Set": "Base Set", "Grade": ["9", "10"]},  # Grade 9 or 10, from Base Set
)

Export sold listings to CSV or pandas

import csv

from trawl_api import Trawl

COLUMNS = ["date_sold", "title", "sale_price", "currency", "condition", "item_id", "item_link"]

client = Trawl()
sold = client.ebay.sold("charizard base set holo", max_pages=10)

with open("sold.csv", "w", newline="", encoding="utf-8") as file:
    writer = csv.DictWriter(file, fieldnames=COLUMNS)
    writer.writeheader()
    for listing in sold.results:
        writer.writerow(listing.model_dump(mode="json", include=set(COLUMNS)))

For pandas: pd.DataFrame(listing.model_dump() for listing in sold.results).

Get one listing's full details

from trawl_api import NotFoundError, Trawl

client = Trawl()

# The item_id of any sold() result; here, the newest sale of a search.
item_id = client.ebay.sold("iphone 15 pro 256gb").results[0].item_id

try:
    item = client.ebay.item(item_id)
except NotFoundError:
    # Details arrive a few minutes after a sale. A 404 is never billed.
    raise SystemExit("Details are not available yet.")

print(item.title, item.sale_price, item.currency)
print(item.specifics.get("Brand"))  # item specifics as a dict
if item.seller:
    print(item.seller.username, item.seller.feedback_percent)
print(len(item.images), "images")

To get the details of every result of a search in one call, pass details=True to sold() and read listing.details.

Find a category and search inside it

found = client.ebay.categories("trading card singles", site="EBAY_US")
for category in found.categories:
    print(category.category_id, category.name, category.group)

sold = client.ebay.sold("charizard", category=found.categories[0].category_id)

Category ids differ per marketplace, so look them up with the same site you search with.

Credits

Every answer says what it cost, and how much of the month's allowance is left:

sold = client.ebay.sold("rolex submariner", max_pages=3)

sold.credits_charged  # 3 when three pages came back, 0 when nothing matched
sold.rate_limit.remaining  # credits left in this billing window
sold.rate_limit.reset  # when the allowance resets

Errors are never billed.

Errors

import trawl_api

try:
    sold = client.ebay.sold("rolex submariner", min_price=2000)
except trawl_api.BadRequestError as error:
    print(error)  # the API names the field and the rule it broke
except trawl_api.InsufficientCreditsError as error:
    print(error)  # the month's credits are spent, or too few remain
except trawl_api.RateLimitError as error:
    print(error.retry_after)  # seconds to wait
except trawl_api.APIStatusError as error:
    print(error.status_code, error)
Exception When
BadRequestError 400, a parameter failed validation
AuthenticationError 403, the key is missing, invalid or deleted
NotFoundError 404, e.g. an item whose details are not available yet
RateLimitError 429 with Retry-After, the plan's per-second rate was exceeded
InsufficientCreditsError 429 without Retry-After, not enough credits for the request
ServerError 5xx, a failure on trawl's side
APIConnectionError, APITimeoutError the request got no answer

All of them inherit from trawl_api.TrawlError. Connection errors, 5xx answers and per-second rate limits are retried twice with backoff before they are raised; change that with Trawl(max_retries=...). The per-second rate belongs to the account, so keep concurrent calls within your plan's rate.

Async

import asyncio

from trawl_api import AsyncTrawl


async def main():
    async with AsyncTrawl() as client:
        sold = await client.ebay.sold("iphone 15 pro 256gb")
        print(sold.count)


asyncio.run(main())

Configuration

client = Trawl(
    api_key="sk_live_...",  # default: the TRAWL_API_KEY environment variable
    timeout=60.0,  # seconds
    max_retries=2,
)

Responses are pydantic models: model_dump() gives a dict, model_dump_json() a JSON string, and fields the API adds later are kept on the object.

trawl is an independent service and is not affiliated with or endorsed by eBay Inc.

Metadata

Release files for trawl-api 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for trawl-api 0.1.1
File Size Uploaded Provenance
trawl_api-0.1.1.tar.gz 17.0 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for trawl-api 0.1.1
File Interpreter ABI Platform
trawl_api-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 30.6 kB

Release files / trawl_api-0.1.1.tar.gz

Download URL trawl_api-0.1.1.tar.gz
Size 17.0 kB
Tags Source
SHA-256 checksum
How to use checksums
77e9fa5b0041c4cc7bd39b308b70b413b1d845c72c215c654032c05575b5ef6b
BLAKE2b-256 checksum
How to use checksums
918570d9f7fd194d64a5b25cd4046bc5465510aa120046eb03154cdb985abed0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release files / trawl_api-0.1.1-py3-none-any.whl

Download URL trawl_api-0.1.1-py3-none-any.whl
Size 13.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
039df3a15ea3b3a44fbc8c0b473cf2e09be0be36b34bd5661c896d343c04820c
BLAKE2b-256 checksum
How to use checksums
31e753f12beadca13712c7f16d890f884f8a1c482c92ef510049f84d03ddbb1c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Security for trawl-api 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for trawl_api-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page