Why is nothing arriving
Work down the list. They are ordered by how often each one is the answer, and only some of them are a problem.1. The SDK key is missing, wrong or revoked
1. The SDK key is missing, wrong or revoked
Nothing reaches Orbit until an app sends a key the project owns. Check Settings, then Project, then SDK: if the panel says no key exists yet, create one. Keys are shown once, so a lost key is replaced rather than recovered, and a revoked key is refused for any app still sending it.The key goes in the app’s build configuration or a secret store, never the repository, and it is sent as the
X-Orbit-Key header. It identifies the project rather than a person, and it grants no read access.2. The app never called the SDK, or called it with enabled: false
2. The app never called the SDK, or called it with enabled: false
Collection is off until you turn it on.
enabled defaults to false and is the privacy opt in, so a build that starts the SDK with a literal false, or with a consent value that has not been granted yet, sends nothing by design.Check that Orbit.Vitals.start or Orbit.Capture.start really runs on the path the build takes, once, early, on the main thread.Two things are your app’s to call and will never appear on their own: Capture.screen(_:), which the session timeline, the screen map and the tap heatmaps are cut on, and Capture.setUser(idHash:), without which the Users tab and the users unit in Analytics stay empty.3. The surface is off in the capture policy
3. The surface is off in the capture policy
enabled says the SDK may send. Whether it does is the project’s call, in Settings, then Telemetry.Projects created before 8 September 2026 kept whatever answer they already had, which for most of them is off. network, logs, replay and revenue are off by default on every project, so a session can be arriving with no requests, no log lines, no wireframe and no purchases in it and nothing be broken.replay and revenue need both sides: the app’s replayEnabled or revenueEnabled, and the policy switch. Neither turns one on alone.Also check the kill switch. A killed device does nothing but poll, and the change log says who enabled it and why.4. The device has not polled yet
4. The device has not polled yet
The capture policy is never pushed. A device applies a change on its next poll, so turning a surface on and watching the page for ten seconds proves nothing.
A live stream’s first frame is about a minute away, not instant, and stopping one is as slow as starting it. An upload request rides the next poll too, and expires unanswered after 24 hours.Vitals are slower still, and that is Apple: MetricKit hands an app one payload per device per day, so the first vitals card appears within a day of the SDK starting, not within minutes.
5. The workspace is on Free, which refuses ingest
5. The workspace is on Free, which refuses ingest
Continuous SDK ingest is a plan feature. On Free, every
POST /v1/ingest/* an app makes with the project’s key is answered 402 and nothing it sends is stored. The key still exists and the policy poll still answers, so a device can still be told to stop.This is not a page waiting for a device, it is a page refusing what one sends, and no other reason on this list would ever explain it. Telemetry says so in a sentence above the ordinary empty states. Evidence on Free is uploaded by hand instead; Pro and above ingest continuously. See Overview for the tier table.6. A browser upload fails before it starts (R2 CORS)
6. A browser upload fails before it starts (R2 CORS)
Browser uploads (the Crashes dropzone, the Performance dropzone)
PUT their bytes straight to a presigned storage URL, cross-origin from the console and with a signed Content-Type header, which makes it a preflighted request. An object storage bucket with no CORS rules fails every one of those before it starts, and the upload row is left pending forever with no visible error.The symptom is exactly that: a row that never leaves pending, from the browser only. The CLI is unaffected, because it is not a browser and there is no preflight, so orbit upload is both the workaround and the way to tell the two apart.On the hosted console this is already configured. On a self-managed bucket, add a CORS policy allowing your console origin, the PUT method and the Content-Type header.7. The build is pointed at the wrong environment
7. The build is pointed at the wrong environment
A TestFlight build and an App Store build are the same binary with different surroundings, and two things routinely differ between them.The ingest URL and key. If the values come from
Info.plist or a build configuration, check which configuration the archive was built with. A TestFlight build carrying a staging ingest URL reports perfectly, to somewhere else.The revenue environment. StoreKit reports production, sandbox or xcode, and only production reaches your numbers. Sandbox and Xcode transactions are stored so a developer testing StoreKit sees rows arrive, and they deliberately do not move the numbers anybody reads. A TestFlight tester’s purchase is a sandbox purchase.Crash reports differ too: TestFlight crash feedback is pulled every 30 minutes through your App Store Connect key, while App Store crashes are not exposed by Apple’s API at all and arrive as .ips reports somebody uploads or as MetricKit diagnostics from the SDK.Other things that read as empty and are not
- A session that sent replay frames and nothing else. Layout frames ride the same pipeline as events but never appear in the live tail and never become issues. A session that looks empty in the tail can still have a full wireframe behind it.
- A vitals-only session.
OrbitVitalsalone carries MetricKit payloads and no events, so its timeline is empty by construction. - A sampled-out session.
sampleRateis per session: half the sessions with every tap, not half the taps. A session outside the share collects that surface at all. --is not zero. It means no value has arrived. A crash free rate reads--when the window holds no session, which the caption tells apart from a failed read.
App Store Connect says 403 on analytics but Release works
The role the key needs for analytics reports is not the role Release needs. Requesting a report type for the first time needs an Admin key; downloading the reports needs Admin, Account Holder, Finance, or Sales and Reports. A key with only Developer or App Manager reads Release perfectly and gets a 403 on the reports sync, so the two record their outcomes separately and the card shows Apple’s own message. See Analytics.Refused notification signatures above zero
On Settings, then Analytics, the notification card counts bodies that arrived with a signature Orbit refused. A number above zero there is a misconfiguration, almost always your notification URL pasted into another app’s App Store Connect entry.Getting help
Contact support
Include the project name, the SDK version, and what the empty state on the page actually says. The empty states are written to name which of the reasons above applies.