Technology Apr 25, 2026 · 2 min read

I built a competitor pricing monitor in 3 days, here's how it actually works

I lost a deal last month. Prospect told me my competitor had dropped their pricing two weeks earlier. Found out during a live demo. Looked completely unprepared. Started looking for a tool to automate this. Found Visualping, alerts on every pixel change, completely noisy. Found enterprise to...

DE
DEV Community
by Ahmed Errami
I built a competitor pricing monitor in 3 days, here's how it actually works

I lost a deal last month.

Prospect told me my competitor had dropped
their pricing two weeks earlier. Found out
during a live demo. Looked completely
unprepared.

Started looking for a tool to automate this.
Found Visualping, alerts on every pixel
change, completely noisy. Found enterprise
tools at $500+/year. Nothing in between.

So I built one.

The stack

  • Next.js 16 (App Router)
  • Playwright for scraping
  • Supabase for storage
  • Resend for emails
  • vercel for hosting and cron worker

The hardest part: signal vs noise

Generic page monitoring is easy. Meaningful
change detection is hard.

A pricing page changes constantly, rotating
banners, timestamps, cookie notices, ad content.
If you alert on every pixel diff you're just
building a noise machine.

I built a classification engine that categorizes
changes before deciding whether to alert:

  • PRICE_CHANGE — dollar amounts moving
  • PLAN_CHANGE — plans appearing or disappearing
  • FEATURE_CHANGE — features shifting between tiers
  • COSMETIC — everything else (ignored)

The key insight: normalize the text before diffing. Strip dates, times, navigation text, cookie notices, social handles. Then run a line-by-line diff on what's left.

Only PRICE_CHANGE, PLAN_CHANGE, and FEATURE_CHANGE trigger an email.

Why Playwright over Puppeteer

Pricing pages are almost always JS-heavy SPAs. Puppeteer struggles with modern React apps,content loads after the initial HTML response.

Playwright with waitUntil: 'networkidle' plus a 2 second additional wait handles even the most aggressive lazy-loading. Worth the slightly heavier dependency.

The cron worker

Runs at 9am daily. Processes monitors sequentially with a 3 second delay between each — not parallel. Parallel scraping gets you rate-limited and blocked fast.

On first run: saves a baseline snapshot. On subsequent runs: diffs against the previous snapshot, classifies the change, sends alert if significant

What I'd do differently

The diff algorithm is the weakest part right now. Line-by-line text diff catches most changes but misses subtle restructuring, when a competitor moves a feature to a different plan section without changing the text, the diff doesn't catch it cleanly.

Next step is extracting structured data (plan name → price → features[]) and diffing the structure instead of raw text.

It's live and free

https://priceblind.vercel.app/

No account, no credit card. Paste a URL, get emailed when pricing changes.

Happy to answer questions about any part of the implementation, the scraping, the diff engine, or the email delivery.

What would you build differently?

DE
Source

This article was originally published by DEV Community and written by Ahmed Errami.

Read original article on DEV Community
Back to Discover

Reading List