Feature spec
IntermediateCategory
notifications-alerts
Build with AI
4–6 hours with Lovable or V0
Custom build
1–2 weeks custom dev
Running cost
$0–5/mo up to 100 users · $50–100/mo at 10K users
Works on
Everything it takes to ship Price Alerts — parts, prompts, and real costs.
Price alerts need four pieces: a target-price form on the product detail page, a price monitoring cron job (Supabase Edge Function or Vercel Cron running every 15–60 minutes), an alert evaluation SQL query that fires only once per threshold cross, and a notification sender (FCM for mobile push, web-push for browser, Resend for email). With Lovable or V0 you can ship this in 4–6 hours for $0–5/month at small scale — FCM push delivery is free at any volume and Resend covers early email volume on the free tier.
What Price Alerts Actually Are
Price alerts let shoppers set a target price on a product and get notified the moment the price drops to or below that target — without checking back manually. For e-commerce and marketplace apps, this is a conversion engine: users who set a price alert have already decided to buy, so the notification converts at significantly higher rates than typical marketing emails. The mechanics are a monitoring cron job that compares the current product price against every active alert for that product, plus a deduplication system that prevents the same alert from firing every time the cron runs while the price stays low.
What users consider table stakes in 2026
- Set a target price directly on the product detail page — no separate section to navigate to — with the input pre-filled at 10% below the current price as a sensible default
- Notification fires when price drops to or at or below the target — users expect 'at or below', not strictly below
- Alert persists across sessions and browser tabs without the user needing to re-set it after logging out and back in
- Active alerts list shows current price versus target price so users can see how close each product is to triggering
- Alert auto-expires after 90 days so stale alerts don't accumulate and confuse users; expiry date is visible and editable
- One-tap to buy directly from the notification payload — the deep link lands on the product page with the cart action immediately accessible
Anatomy of the Feature
Seven components across four layers. Lovable and V0 generate the UI and the basic cron setup well. The deduplication logic and the FCM mobile push setup are where first builds fail.
Set Alert Button
UIA 'Notify me when price drops to $X' button on the product detail page. Opens a modal (shadcn/ui Dialog on web, Flutter AlertDialog on mobile) with a target price number input pre-filled at 10% below the current price. Saves to the price_alerts table on submit.
Note: Pre-fill the target price input at current_price * 0.90 — it gets the form opened and converted faster than an empty input.
Price Alert Form
UITarget price number input with currency symbol and locale-aware formatting (USD, EUR, GBP). Optional channel toggle (email or push, or both). Validated with React Hook Form + Zod on web or flutter_form_builder on Flutter. Inserts into price_alerts table with expires_at set to NOW() + 90 days.
Note: Accept currency input with commas (e.g. '1,299') and strip formatting before saving — Zod's z.coerce.number() handles this cleanly.
Price Monitoring Job
BackendSupabase Edge Function or Vercel Cron running every 15–60 minutes. Queries the products table for prices that have changed since the last run (compare against a cached previous_price column or the price_history table). For each changed product, passes the new price to the Alert Trigger Engine for evaluation.
Note: Don't scan all products every run — index on updated_at and compare against last_run_at from a cron_runs metadata table to limit the scan to recently changed products.
Alert Trigger Engine
BackendSQL function: SELECT pa.* FROM price_alerts pa JOIN products p ON pa.product_id = p.id WHERE p.current_price <= pa.target_price AND pa.is_active = true AND pa.last_fired_at IS NULL AND pa.expires_at > NOW(). Sets is_active = false after firing so the alert doesn't re-trigger while the price stays low. User can reset the alert from the dashboard if they want to be notified again.
Note: Setting is_active = false after firing (rather than relying on last_fired_at cooldown) is the cleanest deduplication pattern for price alerts — the condition is now 'permanently met' until the user explicitly resets it.
Push Notification
ServiceFirebase Cloud Messaging (FCM) for mobile push via the firebase_messaging Flutter package on native apps. Web-push with VAPID keys for browser push on web. Notification payload includes product name, current price, target price, and a deep link to the product page.
Note: FCM requires APNs (Apple Push Notification service) certificate for iOS — upload the APNs Auth Key in Firebase Console → Project Settings → Cloud Messaging → iOS app configuration.
Email Notification
ServiceResend transactional email with product image, a price comparison table (was $X, now $Y, your target was $Z), and a prominent 'Buy Now' CTA button. Sent from a Supabase Edge Function using RESEND_API_KEY from Supabase Secrets.
Note: Include the product image by URL in the email template — visual emails with product photos convert substantially better than text-only price drop emails.
Alert Management Screen
UIList of all active price alerts with product image thumbnail, current price, target price, a visual progress bar showing how close the current price is to the target, expiry date, and edit/delete/pause controls. Loaded from price_alerts with a JOIN to products for current prices.
Note: The progress bar (current_price - target_price) / (original_price - target_price) gives users a satisfying sense of how close they are to their target.
The data model
Two tables cover alerts and price history. Run this in the Supabase SQL editor. The price_alerts table references your existing products table — adjust the foreign key if your products table has a different name.
1create table public.price_alerts (2 id uuid primary key default gen_random_uuid(),3 user_id uuid references auth.users(id) on delete cascade not null,4 product_id uuid references public.products(id) on delete cascade not null,5 target_price numeric not null check (target_price > 0),6 last_fired_at timestamptz,7 is_active bool not null default true,8 expires_at timestamptz not null default (now() + interval '90 days'),9 created_at timestamptz not null default now()10);1112create table public.price_history (13 id uuid primary key default gen_random_uuid(),14 product_id uuid references public.products(id) on delete cascade not null,15 price numeric not null,16 recorded_at timestamptz not null default now()17);1819alter table public.price_alerts enable row level security;20alter table public.price_history enable row level security;2122create policy "Users manage own price alerts"23 on public.price_alerts for all24 using (auth.uid() = user_id)25 with check (auth.uid() = user_id);2627create policy "Authenticated users view price history"28 on public.price_history for select29 using (auth.role() = 'authenticated');3031create policy "Service role inserts price history"32 on public.price_history for insert33 with check (auth.role() = 'service_role');3435create index price_alerts_product_active_idx36 on public.price_alerts (product_id, is_active)37 where is_active = true;3839create index price_alerts_user_idx40 on public.price_alerts (user_id, created_at desc);4142create index price_alerts_expiry_idx43 on public.price_alerts (expires_at)44 where is_active = true;4546create index price_history_product_time_idx47 on public.price_history (product_id, recorded_at desc);Heads up: The partial index on active alerts keyed by product_id makes the evaluation query fast — for a given product price change, finding all active alerts for that product is a single index scan rather than a full table scan. The expiry index supports a nightly cleanup job that auto-deactivates alerts past their expires_at date.
Build it — pick your path
Each tool fits this feature differently. Switch tabs to compare fit, time, the exact steps, and a copy-paste prompt.
Custom development for price alert infrastructure that must react to price changes in sub-minute latency via Supabase Realtime triggers, support multi-currency with live FX conversion, or deliver via SMS as a mandatory channel.
Step by step
- 1Supabase Realtime trigger on the products table price column: when current_price changes, an Edge Function is triggered immediately via a Postgres trigger + net.http_post() without waiting for the next cron run
- 2Multi-currency alert engine: store target_price in the user's preferred currency, convert to product base currency at evaluation time using an FX rate table updated hourly from the European Central Bank API
- 3SMS delivery via Twilio for mandatory channel: send a short message with product name, price, and a shortened buy link; handle Twilio delivery receipts to confirm message received
- 4Price history chart on the alert management screen using Recharts — line chart showing price_history for the last 90 days with the target_price as a horizontal threshold line
Where this path bites
- Supabase Realtime trigger on a high-write products table (frequent price updates) may introduce notification latency if the trigger function queue backs up
- Twilio SMS adds per-message cost ($0.0079/message in US) plus a phone number rental fee (~$1/mo) — significant at scale
Third-party services you'll need
Push delivery is free. Email costs appear at moderate scale. The main variable cost at high scale is the Supabase plan needed for pg_cron and Edge Function execution volume.
| Service | What it does | Free tier | Paid from |
|---|---|---|---|
| Firebase Cloud Messaging | Mobile push delivery on iOS and Android via firebase_messaging; no per-message cost; Blaze plan required for Cloud Functions | Free for all push delivery at any volume | Free push delivery; Cloud Functions billed on Blaze pay-as-you-go (approx $0.40 per million invocations) |
| web-push | Open-source npm package for browser push notification delivery using VAPID keys; zero per-message cost | Open-source, zero cost | Free |
| Resend | Transactional email for price drop notifications; HTML template with product image, price comparison, and buy CTA | 100 emails/day, 3K/mo | Pro $20/mo for 50K/mo |
| Supabase pg_cron | Server-side scheduler for the price monitoring cron job; runs the Edge Function every 15–60 minutes | Not available on Supabase free tier | Included in Supabase Pro $25/mo (approx) |
Swipe the table sideways to see pricing.
What it costs to run
Drag through the tiers to see how your monthly bill scales with users — no surprises later.
Estimated monthly running cost
Supabase free tier handles DB and Edge Function calls. Resend free tier covers email volume at 100 users. FCM is free. Use cron-job.org (free external cron) to call the Edge Function URL on schedule instead of pg_cron.
Estimates use verified 2026 pricing and assume typical usage per user. Your real bill depends on activity, storage, and third-party plans.
What breaks when AI tools build this
The failures people actually hit on their first build — the symptom, why it happens, and the exact fix.
Same price alert fires every time the cron runs while price stays low
Symptom: The alert evaluation query checks whether current_price <= target_price, which remains true as long as the price stays at or below the target. Without a definitive 'fired' state, every cron run sends a new notification. Using only a last_fired_at cooldown (e.g. don't re-fire within 1 hour) still lets the alert fire repeatedly every hour for as long as the price is low.
Fix: Set is_active = false immediately after firing, inside the same database transaction as the notification send. This is a permanent state: the alert won't fire again until the user explicitly resets it from the dashboard. Add a 'Reset alert' button on the alert card that sets is_active = true, so users can opt back in to future notifications on the same product.
FCM push works on Android but not on iOS in FlutterFlow
Symptom: iOS FCM push requires an APNs (Apple Push Notification service) Auth Key to be uploaded in the Firebase Console, in addition to the google-services.json configuration. FlutterFlow connects to Firebase and configures Android FCM automatically, but doesn't prompt the developer to upload the APNs key. Without it, iOS devices register for FCM but never receive messages — the registration appears to succeed, making the issue invisible until testing on a real iPhone.
Fix: In the Apple Developer Portal, go to Certificates, Identifiers & Profiles → Keys → create a new key with the Apple Push Notifications Service (APNs) capability. Download the .p8 file. In Firebase Console → Project Settings → Cloud Messaging → iOS app configuration, upload the .p8 file with the Key ID and Team ID. Regenerate and re-upload this key if it expires or if you rotate your Apple Developer membership.
Alert management screen is slow for users with 50+ active alerts
Symptom: The default Supabase query for a user's price_alerts table fetches all rows at once with a JOIN to the products table for current prices. A user who has set alerts on 100 products receives a 100-row JSON payload on every page load, causing a noticeable render delay on mobile and a flash of loading state on every navigation to the page.
Fix: Add .range(from, to) pagination to the Supabase query — start with 20 alerts per page and a 'Load more' button. Use SWR or React Query with a stale-while-revalidate strategy to avoid blocking navigation. On mobile Flutter, use Supabase's stream() with a range parameter and a ListView.builder that renders lazily — only the visible rows are rendered at any time.
Alert fires when product price temporarily errors and returns $0
Symptom: If the product price feed has a bug, a data import error, or a momentary API outage, the current_price column might be set to 0 or NULL. Any alert with a target_price > 0 satisfies the condition current_price <= target_price when price is 0, so every active alert fires simultaneously — which looks like a mass notification bug to users.
Fix: Add a guard in the alert evaluation function: skip any product where new_price <= 0 OR new_price IS NULL before comparing against target prices. Log anomalous price values to a price_anomalies table for review. Optionally, add a plausibility check: if the new price is more than 90% lower than the previous recorded price in price_history within the last hour, treat it as suspect and skip alert evaluation for that product until the price stabilizes.
Best practices
Pre-fill the target price input at 10% below the current price — users who see a number already entered convert to saving alerts at much higher rates than users who see an empty input
Set alerts to is_active = false (not just cooldown) after firing — price drop conditions can persist for days, and hourly re-notification is a fast way to get unsubscribes
Add a 'Reset alert' button so users can opt back in after an alert fires without deleting and recreating the alert with the same parameters
Guard against $0 and NULL prices in your evaluation query — a data error can trigger thousands of simultaneous false alerts
Auto-expire alerts after 90 days (default) with an editable expires_at field — stale alerts are noise on the management screen and waste evaluation cycles
Include the product image in email notifications — price drop emails with product visuals have measurably higher click-through rates than text-only variants
Paginate the alert management screen at 20 items — users with large wishlists will set many alerts and the page must stay fast
When You Need Custom Development
Lovable and V0 handle polling-based price alerts for standard e-commerce flows. These requirements exceed what AI tools generate reliably:
- Your marketplace has thousands of products with prices updating multiple times per hour — sub-minute detection requires a Supabase Realtime trigger on the price column instead of a polling cron, which demands careful queue management
- Multi-currency support with live FX conversion is required — target prices set in EUR need to compare against USD prices at the current exchange rate at evaluation time, not the rate at alert creation time
- SMS delivery via Twilio is a mandatory channel (for markets where mobile push adoption is low or where your user base expects SMS confirmation)
- Integration with an external price tracking API (CamelCamelCamel-style) to monitor prices on third-party platforms rather than your own product catalog
RapidDev builds these features for production
Real auth, database, and payments — fixed price, delivered in weeks. You own 100% of the code.
Frequently asked questions
How quickly will I be notified after a price drops?
With a polling-based approach (Lovable or V0), the notification fires within the cron interval — typically 15–60 minutes after the price changes. For most e-commerce apps, 30-minute latency is acceptable. If your products have flash sales where prices change and sell out within minutes, you need a Supabase Realtime trigger on the price column that fires the evaluation immediately on every price update, which requires custom development.
Can I set a price alert without creating an account?
Not with this architecture — price alerts are stored in the database linked to a user_id, which requires authentication to persist across sessions. You could implement a guest alert using a browser cookie and email address only, but the alert would be lost if the user clears cookies. The standard pattern is to require a lightweight account creation (email/password or Google OAuth) before setting an alert, since most users who want to track prices are willing to create a free account.
Will the alert fire for a small price drop of just $1?
Yes — the alert fires whenever current_price <= target_price, regardless of the size of the drop. If you want to prevent alerts for trivially small drops (e.g., only notify on drops of 5% or more), add a minimum_discount_pct column to the price_alerts table and add a condition in the evaluation query: AND (original_price - current_price) / original_price >= minimum_discount_pct. Store the original_price at alert creation time as a reference point.
What if the product goes out of stock before the price drops?
When the product becomes unavailable (is_available = false on the products table), the monitoring job should pause the alert (set is_active = false) but not delete it. Show an 'Out of stock' badge on the alert card in the management screen. When the product comes back in stock, automatically resume the alert (set is_active = true) — this creates a better experience than forcing users to recreate their alert when stock returns.
Can I set alerts on multiple products at once?
That depends on the UI you build. The standard pattern is one alert per product — users set an alert on each product detail page individually. You could add a 'bulk alert' feature on a wishlist or cart page that sets a 10% discount alert on all items in one action. Each alert is stored as a separate row in price_alerts, so the backend handles multiples natively.
Do alerts expire automatically?
Yes, in the schema above, expires_at defaults to 90 days from creation. A nightly cleanup query (or pg_cron job) sets is_active = false for all rows where expires_at < NOW(). The expiry date is visible on the alert management screen, and users can edit it to extend it. 90 days covers most seasonal shopping cycles while keeping the active alert table clean.
How do I cancel all my price alerts at once?
Add a 'Clear all alerts' button on the alert management page that runs UPDATE price_alerts SET is_active = false WHERE user_id = auth.uid(). For users who want to permanently delete rather than just pause, add a 'Delete all' button that runs DELETE FROM price_alerts WHERE user_id = auth.uid(). Give the delete action a confirmation dialog — this action is not reversible.
Does this work on mobile apps too?
Yes — the Supabase backend works identically for both web and mobile. On mobile Flutter apps, replace browser push (VAPID/web-push) with Firebase Cloud Messaging (firebase_messaging package), which delivers push notifications to iOS and Android even when the app is fully closed. The price_alerts database schema, the cron monitoring job, and the email delivery via Resend work identically on both platforms.
Need this feature production-ready?
RapidDev builds price alerts into real apps — auth, database, payments — at $13K–$25K.
Book a free consultation30-min call. No commitment.