Track product prices across e-commerce sites and get alerts on price drops. Built with Next.js, Firecrawl, and Supabase.
- π Track Any Product - Works with Amazon, Zara, Walmart, and more
- π Price History Charts - Interactive graphs showing price trends over time
- π Google Authentication - Secure sign-in with Google OAuth
- π Automated Daily Checks - Scheduled cron jobs check prices automatically
- π§ Email Alerts - Get notified when prices drop via Resend
- Next.js 16 - React framework with App Router
- Firecrawl - Web data extraction API
- Handles JavaScript rendering
- Rotating proxies & anti-bot bypass
- Structured data extraction with AI
- Works across different e-commerce sites
- Supabase - Backend platform
- PostgreSQL Database
- Google Authentication
- Row Level Security (RLS)
- pg_cron for scheduled jobs
- Resend - Transactional emails
- shadcn/ui - UI component library
- Recharts - Interactive charts
- Tailwind CSS - Styling
Before you begin, ensure you have:
- Node.js 18+ installed or bun installed
- A Supabase account
- A Firecrawl account
- A Resend account
- Google OAuth credentials from Google Cloud Console
git clone https://github.com/muditkalra/Costtrack
cd Costtrack
bun install- Create a new project at supabase.com
- Wait for the project to be ready
Go to SQL Editor in your Supabase dashboard and run these:
Database Schema
-- Enable UUID extension
create extension if not exists "uuid-ossp";
-- Products table
create table products (
id uuid primary key default uuid_generate_v4(),
user_id uuid references auth.users(id) on delete cascade not null,
url text not null,
name text not null,
current_price numeric(10,2) not null,
currency text not null default 'USD',
image_url text,
created_at timestamp with time zone default now(),
updated_at timestamp with time zone default now()
);
-- Price history table
create table price_history (
id uuid primary key default uuid_generate_v4(),
product_id uuid references products(id) on delete cascade not null,
price numeric(10,2) not null,
currency text not null,
checked_at timestamp with time zone default now()
);
-- Add unique constraint for upsert functionality
ALTER TABLE products
ADD CONSTRAINT products_user_url_unique UNIQUE (user_id, url);
-- Enable Row Level Security
alter table products enable row level security;
alter table price_history enable row level security;
-- Policies for products
create policy "Users can view their own products"
on products for select
using (auth.uid() = user_id);
create policy "Users can insert their own products"
on products for insert
with check (auth.uid() = user_id);
create policy "Users can update their own products"
on products for update
using (auth.uid() = user_id);
create policy "Users can delete their own products"
on products for delete
using (auth.uid() = user_id);
-- Policies for price_history
create policy "Users can view price history for their products"
on price_history for select
using (
exists (
select 1 from products
where products.id = price_history.product_id
and products.user_id = auth.uid()
)
);
-- Indexes for performance
create index products_user_id_idx on products(user_id);
create index price_history_product_id_idx on price_history(product_id);
create index price_history_checked_at_idx on price_history(checked_at desc);Setup Cron Job
-- Enable required extensions
CREATE EXTENSION IF NOT EXISTS pg_cron;
CREATE EXTENSION IF NOT EXISTS pg_net;
-- Create function to trigger price check via HTTP
CREATE OR REPLACE FUNCTION trigger_price_check()
RETURNS void
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
BEGIN
PERFORM net.http_post(
url := 'https://your-app-url.vercel.app/api/cron/check-prices',
headers := jsonb_build_object(
'Content-Type', 'application/json',
'Authorization', 'Bearer YOUR_CRON_SECRET_HERE'
)
);
END;
$$;
-- Schedule cron job to run daily at 9 AM UTC
SELECT cron.schedule(
'daily-price-check',
'0 9 * * *',
'SELECT trigger_price_check();'
);Note: Update the URL and Authorization Bearer token in the function after deployment.
- Go to Authentication β Providers in Supabase
- Enable Google provider
- Get OAuth credentials from Google Cloud Console:
- Create a new project or select existing
- Enable Google+ API
- Create OAuth 2.0 credentials
- Add authorized redirect URI:
https://<your-project>.supabase.co/auth/v1/callback
- Copy Client ID and Client Secret to Supabase
- Go to Settings β API
- Copy your Project URL
- Copy your anon/public key
- Copy your service_role key (keep this secret!)
- Sign up at firecrawl.dev
- Go to dashboard and get your API key
- Sign up at resend.com
- Get your API key from the dashboard
- (Optional) Add and verify your domain for custom email addresses
Create .env in the root directory, for your reference .env.example given:
# Supabase
NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=your_supabase_publishable_key
SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key
# Firecrawl
FIRECRAWL_API_KEY=your_firecrawl_api_key
# Resend
RESEND_API_KEY=your_resend_api_key
RESEND_FROM_EMAIL=onboarding@resend.dev
# Cron Job Security (generate with: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))")
CRON_SECRET=your_generated_cron_secret
# App URL
NEXT_PUBLIC_APP_URL=http://localhost:3000Generate CRON_SECRET:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"bun run dev-
Install Vercel CLI (optional)
npm install -g vercel
-
Deploy
vercel --prod
Or connect your GitHub repository to Vercel for automatic deployments.
-
Add Environment Variables in Vercel
Go to your project settings and add all variables from
.env:NEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_ANON_KEYSUPABASE_SERVICE_ROLE_KEYβ οΈ FIRECRAWL_API_KEYRESEND_API_KEYRESEND_FROM_EMAILCRON_SECRETNEXT_PUBLIC_APP_URL(set to your Vercel URL)
-
Update Supabase Cron Function
After deployment, update the cron function with your production URL:
CREATE OR REPLACE FUNCTION trigger_price_check() RETURNS void LANGUAGE plpgsql SECURITY DEFINER AS $$ BEGIN PERFORM net.http_post( url := 'https://<your_app_name>.vercel.app/api/cron/check-prices', headers := jsonb_build_object( 'Content-Type', 'application/json', 'Authorization', 'Bearer your_actual_cron_secret' ) ); END; $$;
-
Update Google OAuth Redirect URI
Add your Vercel domain to Google Cloud Console authorized redirect URIs.
- User adds product - Paste any e-commerce URL on the homepage
- Firecrawl scrapes - Instantly extracts product name, price, currency, and image
- Data stored - Product saved to Supabase with Row Level Security
- View tracking - See current price and interactive price history chart
- Supabase pg_cron - Runs daily at 9 AM UTC
- Triggers API endpoint - Makes secure POST request to
/api/cron/check-prices - Firecrawl scrapes all products - Updates prices for all tracked products
- Updates database - Saves new prices and adds to history if changed
- Sends email alerts - Notifies users via Resend when prices drop
Firecrawl solves the hard problems of web scraping:
- β JavaScript Rendering - Handles dynamic content loaded via JS
- β Anti-bot Bypass - Built-in mechanisms to avoid detection
- β Rotating Proxies - Prevents IP blocking
- β AI-Powered Extraction - Uses prompts to extract structured data
- β Multi-site Support - Same code works across different e-commerce platforms
- β Fast & Reliable - Built for production use
No need to maintain brittle, site-specific scrapers!
costtrack/
βββ app/
β βββ page.tsx # Landing page with product input
| βββactions
β βββ product.ts # Server actions for DB operations
β βββ auth/
β β βββ callback/
β β βββ route.ts # OAuth callback handler
β βββ api/
β βββ cron/
β βββ check-prices/
β βββ route.ts # Cron endpoint for price checks
βββ components/
β βββ ui/ # shadcn/ui components
β βββ AddProductForm.tsx # Product URL input with auth modal
β βββ ProductCard.tsx # Product display with chart toggle
β βββ PriceChart.tsx # Recharts price history
β βββ AuthModal.tsx # Google sign-in modal
βββ lib/
| βββ supabase/
β βββ client.ts # Browser Supabase client
β βββ server.ts # Server Supabase client
β βββ proxy.ts # Session refresh middleware
β βββ firecrawl.ts # Firecrawl API integration
β βββ email.ts # Resend email templates
β βββ utils.ts # Utility functions
βββ utils/
β βββ SvgIcon.ts # Svg icons Utility fuctions
βββ proxy.ts # Next.js 15 proxy (replaces middleware)
βββ .env.example # Example Environment variables
POST https://localhost:3000/api/cron/check-prices
"Authorization": Bearer your_cron_secret
"Content-Type": application/jsonCheck if cron is scheduled:
SELECT * FROM cron.job;View cron run history:
SELECT * FROM cron.job_run_details
ORDER BY start_time DESC
LIMIT 10;Edit the cron expression in supabase:
-- Daily at 9 AM UTC
'0 9 * * *'
-- Every 6 hours
'0 */6 * * *'
-- Daily at 9 AM and 9 PM
'0 9,21 * * *'
-- Every Monday at 9 AM
'0 9 * * 1'Customize the email template in lib/email.ts - modify HTML, styling, or content.
Update the Firecrawl prompt in lib/firecrawl.ts to extract additional fields:
prompt: "Extract product name, price, currency, image URL, brand, rating, and availability";- Make sure
SUPABASE_SERVICE_ROLE_KEYis set in Vercel - Service role bypasses RLS to access all products
- Some sites may be difficult to scrape
- Check Firecrawl dashboard for error logs
- Try adjusting the extraction prompt
- Verify
RESEND_API_KEYis correct - Check Resend dashboard for delivery logs
- Ensure sender email is verified (for custom domains)
- Check cron job exists:
SELECT * FROM cron.job; - Verify the function URL and Authorization header are correct
- Check Supabase logs for errors
Contributions are welcome! Please follow these steps:
- 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
Built by Mudit kalra using Next.js, Firecrawl, and Supabase