How We Built
Subcut
A native iOS app that tracks your subscriptions without tracking you. Here's what's under the hood - and why we made the choices we did.
The Stack
No Electron. No React Native. No web views pretending to be native. Subcut is built the way Apple intended.
SwiftUI
100% SwiftUI with iOS 17+ features. Declarative UI, @Observable macro for state management, spring animations throughout. No UIKit bridges needed.
Core Data + CloudKit
Local-first persistence with iCloud sync. Your data lives on your device first, syncs to iCloud second. Three-tier fallback: CloudKit, local SQLite, in-memory.
RevenueCat
Handles in-app purchases, subscription management, and entitlements. Monthly, yearly, and lifetime plans - all managed through RevenueCat's SDK and dashboard.
Gemini AI
Powers the email import feature. When our local pattern matching (80+ known services) can't identify a subscription, AI extracts the details from email bodies.
Keychain + FaceID
API keys stored in Keychain. Biometric authentication via LocalAuthentication framework. Session timeouts, failed-attempt lockouts, the works.
Mixpanel
Lightweight analytics for understanding how people use the app. Disabled in debug builds. No personally identifiable information is ever tracked.
Architecture
MVVM with dependency injection. Clean layer separation. No spaghetti.
App Layer
Entry point, service initialization, tab navigation
Feature Modules
Calendar, Subscriptions, Import, Settings, Paywall, Onboarding
Core Layer
Models, Services, Persistence (Core Data + CloudKit), Utilities
State Management
Global state lives in an @Observable AppState class - Pro status, selected tab, biometric lock, user settings. Injected via SwiftUI's environment system.
Feature-level state stays in per-screen ViewModels. No bloated god objects. Each screen owns its own state.
Dependency Injection
All services are bundled into a DependencyContainer - a simple Sendable struct - and injected via @Environment. No singletons scattered across the codebase.
Ships with both .live and .mock implementations for previews and testing.
The Import Pipeline
Three ways in. Zero bank credentials required.
Email Import
Gmail OAuth (with PKCE) scans your inbox for subscription receipts. Known services are matched locally against 80+ domain patterns - instant, no API cost. Unknown services get sent to Gemini AI for extraction. Two-stage pipeline: fast local matching first, AI fallback second.
Bank Statement Upload
Upload an .xlsx bank statement and Subcut parses it with CoreXLSX. Recurring charges are detected through pattern matching. No bank login, no Plaid, no third-party access to your accounts. You export, you upload, we parse. That's it.
Apple App Store Import
StoreKit 2 integration pulls in subscriptions managed through the App Store. If you're paying for something through Apple's ecosystem, Subcut knows about it.
Monetization with RevenueCat
We use RevenueCat to handle the hard parts of iOS subscriptions so we can focus on the product.
Soft Paywall Model
Free users can add unlimited subscriptions but only see the first six in full detail. The rest appear blurred - a gentle nudge, not a hard wall.
Tapping a blurred subscription opens the paywall. After upgrading, the blur fades with a smooth animation. It feels like unlocking, not purchasing.
Plans & Pricing
How RevenueCat Fits In
Entitlements
Single "Subcut Pro" entitlement. RevenueCat's SDK checks status on launch and updates in real-time via delegate callbacks.
Paywall UI
RevenueCatUI provides pre-built paywall components. We wrap them with custom context tracking for analytics.
Analytics
Every paywall view and purchase event is tracked with context - which screen triggered it, which feature was gated.
Privacy Is Architecture, Not Marketing
We didn't add privacy as an afterthought. We built the entire app around it.
On-Device Processing
Bank statement parsing happens entirely on your device. Email pattern matching runs locally for 80+ known services. AI is only called for unknown subscriptions.
No Bank Credentials
We never ask for, store, or transmit bank login credentials. No Plaid integration. No third-party financial data access. Period.
Biometric Security
FaceID/TouchID via LocalAuthentication. Session timeouts after 5 minutes. Lockout after 5 failed attempts. API keys stored in Keychain, not in code.
GDPR Ready
Full account deletion support. Export your data in CSV or JSON (encrypted, if you want). Delete everything in one tap. Data erasure, not data hoarding.
By the Numbers
Languages supported
Currencies
Cancel guides
Auto-detected services
That's How We Built It.
Now Try It.
All of the above powers an app that takes 60 seconds to set up and saves you hundreds a year. Not a bad trade.
Download Free on App Store