DEV Community

Cover image for Udemy prices change daily — so I built a free price tracker
courselens
courselens

Posted on

Udemy prices change daily — so I built a free price tracker

If you've ever bought a Udemy course, you've probably seen this: the same course costs one price on Monday and a fraction of it on Thursday. One course I watch was listed at $110 and sold for under $20 a few days later.

Udemy doesn't show price history. The "sale ends in 6 hours!" banner tells you nothing about whether the price will be even lower next week. So I started checking prices every morning and publishing what I saw: CourseLens.

This post covers how it's built for $0/month, and the two bugs that made it show wrong prices for weeks without me noticing.

What it does

  • Every morning, it records the real price of each listed course (no login, no cookies, the price an anonymous visitor sees).
  • Each course page shows a price chart and the periods when it was cheaper.
  • A /sale/ page shows whether a sitewide sale is on right now.
  • Each course has an RSS feed that fires when the price drops.

The stack

GitHub Actions (daily cron)
   └─ Python: fetch prices → append to JSON in the repo → commit
Cloudflare Pages (watches the repo)
   └─ build.py: JSON → static HTML (no framework, no database)
Enter fullscreen mode Exit fullscreen mode
  • No server, no database. Price history is a JSON file committed to the repo. Git is the database, and git log is the audit trail.
  • One Python script builds every page. No framework. The build also runs the test suite; if a test fails, the build fails and the previous version stays live.
  • Staging first. Every change goes to a staging branch, gets checked, then fast-forwards to main. (I learned this the hard way, see below.)
  • Cost: GitHub Actions free tier + Cloudflare Pages free tier + a domain.

Bug 1: three weeks of prices in the wrong currency

CourseLens has a second regional edition that shows prices in a local currency. For three weeks, that edition showed prices about a hundred times too low.

What happened: I was traveling when I wrote the fetcher, and the network I was on happened to get local-currency prices back. I assumed that was the default and didn't ask for a currency. GitHub Actions runners sit in US data centers. They got dollar amounts, and my code put the local currency symbol in front of them. A $15 course suddenly looked like it cost pocket change.

Lesson: never rely on an implicit default that depends on where the code runs. Set the region and currency explicitly, for every market, and add a test that fails if the currency comes back wrong.

Bug 2: US prices stuck for weeks because of time zones

To save requests, I only refreshed the US edition's prices when the other regional edition detected that a sale had started or ended. It seemed reasonable: Udemy sales are sitewide, so one market should tell you about the other.

They aren't in sync. Sales start and end on local time boundaries, so two markets can be a day apart. When the other edition saw "no change", the US edition never refreshed, and some of its pages showed prices up to 85% below the real one.

Lesson: don't make one market's data depend on another market's events. The fix was boring: refresh every US course every day, unconditionally. It costs a few extra requests and removes a whole class of bugs.

What I'd tell anyone building a price tracker

  1. Store every observation, not just the latest price. You can't recompute history later.
  2. Treat "unchanged" as data. A day with no change is still an observation.
  3. Make the build your safety net. Tests that run inside the deploy are worth more than tests you remember to run.
  4. Write down every incident. Neither bug above was caught by an automated check. I now keep a "lessons" file that I read before every change.

Try it

If you watch a specific course, subscribe to its price-drop RSS feed from its page.

Disclosure: course links on CourseLens are Udemy affiliate links. Prices and scores are not affected by that.

Top comments (0)