PriceBuddy: a self-hosted price tracker for stores that have no integration
A self hostable app that tracks prices and sends you notifications when prices match your preferences
At a glance
- What is it?
- PriceBuddy is a Laravel and Filament application you run with Docker, aimed at people who want price history and alerts from arbitrary product pages rather than from a fixed list of supported retailers. The trade-off is that scraping arbitrary pages is a maintenance job, not a one-time setup.
- Who is it for?
- Adopt PriceBuddy if you already run Docker on a home server or VPS and you want price history and alerts for stores that no commercial tracker covers, and if you accept that a store's markup can break a scraper and that fixing it is your job. Do not adopt it if you want a hosted service with no server, or if you only track Amazon and a handful of large retailers where an existing tool already has integrations.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 35 days ago.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem PriceBuddy targets: stores nobody has integrated
Most price trackers are built around a catalogue of supported retailers. If your product lives in one of those catalogues, the tracker works. If it lives on a small webshop, a regional marketplace or a store that changed its markup last month, the tracker either does not list it or silently stops returning prices. PriceBuddy's README frames the project around that gap: it is "built for the messy web", with normal product pages, changing markup, multiple listings for the same item and stock states that move around.
The audience follows from that. It is for someone willing to run a server who tracks things that fall outside the big retailers: hobby gear, computer parts, household wishlists, marketplace listings. The README also lists multi-user accounts, tags and filters, so a household or a small team sharing one instance is an intended use, not an afterthought.
The design consequence is worth stating plainly. Because PriceBuddy does not require a code change per retailer, the burden of correctness moves to configuration and to the scrapers themselves. That is the central trade-off of the whole project.
How the Docker stack is wired: app, MySQL and a separate scraper
The repository's docker-compose.yml defines three services, and the split is the most informative thing about the architecture. The app service runs the image jez500/pricebuddy:latest, publishes port 8080 on the host mapped to port 80 in the container, and mounts a storage volume plus your .env file. It depends on the database service being healthy before it starts.
The second service is mysql:8.2 with a healthcheck that pings the server every ten seconds, which is why the app waits rather than retrying blindly. The third is jez500/seleniumbase-scrapper:latest, and the app reaches it through the SCRAPER_BASE_URL environment variable, set to http://scraper:3000 in the shipped file. Scraping therefore happens in a separate browser-automation container, not inside the PHP process. That is a sensible boundary: a page that hangs or a browser that crashes takes down the scraper, not the web app.
The scheduler is inside the app image. The README states that the Docker image includes the scheduler needed for background work, so price checks, history updates and notifications run without a separate cron container. If you deploy the app image on its own, you own that scheduling yourself.
Data flow is conventional for a Laravel application: products and their listings live in MySQL, the scheduler triggers checks, the app calls the scraper service for each product URL, and the result is written back as a price and availability record. Notifications then go out through whichever channel you configured.
Installing PriceBuddy with Docker Compose and tracking a first product
The README says Docker is the recommended install path and that all you need is Docker. Download docker-compose.yml, adjust it for your environment, then create an empty .env file and bring the stack up. The two commands below are the ones the README gives, and they run from the directory containing the compose file.
touch .env
docker compose up -dWith the defaults, the app is served at http://localhost:8080. The first start seeds the database using the APP_USER_EMAIL and APP_USER_PASSWORD values from the compose file, which are [email protected] and admin. Log in with those credentials and change the password immediately; the README says so directly, and it is the one step you should not postpone on a machine reachable from outside your network.
Before the first start, check the database credentials in the compose file line up with the MySQL service. They ship matched, and the comments in the file say as much.
environment:
DB_HOST: database
DB_USERNAME: pricebuddy
DB_PASSWORD: pric3buddy
DB_DATABASE: pricebuddy
SCRAPER_BASE_URL: http://scraper:3000
AFFILIATE_ENABLED: 'true'If you would rather not have affiliate codes added on outbound links, set the affiliate flag to false in .env or in the compose file. The README documents the exact key.
AFFILIATE_ENABLED=falseFor a first real use, paste a product URL into the app and let PriceBuddy attempt to read the title, image, price and availability. The README says many stores work straight away and that trickier sites need the scrape strategy tuned without changing code. Set a target price or a percentage drop on the product, then wait for a scheduled check. The README does not document how long the first check takes, so treat the first successful price entry as the confirmation that scraping works for that store.
Notifications, stock states and unit price comparison
Alerts are the feature most people install a tracker for, and PriceBuddy covers the usual channels: in-app, email, Pushover, Gotify, Apprise, Telegram, Discord and ntfy. That list matters more than it looks. ntfy and Gotify mean you can keep notifications on infrastructure you already run instead of handing a third party your watchlist activity.
Availability is tracked as a state, not a boolean. The README lists in stock, pre-order, back order, special order, out of stock and discontinued. Anyone who has watched a listing flip to out of stock the moment a price target was hit will recognise why that granularity is useful: a price alert on a discontinued listing is noise.
Unit price calculation is the other feature worth calling out. PriceBuddy can compute price per unit so a 10-pack and a 3-pack can be compared fairly. Combined with price history, that is the part that addresses the README's own framing of the problem, the "sale" prices that are not really sales. A discount is only meaningful against a recorded high, and PriceBuddy keeps that record.
Where the documentation is thin is the notification layer's behaviour under failure. The README lists the channels but does not describe retry behaviour when a channel is unreachable, nor whether a failed send is recorded anywhere. If alerting is the reason you are installing this, test each channel you enable rather than assuming delivery.
Where the scraping approach breaks down
The flexibility that distinguishes PriceBuddy is also its main failure mode. A scraper tuned to a store's markup stops returning correct prices when that markup changes, and the README acknowledges changing markup as part of the problem space rather than something solved once. The practical result is that any store you track is an ongoing commitment. A watchlist of thirty stores is thirty things that can break independently, and a broken scraper may report a stale price rather than an obvious error.
Two optional features exist to soften that. You can bring your own OpenAI, Anthropic, Gemini or local Ollama provider, and PriceBuddy can use AI to recover missing data from a page or help repair scraping rules. It is off by default, and the README is explicit that it is optional. If you enable it, page content leaves your server for whichever provider you chose, or stays local with Ollama. That is a real decision, not a checkbox.
The second is SearXNG, which you connect to search for products from inside PriceBuddy. That requires running a SearXNG instance as well, so it adds a service rather than removing one.
PriceBuddy is the wrong tool if you want a tracker that works without you looking at it. It is also the wrong tool if you only track one or two large retailers that already have integrations elsewhere; you would be paying the self-hosting and scraping-maintenance cost for coverage you do not need. It is also not a hosted service, so if you have no server and no wish to run one, nothing here helps.
How PriceBuddy differs from Discount Bandit
The README names its inspiration directly: PriceBuddy was inspired by Discount Bandit, and the stated difference is flexibility, with the aim of tracking products from arbitrary stores without requiring a code change for each retailer. That is a specific architectural claim, and it points at a specific difference in approach. A tracker built around per-retailer integrations gains reliability on the retailers it covers, because someone maintains that integration and the parsing logic is written against known markup. A tracker built around configurable scrape strategies gains reach, because a new store is a configuration task rather than a pull request, and loses the guarantee that anyone has verified the result.
There is a second difference in the tooling around the project. PriceBuddy ships a CLI, documented in a separate repository, that the README describes as providing command-line access for humans and agents: syncing a local mirror, searching products, inspecting price history, running deal and drop reports, calling the REST API and exposing PriceBuddy through MCP. It also ships a Chrome and Edge extension, PriceBuddy Companion, which adds a panel to a product page so you can start tracking from where you are and tune a store's scrape strategy in place. Neither exists to make scraping more reliable; both exist to make the configuration work less tedious, which is the honest answer to the maintenance problem.
Licence, upgrade cost and what the repository does not settle
The repository's licence is reported as NOASSERTION, which means the licence could not be identified automatically. The repository contains a LICENSE.md file, so the terms exist, but nothing in the README describes them and this article cannot tell you what they permit. Read LICENSE.md yourself before you build anything commercial on top of the app, and note that the affiliate code list lives in config/affiliates.php if that affects your decision. This is not legal advice, only a pointer to the file that answers the question.
Upgrades are the ordinary Docker Compose kind. The app service pins jez500/pricebuddy:latest, so a pull followed by a restart moves you to the newest image, and a MySQL volume holds your data across that. The repository's release history shows frequent patch releases, with v1.0.54, v1.0.53 and v1.0.52 all landing within roughly six weeks. Frequent small releases are easier to absorb than rare large ones, but they also mean you should read the release notes rather than assume a patch bump is inert. The last push to the repository was on 2026-08-27.
The README does not document rollback, and it does not describe a migration path if a release changes the database schema. If you care about that, the database volume is the thing to back up, and the time to work out how is before an upgrade, not after.
Local development is a separate path: Lando, with lando start as the documented command, and Pint, PHPStan and Pest or PHPUnit for standards, static analysis and tests. That is relevant if you intend to fix a scraper yourself rather than wait for someone else to.
Editorial conclusion
Adopt PriceBuddy if you already run Docker on a home server or VPS and you want price history and alerts for stores that no commercial tracker covers, and if you accept that a store's markup can break a scraper and that fixing it is your job. Do not adopt it if you want a hosted service with no server, or if you only track Amazon and a handful of large retailers where an existing tool already has integrations. Before committing, check the installation guide for the required services and PHP extensions, confirm which stores already appear in config/affiliates.php, and decide whether you want AFFILIATE_ENABLED left at its default. Then change the seeded [email protected] password.
Frequently asked questions
What is PriceBuddy?
PriceBuddy is an open source, self-hostable price tracker. You paste in a product URL, it checks the page on a schedule, keeps price history and notifies you when the price or availability matches your preferences.
Is PriceBuddy reliable?
Reliability depends on how well a given store's page can be scraped, since PriceBuddy is built to track arbitrary stores rather than a fixed list of integrated retailers. The README notes that changing markup is part of the problem it targets, and that tricky sites need their scrape strategy tuned.
Is PriceBuddy safe to run?
It is designed to be self-hosted with Docker, so your watchlist, price history and notification settings stay on your own server. The README warns to change the default admin password immediately after installation. Enabling the optional AI provider sends page content to whichever provider you configure, unless you use local Ollama.
What is the best price tracking tool?
The README does not compare PriceBuddy with other trackers. It names Discount Bandit as its inspiration and states that PriceBuddy's difference is flexibility: tracking products from arbitrary stores without a code change for each retailer.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/jez500-pricebuddy)