You can test your own app a hundred times and still miss the obvious.

That’s what happened when Blood got its first real users outside my own testing. Things I thought were clear weren’t. Flows I’d clicked through fifty times suddenly had friction. And one user asked a question that made me rewrite the entire privacy notice.

This post covers the feedback that mattered, the pivots it triggered, and why I’m grateful the first users were patient enough to report problems instead of just leaving.

The First Upload (Outside My Own Tests)

May 12th. A friend uploads his Synlab blood test.

The PDF is password-protected — Synlab does this for security. The password is his date of birth.

He hits upload. The spinner spins. And spins. And spins.

After 45 seconds, nothing. No error message. Just… stuck.

What Actually Happened

Two problems:

  1. No progress indicator: The backend was processing fine, but the frontend had no way to show progress. Just an infinite spinner.

  2. Password handling was broken: The upload flow expected passwords in a separate step. But the UI didn’t prompt for it clearly. Users had to figure out they needed to enter it.

The Fix

Commit d8244a7 added:

  • Progress indicator with pipeline stages (“Extracting markers → Explaining results → Writing conclusion”)
  • Inline password prompt in the upload queue
  • Status messages that update as each stage completes

Now users see:

Uploading... ✓
Analyzing... ⏳
  Extracting markers... ✓
  Explaining outliers... ⏳
  Writing conclusion...

Small change. Massive difference in perceived reliability.

”Where Did My Data Go?”

First user session ended. User came back next day. His tests were gone.

Panic message: “Did you delete my data? Is this thing secure?”

No, I hadn’t deleted anything. His browser cache had been cleared (or he was on a different device).

The Problem

I’d built Blood with client-side storage only. IndexedDB. No accounts. No server-side persistence.

This was intentional (privacy by architecture). But I hadn’t made it clear enough.

Users assumed their data was saved somewhere permanent. Like every other health app they’d used.

The Fix: Three Changes

  1. Persistent indicator in UI: Added a small badge: “Your data stays on this device only” visible on every page.

  2. Export functionality: Commit 3894681 added JSON export. Users can download their full result data anytime.

  3. Privacy notice overhaul: Wrote a full-page privacy notice explaining:

    • What data is processed (PDF → AI → results)
    • Where it’s processed (AWS eu-west-3)
    • Where it’s stored (your browser only)
    • How long it’s retained (until you clear cache)
    • Your rights under GDPR (access, rectification, erasure, portability)

The privacy notice now links from both the consent banner and the footer. No hiding it.

Mobile Testing Lied To Me

Desktop Chrome: perfect. Mobile Safari: disaster.

First iPhone user reported: “The upload button is off-screen.”

Turns out, my beautiful responsive layout had a 100vh issue. On iOS Safari, 100vh includes the address bar. So the bottom of my page was literally unreachable.

The Fix

Commit a1f9c23:

/* Old */
.container { height: 100vh; }

/* New */
.container { height: 100dvh; } /* Dynamic viewport units */

Also added proper meta viewport tags and tested on:

  • iOS Safari (iPhone 12, 14, 16)
  • Android Chrome (Pixel, Samsung)
  • iPad Safari

Mobile-first isn’t a slogan. It’s testing on actual devices.

I’d built a nice consent banner. First-time visitors saw it. Explained AI processing, storage, etc.

Users clicked “Accept” without reading. Of course they did. That’s what everyone does with cookie banners.

The Redesign

New approach:

  • “Recommended” badge on the AI option (not pre-selected)
  • Clearer copy: “AI analysis processes your PDF on AWS Bedrock (EU). Results stored locally.”
  • Upload mode selector shown only on first upload
  • “Change preference” link visible in upload queue for subsequent uploads

Consent isn’t a checkbox. It’s an ongoing choice.

Feedback That Made It Into The Product

User FeedbackImplementation
”How do I re-analyse with updated AI?”Re-analyse button in test list with version check
”Can I enter results manually?”Manual entry mode (JSON paste or form)
“What if I want to use Claude instead?”BYOK flow (bring your own API key)
“This marker explanation is wrong”Source links + diet/supplement tips on outlier cards
”How do I contact you?”Feedback widget → Discord notification

Every feature post-MVP came from user feedback. Not roadmap speculation.

The Metric That Mattered

Not daily active users. Not conversion rate.

Time-to-first-result.

From landing on the page to seeing their analyzed results. We got it down to ~25 seconds for typical PDFs (10s upload + 15s processing).

That’s the metric that predicts whether someone comes back.


This is post #4 in the Blood Development Log series. Read post #3 → | Series index →