← All notes
Device Testing7 min

An Xcode launch is not a MetricKit session

You can wire MetricManager, await diagnosticReports, ship a build from Xcode to a tethered iPad, and receive nothing. That silence is not a broken subscriber. Apple does not deliver MetricKit payloads for apps launched directly from Xcode. Hang rates and hang reports live on the TestFlight and App Store path. Desk Instruments work still matters. It is a different pipeline, and treating a quiet debug session as a MetricKit verification is how the field stays dark until a real user hangs.

Two pipelines that answer different questions

Instruments on a plugged-in device answers: can I reproduce this stutter right now, with symbols, while I still have the screen in my hands. MetricKit answers a different question: what is happening on builds that left the desk — daily metric summaries, and diagnostics when the system captures a hang, crash, or memory exception on a real session.

Conflating them is easy because both talk about hangs. One is an interactive profile you start. The other is a delivery channel that only arms after the build is installed through TestFlight or the App Store. If your verification story is "I launched from Xcode and the await never fired," you have not tested MetricKit. You have confirmed the empty path.

What a hang rate is allowed to say

Organizer hang rate and MetricKit hang histograms are aggregate health: roughly how many seconds per hour the main thread was stuck long enough to count. They are useful the same way a crash-free session rate is useful — as a trend and a smoke signal, not as a stack.

A hang diagnostic is the investigation packet. It carries the call stack and metadata for a specific unresponsive stretch. The rate can go up without telling you whether ink rendering, a Vision pass, or a thumbnail rebuild is the culprit. We already refuse to treat crash-free percentage as a ship gate; hang rate inherits the same limit. You need the reports, not only the curve.

Why the Xcode path stays silent

MetricKit is designed for field telemetry on distributed builds. Debug launches from Xcode already have Energy Log, Instruments, and the debugger. Apple avoids double-counting and overlapping channels by not delivering MetricKit payloads on that path. Wireless debugging does not change the rule.

The practical consequence: you cannot unit-test the subscriber by running the scheme. You can compile it, you can assert your encoding path with synthetic fixtures, and you can prove delivery only after a TestFlight install. Teams that stop at "integrated MetricKit" after a desk build often discover weeks later that nothing ever reached the server — because nothing was ever supposed to on that launch style.

How we verify the field path

For Endeo and anything else that spends long stretches on the main thread around Pencil input, the check is boring and specific. Ship a TestFlight build with the MetricManager listener started at launch. On a device that is not tethered for debug, exercise a known heavy path — dense ink, OCR coalescing, a large notebook open — long enough that a hang is plausible. Confirm a diagnostic or metric payload actually arrives in your sink.

If you need a controlled hang for a pipeline smoke test, force one behind a debug-only affordance on a TestFlight build, not on an Xcode run. Pair that with the session-length habit we already use: short cold starts hide thermal and sustained stutter. MetricKit will not invent a hang you never produced in a real install.

Symbolication still matters. A hang report with hex frames is the same false comfort as an unsymbolicated crash. Upload dSYMs for the TestFlight binary before you treat a quiet Organizer as health.

What we treat as done

MetricKit is not done when the code compiles. It is done when a TestFlight build has delivered at least one real metric or diagnostic payload to whatever we claim reads it, hang groups are reviewable with symbols, and we know which hangs we are willing to ship with versus fix before release.

Desk Instruments stays on the checklist for reproducing candidates. Field MetricKit stays on the checklist for proving the channel works and for catching hangs nobody sat through in the lab. An Xcode launch that stays silent is expected. A TestFlight launch that stays silent after real use is the failure.

Desk profile vs field MetricKit
Xcode / Instruments
  • Interactive reproduce on a tethered device
  • No MetricKit payload expected
  • Proves you can see the stutter live
  • Does not prove the field channel
TestFlight / App Store
  • Metric and diagnostic delivery arms
  • Hang rate plus hang reports
  • Needs dSYMs for the shipped binary
  • Proves the subscriber and sink

Silence under Xcode is the empty path. Silence after TestFlight use is the bug.

Questions

Why does my MetricKit subscriber never fire when I run from Xcode?
MetricKit metrics and diagnostics are delivered for TestFlight and App Store installs, not for apps launched directly from Xcode (including wireless debugging). Quiet awaits on a debug launch are expected, not proof the integration failed.
Is hang rate enough to ship?
No. Hang rate is an aggregate smoke signal. Hang diagnostics with symbolicated stacks are what tell you which code path stuck the main thread. Treat the rate like crash-free percentage: useful, not a gate by itself.
How do you verify MetricKit before release?
Install a TestFlight build, start MetricManager at launch, exercise sustained real-device work, and confirm a metric or diagnostic payload reaches your sink. Keep dSYMs matched to that binary so hang stacks are readable.

Sources

  1. WWDC26 — Meet the new MetricKit — MetricManager, metricReports / diagnosticReports, hang and crash diagnostic delivery.
  2. Apple — Analyzing responsiveness issues in your shipping app — Hang rate vs hang reports; Organizer and MetricKit hang diagnostics.
  3. MetricKit delivery on TestFlight / App Store builds — Field telemetry channel; desk Xcode launches are a separate profiling path.

Have something to build?

Tell us what you're working on and we'll tell you honestly whether we're the right fit.

Work with us