Skip to main content
Back to Blog

PickMyClass: Never Miss Your Dream Class Again

5 min read
Side Project Puppeteer Web Scraping Next.js Cloudflare Workers Supabase ASU College SaaS Full Stack
Featured image for PickMyClass: Never Miss Your Dream Class Again

TL;DR

PickMyClass is a notification system that monitors ASU class availability every 30 minutes and emails students when seats open or instructors are assigned, serving 10,000+ users for $34/month.

Key Takeaways

  • Built to solve personal frustration with missing class seats at 2 AM
  • Uses Puppeteer on Oracle Cloud to scrape JavaScript-rendered pages
  • Scales to 10,000 users at $0.0034 per student per month
  • Real-time updates via Supabase subscriptions
  • 2,500x database query reduction through batch optimizations

The Story Behind the Build

Picture this: It’s 3 AM. You’re refreshing the ASU class search page for the hundredth time. That coding class you need to graduate? Still full. The professor everyone raves about? Still listed as “Staff.”

Sound familiar? It happened to me during my sophomore year.

I needed CSE 310 with Professor Martinez. The class was full. I set phone alarms every hour. I checked between classes. I even woke up in the middle of the night to refresh the page. When a seat finally opened at 2:47 AM on a Tuesday, I was asleep. Someone else got it.

That’s when I remembered pickaclass.app—a tool that watched classes for you. It sent emails when seats opened up. Perfect solution, right? Except it shut down in 2023.

So I built my own.

What PickMyClass Does

PickMyClass is a notification system for university students. Enter your section number, and the app does the watching for you.

The system checks every 30 minutes for two things:

  • Open seats – Get notified the moment a full class has availability
  • Instructor updates – Know when “Staff” changes to an actual professor name

No more constant refreshing. No more missed opportunities. Just an email when something changes.

The Architecture

Here’s how the system flows:

User Request → Cloudflare Worker (Edge)

              Supabase (Auth + DB)

            Cloudflare Queue (Job)

        Oracle Cloud (Puppeteer Scraper)

              Supabase (Update DB)

            Resend API (Email Notification)

The architecture keeps costs low: Cloudflare handles edge logic for free, Oracle’s always-free tier runs the heavy Puppeteer work, and Supabase’s generous free tier stores user data.

The Technical Challenge

Building this wasn’t straightforward. ASU’s class search loads data with JavaScript. Their API returns 401 errors without browser context. Simple HTTP requests don’t work.

The solution? A Puppeteer-based scraper running on Oracle Cloud. It uses a real Chrome browser to fetch class data.

Here’s the core scraping logic:

// Wait for the class results to load
await page.waitForSelector('.class-results-row', { timeout: 30000 });

// Extract class data from the page
const classData = await page.evaluate(() => {
  const rows = document.querySelectorAll('.class-results-row');
  return Array.from(rows).map(row => ({
    sectionNumber: row.querySelector('.section-id')?.textContent?.trim(),
    seatsAvailable: parseInt(
      row.querySelector('.seats-open')?.textContent || '0'
    ),
    instructor: row.querySelector('.instructor-name')?.textContent?.trim()
      || 'Staff',
  }));
});

The tricky part? Handling authentication cookies, session timeouts, and random 401 errors. Circuit breaker patterns prevent one failed request from crashing everything.

The 2,500x Query Optimization

Initially, each class check triggered individual database queries. With 10,000 users watching 3 classes each, that’s 30,000 queries per cron run. Unacceptable.

The fix: batch everything.

-- Before: Individual queries per class (30,000 queries)
SELECT * FROM watches WHERE section_id = $1;

-- After: Single batch query (1 query)
SELECT section_id, array_agg(user_id) as watchers
FROM watches
WHERE section_id = ANY($1)
GROUP BY section_id;

One query fetches all watches. One query updates all changes. The email API supports batch sends. Total queries dropped from 30,000 to under 12.

Cost Breakdown at Scale

Here’s what it costs to run PickMyClass for 10,000 users:

ServiceMonthly CostNotes
Oracle Cloud$0Always-free tier for Puppeteer VM
Cloudflare Workers~$5Beyond free tier at scale
Supabase$25Pro tier for reliability
Resend~$4Email volume pricing
Total~$34$0.0034 per user

Compare that to a traditional AWS setup that would run $200-500/month for the same workload.

Working With (Not Against) ASU’s Systems

Web scraping has ethics. Here’s how PickMyClass stays responsible:

  1. 30-minute intervals – Not hammering their servers every minute
  2. Request queuing – Max 5 concurrent scraper instances
  3. Exponential backoff – Failed requests wait longer before retry
  4. User-Agent honesty – Not pretending to be Googlebot
  5. Circuit breakers – If ASU is having issues, we stop trying temporarily

The goal is to be a good citizen. If everyone scraped irresponsibly, they’d block everyone.

Built With Modern Web Tech

The stack includes:

  • Next.js 15 for the frontend
  • Cloudflare Workers for edge computing
  • Supabase for authentication and real-time features
  • PostgreSQL with row-level security
  • Puppeteer for web scraping
  • Resend for transactional emails

The dashboard updates live. Add a class watch, and it appears instantly. When the cron job detects changes, your browser sees them without refreshing.

Why It Matters

Getting into the right class can change your college experience. The right professor makes difficult subjects click. Required courses at convenient times let you work or do internships. Popular electives fill up in minutes.

Students shouldn’t lose opportunities because they were in class or asleep. Technology should work for us, not against us.

PickMyClass levels the playing field. Whether you’re a morning person or a night owl, you get the same chance at that open seat.

What I Learned

This project taught me how to:

  • Build fault-tolerant systems at scale
  • Work with headless browsers and anti-bot measures
  • Design database schemas with security policies
  • Implement edge caching for performance
  • Handle webhook integrations for email delivery
  • Set up self-hosted logging to debug scraper failures at 3 AM

But the biggest lesson? Solve problems you actually have. The best projects come from real frustrations. When you’ve experienced the problem firsthand, you know exactly what the solution needs to do.

Looking Forward

PickMyClass is live and watching classes right now. The system currently supports ASU, but the architecture works for any school with a web-based class search.

Need to track a class at your university? Visit pickmyclass.app to get started. The notification system is designed to be adaptable to different institutions with similar class registration challenges.

Frequently Asked Questions

How often does PickMyClass check for open seats?

Every 30 minutes. This balances timely notifications with responsible server load on ASU's systems.

Why use Puppeteer instead of direct API calls?

ASU's class search loads data with JavaScript and returns 401 errors without proper browser context. Puppeteer simulates a real Chrome browser to fetch the data successfully.

How much does it cost to run PickMyClass at scale?

About $34/month for 10,000 users. That breaks down to Oracle Cloud free tier for Puppeteer, Cloudflare Workers, Supabase, and Resend for emails.

Can PickMyClass work for other universities?

The architecture is designed to be adaptable. Any school with a web-based class search can be supported with a new scraper configuration.

How do you handle rate limiting and anti-bot detection?

Circuit breaker patterns prevent cascading failures. The scraper uses realistic browser fingerprints and respects rate limits to avoid being blocked.

Divanshu Chauhan

Divanshu Chauhan (@divkix)

Software Engineer based in Tempe, Arizona, USA. More about divkix