A Flutter subscription tracker that automatically detects subscriptions from your Gmail inbox, tracks spending, sends renewal reminders, and helps you manage all your recurring payments in one place.
- Gmail Auto-Scan — Scans your inbox using the Gmail API + Gemini AI (Cloud Function) to extract subscription details (provider, cost, renewal date, billing cycle)
- Manual Entry — Add subscriptions manually with full control over all fields
- Renewal Notifications — Local push notifications at 7 days, 1 day, and same-day before renewal
- Email Reminders — Scheduled Cloud Function sends daily email digests for upcoming renewals
- Price Hike Detection — Tracks price history and alerts you when a subscription's cost increases
- Cost Splitting — Split subscription costs with friends and track your personal share
- Analytics Dashboard — Spending breakdown by category, top subscriptions, monthly/yearly projections
- Privacy Mode — Toggle to hide all cost amounts in the UI
- One-Click Cancel — Direct links to 35+ popular subscription management pages (Netflix, Spotify, etc.)
- Offline-First — Isar local database with background Firestore sync
- Multi-Auth — Google Sign-In, Apple Sign-In, and Email/Password with email verification
- Account Linking — Link multiple auth providers to a single account
lib/
├── main.dart # Entry point, Firebase/Isar/Notification init, auth gate
├── env_config.dart # Environment variables via --dart-define-from-file
├── firebase_options.dart # Firebase platform config (reads from env_config)
│
├── models/
│ ├── subscription.dart # Core Subscription model, Firestore serialization
│ ├── subscription_isar.dart # Isar collection schema
│ └── subscription_isar.g.dart # Generated Isar adapter
│
├── providers/
│ └── providers.dart # All Riverpod providers, SubscriptionRepository,
│ # auto Gmail sync, analytics providers
│
├── services/
│ ├── auth_service.dart # Google/Apple/Email auth, account linking
│ ├── gmail_service.dart # Gmail API integration, email parsing, Cloud Function calls
│ ├── isar_service.dart # Local Isar DB operations (offline-first)
│ └── notification_service.dart # Local notification scheduling & permissions
│
├── screens/
│ ├── auth/
│ │ ├── login_screen.dart # Sign-in screen (Google, Apple, Email)
│ │ ├── verify_email_screen.dart # Email verification flow
│ │ └── link_account_dialog.dart # Link auth providers dialog
│ ├── dashboard/
│ │ ├── dashboard_screen.dart # Main subscription list with filters
│ │ ├── add_subscription_sheet.dart # Manual subscription entry
│ │ └── gmail_import_sheet.dart # Gmail scan results & selective import
│ ├── analytics/
│ │ └── analytics_screen.dart # Spending analytics & charts
│ └── profile/
│ └── profile_screen.dart # User settings, email reminders toggle, test notifications
│
└── widgets/
└── private_cost_text.dart # Privacy-aware cost display widget
functions/
└── src/
└── index.ts # Cloud Functions:
# - analyzeSubscriptionEmails (Gemini AI parsing)
# - sendEmailReminders (daily scheduled emails)
Gmail Inbox
│
▼
Gmail API (googleapis) ──► Cloud Function (Gemini 2.5 Flash)
│ │
│ ▼
│ Structured JSON
│ (provider, cost, date)
│ │
▼ ▼
GmailService ──────────► ExtractedSubscriptionData
│
▼
SubscriptionRepository
│ │
▼ ▼
Isar DB Firestore
(primary) (sync/backup)
│
▼
Riverpod Stream
│
▼
Dashboard UI
- Riverpod for all app state
subscriptionsStreamProvider— Isar stream for instant offline-first UIautoGmailSyncProvider— Background sync with 30-minute cooldownfilteredSubscriptionsProvider— Dashboard filters (All / Active / Renewing Soon)- Analytics providers for spending breakdowns and projections
| Layer | Technology | Purpose |
|---|---|---|
| Local | Isar 3.x | Primary data source, instant reads, offline support |
| Cloud | Firestore | Cross-device sync, backup, email reminder queries |
| Secure | flutter_secure_storage | OAuth tokens (Keychain/Keystore) |
| Category | Package |
|---|---|
| Framework | Flutter 3.x (Dart >=3.4) |
| State | flutter_riverpod |
| Auth | firebase_auth, google_sign_in, sign_in_with_apple |
| Database | isar (local), cloud_firestore (cloud) |
| API | googleapis (Gmail), cloud_functions |
| AI | Gemini 2.5 Flash (via @google/generative-ai in Cloud Functions) |
| Notifications | flutter_local_notifications, timezone |
| UI | google_fonts, flutter_animate, shimmer, cached_network_image |
| Utilities | intl, url_launcher, crypto, uuid, permission_handler |
- Flutter SDK >=3.4.0
- Firebase project with Auth, Firestore, and Cloud Functions enabled
- Google Cloud project with Gmail API enabled
- Node.js 18+ (for Cloud Functions)
-
Clone the repository
git clone https://github.com/yourusername/TogglSub.git cd TogglSub -
Create your
.envfile from the templatecp .env.example .env # Fill in your Firebase API keys -
Firebase configuration files (not in repo — get from Firebase Console)
android/app/google-services.jsonios/Runner/GoogleService-Info.plistmacos/Runner/GoogleService-Info.plist
-
Install dependencies
flutter pub get
-
Generate Isar schemas
dart run build_runner build --delete-conflicting-outputs
-
Deploy Cloud Functions
cd functions npm install # Set the Gemini API key as a Firebase secret firebase functions:secrets:set GEMINI_API_KEY firebase deploy --only functions
-
Run the app
flutter run --dart-define-from-file=.env
# iOS
flutter build ios --dart-define-from-file=.env
# Android
flutter build apk --dart-define-from-file=.envAfter building the APK, you can test it on an Android device or emulator.
- Android device with USB debugging enabled, or Android emulator
- ADB (Android Debug Bridge) installed
-
Build the APK (if not already done):
flutter build apk --dart-define-from-file=.env
-
Locate the APK: The release APK is generated at
apk/app-release.apk -
Install on device:
- Connect your Android device via USB
- Enable USB debugging in Developer Options
- Run:
adb devices # Verify device is connected adb install build/app/outputs/flutter-apk/app-release.apk
-
Install on emulator:
- Start an Android emulator
- Run:
adb install build/app/outputs/flutter-apk/app-release.apk
-
Launch the app:
- Open the app on your device/emulator
- Test features like authentication, subscription management, and notifications
- Ensure Firebase and Gmail API are properly configured for full functionality
- For production testing, use a real device with Google Play Services
- The APK is signed with the debug keystore by default; for release distribution, configure signing in
android/app/build.gradle.kts
- Authentication — Enable Google, Apple, and Email/Password providers
- Firestore — Create database with the security rules in
firestore.rules - Cloud Functions — Deploy functions from the
functions/directory - Gmail API — Enable in Google Cloud Console and configure OAuth consent screen
- Trigger Email Extension (optional) — Install for email reminder delivery
To allow all users (not just test users) to sign in:
- Go to Google Cloud Console > APIs & Services > OAuth consent screen
- Click Publish App to move from Testing to Production
- If using
gmail.readonlyscope, submit for Google verification review
User-scoped access — each user can only read/write their own subscriptions:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId}/{document=**} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
}
}| Function | Trigger | Description |
|---|---|---|
analyzeSubscriptionEmails |
HTTPS Callable | Sends email content to Gemini 2.5 Flash for structured extraction |
sendEmailReminders |
Pub/Sub (daily 9:00 UTC) | Queries Firestore for upcoming renewals, queues reminder emails |
This project is proprietary. All rights reserved.
