← Projects
Design case study

Product Insight Scanner

A barcode-led product reader that turns messy open data into a small set of scores and plain-language cues—so someone in a store can decide without opening five tabs.

Product Insight Scanner showing product lookup and score presentation
Scan path: lookup → normalized fields → readable summary.
RoleFront-end · API integration · UI
TimelineCourse-scale build
ToolsReact · Node.js · REST
TypeConsumer web · transparency

Why this exists

Problem

Ingredient lists and nutrition panels are accurate on the label and hostile on a phone screen. Most people are not trying to become dietitians in the aisle—they want a fast read on whether a product is roughly aligned with what they care about.

This project asks how far you can get with open data if you commit to a narrow job: scan, summarize, explain in one place.

Intent

Goals

Ownership

Role & scope

What I owned

Client request flow, presentation of API payloads, error and empty states, and the visual hierarchy between score, ingredients, and context chips.

Scope & constraints

In scope: Open Food Facts–style lookup path, scoring presentation, responsive layout.

Out of scope: Owning the full global product database or certifying medical claims.

How the work moved

Process overview

Data-heavy products need the same narrative discipline as visual apps: what enters, what transforms, what leaves.

  1. 01Frame — Decide which signals matter for a first screen vs. secondary detail.
  2. 02Shape data — Normalize inconsistent API fields into a stable view model.
  3. 03Design UI — Match the mental model: product identity → scores → breakdown.
  4. 04Harden — Handle not-found, slow network, and partial nutrition.

Framing

Research & insights

Review of similar transparency apps and a few informal scans of real products. The friction was rarely “missing a barcode”—it was inconsistent payloads and jargon-heavy additives lists.

Intentional choices

Key design decisions

Structure

Turning API data into a readable product story

The design problem is not “call an API”—it is deciding what to throw away so the screen stays legible. The client maps raw records into a view model the UI can render predictably; scores and copy sit on top of that layer so presentation stays stable when fields are missing.

Normalization sketch

This pattern keeps rendering dumb and transformation explicit: easier to debug when a barcode returns half a nutrition table, and easier to explain in critique.

const product = await fetchByBarcode(code);
const viewModel = normalizeProduct(product);
return {
  scores: deriveScores(viewModel),
  highlights: pickHighlights(viewModel)
};

Fetch → Normalize → Present

Evolution

Iteration & refinement

Earlier drafts tried to show everything the API returned. Later passes cut secondary metrics and tightened typography so the score and rationale stayed the focal point on small screens.

Product Insight Scanner after information hierarchy refinement
Refinement pass: fewer competing blocks; clearer path from product header to scores.

Outcome

Final product

Final Product Insight Scanner interface
Shipped flow: identity, scores, and explainable detail in one vertical rhythm.

Implementation

Build snapshot

The split between Node and the client exists so the browser is not holding secrets or duplicating validation—the UI stays focused on presentation while the server handles fetch and shaping concerns.

Product Insight Scanner code excerpt
Representative module from the repo.

Closing

Reflection & next steps

Insight: The interface quality tracked how disciplined the view model was. When normalization was sloppy, the UI had to lie or clutter; fixing structure upstream made layout decisions easier.

Tradeoff: A simple scoring model is easier to explain but cannot capture every dietary nuance—that is an honest limit for this scope.

Next: User test with ten real products people actually buy; add clearer sourcing for where each score comes from; tighten keyboard and screen-reader paths for the scan field.