The Problem

E-commerce prices fluctuate constantly, and manual checking is impractical. This repo solves that by scraping Amazon product pages, storing price history, and emailing users when a tracked product drops in price or goes out of stock. It's the companion code to a JavaScript Mastery YouTube tutorial, forked from adrianhajdin/pricewise.

What This Does

A Next.js 13 application with three moving parts: a scraper (lib/scraper/index.ts) that pulls price, currency, and description from Amazon product pages using Cheerio and Bright Data's webunlocker; a MongoDB persistence layer (lib/mongoose.ts and lib/models/product.model.ts) that keeps price history per product; and a notification system (lib/nodemailer/index.ts) that sends price-drop, back-in-stock, and out-of-stock emails via Nodemailer. The UI—search bar, product cards, detail pages, and a tracking modal—lives in components/ and app/.

How It Is Wired

Execution starts in lib/actions/index.ts, the hub of the system. It imports 5 modules and nothing imports it (instability 1), so every change there ripples outward. scrapeAndStoreProduct (line 11) is the main entry point: it reaches 8 functions and calls connectToDB (a database write via mongoose.set) and scrapeAmazonProduct (an outbound network call via axios.get)—two hops from user input to external effects.

The cron job in app/api/cron/route.ts defines GET, which routes through updatedProducts in lib/actions/index.ts. That single function calls scrapeAmazonProduct, getLowestPrice, getHighestPrice, getAveragePrice, getEmailNotifType, generateEmailBody, and sendEmail—the widest blast radius in the repo. connectToDB is called from 5 places, so changing the connection strategy touches nearly every code path. The module graph shows 20 modules, 6 import edges, and zero circular dependencies—clean layering, but lib/actions/index.ts and lib/scraper/index.ts are the coupling points to watch.

File-by-file: lib/utils.ts owns parsing helpers (extractPrice, extractCurrency, extractDescription) and price calculations; types/index.ts defines the Product, User, and PriceHistoryItem shapes; components/Modal.tsx handles email opt-in; components/Searchbar.tsx validates Amazon URLs.

How To Use It

Clone with git clone https://github.com/moses-y/pricewise. Per the README: npm install, then npm run dev. Required environment variables: MONGODB_URI, BRIGHT_DATA_USERNAME, BRIGHT_DATA_PASSWORD, EMAIL, and EMAIL_PASSWORD (an app-specific Gmail password). No .env.example is committed, so the variable names come from the tutorial, not the repo—verify against lib/mongoose.ts and lib/nodemailer/index.ts before assuming.

Real-World Use

A user pastes an Amazon URL into the search bar. Searchbar validates it, scrapeAndStoreProduct scrapes the page, stores the product and price point in MongoDB, and renders it on the home page. The cron job runs daily, rescrapes every tracked product, and updatedProducts compares prices—if the current price beats the historical low, sendEmail fires a notification to every subscribed address.

Code Health & Issues

Static analysis found 1 measured finding (0 high, 1 medium, 0 low): [MEDIUM] deep nesting in components/Modal.tsx—max indentation depth 6, hard to follow control flow; fix with early returns.

Beyond that, the structure shows: [HIGH] no test suite across 20 source files; [HIGH] no CI configuration; [HIGH] no LICENSE (all-rights-reserved by default); [HIGH] rejectUnauthorized: false in lib/scraper/index.ts disables TLS certificate verification, leaving traffic readable by anyone positioned between hosts; [MEDIUM] no Dependabot/Renovate; [LOW] missing .editorconfig, .gitattributes, and formatter config. No committed secrets detected.

The Bottom Line

A functional tutorial-grade price tracker with clean module structure and a working end-to-end flow from scrape to email. It's not production-ready: no tests, no CI, no license, and the disabled certificate check is a real security gap. Use it as a learning reference or a starting point, not as-is for a client deployment.