iTranslated by AI
I Developed an App to Automatically Detect Subscriptions Using AI-Powered Gmail Analysis
What I built
I created a web app called Saburi (saburi.app).
It is an app that parses your Gmail or credit card CSVs to automatically detect and register your active subscriptions.
It features these three main functions, with automatic Gmail detection being its biggest selling point (details on the Gmail integration follow later).
- Automatic Gmail detection: AI analyzes receipts and billing emails to automatically list subscriptions
- CSV parsing: Detection just by dropping statement files from banks or credit cards
- Checklist: Register by simply selecting popular services like Netflix, Spotify, etc.
On the dashboard, you can see monthly/annual total summaries, category-based graphs, and renewal date alerts. Data is saved to Google Drive, so it syncs across devices. Since it supports PWA, you can use it like a native app by adding it to your smartphone's home screen.
![]() |
![]() |
![]() |
A bit of an introduction
I have a fatal weakness as an engineer: I am bad at 0-to-1 design. The phase of "thinking about architecture and designing from scratch" is exhausting. It is hard to keep up with web trends or find an architecture that fits my development style.
However, I do have a strength to compensate for that.
I am good at running things and finding suspicious parts.
Since I used to work as a tester, I get a hunch early on when I touch something running that "this feels a bit off." Now that I mainly focus on development, I can usually gauge "which part of the code might be suspicious" based on that discomfort. I can just throw the identification of the cause at an AI, and I don't hate catching up later—actually, I kind of like it.
I want to talk about how this style surprisingly pairs well with development in the AI era.
It started entirely for myself
Initially, I just really wanted to use it myself.
Although I had manually registered subscriptions in a management app and was keeping track of certain services, I started building this because I thought, "I want an app that can automatically detect new subscriptions." Even if I didn't manage them, I thought it could be useful for detecting frequent payments, or maybe even preventing overpayments if done correctly.
As I continued building it, the feeling that "Hey, it might be a waste for only me to use this" emerged, and I began researching whether I could release it to the public.
When I checked the competition, there were a few subscription management apps in Japan. However, they were all stuck with a design where you "manually register and get reminders." None of them existed that could parse Gmail and automatically detect them.
With that realization, I felt I could differentiate the app, so I pushed forward with that mindset until I could release it.
In the past, even if I put my heart and soul into trying to do the same thing, I often couldn't reach a level of completion that allowed me to release a service, or I would lose motivation. But thanks to AI, I was able to build it out while my motivation was still high.
Development style with AI
This is the part I most want to write about.
Since I am not good at 0-to-1 design, I left the initial scaffolding and design to the AI. When I tell it, "I want to build an app like this with this tech stack," it outputs everything from the file structure to the implementation.
What I do is try to run it.
When I run it, I always find places where I think, "this feels weird." The discomfort I feel when using it as a user and the suspicion I feel as an engineer come together, and I narrow down which part of the code might be the cause and throw it to the AI. When I ask, "Isn't this behavior strange?" or "Is there a security issue with this flow?", the identification of the cause and the improvements happen all at once.
This cycle was faster than I imagined.
And within this cycle, I internalize the design choices, thinking, "Oh, so that's why it was designed this way."
Also, I was honestly surprised that this flow didn't break down (in a naive sort of way).
Get AI to output a scaffold
→ Try running it
→ Find suspicious parts and form a hypothesis
→ Throw it to the AI to fix it (of course, this sometimes involves larger course corrections)
→ Read the fixed parts myself
→ Run it again
Instead of starting from design, starting from something that works and refining it from my own perspective matched well with development in the AI era.
Used 1Password CLI for env management
To use AI with peace of mind, I operated in a way that didn't write secrets into files.
In Saburi, I inject secrets with .envrc + 1Password CLI and pass them to Wrangler.
# Terminal 1: Vite (variables already expanded by direnv)
npm run dev
# Terminal 2: Wrangler (pass shell variables via --binding)
npx wrangler pages dev --proxy 3000 --port 8788 \
--binding GEMINI_API_KEY=$GEMINI_API_KEY \
--binding VITE_GOOGLE_CLIENT_ID=$VITE_GOOGLE_CLIENT_ID
Since there are no .env-style files with hardcoded values, secrets don't remain in the repository. There is no worry of actual values leaking even if AI coding tools scan the directory, and the same mechanism can be shared when developing as a team.
Technical composition
Honestly, I don't think it's that complicated of a structure. However, if I were told to reach this point on my own without AI, it would have been exhausting.
But the way it worked was: I had the AI suggest options, I expanded my expectations on how to proceed, bounced ideas off it with "what if we did it this way?", decided, and implemented it. Repeating this process resulted in the final configuration. This was extremely easy.
Frontend: React + TypeScript + Vite
Hosting: Cloudflare Pages (including Pages Functions)
AI Analysis: Gemini 2.5 Flash
Data Storage: Google Drive appdata
Auth: Google OAuth 2.0
PWA: vite-plugin-pwa
Design for calling Gemini 2.5 Flash via Cloudflare Pages Functions
If you include an API key in the frontend JS bundle, it will be visible in browser DevTools. Be careful, as all environment variables prefixed with VITE_ are included in the bundle.
In Saburi, I created a Cloudflare Pages Function at functions/api/gemini.ts and designed it so the Gemini API is called only from there.
// api/gemini.ts (server-side)
// GEMINI_API_KEY has no VITE_ prefix → not exposed to frontend
const apiKey = process.env.GEMINI_API_KEY
From the frontend, you just send a request to /api/gemini.
Serverless synchronization with Google Drive appdata
I struggled with where to save user data. If I own the DB myself, server costs occur.
By using the appdata scope of Google Drive, you can save app-specific data in a hidden folder in the user's Google Drive. It is an area that is invisible to the user and inaccessible by other apps.
I was able to realize device-to-device synchronization without a server.
Points I struggled with (and will likely continue to struggle with)
The dual wall of Gmail integration
When implementing Gmail integration, which is a key selling point, the issues of screening and the "is this scary?" factor stood in my way simultaneously.
Screening cost issues
gmail.readonly is classified as a Google "Restricted Scope," requiring a rigorous screening process for production release.
There is historical context behind this regulation. In 2018, the Wall Street Journal reported that third-party developers were reading the body of Gmail emails, leading Google to significantly tighten its Gmail API policies starting in January 2019. Initially, the security screening fee was very high, ranging from $15,000 to $75,000, making it effectively impossible for individual developers to enter the market.
Later, CASA (Cloud Application Security Assessment) was introduced, and the fee for Tier 2 has dropped to $540 and up. However, it requires annual renewal, which is still a heavy burden for solo developers.
It is my personal speculation that this high cost of screening, combined with the difficulty of implementing email parsing in the pre-AI era, is one of the reasons why there are so few apps for individuals that feature Gmail integration.
The "Is this scary?" issue
Beyond screening costs, there is the fundamental issue of "it's scary to have an AI parse people's Gmail." This was a concern I anticipated from the very beginning.
Even while developing it, it feels naturally scary—you need a certain level of resolve to release something like this, don't you?
Saburi's design:
- Uses
gmail.readonlyonly (cannot send or delete) - Extracts only key information such as amounts and store names from the email body before sending it to Gemini
- Does not save email bodies on the server
- Tokens are stored only in
sessionStorage(deleted when the tab is closed)
The process of pulling emails and extracting key information is performed on the user's device, and the extracted results are sent in the order of: device → Cloudflare Pages (proxy) → Gemini API. There is no proprietary DB, and Cloudflare simply acts as a proxy without storing anything.
I also created a security audit document from the perspective of "what would be needed to pass CASA Tier 2?" By confirming with AI while running the app, "Is this flow problematic?", it points out oversights.
Countermeasure: Allowlist (Invite-only)
For the time being, I've adopted an Allowlist method to avoid CASA screening while allowing trusted users to use it.
const GMAIL_ALLOWLIST: string[] = ['user@gmail.com']
export const isGmailEnabled = (email: string) =>
GMAIL_ALLOWLIST.includes(email)
Once the number of users grows, I plan to undergo CASA screening and release it publicly.
![]() |
![]() |
What I learned through this process
Even if you aren't good at 0-to-1 design, you can still get to a release.
A natural division of labor emerged where AI handled the 0-to-1, and I played the role of refining it while trying it out. The cycle of identifying suspicious parts of the code based on discomfort in behavior and throwing them to the AI worked well.
Instead of starting from a perfect design, getting AI to build something that works, and then improving it from my own perspective—this style suited me.
Future goals
- Implement Stripe (plan to introduce a paid plan as user numbers grow)
- Gmail CASA screening (after MAU increases)
- Google Calendar integration (automatically register renewal dates to the calendar)
There are various other things as well.
I hope to create and publish a roadmap.
Finally, due to the nature of this app touching highly private data like Gmail, it cannot provide value unless users feel they can "use it with peace of mind." No matter how convenient the features are, an app won't be used without trust. It was just built, and I don't know what will happen, but if I can continue, I want to develop it by placing security and transparency at the heart of the product.
I would be happy to receive your thoughts or feedback after trying it out.





Discussion
実はすでにCASA認証取得作業中です。(安心感ないとお試しもしづらいと思うので)
CASA認証取得しました🎉