Inspiration
Everything about our dog's health lived in five different places. Weight in a paper notebook. Vaccination certificates buried somewhere in the camera roll. What the vet said, in a notes app. When the next heartworm pill was due, in someone's head.
None of it could be found on the evening it actually mattered. wanote is the app we wanted in that moment.
What it does
wanote keeps one dog's whole health record in one place.
- Weight, charted. Every entry builds the curve, so a puppy's growth or a diet is easy to follow.
- Daily records. Bathroom (with stool condition and urine colour), appetite, mood, and a photo when something is hard to put into words.
- Vet visits, medication and prevention, with reminders for medication times, heartworm and flea prevention, and vaccination due dates. Reminders are scheduled entirely on the phone.
- Vaccination certificates from a photo. Photograph the certificate the clinic hands you and the date, the next due date and the clinic name are filled in for you. Whatever it reads, you can correct on the spot.
- Ask the AI. Describe what you noticed and get a sense of whether it is worth a trip to the vet. The answer takes the dog's age, breed and existing records into account. It is reference information, not a diagnosis, and the app says so.
- A monthly report, with an AI-written summary on Premium.
Japanese and English, yen and dollars. As many dogs as you like.
How we built it
- Flutter for iOS and Android, from one codebase.
- Firebase for Auth, Firestore, Storage and Cloud Messaging.
- Cloudflare Workers (TypeScript) as the backend. Every AI call goes through it, so the model key never ships inside the app, and the monthly free quota and rate limits are counted somewhere the phone cannot edit.
- Claude Haiku 4.5, including vision, for the consultations, the monthly summary, and reading vaccination certificates.
- RevenueCat for everything paid.
- Google AdMob on the free plan.
How we used RevenueCat
Three different things, all through RevenueCat:
- A monthly and a yearly subscription, with a 14-day free trial for new subscribers, once per store account.
- Consumable tickets for extra AI consultations, for owners who do not want a subscription.
- Promotional entitlements for campaign codes and referral codes, granted server-side from the Worker.
The third one taught us the most. RevenueCat's promotional duration is added to the current time, not to an existing expiry, so five deferred free months sent as five monthly grants all computed "now + 1 month" and the owner ended up with one. There is no five_month in the enum either. We moved to an explicit end_time_ms and the problem disappeared.
We also learned that a grant landing within two hours of an active promotional entitlement is treated as a duplicate and quietly ignored - and the response is still a 201 carrying the previous grant's details. "Succeeded" and "changed nothing" looked identical until we started reading the expiry back and comparing it to what we asked for.
Challenges we ran into
Two stores, one entitlement. An owner who subscribed on Google Play and then opened the app on an iPhone could buy a second subscription on top of the first: two charges, one entitlement, and no way to cancel one of them from the device in their hand. The paywall now reads which storefront the active plan came from and refuses to sell over it.
A free plan that limits the view, not the data. Nothing is ever deleted. On the free plan lists and the weight chart show the last three months; Premium brings the dog's whole history back on screen, and cancelling Premium takes nothing away. Medication still being taken, vaccination records and due-date reminders are never limited by that window, on any plan.
Units that disagreed with each other. A food-portion field was labelled in grams, stored in grams, and sent to the model in ounces. The number reaching the AI was 28 times off, and nothing crashed. There is now a test that checks the label, the input and the stored value all mean the same thing.
Failures that looked like nothing happening. A try without a catch meant a whole screen of vet-visit records silently failed to save. The screen just sat there. We went through every form and made saving say so when it fails, and keep what was typed.
What we learned
Most of the hard parts were not the AI. They were the quiet failures: a grant that reports success and does nothing, a unit that is wrong but plausible, an exception nobody catches. We ended up writing tests for the boring things, and reading responses back instead of trusting status codes.
What's next for wanote
Shipped. wanote 1.0 went live on the App Store in Japan and the United States on September 24, and the Google Play release is in review. After that: sharing a dog's record with a second family member, and giving the monthly report something to say about the season.
Log in or sign up for Devpost to join the conversation.