Skip to content

Hair

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: hair
request:
query: "components=hair"
response_path: "results[].description == \"hair\""
value_range: null
sum_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..1
input_hint:
hairtype_query: "?hairtype=<-1|0|1|2|3|4>"
warnings: [5000, 5002, 5003]
hair_typeType
0Coily
1DEPRECATED
2Curly
3Straight
4Wavy

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.

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..1

For 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.

  • 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.
  • 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.