# Changelog of eBay Product & Listings Scraper (`devilscrapes/ebay-product-listings-scraper`) Actor

- **URL**: https://apify.com/devilscrapes/ebay-product-listings-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/devilscrapes/ebay-product-listings-scraper.md

## Changelog

### v0.1.0 — Fix: empty search is a success, not a FAILED run (2026-09-09)

#### Fixed

- **A zero-row search no longer FAILs the run.** 65% customer success rate
  (7/20 FAILED runs, 30d) traced to `main._finish()` unconditionally
  `raise SystemExit(1)` whenever a run emitted zero rows (spec REQ-9,
  "fail loud on zero rows") — charging the customer `actor-start` and then
  reporting FAILED for what could be an ordinary empty search. See
  `ops/os/EMPTY-IS-NOT-A-FAILURE-2026-08-19.md`; this Actor was built
  2026-08-13/31, after that fleet-wide finding, and slipped through
  un-retrofitted. `_finish()` now finishes SUCCEEDED with a status message
  naming the query/filters on zero rows.
- **Root cause of the zero rows themselves: an undetected 200-status block.**
  Live local recon (2026-09-09, via Apify proxy and direct) reproduced eBay
  serving a 200 response whose body carries none of the site's own
  `srp-results` search-results markup — a soft block/interstitial dressed as
  success. The old code handed that body straight to `parser.parse_cards()`,
  which correctly found zero cards on it (there was nothing to find), and
  that read identically to a genuine no-match query. `EbaySession.fetch_search_page`
  now checks `parser.is_recognizable_results_page(html)` on every 200 and, if
  the body isn't recognizable, rotates session/profile and re-warms-up
  exactly like a 403 challenge (REQ-7), raising `EbayRequestError` only after
  retries are exhausted. Reproduced live: the QA fixture run hit this exact
  path on its very first attempt, rotated once, and then emitted 5 real rows.
- Retitled the zero-rows status message ("Found 0 listings for query=…") since
  it can no longer be an ambiguous block-vs-no-match message — every block
  path raises before `_finish` is reached now.
- Fixed a stale test (`test_pay_per_event_matches_spec_exactly`) asserting the
  actor-start fee was still $0.05; `pay_per_event.json` already carries the
  fleet-standard $0.20 flat start fee, only the test hadn't been updated.

### v0.1 — Initial scaffold (2026-08-13)

- Actor skeleton scaffolded: `.actor/actor.json`, `input_schema.json`,
  `output_schema.json`, `dataset_schema.json`, `pay_per_event.json`,
  `Dockerfile`, `pyproject.toml`, minimal `src/main.py` placeholder.
- PPE wired: `actor-start` ($0.05), `result-row` ($0.0012).
- Real scraping logic (`src/models.py`, `src/scraper.py`,
  `src/parser.py`) lands in follow-up tasks — see
  `docs/specs/ebay-product-listings-scraper/tasks.md`.
