Back to blog
SubXtract - A Subscription Tracker App
react nativeexpozustandreanimated

SubXtract - A Subscription Tracker App

Mohit Kumar
Mohit KumarSenior Software Engineer
April 19, 2025
6 min read

Managing your monthly subscriptions shouldnโ€™t be a mess of reminders and scattered notes. That's the idea behind SubXtract โ€” a thoughtfully designed subscription tracking app that helps users keep track of their recurring expenses in one simple place.

But behind the clean UI and user-friendly design lies a robust offline-first tech stack, built to ensure performance, reliability, and a delightful experience even without internet.

In this post, Iโ€™ll walk you through what SubXtract is, what tech powers it, and how I implemented key features using Expo, Zustand, MMKV, and Reanimated.


๐Ÿงน What is SubXtract?

SubXtract helps users:

  • Track recurring subscriptions like Netflix, Spotify, Rent, etc.
  • Add billing details like start date, cycle (monthly, yearly, etc.), and custom notes
  • Set preferred currency and theme
  • Toggle auto-renew status
  • Archive old/canceled subscriptions
  • Get notified about upcoming payments
  • Use the app completely offline

With an elegant UI and local-first architecture, SubXtract focuses on privacy, speed, and user control.


๐Ÿ› ๏ธ The Tech Stack

โšก Expo

SubXtract is built with Expo for rapid development, native APIs out of the box, and easy deployment. I used the Bare workflow when necessary, especially for MMKV and notification features.

Why Expo?

  • Fast iteration cycle
  • OTA updates
  • Great community ecosystem

๐Ÿ“ฆ Zustand + MMKV for Local-First State Management

SubXtract stores all user data locally on the device using a combination of Zustand (for state management) and MMKV (for super fast key-value storage).

๐Ÿ” Setting up MMKV

// storage.ts
import { MMKV } from "react-native-mmkv"
 
export const storage = new MMKV()

๐Ÿง  Zustand with Persistence Middleware

import { create } from "zustand"
import { persist } from "zustand/middleware"
import { storage } from "./storage"
 
export const useSubscriptionStore = create(
  persist(
    (set) => ({
      subscriptions: [],
      addSubscription: (sub) =>
        set((state) => ({
          subscriptions: [...state.subscriptions, sub],
        })),
      toggleRenewal: (id) =>
        set((state) => ({
          subscriptions: state.subscriptions.map((s) =>
            s.id === id ? { ...s, autoRenew: !s.autoRenew } : s
          ),
        })),
      archiveSubscription: (id) =>
        set((state) => ({
          subscriptions: state.subscriptions.map((s) =>
            s.id === id ? { ...s, archived: true } : s
          ),
        })),
    }),
    {
      name: "subxtract-store",
      storage: {
        getItem: storage.getString.bind(storage),
        setItem: storage.set.bind(storage),
        removeItem: storage.delete.bind(storage),
      },
    }
  )
)

This setup ensures lightning-fast access to your app's state, even when offline.


๐ŸŽญ Reanimated for Smooth Animations

To give users a fluid and polished experience, I used React Native Reanimated for subtle animations across components like the add/edit modal, theme transitions, and button presses.

๐ŸŽฎ Simple Reanimated Example

import Animated, {
  useSharedValue,
  withSpring,
  useAnimatedStyle,
} from "react-native-reanimated"
 
const offset = useSharedValue(0)
 
const animatedStyle = useAnimatedStyle(() => {
  return {
    transform: [{ translateY: withSpring(offset.value) }],
  }
})

๐ŸŒˆ Custom Theming

Users can select between light, dark, or system themes. A Zustand store syncs the selected theme across the app, and I use context + MMKV to persist it.

export const useThemeStore = create(
  persist(
    (set) => ({
      theme: "system",
      setTheme: (theme) => set({ theme }),
    }),
    {
      name: "theme-settings",
      storage: {
        getItem: storage.getString.bind(storage),
        setItem: storage.set.bind(storage),
        removeItem: storage.delete.bind(storage),
      },
    }
  )
)

๐Ÿ”” Local Notifications

SubXtract notifies users about upcoming payments based on their billing cycle. This is implemented using Expo Notifications and scheduled jobs at the time of adding a subscription.


๐Ÿš€ Check Out SubXtract on Product Hunt

If you like what you see, don't forget to check out SubXtract on Product Hunt and show your support!


๐Ÿ“Š Coming Soon: Analytics + Budgeting

Iโ€™m actively working on adding:

  • ๐Ÿ’ธ Budget Cap Alerts
  • ๐Ÿ“ˆ Analytics and trends for monthly/yearly spend
  • ๐Ÿ—–๏ธ Upcoming view to filter subscriptions by due date

These features will make SubXtract even more powerful and insightful for users managing multiple recurring expenses.


โœจ Final Thoughts

SubXtract is built with care to provide a fast, offline-first, and privacy-respecting experience for tracking subscriptions. Whether you're a minimalist user or someone who manages a dozen recurring payments, this app has you covered.

If you're curious to try it out, download it now on the App Store.


Thanks for reading! ๐Ÿ’™
Happy tracking!

Enjoyed this article?

Let's build something together

Have a project in mind or just want to chat about React and mobile development? I'd love to hear from you.

Email me
โ† All posts