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.
The full example
Section titled “The full example”<!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>What it does, step by step
Section titled “What it does, step by step”-
The user picks a JPEG. Anything ≥ 600×600 px works.
-
We build the URL. Required:
skintoneandgender. Optional:components(we ask for four). The full enum is in the API reference. -
We POST a multipart form. The body has
partner_idandimage. Browsers set theContent-Typeboundary automatically. -
We branch on the response shape.
data.message === "OK"— clean run, renderdata.results.data.message === "Warning"— usable results, optional UX nudge (“try better lighting”).data.message === "Error"— no results returned; surfacedata.status[0]to the user.
-
We render
results. Each entry we asked for here has avaluebetween 0 and 1 — multiply by 100 for percentage UI. Not every metric works this way: integer/categorical findings (e.g.skin_age,skin_type) leavevaluenull and carry their result insum_measures[]instead — see below.
Where to go from here
Section titled “Where to go from here”- For richer rendering, the
measurement_locations[]andmask_shapesfields 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-levelvalue— for these,valueis null. - For real-time AR try-on, use Revieve VTO — the Skin Analysis API is for still-image scoring only.
Common quality issues
Section titled “Common quality issues”| Symptom | Likely cause | Fix |
|---|---|---|
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. |