A full-featured flight deal tracking platform with automated scanning, price alerts, and beautiful email notifications.
100% Free - Uses free tiers of Vercel, Supabase, SerpApi, and Gmail.
🌍 Smart Search
- Multiple origin airports (SFO, SJC, OAK, LAX, etc.)
- Custom date ranges ("Aug-Sep", "Jan-Mar")
- Multiple trip lengths (weekend, week, extended)
- Regional preferences (Europe, Asia, Latin America priority)
💰 Price Tracking
- Historical price data storage
- Week-over-week price comparisons
- Price trend visualization
- Automatic price drop alerts
📧 Email Notifications
- Beautiful HTML weekly digests
- Price drop alerts
- Top 20 deals grouped by region
- One-click booking links
🎯 Web Dashboard
- View all past searches
- Manual scan triggers
- Configure preferences
- Manage price alerts
- Frontend: Next.js 16, React 19, Tailwind CSS
- Backend: Next.js API Routes, TypeScript
- Database: Supabase (Postgres)
- Flight Data: SerpApi (Google Flights)
- Email: Gmail SMTP / Nodemailer
- Deployment: Vercel
- Cron: Vercel Cron Jobs
| Service | Free Tier | Usage | Monthly Cost |
|---|---|---|---|
| Vercel | Hobby Plan | Hosting + Cron | $0 |
| Supabase | Free Plan | 500MB DB, 50MB storage | $0 |
| SerpApi | 100 searches/month | ~48 searches/month | $0 |
| Gmail SMTP | Unlimited | Email sending | $0 |
| Total | $0 |
- Node.js 18+ and npm
- GitHub account
- Vercel account (free)
- Supabase account (free)
- SerpApi account (free)
- Gmail account with 2FA enabled
git clone <your-repo-url>
cd flight-deal-scanner
npm install-
Go to supabase.com and create a new project
-
Wait for the database to be provisioned
-
Go to Settings > API and copy:
- Project URL →
NEXT_PUBLIC_SUPABASE_URL anonpublic key →NEXT_PUBLIC_SUPABASE_ANON_KEYservice_rolesecret key →SUPABASE_SERVICE_ROLE_KEY
- Project URL →
-
Go to SQL Editor and run the migration:
-- Copy and paste contents from supabase/migrations/001_initial_schema.sql -
Update the default email in the migration:
-- Change 'your.email@gmail.com' to your actual email
- Sign up at serpapi.com
- Free tier includes 100 searches/month
- Copy your API key from the dashboard
- Weekly scans from 2 airports with 2 date ranges and 3 trip lengths = ~48 searches/month ✅
-
Enable 2-Step Verification:
- Go to myaccount.google.com/security
- Enable "2-Step Verification"
-
Generate App Password:
- Go to myaccount.google.com/apppasswords
- Select "Mail" and your device
- Click "Generate"
- Copy the 16-character password (you won't see it again)
# Copy the example file
cp .env.example .env
# Edit .env with your credentials
nano .envAdd your credentials:
# Supabase
NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOi...
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOi...
# SerpApi
SERPAPI_KEY=your_serpapi_key_here
# Gmail
GMAIL_USER=your.email@gmail.com
GMAIL_APP_PASSWORD=abcd efgh ijkl mnop
# Cron Secret (generate random string)
CRON_SECRET=some_random_secret_string_12345
# App URL
NEXT_PUBLIC_APP_URL=http://localhost:3000npm run devTest the manual scan:
- Go to Dashboard
- Click "Run Manual Scan"
- Wait 1-2 minutes (searches take time)
- You should see flight deals appear
npm install -g vercel
vercel login
vercel-
Push code to GitHub:
git init git add . git commit -m "Initial commit" git remote add origin <your-repo-url> git push -u origin main
-
Go to vercel.com
-
Click "New Project"
-
Import your GitHub repository
-
Add all environment variables from
.envto Vercel project settings -
Deploy!
The cron job is already configured in vercel.json:
{
"crons": [{
"path": "/api/cron",
"schedule": "0 9 * * 0"
}]
}This runs every Sunday at 9 AM (your server time).
Important: Add the CRON_SECRET environment variable to Vercel for security.
To manually trigger the cron (for testing):
curl -X GET https://your-app.vercel.app/api/cron \
-H "Authorization: Bearer your_cron_secret"- Go to your deployed app
- Navigate to Dashboard > Preferences
- Update:
- Your email address
- Origin airports
- Max price
- Date ranges
- Trip lengths
- Regional preferences
- Click "Save Preferences"
Every Sunday at 9 AM, the system will:
- Search flights based on your preferences
- Store all deals in Supabase
- Check for price drop alerts
- Send you a beautiful email digest with top 20 deals
- Go to Dashboard
- Click "Run Manual Scan"
- Wait for results (1-2 minutes)
- View deals immediately
- Go to Dashboard > Price Alerts
- Click "+ New Alert"
- Enter:
- Origin (e.g., SFO)
- Destination Code (e.g., CDG for Paris)
- Alert Price (e.g., $400)
- Get emailed when price drops below threshold
- Go to Dashboard
- Click on any past search in the sidebar
- View all flights found in that search
- Sorted by region and price
flight-deal-scanner/
├── app/
│ ├── api/
│ │ ├── cron/route.ts # Weekly automated scan
│ │ ├── manual-scan/route.ts # Manual trigger
│ │ ├── preferences/route.ts # Get/update preferences
│ │ ├── alerts/route.ts # Manage price alerts
│ │ └── search-history/route.ts # Fetch past searches
│ ├── dashboard/
│ │ ├── page.tsx # Main dashboard
│ │ ├── preferences/page.tsx # Settings page
│ │ └── alerts/page.tsx # Price alerts page
│ ├── page.tsx # Landing page
│ ├── layout.tsx # Root layout
│ └── globals.css # Global styles
├── lib/
│ ├── supabase.ts # Supabase client & types
│ ├── flight-scanner.ts # Core search logic
│ ├── email-service.ts # Email templates & sender
│ └── price-tracker.ts # Price history logic
├── supabase/
│ └── migrations/
│ └── 001_initial_schema.sql # Database schema
├── vercel.json # Cron job config
├── .env.example # Environment template
├── package.json
├── tsconfig.json
├── tailwind.config.ts
└── README.md
user_preferences - Search configuration
origin_airports: ["SFO", "SJC"]date_ranges: [{start: "aug", end: "sep"}]location_preferences: {europe: 1, asia: 2, ...}trip_lengths: [3, 7, 14]max_price: 600
search_runs - Each scan execution
run_date,airports_scanned,total_deals_found,status
flight_deals - All discovered flights
origin,destination,price,dates,airline,region, etc.
price_alerts - Route price monitoring
route,origin,destination_code,threshold_price,is_active
GET /api/cron- Weekly automated scan (triggered by Vercel Cron)POST /api/manual-scan- Trigger manual scanGET /api/preferences- Get user preferencesPUT /api/preferences- Update preferencesGET /api/alerts- Get all price alertsPOST /api/alerts- Create new alertPUT /api/alerts- Update alertDELETE /api/alerts?id=xxx- Delete alertGET /api/search-history- Get recent searchesGET /api/search-history?search_run_id=xxx- Get flights for specific search
- Add SMS notifications (Twilio)
- Support for one-way flights
- Hotel + flight packages
- Multi-user support with authentication
- Price prediction with ML
- Slack/Discord integration
- Mobile app (React Native)
- Check that your
max_priceisn't too low - Verify origin airport codes are correct (3-letter IATA codes)
- Try increasing
date_flexibility_days - Check SerpApi dashboard for API usage/errors
- Verify Gmail App Password (not your regular password)
- Check that 2FA is enabled on Google account
- Remove spaces from the app password in
.env - Check Gmail "Less secure app access" is OFF (use App Password instead)
- Verify
CRON_SECRETis set in Vercel environment variables - Check Vercel deployment logs for errors
- Free tier allows only daily cron jobs (weekly is fine)
- Test manually with curl to the
/api/cronendpoint
- Check that all three Supabase env vars are set correctly
- Verify the migration was run successfully
- Check Supabase dashboard for connection limits
- Make sure anon key and service role key aren't swapped
- Free tier: 100 searches/month
- Current usage: ~48/month with default settings
- Reduce origin airports or date ranges if needed
- Check usage on SerpApi dashboard
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
MIT License - Feel free to use for personal or commercial projects.
- SerpApi Docs: serpapi.com/google-flights-api
- Supabase Docs: supabase.com/docs
- Vercel Docs: vercel.com/docs
- Next.js Docs: nextjs.org/docs
Happy traveling!
Made with ❤️ for budget-conscious travelers