Skip to content

Your first skin analysis

This goes one step beyond Getting started: capture an image in a browser, send it to the Skin Analysis API, and render the response into a small UI.

The example uses plain HTML and fetch so it ports trivially into React, Vue, or any framework. About 60 lines of code, no build step.

index.html
<!doctype html>
<html>
<head><meta charset="utf-8"><title>Revieve demo</title></head>
<body>
<input type="file" id="file" accept="image/jpeg" />
<button id="go" disabled>Analyze</button>
<pre id="out"></pre>
<script type="module">
const PARTNER_ID = "jmlv6b2qtS";
const BASE = "https://partner-test.revieve.com/api/3";
const file = document.getElementById("file");
const go = document.getElementById("go");
const out = document.getElementById("out");
file.addEventListener("change", () => { go.disabled = !file.files[0]; });
go.addEventListener("click", async () => {
out.textContent = "Analyzing...";
const url = new URL(`${BASE}/analyzeImage/`);
url.searchParams.set("skintone", "0"); // 0 = let CV decide
url.searchParams.set("gender", "unknown"); // 3.25+ accepts unknown
url.searchParams.set("components", [
"wrinkles", "redness",
"hyperpigmentation", "acne",
].join(","));
const form = new FormData();
form.append("partner_id", PARTNER_ID);
form.append("image", file.files[0]);
const res = await fetch(url, { method: "POST", body: form });
const data = await res.json();
if (data.message === "Error") {
out.textContent = `Failed: ${data.status?.[0]?.description ?? "unknown"}`;
return;
}
out.textContent = data.results
.map((r) => `${r.description.padEnd(20)} ${(r.value * 100).toFixed(0)}`)
.join("\n");
});
</script>
</body>
</html>
  1. The user picks a JPEG. Anything ≥ 600×600 px works.

  2. We build the URL. Required: skintone and gender. Optional: components (we ask for four). The full enum is in the API reference.

  3. We POST a multipart form. The body has partner_id and image. Browsers set the Content-Type boundary automatically.

  4. We branch on the response shape.

    • data.message === "OK" — clean run, render data.results.
    • data.message === "Warning" — usable results, optional UX nudge (“try better lighting”).
    • data.message === "Error" — no results returned; surface data.status[0] to the user.
  5. We render results. Each entry we asked for here has a value between 0 and 1 — multiply by 100 for percentage UI. Not every metric works this way: integer/categorical findings (e.g. skin_age, skin_type) leave value null and carry their result in sum_measures[] instead — see below.

  • For richer rendering, the measurement_locations[] and mask_shapes fields drive overlay visualizations. See Interpreting results.
  • For integer and categorical findings (skin age, skin type, undertone, hair type, eye color), look at sum_measures[] rather than the top-level value — for these, value is null.
  • For real-time AR try-on, use Revieve VTO — the Skin Analysis API is for still-image scoring only.
SymptomLikely causeFix
idx: 100 (input format)Sent PNG/HEIC, or file isn’t readable.Convert to JPEG client-side.
idx: 101 (resolution)Image smaller than 600×600.Recapture at higher resolution — don’t upscale.
idx: 301 (face too small)Face narrower than 300 px in the frame.Prompt the user to move closer.
idx: 103/104 (lighting)Over- or under-exposed.Reshoot in even lighting; warn the user.
idx: 201 (no face)Face is occluded or out of frame.Prompt the user to recentre.
idx: 308 (overexposure)Hot spot from direct flash.Diffuse light or move away from window.