Inspiration

It started with Amy, a calorie-tracking app that is just a text box. I'm an avid reader and use Goodreads, but filling in countless forms just to do simple things like updating a page number felt like paperwork. So I combined the two ideas: talk naturally, and cactus does the rest.

What it does

cactus is a reading tracker you talk to. Type what you did in plain words, like "finished dune, 4.5 stars, started circe yesterday", and it updates your shelf, progress, ratings and streak.

Free

  • A classic command grammar, plus an on-device parser that understands everyday sentences, forgives typos and matches titles against your shelf.
  • Shelves, series, tags, comments and owned editions.
  • Search across Google Books, with an Open Library fallback.
  • A yearly reading goal and a reading-days heatmap.
  • A real offline mode that syncs when you're back online.
  • Goodreads import and CSV export.

cactus pro (a RevenueCat subscription)

  • An AI that turns a whole rambling message into several actions.
  • Deeper stats, memory notes and recommendations.
  • Customisation: themes, fonts and 16 app icons.

How I built it

Flutter front end, Supabase backend (Postgres with row-level security, anonymous auth, edge functions), and RevenueCat for subscriptions.

  • RevenueCat: the live entitlement drives every pro gate, and every gate fails closed. The paywall is always dismissible, opens on the feature you tapped, and shows the store's own localized prices.
  • No sign-up wall: every reader gets an anonymous account on first launch. An optional verified email link secures the library across devices.
  • Secrets stay server-side: the AI key lives in a Supabase edge function, never on the device, and each call is rate-limited per reader.

Challenges I ran into

  • Flaky book data. Google Books returned random 503s and ran out of its free quota. I added a server-side retry proxy, a keyless Open Library fallback and caching.
  • Offline writes in the right order. Queued changes have to replay in sequence, or an old value overwrites a newer one after reconnecting.
  • Language without a model. The free parser needed fuzzy title matching and date phrases like "yesterday" without misreading titles such as Pride and Prejudice.
  • Balancing free and pro. The free tier had to be genuinely useful, or nobody would ever see a reason to upgrade, while pro still had to feel worth paying for.
  • Designing for readers, not developers. Most readers won't memorise commands, so I built an on-device parser that understands everyday sentences, and tested it with real readers to see what worked and what didn't.

Accomplishments that I'm proud of

  • A free tier that's genuinely useful, with pro as a real upgrade rather than a lock on the basics.
  • 800+ automated tests, and a codebase that passes strict static analysis with zero issues.
  • A genuine offline mode.
  • Fixing things I found frustrating in other trackers: slow forms, no offline support, and an account wall before you can start.
  • Turning flaky book data into a polished search system that rarely misses.
  • Heavy customisation, so you can use cactus the way you like.
  • The countless easter eggs I hid which create for a fun user experience

What I learned

  • How to integrate RevenueCat properly: entitlements, gating and a paywall that reflects real subscription state.
  • How to build a resilient book search across Google Books and Open Library.
  • How to wire in crash reporting and analytics without sending any reader-written content.
  • How to design a paywall, and what to put in it.

What's next for cactus

  • Adding books while offline (it currently needs a connection).
  • Stronger recommendations and reading-time insights.
  • A release on Google Play and the App Store.
  • Wider testing with readers to find and fix pain points.
  • Improve speed of Pro mode

Built With

Share this project:

Updates

Submission history