DEV Community

Cover image for From Side Project to Play Store: Shipping a Stock Analyser with Capacitor, Cloudflare Workers, and Claude Code
Anurag Kashyap
Anurag Kashyap

Posted on

From Side Project to Play Store: Shipping a Stock Analyser with Capacitor, Cloudflare Workers, and Claude Code

                                                                                             The stack nobody warns you about — and what actually got it live.                                                                                                                             ---                                                                                            I built Buffett Stock Evaluator (https://kashvector.com/stock/) — a free tool that scores any stock against the Buffett, Ray Dalio, and Benjamin Graham frameworks — as a weekend project.
Enter fullscreen mode Exit fullscreen mode

One month later it's live on Google Play. Here's the story-


The Stack

  • Vanilla HTML/CSS/JS — no framework, no build step
  • Cloudflare Worker — the secret glue that makes Yahoo Finance work
  • Capacitor — wraps the web app into a native Android APK with almost no code changes
  • Claude Code — AI pair programmer throughout

The Yahoo Finance Problem

Every free stock data project eventually hits the same wall: Yahoo Finance's quoteSummary endpoint requires a crumb — a token you can only get after completing a cookie handshake with fc.yahoo.com. You can't do this from a browser because of CORS. Public proxies that used to work got blocked or paywalled in early 2026.

My solution: a ~150-line Cloudflare Worker that handles the entire auth dance server-side.

// worker/yahoo-proxy.js (simplified)
async function getAuth() {
const cookieRes = await fetch('https://fc.yahoo.com');
const cookie = cookieRes.headers.get('set-cookie');
const crumbRes = await fetch(
'https://query2.finance.yahoo.com/v1/test/getcrumb',
{ headers: { Cookie: cookie } }
);
return { cookie, crumb: await crumbRes.text() };
}

The Worker caches the crumb per-isolate for an hour, adds an origin allowlist to prevent abuse, and rate-limits by IP using an in-memory sliding window — all without Cloudflare's paid add-ons.

The killer feature: the Worker is git-connected to the repo via wrangler.toml. Committing a change and pushing to main auto-deploys it. No dashboard clicking.


The Architecture Decision That Made Native Cheap

Before touching Capacitor I made one rule: only app.js is allowed to touch the DOM.

Every other file — the scorer logic, the data fetcher, the formatters — had to be pure functions: data in, data out. No document.querySelector, no window.*, nothing.

This felt like overkill for a web app. But when I ran npx cap sync to wrap it in a native Android shell, I made zero changes to any of the logic files. Capacitor just needed webDir:

"www" and the WebView handled the rest.

npx cap sync # copies www/ into android assets
npx cap open android # launches Android Studio to build

The DOM boundary isn't a style preference — it's the constraint that makes "ship to Android" a two-command operation instead of a rewrite.


Three Scoring Frameworks, One Data Contract

Each scorer (buffettScore, dalioScore, grahamScore) takes the same raw Yahoo data object and
returns:

{ results: [...], totalScore, maxScore, verdict }

Verdicts are ratio-based — totalScore / maxScore >= 0.85 → "Strong Buy" — because some criteria get skipped for financial stocks (banks shouldn't be penalised for high debt-to-equity ratios). maxScore shrinks when criteria are skipped, so the threshold stays meaningful.

One trap I hit: Yahoo reports debtToEquity as a percentage (53.2 means 53.2%). Every scorer divides by 100 before comparing thresholds. Miss this once and every stock looks catastrophically leveraged.


The Play Store Journey

The part nobody writes about honestly:

  1. Create a Google Play developer account ($25 one-time fee, instant)
  2. Closed testing — you must have at least 12 testers opt-in and run for 14 days before you can apply for production access
  3. Production access review — Google manually reviews the app. Mine took about 7 days after applying
  4. Sign with an upload keystore — lose this .jks file and you can never update the app again. Back it up somewhere outside the repo.

The closed testing period is the real wait. Recruit your testers early — getting 12 people to click an opt-in link takes longer than you'd think.

For the signed AAB I used Android Studio's built-in bundle generator rather than CLI signing.


Building with Claude Code

I used Claude Code as a pair programmer throughout — not just for boilerplate, but for architecture decisions, debugging Yahoo's auth changes, and writing the Play Store submission checklist.

The most useful pattern: describe a constraint first, then ask for implementation. "The scorer must be a pure function with no DOM access" produced much better code than "write a Buffett scorer." The AI respected the architecture rules when they were explicit.

One thing that surprised me: Claude caught the debtToEquity percentage trap before I did, flagged it as a known Yahoo Finance gotcha, and added a comment explaining why. That's the kind of domain-specific knowledge that would have cost me an hour of head-scratching.


What I'd Do Differently

  • Set up the Worker origin allowlist on day one. I added it after the Worker was already deployed and got a surprise traffic spike from a scraper.
  • Recruit closed testers before submitting. I lost a week waiting for the 12-tester threshold.
  • Don't skip the DOM boundary rule even on weekend projects. The Capacitor port took one afternoon. Without the rule it would have been a weekend.

The app is free, no sign-in required: kashvector.com/stock (https://kashvector.com/stock/) or
search "Buffett Stock Evaluator" on Google Play.


Built with Capacitor · Cloudflare Workers · vanilla JS · Claude Code

Top comments (0)