Inspiration

Every brand's skin quiz maps your answers onto that brand's own shelf. Answer five questions, get a recommendation that happens to be their bestseller. That's not malicious — it's just what happens when the company diagnosing you also sells the cure. We wanted to know what a skin recommendation looks like from a company with no shelf to defend.

What it does

GlowProof turns one selfie into measured skin scores using Perfect Corp's skin analysis API — real per-region measurements across wrinkles, pores, texture, and acne, not a filter or a self-rated quiz. From there it splits into two deliberately separate jobs: an LLM (Claude or Gemini) reads the scores and writes a short routine, but it's only ever allowed to name a product type and an active ingredient — never a brand. A second lookup against live Google Shopping data (SerpApi) then finds the actual product that satisfies it, at today's real price. GlowProof itself sells nothing, so there's no shelf for either step to quietly steer toward.

Every scan also persists in Xano, so results survive a page refresh and show up in a "recent scans" history — instead of vanishing the moment you close the tab, the way most quiz results do.

How we built it

FastAPI backend, no-build vanilla JS frontend. /api/analyze and /api/routine are separate endpoints on purpose — scores paint the instant they land, the routine generates underneath, so one slow call never blocks the other. Every external dependency (Perfect Corp, the LLM, SerpApi, Xano) degrades independently: no key means fixtures/canned output/no history, never a broken demo.

Challenges we ran into

The biggest one only showed up on the one real selfie capture we allowed ourselves, deliberately gated behind a GLOWPROOF_FORCE_FIXTURE flag so we wouldn't burn our limited unit budget iterating. Perfect Corp's response mixes non-concern housekeeping entries — all, skin_age, resize_image — into the same array as the real concerns, each scored 0. Our parser was treating every entry as a concern, which meant those three zero-score entries were silently winning the "priorities" ranking over every real measurement. Unfixed, the routine would have been generated for concerns literally named "All" and "Resize Image" instead of the person's actual skin. A fixture never would have caught this — it took a real API response to break the assumption.

Wiring persistence was its own saga: getting the Xano CLI authenticated and its dev tooling connected ran into a Windows PATH caching issue, a PowerShell execution-policy block on npm, and a couple of stale one-time browser review links before the sandbox-to-production promotion actually landed. All safe, all recoverable, just slower than expected.

Accomplishments that we're proud of

  • Catching a real, routine-breaking bug specifically because we insisted on validating against a live capture instead of trusting fixtures indefinitely
  • The what/which split staying clean end-to-end — the LLM never once has the option to name a brand
  • Full persistence with a real safety flow: schema changes go through a sandbox and a manual review-and-promote step before touching production data, never a silent direct write
  • A skin-analysis unit budget spent almost entirely on deliberate, logged captures rather than iteration guesswork

What we learned

Fixtures are for iteration speed, not for trust. The one real capture we allowed ourselves surfaced a bug that months of fixture-driven development never would have — undocumented API response shapes hide in the gap between "what the docs say" and "what actually comes back." We'd rather budget for one honest real call early than discover a silent bug on stage.

What's next for GlowProof

  • Wider concern coverage (redness, dark circles, radiance) once the SD/HD unit-tier tradeoff is worth it
  • Direct retailer links instead of Google Shopping redirects
  • A re-scan comparison view, now that history actually persists

Built With

Share this project:

Updates

Submission history