Skip to content

Wrinkles

Wrinkles measures the visible depth, count, and distribution of lines on the face. The value is a normalized severity score; wrinkles_visualization returns one polyline feature per detected line — x[] / y[] arrays of point coordinates that draw the actual line back onto the source image, plus per-point and aggregate intensity values.

component: wrinkles
request:
query: "components=wrinkles,wrinkles_visualization"
response_path: "results[].description == \"wrinkles\""
value_range: [0, 1]
also_request:
- wrinkles_visualization # polyline features, one per detected line
warnings: [] # no wrinkles-specific codes; see local_warnings below

Within the single wrinkles finding, measurement_locations[] carries one entry per face sub-region (12 in total) — partners see these descriptions verbatim and can style different sub-regions differently:

measurement_locations[].descriptionRegion
forehead worry linesHorizontal lines across the forehead.
between-brows frown linesGlabellar / “11” lines.
noseline bunny linesWrinkles across the nose bridge.
left side eye crow's feet / right side eye crow's feetLines radiating from the outer corner of the eye.
left side tearline / right side tearlineLines below the inner corner of the eye.
left side nasolabial line / right side nasolabial lineNasolabial folds.
left side marionette line / right side marionette lineMarionette lines from mouth corners.
vertical lip linesLines around the lips.

These are descriptions on the same finding, not separate top-level metrics — there’s no nasolabial_folds or crows_feet component to request.

Each entry also carries its own per-region score — value (0..1 severity for that sub-region), a deprecated value_raw, and a Wrinkle intensity sub-measure in measures[] — so you can surface region-level scores, not just the aggregate value on the finding.

For a numeric UI:

const w = response.results.find((r) => r.description === "wrinkles");
const score = Math.round(w.value * 100);

For drawing the lines themselves, request wrinkles_visualization and iterate. Each visualization_data[] feature is a polyline — x[] and y[] are arrays of length N covering the points along one detected line:

for (const loc of w.measurement_locations ?? []) {
// The location's description (e.g. "left side nasolabial line")
// tells you which face region this group of lines belongs to —
// useful for region-specific styling.
for (const line of loc.visualization_data ?? []) {
// line.x and line.y are length-N arrays
// line.intensity is an array of per-point intensities
// line.length_weighted_intensity is a composite ranking value
// line.length is the point count; line.mean_intensity / line.median_intensity are summary stats
drawPolyline(line.x, line.y);
}
}

Three details that matter for polylines:

  1. Decimate dense lines. A wrinkle feature can carry hundreds of points. Keep every Nth point above a threshold — every 3rd above 20 is a workable default. Visually identical, much cheaper.
  2. length_weighted_intensity is the canonical “how bad is this wrinkle” composite — combines line length with per-point intensity. Sort features descending by it to surface the worst N findings.
  3. Stroke style. A 1–2 px stroke at low opacity reads better than a hard line.

Paste-ready code: Rendering recipes → Polylines.

  • Male users. Beard-area sub-regions return value: null (with null visualization_data and a null Wrinkle intensity) — beard area of skin isn’t analysed. Skip null entries when iterating measurement_locations[].
  • Smiling expressions dynamically increase apparent wrinkle count. Capture in a neutral expression for trend tracking.
  • Heavy makeup reduces wrinkle visibility. The API does not detect whether makeup is worn, so show a standing “based on visible skin” disclaimer rather than conditioning it on a makeup signal.
  • Low resolution reduces line-finding precision. wrinkles adds no threshold of its own beyond the API-wide resolution floors — see Image quality → Resolution.

The wrinkles metric emits no metric-specific local_warnings[] codes. It inherits the global image-quality codes (100–308); a skin-masking failure upstream (401, a shared code) can also make results unreliable. See Status codes.

  • Visualization data — Cat D (AOI + mask + advanced); polyline-type features with per-point intensities and the length_weighted_intensity composite.
  • Rendering recipes → Polylines — paste-ready renderer with the dense-point decimation pattern.
  • Sub-area divisions — wrinkles uses a custom division (the sub-regions listed above), not the standard primary or alternative face splits.