Guides / Scrape eBay

How to Scrape eBay in 2026

eBay uses anti-bot detection, JavaScript rendering, various listing formats (auction, Buy It Now, best offer), and rate limiting. Parsing eBay is especially tricky because search results mix different listing types with different data structures. With Browser7, you get fully rendered search results and listing data in a single API call.

What makes eBay hard to scrape

Anti-bot detection

eBay uses browser fingerprinting, behavioral analysis, and IP reputation scoring to detect automated traffic. Datacenter IPs are blocked, and suspicious request patterns trigger CAPTCHA challenges or temporary bans.

JavaScript rendering

eBay renders search results, product details, and seller information using client-side JavaScript. A simple HTTP request returns incomplete page content. You need a real browser to get pricing, condition, shipping, and seller data.

Various listing formats

eBay search results mix auction listings, Buy It Now listings, and best offer listings. Each format has slightly different HTML structures and data fields (current bid vs fixed price, time remaining vs quantity available). Parsing logic needs to handle all formats.

Rate limiting

eBay enforces rate limits and will block IPs that make too many requests in a short period. High-volume scraping without proper proxy rotation results in CAPTCHA challenges or temporary IP bans.

Scrape eBay search results

Browser7 handles proxy rotation, browser fingerprinting, CAPTCHA solving, and JavaScript rendering automatically. This example scrapes iPhone 15 search results and returns the fully rendered HTML with all listing cards.

from browser7 import Browser7

client = Browser7(
    api_key="b7_your_api_key",
    base_url="https://ca-api.browser7.com/v1"
)

result = client.render(
    "https://www.ebay.com/sch/i.html?_nkw=iphone+15",
    country_code="US",
)

print(result.html)

That is the complete code. No proxy configuration, no browser setup, no CAPTCHA handling logic. The response contains the fully rendered HTML of the eBay search results page, including all listing cards with titles, prices, conditions, and shipping information.

Data you can extract

The rendered HTML contains all the data eBay shows to a real visitor. Common data points to extract:

Listing details

  • Listing title and item specifics
  • Item condition (new, used, refurbished)
  • Listing type (auction, Buy It Now, best offer)
  • Item images and gallery URLs
  • Item location and shipping origin

Pricing

  • Current price or bid amount
  • Buy It Now price
  • Shipping cost or free shipping
  • Number of bids (for auctions)
  • Time remaining (for auctions)

Seller info

  • Seller username
  • Seller feedback score
  • Seller feedback percentage
  • Top Rated Seller badge
  • Return policy

Search metadata

  • Total results count
  • Search result positions
  • Sponsored vs organic results
  • Available filters and categories
  • Related search suggestions

Complete example: render and parse listing data

Here is a complete example that renders eBay search results and extracts structured data from the HTML. Listing cards use the li.s-card selector. The code skips "Shop on eBay" sponsored cards that appear at the top of results. Prices use the span.su-styled-text.primary.bold class, and shipping info is in secondary styled-text spans.

from browser7 import Browser7
from bs4 import BeautifulSoup
import json

client = Browser7(
    api_key="b7_your_api_key",
    base_url="https://ca-api.browser7.com/v1"
)

result = client.render(
    "https://www.ebay.com/sch/i.html?_nkw=iphone+15",
    country_code="US",
)

soup = BeautifulSoup(result.html, "html.parser")

listings = []
for card in soup.select("li.s-card"):
    # Skip "Shop on eBay" sponsored cards
    title_el = card.select_one("div.s-card__title span")
    if not title_el:
        continue
    title = title_el.get_text(strip=True)
    if title.lower().startswith("shop on ebay"):
        continue

    listing = {
        "title": title,
        "price": None,
        "condition": None,
        "shipping": None,
    }

    # Price from primary bold styled text
    price_el = card.select_one("span.su-styled-text.primary.bold")
    if price_el:
        listing["price"] = price_el.get_text(strip=True)

    # Condition from subtitle
    condition_el = card.select_one("div.s-card__subtitle span")
    if condition_el:
        listing["condition"] = condition_el.get_text(strip=True)

    # Shipping from secondary styled text spans
    shipping_spans = card.select("span.su-styled-text.secondary")
    for span in shipping_spans:
        text = span.get_text(strip=True)
        if "shipping" in text.lower() or "free" in text.lower():
            listing["shipping"] = text
            break

    listings.append(listing)

print(json.dumps(listings[:5], indent=2))

CSS selectors may change if eBay updates their page structure. Inspect the current page if any fields return null.

Sample output:

[
  {
    "title": "Apple iPhone 15 128GB Unlocked - Black",
    "price": "$629.99",
    "condition": "New",
    "shipping": "Free shipping"
  },
  {
    "title": "Apple iPhone 15 Pro Max 256GB - Natural Titanium (Unlocked)",
    "price": "$849.00",
    "condition": "Pre-Owned",
    "shipping": "Free shipping"
  },
  ...
]

Scrape page 2 and beyond

eBay search results use the &_pgn= parameter for pagination. Page 2 is &_pgn=2, page 3 is &_pgn=3, and so on.

from browser7 import Browser7
from bs4 import BeautifulSoup

client = Browser7(
    api_key="b7_your_api_key",
    base_url="https://ca-api.browser7.com/v1"
)

# Page 2: add &_pgn=2
result = client.render(
    "https://www.ebay.com/sch/i.html?_nkw=iphone+15&_pgn=2",
    country_code="US",
)

soup = BeautifulSoup(result.html, "html.parser")
for card in soup.select("li.s-card"):
    title_el = card.select_one("div.s-card__title span")
    price_el = card.select_one("span.su-styled-text.primary.bold")
    if title_el:
        title = title_el.get_text(strip=True)
        if not title.lower().startswith("shop on ebay"):
            price = price_el.get_text(strip=True) if price_el else "N/A"
            print(f"{title[:80]} - {price}")

Take a screenshot of search results

Capture eBay search results as an image for price monitoring dashboards, market research reports, or tracking listing trends and pricing over time.

import base64
from browser7 import Browser7

client = Browser7(
    api_key="b7_your_api_key",
    base_url="https://ca-api.browser7.com/v1"
)

result = client.render(
    "https://www.ebay.com/sch/i.html?_nkw=iphone+15",
    country_code="US",
    block_images=False,
    include_screenshot=True,
    screenshot_full_page=True,
    screenshot_format="png"
)

# Save the screenshot
with open("ebay-search.png", "wb") as f:
    f.write(base64.b64decode(result.screenshot))

print("Screenshot saved")

What this costs

Every eBay page render costs $0.01 - the same as any other website. Residential proxies, JavaScript rendering, CAPTCHA solving, and screenshots are all included. There are no per-domain surcharges, no credit multipliers, and no bandwidth fees.

10,000 eBay search pages costs $100. You know this before you start, not after.

Try it yourself

100 free renders - enough to test eBay scraping with no payment required.