Troubleshooting

It isn't working

Almost every report we get is one of four things, and the first one accounts for most of them. Work down this page in order. If none of it helps, email us with your app name and roughly when you ran it, we can see what arrived.

Nothing shows up at all

1. Your build isn't sending, by design. Debug and Simulator builds (Android: emulator and debuggable builds) do not send by default. This is the single most common cause. It is deliberate, your development noise should never land in production numbers, but it means a fresh integration looks broken until you opt in:

AppGlance.configure(apiKey: "glance_live_…", debug: true)
AppGlance.configure(this, "glance_live_…", debug = BuildConfig.DEBUG)

With that set, the build sends and the SDK also narrates every event to the Xcode consolelogcat, under the tag AppGlance, so you can see the send happen rather than guessing.

2. You're looking at the wrong scope. Even when a debug build is sending, its events are tagged simulator / debugemulator / debug , and the dashboard opens on Live, which shows App Store traffic only. Your events are arriving; you are filtering them out. Switch the scope selector to All.

This is worth internalising, because it is also the answer to "my TestFlight numbers vanished": TestFlight and Play beta are their own scope, kept apart from production on purpose.

3. The key belongs to a different app. A write key is scoped to one app. Pasting the key from another app in your dashboard sends the events successfully, to that other app. Check the key in Setup against the app you are looking at. Keys shipped before 2026-08-15 (the old lud_… prefix) no longer exist at all; every live key starts glance_live_.

4. You're on Android and the dependency never resolved. app.appglance:appglance:1.0.0 is on Maven Central, and mavenCentral() is in a default Android project's repositories, so it should just resolve. If Gradle can't find it, the usual cause is a repositories block that was narrowed, a dependencyResolutionManagement block in settings.gradle.kts overrides the per-project one. You do not need mavenLocal(); if an older guide told you to add it, remove it. If the build succeeded, this isn't your problem.

Every error the API can return

If you are using the HTTP API directly, or reading SDK logs, these are the complete set. A 202 is success and carries {"accepted": n, "rejected": m}, a non-zero rejected means those rows were malformed and dropped, and retrying will not help.

StatusBodyWhat it meansRetry?
401missing or malformed API keyNo Authorization: Bearer header, or it isn't shaped like a key.No, fix the header
401unknown API keyWell-formed but not a key we know. Usually a rotated or deleted key, or a typo.No, reissue in Setup
400body is not JSONThe payload didn't parse.No
400body must be a JSON array of eventsYou sent a single object. The body is always an array, even for one event.No
400bad bundle id/v1/icon only, the bundle id wasn't usable.No
413body too largeOver 256 KB.Halve the batch and retry
413too many events in one batchOver 500 events.Halve the batch and retry
429too many requestsRate limited. Note that repeated failed auth is rate limited by IP, so a loop retrying a bad key will start seeing this.Yes, after a wait
502storage unavailableWe accepted the request but the database didn't answer. Nothing was stored.Yes, keep the batch
500internal errorOur fault. Tell us.Yes
405POST onlyYou used GET on an endpoint that takes POST.No
404not foundNo such path.No

The retry rule, in one line. 429, 408, 425, any 5xx, or no response at all → keep everything and retry later. Any other 4xx → that batch will never be accepted, so drop it rather than wedging the queue behind it forever. Both shipped SDKs already do this for you.

The numbers look wrong

Presence pings and user labels are not events. Heartbeats (which is how "active right now" works), user.identify and user.reset are free: they never count toward your quota, never appear in your bill, and are excluded from event counts and charts. If you are comparing a number in your own logs against the dashboard, this is usually the gap.

Old events are gone, deliberately. Every plan has a history window, and events past it are purged nightly. A count over "all time" is a count over your retention window. Per-user lifetime totals and the retention curve are kept as separate lifetime counters, so they are not affected, which is why subtracting one from the other never gives a meaningful answer.

Over quota drops billable events, but never identity. Past your monthly allowance, billable events stop being stored. user.identify and user.reset keep flowing, so your user labels stay correct and nothing is silently mislabelled when you upgrade. The Plan page shows where you are.

Country is empty. Country comes from the device's locale/region setting, never GPS and never the IP address, so a device with no region set has no country. An app can be switched to derive country from the connecting address instead; in that mode the SDK's value is ignored entirely and only the two-letter code is kept.

Still stuck

[email protected]. Include your app name and roughly when you ran the build, we can look up exactly what arrived and what we did with it, which is usually faster than guessing from this page. Please don't paste your write key into a public issue; mail reaches us privately.