Skip to content

Releases: mikeknight85/PriceStalker

v1.4.0

Choose a tag to compare

@mikeknight85 mikeknight85 released this 29 Jun 12:40

Added

  • Edit a price watcher's selection after creation (#21). New "Edit Price Selection" button on the product detail page re-scrapes the page and reopens the price picker, so you can correct a wrong price (e.g. a bad CSS match) without deleting the watcher or losing its price history. The corrected price is recorded as a new point.

Fixed

  • Broken product images from relative URLs (#22). Image URLs returned as site-relative paths (e.g. /i/abc123) are now resolved to absolute URLs against the source page, so they render correctly. Existing broken images self-heal on the next price check.

v1.3.1

Choose a tag to compare

@mikeknight85 mikeknight85 released this 16 Jun 15:06
2b531e2

[1.3.1] - 2026-06-05

Documentation

  • README "What's new" table caught up to the 1.3.x line (was stale at
    1.1.x).
  • New Notifications → Custom Webhook config section with the full
    placeholder reference table.
  • Notifications feature blurb now mentions the Custom Webhook provider
    and the any-change alert added in 1.2.8.

No code changes — pure docs/version-bump release so :latest users on
prod see the most recent README on the GitHub release page.

v1.3.0

Choose a tag to compare

@mikeknight85 mikeknight85 released this 05 Jun 12:09

[1.3.0] - 2026-06-05

Added

  • Configurable generic webhook notification provider (#4). New
    "Custom Webhook" provider alongside the existing 5 (Telegram,
    Discord, Pushover, ntfy, Gotify). Configure URL, method (GET / POST
    / PUT / PATCH / DELETE), optional headers (JSON object), and a body
    template with placeholders — {title}, {type}, {url},
    {currency}, {price}, {new_price}, {old_price}, {threshold},
    {target_price}, {timestamp}. Routes notifications to anything
    that speaks HTTP: Apprise, Home Assistant, n8n, Zapier, custom
    backends.
  • Beta channel (:beta Docker tag). Tracks every merge to main.
    :latest now only updates on tagged releases. Demo / staging stacks
    pin to :beta for auto-rolling pre-release deployments; prod stacks
    stay on :latest until the next tag.
  • BETA pill next to the running-version display in Settings when
    the image was built from main. Makes pre-release deployments
    visually distinguishable from prod without checking the image tag.
  • Themed textareas — global form-group CSS now styles textareas
    the same as inputs (was missing the selector, every textarea fell
    through to browser defaults). Plus a .code-input modifier class
    for monospace JSON/code-shaped fields.

Fixed

  • Webhook save/test feedback uses toast instead of the top-of-page
    alert bar. The webhook form sits at the bottom of a long Settings
    page; feedback was previously invisible to anyone scrolled there.
  • Product card alert badges respect product currency. Price-drop
    and target-price badges in the dashboard's product card hardcoded a
    $ prefix and ignored the product's actual currency. Now use the
    same formatPrice helper as the displayed price next to them.

v1.2.11

Choose a tag to compare

@mikeknight85 mikeknight85 released this 02 Jun 06:06

[1.2.11] - 2026-06-02

Fixed

  • Wrong product images on SPA pages with recommendation widgets
    (digitec.ch, etc.). scrapeProductWithVoting read JSON-LD for price
    and stock but ignored the image field, so the cascade fell to the
    generic image scan which picked the first matching element — often
    a recommendation card on React-rendered pages, not the actual hero
    image. The stored URL pointed at a different product's image.
    Same class of bug as the JSON-LD stock-signal drop fixed in v1.2.6.
    The voting path now applies the type-aware JSON-LD Product.image
    whenever the page exposes it.
  • Stored bogus image URLs were permanent. The image self-heal added
    in v1.2.9/1.2.10 only triggered when image_url was NULL, so once
    a bad URL was in the DB it stayed forever. Self-heal now also fires
    when the scrape returns a different non-null URL — broken products
    recover on their next check or the next manual refresh.

v1.2.10

Choose a tag to compare

@mikeknight85 mikeknight85 released this 02 Jun 05:38

[1.2.10] - 2026-06-02

Fixed

  • Manual "Refresh Price now" now also backfills missing image_url.
    Parity with the scheduler's image self-heal added in v1.2.9 — the
    manual refresh route was a separate code path that wasn't updated.
    Clicking refresh on a product missing a picture now rescues it
    immediately instead of waiting up to a full refresh interval.

v1.2.9

Choose a tag to compare

@mikeknight85 mikeknight85 released this 02 Jun 05:16

[1.2.9] - 2026-06-02

Fixed

  • Missing product images that never recovered. image_url was
    only written at create-time, so a first-scrape miss became permanent
    even when later scrapes would have succeeded. JS-heavy SPAs
    (digitec.ch via Puppeteer) hit this when render timing varied.
    Scheduler now backfills image_url whenever the current value is
    null and the scrape produced one — existing broken products
    self-heal on their next scheduled check.
  • Lazy-load attribute coverage. extractGenericImage now also
    reads data-original, data-lazy, data-lazy-src, data-srcset
    and srcset (picking the first URL out of srcset descriptor lists).
    Reduces first-scrape misses on lazy-loaded image elements.

v1.2.8

Choose a tag to compare

@mikeknight85 mikeknight85 released this 01 Jun 15:03

[1.2.8] - 2026-06-01

Added

  • In-app update notification. The backend queries the GitHub
    releases API once a day. When a newer PriceStalker release is
    available, logged-in users see a dismissible banner with a link to
    the release notes. Dismissals are per-version (localStorage), so
    a future release re-surfaces it. No telemetry — the only outbound
    request is a single HTTPS GET to api.github.com from the backend
    (never from the user's browser), with User-Agent: PriceStalker/<v>.
    Opt-out entirely with DISABLE_UPDATE_CHECK=true.

v1.2.7

Choose a tag to compare

@mikeknight85 mikeknight85 released this 01 Jun 12:57

[1.2.7] - 2026-06-01

Fixed

  • Wrong currency in the price-selection modal on stores that emit
    canonical schema.org markup (<meta itemprop="price" content="X">
    plus <meta itemprop="priceCurrency" content="EUR">). The generic
    CSS candidate extractor read the numeric content attribute, found
    no symbol, and parsePrice() defaulted to USD — so the modal
    preview showed $ even on EUR/GBP/etc. stores. The post-confirm
    scrape used a different code path that did find the symbol, so the
    saved row was correct, but the modal was misleading. The extractor
    now falls back to the companion [itemprop="priceCurrency"], then
    OpenGraph product:price:currency / og:price:currency, before
    accepting the USD default.

v1.2.6

Choose a tag to compare

@mikeknight85 mikeknight85 released this 01 Jun 12:35

[1.2.6] - 2026-06-01

Fixed

  • Shopify restock detection (#2) — three compounding bugs made the
    voting scraper mislabel in-stock Shopify products as out-of-stock and
    hide the (correctly extracted) price for any OOS product:
    • scrapeProductWithVoting silently dropped JSON-LD's
      offers.availability signal because it called the price-only
      candidate extractor but not the full extractor that reads stock.
    • The generic CSS detector matched Shopify Dawn-family themes' hidden
      .price__badge-sold-out element on in-stock products (Dawn renders
      both badge states in the DOM and toggles visibility via CSS rules
      Cheerio can't evaluate).
    • The UI suppressed the price entirely when stock was OOS, leaving
      affected users looking at an empty card and concluding detection
      itself was broken.
  • Wrong currency on generic CSS extractions (#6) — the generic
    scraper defaults to USD when it can't detect a symbol or code in the
    text. Added a per-product currency override that wins across writes,
    notifications and SELECTs (via COALESCE), so users can correct it
    without waiting for a code fix.

Added

  • Shopify-aware extraction. New scraper path that detects a Shopify
    storefront by its cdn.shopify.com / Shopify.theme signature and
    fetches /products/<handle>.js for canonical per-variant available
    and price. Bypasses theme/localization variation entirely and covers
    the full Shopify long tail, not just the reported store.
  • Localised in-stock phrases in the generic stock detector
    (Dutch / German / French / Spanish / Italian / Portuguese), so
    non-English Shopify pages produce a positive in-stock signal instead
    of falling through to OOS by default.
  • "Notify on any price change" toggle per product (#5). When
    enabled, the scheduler fires a price_change notification on every
    movement ≥ 0.01 in either direction, replacing the threshold-based
    drop notification while it's on (no double-firing). Implemented for
    Telegram, Discord (green/red embed by direction), Pushover, ntfy
    (up/down trend tags) and Gotify.
  • notify_back_in_stock accepted on POST /products and defaulted
    to true when adding an OOS product — the typical reason someone
    tracks something unbuyable is to know when it returns.
  • Price now shown alongside the OOS badge on the product card and
    detail page (no more "Price unavailable" hiding the last-known price).
  • "Detected via: ()" hint under the price on the
    product detail page (#6). Generic CSS surfaces the actual selector
    that matched, so wrong-currency / wrong-price calls are diagnosable.
  • GitHub Actions runner bump to Node 24-compatible majors
    (actions/checkout v6, dorny/paths-filter v4, docker/* v4/v6/v7),
    ahead of the June 2026 deprecation.

PriceStalker 1.2.5 — Puppeteer fix + DEMO_MODE flag

Choose a tag to compare

@mikeknight85 mikeknight85 released this 27 Apr 12:44

Fixed

  • Puppeteer "Failed to launch the browser process" — the nodejs user in the backend image was created with useradd -r (no -m), leaving $HOME unset at runtime. Chromium's crash handler (chrome_crashpad_handler) derives its --database path from $HOME / $XDG_CONFIG_HOME, so it crashed on launch with --database is required, breaking the browser-fallback branch of the voting scraper. Static-HTML sites (Amazon JSON-LD, Digitec JSON-LD, etc.) were unaffected because they never reach Puppeteer. Fix: create a real home directory for the nodejs user and set HOME=/home/nodejs.

Added

  • DEMO_MODE env flag that disables identity-mutating profile operations. With DEMO_MODE=true, PUT /api/profile and PUT /api/profile/password return 403. Useful for any deployment where the operator wants to keep a shared or test account stable — public demos, multi-tenant sandboxes, QA environments. Per-user-scoped operations stay open (adding products, configuring your own AI provider, configuring your own notification webhooks). Off by default; existing deployments see no change.

Docker images

ghcr.io/mikeknight85/pricestalker-backend:1.2.5
ghcr.io/mikeknight85/pricestalker-frontend:1.2.5

Multi-arch (amd64 + arm64).