Skip to content

7. Vitals and MetricKit

MetricKit delivers pre-aggregated reports about once a day. Reducing them to averages loses the distribution, which is the part teams need. The profile keeps the shape.

  • On iOS 27 and later, when the SDK is built with Xcode 27 or later, an SDK SHOULD use the Swift MetricManager (metricReports, diagnosticReports).
  • On iOS 15 to 26, or from an older Xcode, it uses MXMetricManager.
  • MUST NOT use both in one process; the same day would be reported twice.
  • MUST skip report or metric kinds it does not know, instead of failing.
  • A metric point’s start and end are the report’s window: timeRange (Swift API) or timeStampBegin and timeStampEnd (MX*).
  • With the Swift API, only the full-day entry maps to points. The few-hour interval entries have a duration but no start time; mapping them too would double-count. They stay in the raw payload only.
MetricKit value OTLP metric Temporality
Histograms: time to first draw, resume time, extended launch, hang time, signpost durations Histogram Delta
Totals over the window: CPU time, instructions, disk writes, network bytes, foreground time, termination counts Sum, monotonic Delta
Peaks, averages and ratios: peak memory, average suspended memory, hitch time ratios Gauge n/a
  • MUST keep every bucket. Bucket ends become explicitBounds; the count of the last bucket covers everything above the last bound.
  • MUST NOT invent sum, min or max values the source did not report. A histogram point from MetricKit has count and bucketCounts, and no sum.
  • Metric names are apsio.metrickit.<metric>, in snake case, with the unit in the OTLP unit field (for example apsio.metrickit.time_to_first_draw, unit ms).
  • Hitch time ratios are in milliseconds of hitch per second, unit ms/s: apsio.metrickit.scroll_hitch_time_ratio (MXAnimationMetric.scrollHitchTimeRatio) and apsio.metrickit.hitch_time_ratio (MXAnimationMetric.hitchTimeRatio from iOS 26, or HitchTimeMetric’s total hitch time over its total animation time with the Swift API). A value reported in another unit is skipped, not converted by guess.
  • Termination counts carry the reason as apsio.exit.reason (section 6.4) and apsio.exit.foreground.
  • MetricKit aggregates across all sessions of a day, so its points MUST NOT carry session.id.
  • When the report says it includes more than one app version (includesMultipleApplicationVersions), the point MUST carry apsio.metrickit.multiple_versions = true; its service.version is then the latest one only.

Android vitals the profile maps use the opentelemetry-android instrumentations (app.jank and start and screen spans, section 8). Google Play vitals are not available on the device and are out of scope.