๐Ÿ“ฑ SubXtract: A Clean and Offline-First Subscription Tracker Built with Expo

SubXtract

Mohit Kumar

Mohit Kumar

6 min read

Apr 19, 2025

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:

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?


๐Ÿ“ฆ 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:

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!