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
- flutter
- revenuecat
- supabase
Log in or sign up for Devpost to join the conversation.