# Changelog of eBay Price & Inventory Monitor (`alex1313/ebay-price-inventory-monitor`) Actor

- **URL**: https://apify.com/alex1313/ebay-price-inventory-monitor/changelog.md
- **Full Actor documentation**: https://apify.com/alex1313/ebay-price-inventory-monitor.md

## Changelog

### 1.64 — 2026-08-14

#### Pricing

- Added a fixed 2 GB memory allocation (was a 1–2 GB range) so every run charges the same number
  of `Actor start` events, making that event usable as a predictable per-run floor charge that
  covers this Actor's largely-fixed compute/proxy overhead regardless of item count or how many
  changed. Requires a matching price update to the `Actor start` event in this Actor's Apify
  Console monetization setup (not a code change) — see the updated Pricing section in the README.

### 1.63 — 2026-08-10

#### Internal

- No behavior change. Confirmed, against a live deploy, that bumping the major version (`2.0`)
  does **not** reset Apify's version-line cap: the push failed with the identical "The Actor can
  have at most 10 versions" error as the `1.10` attempt. The cap is a lifetime total across all
  `MAJOR.MINOR` lines regardless of major number, not a per-major-line quota. Reverted `version`
  back to `1.9`.

### 1.62 — 2026-08-10

#### Internal

- No behavior change. Re-verified, against a live deploy, that Apify's undocumented 10-version-line
  cap on `.actor/actor.json`'s `version` field still blocks a push: bumping to `1.10` failed with
  "The Actor can have at most 10 versions" (all 10 lines `1.0`–`1.9` are already used). Reverted
  `version` back to `1.9`.

### 1.61 — 2026-08-10

#### Documentation

- No behavior change. Added direct unit test coverage for `normalizeAlertDigestIntervalHours` and
  `normalizeStateNamespace` (previously only exercised indirectly), plus several DOM-fallback-
  selector test cases in `extraction.ts`, found during a full-codebase review.

### 1.60 — 2026-08-10

#### Fixed

- Fixed sibling-run detection (Layer 2 of the proxy-block prevention strategy) only ever querying
  for `RUNNING` status, silently missing a sibling run that's allocated and about to start
  (`READY`) — exactly the simultaneous-start race this check exists to catch. Now requests both
  statuses.
- Fixed a false "listing removed" report for a variation combination (full-codebase review):
  combination rows were misclassified as indirectly-discovered whenever a search/seller source was
  also tracked in the same run, so a transient one-run scrape hiccup on a single combination could
  be misread as it being genuinely gone.

### 1.59 — 2026-08-10

#### Fixed

- Hardened `mapWithConcurrencyLimit` (used internally for bounded AI-enrichment calls) to throw a
  clear error for a zero or negative concurrency limit, instead of silently returning a sparse
  array of unassigned results — an internal-only defensive fix, not currently reachable from any
  input.

### 1.58 — 2026-08-10

#### Fixed

- Fixed a real data-loss bug in digest mode (full-codebase review): when a digest's flush was due,
  the held alerts were cleared and persisted as sent *before* the webhook POST was even attempted —
  a single failed delivery (network blip, endpoint briefly down) permanently lost the whole
  accumulated batch with no record anywhere. The held batch is now only cleared after delivery is
  confirmed successful; a failed attempt keeps everything queued for the next run to retry.
- Added a length cap to Slack notification bodies, matching the existing Discord cap — an
  unusually large run's notification could otherwise exceed Slack's limit and fail to post with no
  truncation fallback.
- Hardened AI-enrichment's response parsing to explicitly handle a non-object JSON response (e.g.
  `null`) rather than relying on an unrelated error handler to happen to catch it.

### 1.57 — 2026-08-10

#### Fixed

- Fixed several exchange-rate edge cases (full-codebase review): a zero or negative rate (a
  corrupted cache entry, or a malformed value from either exchange-rate API) could produce
  Infinity/NaN/a sign-flipped price instead of the documented "normalization unavailable" null.
  Also hardened the rate-table lookup against resolving an inherited object property for an
  untrusted currency code instead of correctly reporting it as untracked.

### 1.56 — 2026-08-10

#### Fixed

- Fixed a missed price change (full-codebase review finding): when currency normalization was
  unavailable on both sides of a comparison and the raw price number happened to be identical
  despite a currency change (e.g. the proxy's exit country changed between runs), no change was
  recorded at all. A currency change alone now flags the item as changed, consistent with how a
  raw-price mismatch already does.

### 1.55 — 2026-08-10

#### Fixed

- Fixed `condition` extracting as "UsedCondition" instead of "Used" (and similarly for
  New/Refurbished/Damaged) when a listing's condition came from JSON-LD's schema.org enum rather
  than the page's visible text.
- Generalized the "Selectselected" variation-placeholder fix from a full-codebase review: the
  accessibility-label suffix can glue onto whichever option currently carries the widget's
  "selected" state, not only the placeholder — now stripped from every option, not just ones that
  already look like the placeholder.

### 1.53 — 2026-08-09

#### Fixed

- Fixed a real crash-cascade found via live testing of `trackListingVariations`: some listings'
  variation picker placeholder extracts as "Selectselected" rather than plain "Select" (a
  visually-hidden accessibility label glued onto the placeholder text), which slipped past the
  exact-match filter and got treated as a real, clickable option. Attempting to click it timed out
  after 30s and tore down the whole browser page, failing every other variation on that listing
  too. Now matched by prefix instead of exact equality — no real size/color/etc. value starts with
  the word "select".

### 1.52 — 2026-08-09

#### Added

- Added `firstSeenAt` to the main dataset (when this Actor first observed the item, fixed across
  every later run) and `listingLifespanDays` to the `changes` dataset and webhook payload (days
  between `firstSeenAt` and a listing being detected removed). No new scraping — derived entirely
  from data already collected. Not exact "time to sell": a listing can disappear for reasons other
  than a sale, and the clock only starts from this Actor's first observation, not the item's actual
  original listing date.

### 1.51 — 2026-08-09

#### Fixed

- Fixed a crash found via live testing: a run could read back a malformed value for its persisted
  proxy-health state and crash outright partway through, instead of completing. Now treats any
  malformed value as "no history yet" and continues normally.

### 1.50 — 2026-08-09

#### Added

- When a run detects a sibling run of this Actor already active (see 1.49's `siblingRunsDetected`),
  it now waits a random delay of up to 2 minutes before its first request to `ebay.com`, so two
  runs that started at the same instant don't also send their request bursts at the same instant.
  Surfaced as a new `startupJitterMs` field in the run summary. Always `0`, with no delay, when no
  sibling run is detected.

### 1.49 — 2026-08-09

#### Added

- Every run now checks, right when it starts, whether another run of this Actor is already
  active under your account — e.g. two schedules firing at the same time — and warns in the log
  if so. Surfaced as a new `siblingRunsDetected` field in the run summary. Informational only: it
  doesn't change either run's own behavior, and stays `0` and silent for a restricted token that
  can't list other runs.

### 1.48 — 2026-08-09

#### Added

- Every run now caps itself to at most 2 concurrent requests to `ebay.com` and waits at least 1
  second between consecutive requests to the same domain, regardless of history. This is a
  preventive complement to the reactive backoff added in 1.47: it lowers baseline block risk on
  every run, including a first-ever run with no prior signal to react to. Not configurable — it's
  cheap and safe for everyone.

### 1.47 — 2026-08-09

#### Added

- Added optional `stateNamespace` input: if you run more than one schedule of this Actor tracking
  different items, set a distinct value per schedule to keep their price history and other state
  fully isolated. Previously, every schedule under an account silently shared the same state,
  which could corrupt one schedule's data with another's. Leaving it empty (the default) behaves
  exactly as before for a single schedule.
- This Actor now automatically reduces its own retry budget for the rest of a run — and the start
  of the next one — when 80%+ of directly-tracked items are fully blocked (accumulated across the
  last few runs if you only track 1-2 items at a time, so this protects a small schedule's
  sustained bad streak too, not just a single large run), instead of repeating a full-cost retry
  ladder on a pattern already shown not to work. Surfaced as a new `proxyHealthDegraded` field in
  the run summary. Self-heals automatically once runs return to a normal success rate.

### 1.46 — 2026-08-09

#### Added

- Added optional `alertDigestIntervalHours` input: holds price drop/increase alerts and sends
  them together at most once per that many hours, instead of one webhook per run. Off by default.
  A stock-out alert always sends immediately regardless of this setting.
- When `enableInsightSignals` is on, the dataset is now written with the most actionable items
  first (a fired price-insight signal, then the biggest recent price movers) instead of scrape
  order. No change when `enableInsightSignals` is off.

### 1.45 — 2026-08-09

#### Added

- Added optional `trackListingVariations` input: for an eBay listing with a size/color/etc.
  picker, tracks each combination as its own item with its own real price and stock, instead of
  one ambiguous row for the whole listing (which could previously show a price that didn't belong
  to any actual combination). Off by default — each combination bills as its own event, a real
  cost multiplier for a listing with variations enabled. A listing already confirmed to have
  variations no longer falls back to that old ambiguous price on a run where it can't be freshly
  checked at all.

### 1.44 — 2026-08-09

#### Changed

- Reduced cost on repeated checks: if an item is blocked outright but was already successfully
  checked within the last hour, that recent price is reused instead of paying for a second full
  retry pass that a fresh block is unlikely to survive either. A new `dataStaleReason` field on
  each row explains why a price wasn't freshly checked this run.

### 1.43 — 2026-08-09

#### Added

- Added a "Price insights" dataset view, showing price-change percentages alongside the drop-streak,
  all-time-low, and underpriced-vs-history signals in one table.

### 1.42 — 2026-08-08

#### Documentation

- Fixed the "Enable price insight signals" input description — it was only mentioning two of the
  three signals this Actor actually computes, so enabling it gave no warning that a third billable
  signal existed.
- Clarified the Output tab's descriptions to mention AI enrichment and price insight fields when
  enabled.
- Rewrote this changelog in plain, outcome-focused language throughout.

#### Fixed

- Removed a stray build-output file that was being unintentionally included in this Actor's
  published source.

### 1.41 — 2026-08-08

#### Documentation

- Added a clear "enable Residential proxy first" notice to the top of the README and the input
  form, so a first run can't fail for a reason that isn't obvious until it's too late.
- Added a "Built for reliability" summary and a table of contents to the README, and a pointer to
  this Actor's Issues tab for questions or problems.
- Tightened the Store short description to fit Apify's length limit while keeping the reseller/
  dropshipper/agent audience and MCP-readiness clear.

### 1.40 — 2026-08-08

#### Documentation

- Internal test-coverage improvements. No customer-facing change.

### 1.39 — 2026-08-08

#### Documentation

- Internal test-coverage improvements. No customer-facing change.

### 1.38 — 2026-08-08

#### Documentation

- Internal reliability-testing improvements. No customer-facing change.

### 1.37 — 2026-08-08

#### Fixed

- An item with no identifiable brand or model was being re-enriched by AI on every run. It's now
  enriched once, the same as any other item.
- Carried-forward items now get their price correctly re-normalized to your target currency on
  every run, not just on freshly-scraped ones.

### 1.36 — 2026-08-08

#### Fixed

- A webhook alert for an item that both changed price and sold out in the same run only mentioned
  the price change. Both now appear.

#### Changed

- Reduced AI enrichment's output size to what a listing title can realistically produce.

### 1.35 — 2026-08-08

#### Fixed

- The "underpriced vs. its own history" signal could show a broken percentage for an item with no
  meaningful price history yet. It now simply doesn't fire in that case.

### 1.34 — 2026-08-08

#### Fixed

- A price-trend field could go permanently blank for an item. It now falls back to the next
  usable historical data point instead.
- A corrupted cached exchange rate could silently produce a wrong price comparison. It's now
  detected and ignored.

#### Documentation

- Clarified that the 24h/7d/30d price-trend fields track the last 30 check-ins, not a fixed
  30-day window.

### 1.33 — 2026-08-08

#### Fixed

- Removing one of several tracked search/seller pages (while keeping others) could incorrectly
  mark that page's items as removed.
- A price comparison between two runs could occasionally show a wrong percentage change when the
  two runs' currencies didn't match.

### 1.32 — 2026-08-08

#### Fixed

- Some item URLs were being dropped from tracking entirely due to how their identifier was read.

#### Changed

- Item links found on a search or seller page are now only followed if they point back to that
  same eBay site.

### 1.31 — 2026-08-08

#### Added

- New optional price insight (requires "Enable price insight signals"): flags an item priced 15%+
  below its own historical average, so a real deal stands out from normal price noise.

### 1.30 — 2026-08-08

#### Added

- New optional price-increase alert: get a webhook alert when a tracked item's price rises by a
  threshold you set, not just when it drops. Off by default — useful for watching a supplier or
  competitor listing where a rising price cuts into your margin.

#### Documentation

- README and Store listing now explicitly name who this Actor is for (resellers, dropshippers,
  arbitrage buyers, dealers/retailers, collectors, AI agents) and list the eBay marketplaces it
  supports.

### 1.29 — 2026-08-08

#### Added

- Every tracked listing now shows whether its data is fresh or carried forward from a previous
  run, right on the listing itself.

#### Changed

- Increased retry headroom for eBay's bot-check challenges, so more items succeed on a tough run
  instead of falling back to carried-forward data.

### 1.28 — 2026-08-07

#### Fixed

- Hardened this Actor's internal state storage against transient failures across the board, so a
  brief storage hiccup can no longer crash an otherwise-successful run.

### 1.27 — 2026-08-07

#### Fixed

- Hardened exchange-rate caching against storage failures, so a caching hiccup can no longer crash
  a run — it now falls back to a fresh lookup instead.
- Fixed a rare case where two schedules using different currency settings on the same Actor could
  interfere with each other's cached exchange rates.

### 1.26 — 2026-08-07

#### Changed

- Exchange-rate lookups are now cached for 24 hours instead of being re-fetched on every run —
  faster runs, same accuracy, since exchange rates barely move day to day.
- Store listing and README now describe this Actor as an eBay scraper with MCP-ready output.

### 1.25 — 2026-08-07

#### Added

- **Price insight signals (optional).** New "Enable price insight signals" input flags two
  patterns a single run can't see on its own: a 3-run consecutive price-drop streak, and a new
  all-time-low price. Both computed from price history already tracked — no extra scraping. Off
  by default. See the README's "Price insight signals" section.

### 1.24 — 2026-08-07

#### Changed

- Store listing now highlights multi-marketplace support (any eBay country site, not just
  `.com`) up front.
- README's pricing section now recommends tracking direct item URLs over search pages for lower
  ongoing cost, and explains why.

### 1.23 — 2026-08-07

#### Fixed

- Item URLs copied from eBay's personalized recommendations (e.g. a "recently viewed" card) could
  carry extra tracking parameters that increased proxy costs and run time. URLs are now cleaned
  automatically before tracking.

### 1.22 — 2026-08-07

#### Fixed

- The browser fallback no longer loads images, stylesheets, or fonts it never actually uses —
  faster page loads and less wasted proxy bandwidth on every browser-fallback request.
- Skipped an unnecessary exchange-rate lookup on runs where nothing new was scraped.

### 1.21 — 2026-08-07

#### Fixed

- Hardened this Actor's startup against a storage-permission edge case that could otherwise
  prevent a run from starting at all.
- AI enrichment failures are now logged with a specific, actionable reason (e.g. a missing or
  invalid credential) instead of failing silently.

### 1.20 — 2026-08-07

#### Fixed

- A run could fail to save its results under certain account permission setups, even after
  scraping had already succeeded. Runs now complete and save normally in this case.

### 1.19 — 2026-08-04

#### Fixed

- Input values sent via a direct API call (bypassing the normal input form) could crash a run if
  malformed. All input fields are now validated at runtime and fall back to their documented
  default.
- A price-drop alert threshold of 0% or below (only reachable the same way) could trigger
  incorrect alerts. It now falls back to the default threshold instead.
- Documented two Output fields that were already being written on every run but missing from the
  docs.

### 1.18 — 2026-08-04

#### Fixed

- A billing/monetization hiccup could occasionally cause a run to lose its saved progress even
  after scraping had already succeeded. Now handled gracefully.
- Fixed a case where a redirected item URL could permanently disable a cost-saving optimization
  for that specific item.

#### Changed

- This Actor's internal state storage now automatically prunes entries for items you're no longer
  tracking, keeping storage lean as your tracked list changes over time.

### 1.17 — 2026-08-04

#### Fixed

- Fixed a rare case where a listing's original ("was") price could be read instead of its actual
  current price.

### 1.16 — 2026-08-04

#### Fixed

- Fixed a shipping-cost parsing edge case that could misread a listing's shipping label as if it
  were the shipping price.

### 1.15 — 2026-08-04

#### Changed

- Items that have recently needed the browser fallback now skip straight to it instead of
  re-trying the faster method first — with a periodic recheck so this self-corrects automatically
  if the listing stops needing it.

### 1.14 — 2026-08-04

#### Fixed

- Fixed currency misdetection for several dollar-denominated currencies (AUD, CAD, HKD, SGD, NZD)
  that could previously cause inaccurate price-change alerts.
- Improved price-comparison accuracy for currencies with very large or very small typical values
  (e.g. JPY, KRW).

#### Changed

- AI enrichment requests now run with limited concurrency instead of one at a time, speeding up
  runs with many new or retitled items.

### 1.13 — 2026-08-04

#### Fixed

- A single malformed URL in your tracked list could previously stop the entire run. Invalid URLs
  are now skipped (with a warning) instead.
- Items stuck on stale data for 3+ consecutive runs are now always visible on the run's Output
  tab, not only via a webhook alert.

### 1.12 — 2026-08-03

#### Changed

- Billing now reflects whether an item actually changed: items confirmed unchanged from the
  previous run are billed at a much lower rate than new, removed, or changed ones.

### 1.11 — 2026-08-03

#### Fixed

- Corrected this Actor's own internal release/versioning practice. No effect on how you use it.

### 1.10 — 2026-08-03

#### Documentation

- Documented that this Actor's structured output is suitable for driving an AI agent or
  automation pipeline directly, not just a human dashboard.

### 1.9 — 2026-08-03

#### Fixed

- Fixed a case where AI enrichment could permanently stop populating brand/model/category for
  certain previously-tracked items.

### 1.8 — 2026-08-03

#### Added

- Optional AI enrichment: extract brand, model, and category from each listing title via AI —
  through Apify's own proxy, so no separate API key is needed. Off by default.

### 1.7 — 2026-08-03

#### Added

- Rolling price trend: see how a tracked item's price has moved over the last 24 hours, 7 days,
  and 30 checks.

### 1.6 — 2026-08-03

#### Added

- Auction fields: bid count, current bid, time remaining, and reserve status are now captured for
  auction-format listings.

### 1.5 — 2026-08-03

#### Added

- Native Discord and Slack support: paste your channel's webhook URL directly into "Alert webhook
  URL" — no relay needed.

### 1.4 — 2026-08-03

#### Added

- Confirmed and documented support for tracking any eBay country site, not just `ebay.com` — at
  no extra cost.

### 1.3 — 2026-08-03

#### Changed

- Sponsored/promoted listings on search and seller pages are no longer tracked or billed — only
  organic results are.

### 1.2 — 2026-08-03

#### Changed

- Reorganized the README to lead with what this Actor does and what it costs.

### 1.1 — 2026-08-03

#### Added

- Reliability-trend alerts: a webhook alert fires when scraping keeps failing across several
  consecutive runs, distinct from a single bad run.
- Possibly-delisted detection: items running on carried-forward data for 3 consecutive runs are
  now flagged instead of just quietly going stale.
- Empty-listing-page alerts: a search or seller page that returns no items even after a full
  browser retry is now surfaced, since that usually means eBay changed that page's layout.
- Currency normalization: prices are now converted to a single target currency before comparing
  runs, so price-drop detection stays accurate even when eBay shows a different currency from run
  to run.
- A self-healing default example input that can't go stale the way a single hardcoded item link
  eventually would.

#### Changed

- Listings discovered via a search or seller page that later disappear are now correctly reported
  as removed, instead of vanishing with no signal.
- More accurate price parsing for European/Brazilian-style number formats (e.g. `1.234,56`).
- More accurate tracked-item counts when the same listing appears under more than one URL.
- Reduced pricing from a flat $0.20 to $0.12 per result (down to $0.10 on Gold/Platinum/Diamond
  plans), and removed a platform-usage surcharge that was previously billed on top.
- Reduced default run memory to lower costs, based on real observed usage.

#### Fixed

- Fixed a case where a failed scrape could overwrite good historical data instead of preserving
  the last known good snapshot.
- Fixed Docker builds to use consistent, tested dependency versions.
