Image quality and resolution
Overview
Section titled “Overview”The Skin Analysis API rejects an image (returns data.message: "Error") or warns about it ("Warning") for two main reasons: lighting and face positioning. A third, less-frequent reason is resolution — the image must be at least 600×600 px and the face within it at least 300 px wide, while pore_dilation asks for considerably more.
Use this guide to coach users through better captures, or to bake the constraints into your client-side capture flow.
What the CV needs
Section titled “What the CV needs”Lighting
Section titled “Lighting”- Enough light — not too dim, not blown out. Bright but not overexposed.
- Face turned toward the source of light, not backlit.
- Diffuse light — overhead shop lighting, north-facing window, ring light. Avoid direct sunlight or a single bare bulb.
- No shadows across the face — uneven illumination skews colour-driven metrics (redness, dark spots, undertone).
- Consistent background lighting. Strong contrast between face and surroundings can confuse the face-detection step.
Quality codes you’ll see in status[] for lighting issues:
103(warning) — image too dark globally.104(warning) — image overexposed globally.307(warning) — face area too dark.308(warning) — face area overexposed.309/310/311— face channel clipping (blue / green / red overexposed).312(warning) — asymmetric exposure on the face.313(warning) — hard shadows on the face.
Face positioning
Section titled “Face positioning”- Face the camera straight on, neutral expression.
- Empty space around the face — leave enough margin so the head isn’t tightly framed.
- No tilt — chin neutral, head not rotated to either side.
- Whole face must fit in frame — forehead, cheeks, and chin all visible.
Quality codes:
201(error) — no face detected.202(warning) — multiple faces detected; only the best fit is analyzed.203/204(warning) — face detection is uncertain to very uncertain.302–306— face too tilted to the side / down / up.315–318— face partially outside the frame (forehead / lower face / left / right).319(warning) — face too tightly framed.
A useful pattern is to recommend passport-photo-style capture conditions to users — that framing maps almost exactly to what the CV needs.
Resolution
Section titled “Resolution”Three separate thresholds apply, and they’re easy to conflate — the image size and the face size are measured independently:
| Measured on | Requirement | If not met |
|---|---|---|
| The image, both dimensions | ≥ 600 px | 101 (error) — image rejected, nothing is analyzed |
| Face width | ≥ 300 px | 301 (error) — image rejected, nothing is analyzed |
Face width, for pore_dilation only | ≥ 1200 px for full quality | 600–1199 px → 2001 (warning), runs in an upsizing fallback and still returns scores. Below 600 px → 2000 (error), pore_dilation aborts with value: null while every other requested metric still returns normally. |
“Face width” here is the width of the face region the CV crops out of your image, not a measurement of the face itself. That crop carries a margin around the face, so it runs somewhat wider than the visible face.
Clearing the two hard floors is not the same as capturing well. A 600×600 image passes, but a face filling half of it is only ~300 px across — right at the abort boundary, with no headroom for a user who stands slightly further back. Aim comfortably above the minimum, and if pore_dilation is in your component list, frame so the face region alone is ≥ 1200 px wide.
Quality codes for resolution:
101(error) — image smaller than 600 px in either dimension.102(error) — image aspect ratio too extreme to downsample safely.301(error) — face narrower than 300 px. Asks the user to take the photo closer.2000(error) — face narrower than 600 px;pore_dilationaborted.2001(warning) — face between 600 and 1199 px;pore_dilationresults may be unreliable.
Eyeglasses
Section titled “Eyeglasses”The CV detects eyeglasses (status code 314, warning) but does not compensate for them. If the user is wearing glasses, results from the eye region (eye color, eye-specific metrics) are unreliable; the rest of the face is processed normally.
Best UX: ask the user to remove glasses before capture, or surface the warning and skip the eye-region UI when 314 is present.
Why two captures of “the same image” can return different scores
Section titled “Why two captures of “the same image” can return different scores”If you’ve ever seen two partners get different scores for the same selfie, here’s the usual cause list:
- Different CV versions. One partner pinned an older spec; results from a since-retrained model can differ at the margin.
- Time gap. A CV release between the two captures can shift specific metrics — release notes call out which.
- Different image resolutions. Pore-dilation analysis works best with ≥ 1200 px face width; capture flows that switch to a higher-resolution camera mode for it shift what the model sees on every other metric in the same call as a side effect.
The CV is deterministic — same image, same config, same version → same result. The variation lives in those three knobs.
What the partner controls
Section titled “What the partner controls”- Capture conditions — give users live coaching (a head outline, light meter, distance hint).
- Component list — narrowest set that surfaces what your UI renders. Smaller component lists mean faster responses and fewer surprises with capture-mode resolution.
- Retry UX — when
data.message: "Error", surfacestatus[0].descriptionand re-capture rather than failing silently. - Defensive rendering — hide the cards whose
local_warnings[]indicates the metric was unusable; render the ones that succeeded.
Related
Section titled “Related”- Status codes — full reference for every
idxvalue. - Error handling — the HTTP- vs document-level model and a defensive client.
- Pore dilation — why this metric benefits from higher resolution.