eBay Scraper API: How to Scrape eBay Product Pages
An eBay scraper API lets you extract product titles, prices, stock levels, delivery costs, EAN codes, and descriptions from any eBay listing — automatically and at scale. Whether you are monitoring competitor prices, building a price comparison tool, or studying market fluctuations, this guide shows you exactly how to use Scraping-bot.io to collect eBay product data with Python and Node.js examples.
Table of contents
1. Why scrape eBay product pages?
eBay hosts hundreds of millions of active listings across thousands of categories. Collecting that data manually is simply not feasible — even a few hundred product pages would take hours to process by hand. Fortunately, an eBay scraper API automates the entire process, giving you structured, up-to-date data in seconds.
In practice, here are the most common use cases teams build with eBay scraping:
| Use case | What you collect | How you use it |
|---|---|---|
| Price monitoring | Current price, best offer, buy-it-now price | Track competitor pricing and get alerted on changes |
| Price comparison | Price + shipping across multiple sellers | Feed a comparison widget or marketplace aggregator |
| Market research | Sold prices, listing age, category trends | Identify demand patterns and seasonal fluctuations |
| Inventory management | Stock levels, seller ratings, condition | Automate restocking decisions based on competitor stock |
| Product catalogue enrichment | EAN, brand, category, images, descriptions | Populate your own database with structured product data |
2. What data can you extract from an eBay product page?
A typical eBay product page contains far more structured data than what is visible at first glance. With Scraping-bot.io's eBay scraper API, you can reliably extract all of the following fields:
| Field | Example value |
|---|---|
| Product title | Apple iPhone 15 Pro 256GB Natural Titanium — Unlocked |
| Current price | €899.99 |
| Original price | €1,099.00 |
| Delivery cost | Free delivery |
| Stock / quantity available | 12 available |
| Condition | New / Used / Refurbished |
| Seller name & rating | tech_store_eu (99.8% positive) |
| EAN / Item number | 194253716433 |
| Product category | Mobile Phones & Communication > Smart Phones |
| Product description | Full HTML description block |
| Images | Array of high-resolution image URLs |
| Item specifics | Brand, Model, Storage, Colour, Network... |
3. Setting up the eBay scraper API
Prerequisites
- A Scraping-bot.io account — your username and API key are in your dashboard
- Python 3.8+ or Node.js 18+
- The eBay product URL(s) you want to scrape
Why eBay requires a headless browser
eBay loads much of its product data — prices, stock levels, item specifics — via JavaScript after the initial page load. Consequently, a simple HTTP request to the raw HTML will often return an incomplete page with missing fields. In addition, eBay actively detects and blocks datacenter IPs, which means standard requests frequently fail on the first attempt. For these reasons, always use waitForNetworkIdle: true in your API options, and switch to premiumProxy: true whenever you encounter a CAPTCHA or a 403 response.
Basic API call in Python
import requests
import base64
USERNAME = "your_username"
API_KEY = "your_api_key"
creds = base64.b64encode(f"{USERNAME}:{API_KEY}".encode()).decode()
def scrape_ebay(url, premium_proxy=False):
"""
Scrape an eBay product page using Scraping-bot.io.
Returns the full rendered HTML as a string.
"""
response = requests.post(
"https://api.scraping-bot.io/scrape/raw-html",
headers={
"Authorization": f"Basic {creds}",
"Content-Type": "application/json"
},
json={
"url": url,
"options": {
"premiumProxy": premium_proxy,
"waitForNetworkIdle": True
}
}
)
response.raise_for_status()
data = response.json()
if data.get("captchaFound"):
raise RuntimeError("CAPTCHA detected — retry with premiumProxy=True")
if data["statusCode"] != 200:
raise RuntimeError(f"Unexpected status: {data['statusCode']}")
return data["html"]
html = scrape_ebay("https://www.ebay.com/itm/123456789012")
print(f"Page size: {len(html)} characters")
Basic API call in Node.js
const fetch = require("node-fetch");
const USERNAME = "your_username";
const API_KEY = "your_api_key";
const creds = Buffer.from(`${USERNAME}:${API_KEY}`).toString("base64");
async function scrapeEbay(url, premiumProxy = false) {
const res = await fetch("https://api.scraping-bot.io/scrape/raw-html", {
method: "POST",
headers: {
"Authorization": `Basic ${creds}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
url,
options: { premiumProxy, waitForNetworkIdle: true }
})
});
const data = await res.json();
if (data.captchaFound) throw new Error("CAPTCHA — retry with premiumProxy");
if (data.statusCode !== 200) throw new Error(`Status: ${data.statusCode}`);
return data.html;
}
const html = await scrapeEbay("https://www.ebay.com/itm/123456789012");
console.log(`Page size: ${html.length} characters`);
4. Parsing the eBay product page
Once you have the rendered HTML, the next step is to extract the fields you need. In most cases, the most robust approach is to use CSS selectors, which are more resilient to minor HTML changes than XPath or positional indexing.
Full product parser in Python
from bs4 import BeautifulSoup
import json, re
def parse_ebay_product(html):
soup = BeautifulSoup(html, "html.parser")
result = {}
# Product title
title = soup.select_one("h1.x-item-title__mainTitle span")
result["title"] = title.text.strip() if title else None
# Current price
price = soup.select_one(".x-price-primary span.ux-textspans")
result["price"] = price.text.strip() if price else None
# Original price (if discounted)
original = soup.select_one(".x-price-was span.ux-textspans")
result["original_price"] = original.text.strip() if original else None
# Delivery cost
delivery = soup.select_one(".ux-labels-values--shipping .ux-textspans")
result["delivery"] = delivery.text.strip() if delivery else None
# Stock / quantity
qty = soup.select_one(".d-quantity__availability span")
result["stock"] = qty.text.strip() if qty else None
# Condition
condition = soup.select_one(".x-item-condition-text .ux-textspans")
result["condition"] = condition.text.strip() if condition else None
# Seller name and rating
seller = soup.select_one(".x-sellercard-atf__info__about-seller a")
result["seller"] = seller.text.strip() if seller else None
rating = soup.select_one(".x-sellercard-atf__info__about-seller .ux-textspans--SECONDARY")
result["seller_rating"] = rating.text.strip() if rating else None
# Images
imgs = soup.select("div.ux-image-carousel-item img")
result["images"] = [img.get("src") or img.get("data-src")
for img in imgs if img.get("src") or img.get("data-src")]
# Item specifics (brand, model, storage, etc.)
specifics = {}
rows = soup.select(".ux-layout-section--item-specifics .ux-labels-values")
for row in rows:
label = row.select_one(".ux-labels-values__labels")
value = row.select_one(".ux-labels-values__values")
if label and value:
specifics[label.text.strip()] = value.text.strip()
result["specifics"] = specifics
return result
# Full pipeline
html = scrape_ebay("https://www.ebay.com/itm/123456789012")
product = parse_ebay_product(html)
print(json.dumps(product, indent=2, ensure_ascii=False))
A successful extraction returns a clean structured record like this:
{
"title": "Apple iPhone 15 Pro 256GB Natural Titanium — Unlocked",
"price": "€899.99",
"original_price": "€1,099.00",
"delivery": "Free delivery",
"stock": "12 available",
"condition": "New",
"seller": "tech_store_eu",
"seller_rating": "99.8% positive feedback",
"images": ["https://i.ebayimg.com/images/g/...jpg", "..."],
"specifics": {
"Brand": "Apple",
"Model": "iPhone 15 Pro",
"Storage": "256 GB",
"Colour": "Natural Titanium",
"Network": "Unlocked"
}
}
5. Scraping multiple eBay listings at scale
When you need to monitor dozens or hundreds of eBay listings, batching your requests is essential. As a result, the following pattern processes a list of URLs with polite delays and automatic retry on CAPTCHA, rather than firing all requests at once:
import time, random, json
def scrape_ebay_safe(url, max_retries=3):
"""Scrape with automatic escalation to premium proxy on block."""
for attempt in range(1, max_retries + 1):
try:
use_premium = attempt > 1 # upgrade on retry
html = scrape_ebay(url, premium_proxy=use_premium)
return html
except RuntimeError as e:
print(f"Attempt {attempt} failed for {url}: {e}")
if attempt < max_retries:
time.sleep(2 ** attempt) # exponential backoff
return None
def scrape_product_list(urls):
results = []
for i, url in enumerate(urls, 1):
print(f"Scraping {i}/{len(urls)}: {url}")
html = scrape_ebay_safe(url)
if html:
product = parse_ebay_product(html)
product["source_url"] = url
results.append(product)
else:
print(f" ⚠️ Failed after all retries: {url}")
# Polite delay between requests
delay = random.uniform(1.5, 4.0)
time.sleep(delay)
return results
urls = [
"https://www.ebay.com/itm/123456789012",
"https://www.ebay.com/itm/234567890123",
"https://www.ebay.com/itm/345678901234",
]
products = scrape_product_list(urls)
# Save to JSON
with open("ebay_products.json", "w", encoding="utf-8") as f:
json.dump(products, f, indent=2, ensure_ascii=False)
print(f"Saved {len(products)} products")
6. Common errors and how to fix them
| Error | Cause | Fix |
|---|---|---|
captchaFound: true | eBay blocked the datacenter IP | Set premiumProxy: true — residential IPs bypass eBay's bot detection |
statusCode: 403 | IP banned or geo-blocked | Use premiumProxy: true with a country option matching the eBay domain |
| Empty price / title fields | JavaScript not fully rendered | Ensure waitForNetworkIdle: true is set |
CSS selector returns None | eBay updated its HTML structure | Inspect the live page and update the selector — eBay redesigns periodically |
429 Too Many Requests | Too many requests in a short window | Increase delay between requests; reduce concurrency |
| Missing item specifics | Specifics loaded in a lazy iframe | Add a short time.sleep(2) after the initial scrape call |
7. Plans and pricing
Scraping-bot.io offers plans to suit every scale of eBay scraping project — from individual developers testing a new idea to enterprise teams running millions of requests per month:
| Plan | Credits / month | Concurrent requests | JS Rendering | Premium proxies |
|---|---|---|---|---|
| Free | 100 | 1 | ✅ | ❌ |
| Starter | From 1,000 | 5 | ✅ | ❌ |
| Freelancer | 100,000 | 10 | ✅ | ❌ |
| Startup | 250,000 | 25 | ✅ | ✅ |
| Business | 1,000,000 | 50 | ✅ | ✅ + geo-targeting |
| Enterprise | Custom | Custom | ✅ | ✅ + priority support |
Start with the Free plan — 100 credits per month, no payment required — and test your eBay scraper API pipeline directly from the live test tool in your dashboard. Once you are ready to scale, upgrading takes less than a minute. For large-scale or custom requirements, however, the best option is to contact us directly — we will build a plan around your specific needs.


