Inspiration

Close cuts are hard on skin. Skin fades, line-ups and clean shaves take the hair right down to the skin, and the razor and foil finishes that make them look sharp are what cause trouble.

The medical name for razor bumps is pseudofolliculitis barbae. DermNet describes it as a common inflammatory reaction of the hair follicle, most often on the face as a result of shaving. It is more likely with curly and coarse hair, is linked to close shaving, and is more common with blade razors than electric shavers (DermNet: Pseudofolliculitis barbae). The NHS says you may be more likely to get ingrown hairs if you have coarse or curly hair, that the best way to prevent them is not shaving, and suggests an electric razor over wet shaving (NHS: Ingrown hairs).

So the decisions that matter for irritation are barbershop decisions: which guard to finish on, foil, razor or neither, and a beard trim instead of a clean shave. They're usually made by eye, once the customer is in the chair. We wanted the barber to have that information earlier, from the selfie the customer already takes to try on cuts: skin analysis that changes the service, not a product sale.

Fade & Co. is a fictional one-chair barbershop that we use as the demo customer. "Marcus", its owner, is fictional too. The test face in every screenshot and in the video is AI-generated (FLUX), never a real person.

What it does

On their phone, a customer:

  1. Agrees to how the photo is used. A plain consent box comes before the camera opens: the photo goes to the YouCam API for the skin check and try-ons, is deleted from YouCam right after each result, and is never stored by us. The photo buttons stay disabled until the box is ticked.
  2. Takes one selfie. The page resizes it to 1000px and re-encodes it as JPEG on the phone, which strips EXIF and GPS data. The same photo serves every step.
  3. Runs the skin check. The "Skin check before the cut" card sends the photo to YouCam AI Skin Analysis for four concerns: redness, acne (spots and bumps), texture and oiliness. The card shows each as Low, Some or Noticeable and turns them into three things:
    • A finish suggestion. For example: "Your photo showed noticeable redness. Consider a #1 guard instead of a foil or razor finish today."
    • A service nudge, only for services on the shop's live price list: "If you were thinking of a clean shave, a Beard Trim & Shape (£14) is easier on the skin today."
    • Two or three aftercare tips, with no brands and no products.

Every result ends with: "This is not a medical assessment. If your skin is sore, broken or infected, see a pharmacist or GP before a close shave."

  1. Tries the shop's looks. Seven looks, each a real service with its price: Tapered Fade and Textured Crop (Skin Fade, £28), Side-Swept Undercut and Buzz Cut (Classic Cut, £22), Anchor Beard and Goatee (Beard Trim & Shape, £14), and Tapered Fade + Anchor Beard (Cut + Beard, £38). They can compare them with a before/after slider, side by side, or in a grid of everything tried.
  2. Books the look at a time that's really free, through the shop's booking server.
  3. Shares it with the barber, if they choose. One consent box on the booking form covers the chosen look image and a one-line skin note. The barber's "Incoming looks" page then shows, for example: "Skin check: noticeable redness, noticeable oiliness. Suggested #1 guard, no razor." Without consent, the skin check never leaves the phone.

How we built it

One Cloudflare Worker, plain ES modules, no framework. Three YouCam APIs, all following the documented flow: register a file, upload to the presigned URL, start a task, poll it, read the result, delete the task.

API Docs category Endpoints
AI Skin Analysis (v2.1) Skin, Face & Body POST /s2s/v2.1/task/skin-analysis, GET /s2s/v2.1/task/skin-analysis/{task_id}
AI Hairstyle Generator (v2.1) Hair & Beard POST /s2s/v2.1/task/hair-transfer, GET …/{task_id}
AI Beard Style Generator Hair & Beard POST /s2s/v2.0/task/beard-style, GET …/{task_id}
File API Utility POST /s2s/v2.0/file, then PUT to the presigned URL
Task delete Utility POST /s2s/v2.0/task/delete
  • Skin Analysis request. { src_file_id, dst_actions: ["redness", "acne", "texture", "oiliness"], format: "json" }: four SD concerns, the cheapest tier (9 units), chosen because they're the ones that change a barber's decision.
  • Reading the scores. We use raw_score (1–100, higher = healthier), not the deliberately flattering ui_score. Below 65 is Noticeable, 65 to under 80 is Some, 80 and above is Low. These cut-offs are ours, not YouCam's: our first guess (40/60) flagged nothing on live results, because real raw scores cluster high (a clear-skinned test face scored 88–99, a face with visible razor redness 57–71), so we recalibrated on those.
  • Hair and beard. Each look pins a template id checked against the live catalogue. Cut + Beard chains two tasks: the beard task runs on the hairstyle task's result.
  • Booking over MCP. The Worker uses the official @modelcontextprotocol/sdk client (Streamable HTTP) to talk to the shop's booking server for prices, free times and bookings.
  • Storage. Workers KV holds consented looks and skin notes (deleted a week after the appointment), usage counters, and a short cache of skin levels keyed by a photo hash.
  • Tests. npm test runs 82 tests with no network, against a fake YouCam API that speaks the documented shapes: request bodies, every threshold boundary, consent gating, "no charge on failure", and task deletion after success and failure.

Challenges we ran into

  • A try-on alone wasn't enough. Our first version used only Hair & Beard, so it showed the cut but changed nothing about the service. We looked for the barbershop problem a Skin API could actually help with. That became the skin check.
  • The skin check wants a different photo from the hairstyle. Skin Analysis needs the face wider than 60% of the image; the hairstyle engine needs the shoulders in shot. If YouCam answers error_src_face_too_small, the card explains and offers a close-up for the skin check only, and a failed check costs nothing.
  • Redness on darker skin. The NHS notes redness may be harder to see on black or brown skin, and razor bumps predominantly affect men of African ancestry. So a Low result never reads as an all-clear: it says a camera can miss irritation and asks the customer to tell the barber if their skin often reacts.
  • Not sounding like a doctor. Every sentence the card can show lives in one tested file: guards and services, generic aftercare, no brands, no diagnoses, and the disclaimer on every result.
  • Units. A skin check costs 9 units, more than a Cut + Beard (4). We added a daily unit cap, cache results by photo, and only count a check once it returns a result.

Accomplishments that we're proud of

  • The skin check changes what happens in the chair: a guard number, "no razor", or a beard trim instead of a shave, and the barber gets it before the customer arrives.
  • Privacy got stricter with the new feature. The selfie is never stored, each YouCam task is deleted as soon as we've read it, raw scores are never stored, and the barber gets one derived line, only with consent.
  • The server rebuilds the barber's note from the levels, so a tampered request can't put its own words on his screen.

What we learned

  • Read a score's definition before building on it: ui_score is flattering by design, wrong for a caution flag.
  • Unit tiers shape the product: four concerns cost 9 units, five cost 12, so "which four matter to a barber?" was a design question.
  • Honest limits make better UX: the close-up fallback and the darker-skin caveat both came from reading the docs carefully.

What's next

  • Keep checking the thresholds against more real faces, only moving them in the cautious direction.
  • Try YouCam's Mobile Camera Kit to guide the face into frame.
  • Let the barber confirm or adjust the suggested finish, so the note becomes his decision.
  • Send the skin check alone as a pre-appointment link in the booking text.

Built With

  • cloudflare-workers
  • javascript
  • mcp
  • perfect-corp
  • playwright
  • youcam-api
Share this project:

Updates

Submission history