Hair
Overview
Section titled “Overview”The hair component returns four sub-findings: detected hair colour (or colours, for highlights and balayage), volume, type, and frizziness. Each detected colour is matched against a named palette of roughly 140 hair shades, and the result carries both that palette entry’s name and its RGB — so partner UIs can show a swatch and a recognisable name together. Note the RGB is the palette shade’s, not a raw pixel sample, so the swatch and the name always agree with each other.
component: hairrequest: query: "components=hair"response_path: "results[].description == \"hair\""value_range: nullsum_measures: - Hair color # [color_structure, message]; color_structure = [[index, name, prevalence, rgb], ...] - Hair volume # 0..1 - Hair type # 0..4 (categorical; 1 deprecated) - Hair frizziness # label: 0 (low) / 1 (high) - Hair frizziness ranged # continuous 0..1input_hint: hairtype_query: "?hairtype=<-1|0|1|2|3|4>"warnings: [5000, 5002, 5003]Value mappings
Section titled “Value mappings”hair_type | Type |
|---|---|
| 0 | Coily |
| 1 | DEPRECATED |
| 2 | Curly |
| 3 | Straight |
| 4 | Wavy |
The optional hairtype query parameter (-1 for auto, 0–4 for explicit) biases the model toward the type you supply — useful when partner apps already capture the user’s hair type via questionnaire. It is a hint, not an override: a confident detection can still disagree with the hint, so don’t assume the returned Hair type equals what you passed in.
Rendering notes
Section titled “Rendering notes”const hair = response.results.find((r) => r.description === "hair");
// "Hair color" value is [colorStructure, message]; the entries are in [0].const hairColor = hair.sum_measures.find((m) => m.description === "Hair color")?.value;const colors = hairColor?.[0]; // [[index, name, prevalence, [r,g,b]], ...]
const volume = hair.sum_measures.find((m) => m.description === "Hair volume")?.value;const hairType = hair.sum_measures.find((m) => m.description === "Hair type")?.value;const frizziness = hair.sum_measures.find((m) => m.description === "Hair frizziness")?.value; // label: 0 (low) / 1 (high)const frizzinessRanged = hair.sum_measures.find((m) => m.description === "Hair frizziness ranged")?.value; // continuous 0..1For multi-colour hair (highlights, balayage, grown-out roots), colors[] carries one entry per detected colour, ordered by prevalence descending, with prevalence summing to 1 across the entries. Up to four colours can come back. How many you actually get depends on the image, so read the array rather than assuming a count — surfacing the top one or two is usually enough for a UI.
Edge cases
Section titled “Edge cases”- Tied-up hair can register low volume incorrectly. Capture with hair down for accurate volume scoring.
- Wet hair reads as straighter and darker. Capture dry for routine recommendations.
local_warnings[]
Section titled “local_warnings[]”5000— hair analysis aborted due to image quality concerns or internal error.5002— no hair detected. Hair analysis aborted.5003— not enough hair detected. Hair analysis aborted.