Troubleshooting
What the common symptoms mean and how to fix them, from a start that fails to pushes and geofences that don't arrive.
Start with Bubbl.diagnostics() and Bubbl's own log: see Testing and diagnostics. Most problems show up in active, registered, hasPushToken or lastError.
Turn on debug logs#
Bubbl only logs warnings and errors by default. To see everything it does, start it with logLevel set to debug while you investigate, then set it back:
BubblOptions(baseUrl = "https://api.bubbl.tech", logLevel = BubblOptions.LogLevel.DEBUG)BubblOptions(baseUrl: "https://api.bubbl.tech", logLevel: .debug)const BubblOptions(baseUrl: 'https://api.bubbl.tech', logLevel: BubblLogLevel.debug){ baseUrl: 'https://api.bubbl.tech', logLevel: 'debug' }Bubbl logs natively, also from Flutter and React Native apps:
- Android: Logcat, tag
BubblSDK. - iOS: the unified log, subsystem
tech.bubbl.sdk: the Xcode console, or Console.app filtered on the subsystem.
With debug on, you'll see lines such as:
Geofence check:each time Bubbl decides whether to fetch geofences, with the result (Updated,UnchangedorNotDue), orno location fixwhen the phone has no position.Watching N geofences with Play serviceson Android, once the geofences are set.Geofence entry sent: N notification(s) to show(orexit) when the phone crosses a geofence.- Since 5.0.1,
The Bubbl server answered HTTP … to … requests in a rowwhen the server keeps failing (3 requests in a row). This one is an error, so it shows at the default level too.
Leave debug off in release builds.
Bubbl doesn't start#
| Symptom | Cause and fix |
|---|---|
Bubbl.start: the API key is empty | Pass the SDK API key from Configuration › Developers. |
Bubbl.start: baseUrl must be https:// (http:// only for localhost or a .test host) | Use the https:// API address. http:// is only for local development: see Local development over http. |
Bubbl.start: the credential is incomplete | The key ID, secret or install ID of a device credential is empty. |
supported false | The device is below Android 8.1 or iOS 17. Bubbl stays inactive there by design. |
On Android, the native Bubbl.start throws these as an IllegalArgumentException, so they show as a crash in development. On iOS, and in Flutter and React Native, they're logged and Bubbl doesn't start.
The device doesn't register#
| Symptom | Cause and fix |
|---|---|
registered stays false and lastError says The Bubbl server answered HTTP 5xx to 3 requests in a row… | Bubbl's server is having problems, not your app. Bubbl keeps retrying and recovers by itself; check status.bubbl.tech. Since 5.0.1: before, lastError stayed empty during an outage. |
registered stays false and lastError mentions invalid_key | The API key is wrong: a typo, or another workspace's. Copy it again from Configuration › Developers. |
Bubbl logs that the API key and the address don't match (wrong_environment) and stops | A pk_live_ key needs https://api.bubbl.tech. The log says which address to use. A pk_test_ key belongs to a Sandbox, which isn't open on production. See Plans and going live. |
iOS: The app can't use the Keychain (errSecMissingEntitlement) | The build isn't code-signed (for example a Simulator build with signing turned off), and iOS gives an unsigned app no Keychain. Sign the build. |
iOS: An http:// baseUrl needs NSAllowsLocalNetworking… | App Transport Security blocks local http://. In development builds only, set NSAppTransportSecurity › NSAllowsLocalNetworking to YES. |
Registered, but nothing arrives#
| Symptom | Cause and fix |
|---|---|
registered stays false, active false, pausedUntil set, and the server answered own_app_not_in_plan | Your company is on the Free plan, which doesn't include your own app. Subscribe to a paid plan: Bubbl tries again after 24 hours. See Plans and going live. |
active false, consentRequired true, consent null | You started with requireConsent. Call setConsent(true) once the user agrees. |
active false, consent false | The user opted out, or deleteMyData() was called. |
active false, pausedUntil set | The server paused Bubbl, for example because your plan doesn't include your own app (own_app_not_in_plan). It retries later. Check your plan under Billing. |
sdkSupported false, and This SDK (…) is older than the workspace's minimum in the log | Your workspace requires a newer SDK. Update it. |
credentialRejected true | The server refused the device credential (it was revoked, for example). Bubbl has stopped: start it with a new credential. |
Push#
| Symptom | Cause and fix |
|---|---|
Android: hasPushToken false on the first launch only | Normal with the dashboard's google-services.json: Bubbl gets the Firebase settings when it first registers, and the token on the next launch or within the hour. Don't upload the file again. |
Android: hasPushToken stays false | No Firebase: upload google-services.json under Configuration › Push › Android apps, or add it to the app together with the com.google.gms.google-services Gradle plugin (the file alone is ignored). Check your package name is in it. |
| Android: a token, but no pushes and no error | Your app's Firebase project isn't the one whose service account is in the dashboard. They must match. |
| Android: nothing after the user force-stopped the app | Android wakes no app after a force stop until it's opened again. |
Android: Notification not shown: the app is in the background and notifications are off | The user hasn't allowed notifications (Android 13 and later). Ask with Bubbl.permissions.requestNotifications(). |
iOS: hasPushToken false | Notifications aren't allowed yet. Bubbl asks iOS for the token once they are, at the latest the next time the app opens. |
iOS: iOS couldn't give the app a device token … | Usually the Push Notifications capability or the provisioning profile is missing. |
iOS: The app has no delegate, so Bubbl can't get the device token | Call Bubbl.setPushToken from your app delegate. See Handing over pushes yourself. |
| iOS: pushes don't arrive | Check the bundle ID and key under Configuration › Push, and that the build's APNs environment matches: development-signed Xcode builds are sandbox; ad hoc, TestFlight and App Store builds are production. |
| iOS: pushes arrive without their picture | Add the notification service extension, and replace Xcode's template code in it entirely. See Pictures on iOS pushes. |
| A push doesn't show on a phone with a push token | active must be true on the phone, and the device must not have opted out. |
Geofences#
| Symptom | Cause and fix |
|---|---|
| Geofences fire only with the app open | The user allowed location only while using the app (backgroundLocation false). Ask with requestLocation and always set to true. |
iOS: osWatchesGeofences false | "Always" with precise location is needed for iOS to watch geofences itself; otherwise they're checked from location changes, which is coarser. |
Android: backgroundRestricted true | The user restricted the app's background activity in Settings. Bubbl can't run with the app closed until they lift it. |
geofences is 0 | See geofences is 0 below. |
| iOS: some events missing after a reboot | Events before the first unlock after a reboot can't be kept on iOS; transitionsDroppedWhileLocked counts them. |
geofences is 0#
geofences in diagnostics() is how many geofences Bubbl got from its last fetch. It's 0 before the first fetch, and after a fetch that found nothing. It isn't how many the operating system is watching. Check these in order:
- Location. With location off for Bubbl (
locationEnabledfalse) or no location permission, Bubbl doesn't fetch at all. - Distance. Bubbl asks for the geofences within 5 km of the device, nearest first, and gets at most 50. A device more than 5 km from every campaign location gets none. On an emulator, give it a position near your locations: see Positions on emulators and simulators.
- The campaign. Only running geo campaigns are served: started, not paused and not ended, with at least one notification that's sent on entering or on leaving. A campaign with no notification attached, or one that hasn't started yet, adds nothing.
- The key. The SDK API key must be the workspace whose campaigns you expect. Another workspace's key sees none of them.
- Timing. The app fetches again every 15 minutes, or sooner once it has moved 2.5 km. A change to a campaign can take up to 5 minutes to reach the server's answers. Until then, the device keeps the set it last fetched, even an empty one.
To see each fetch on Android, turn on debug logs: Bubbl logs Geofence check: with Updated(geofences=…), Unchanged or NotDue (not time to fetch yet), or no location fix when the device has no position.
Flutter and React Native#
| Symptom | Cause and fix |
|---|---|
| React Native: none of Bubbl's calls do anything | The New Architecture is off, or the app wasn't rebuilt after installing the package. The package is a TurboModule only. |
React Native: diagnostics() says started false with a reason in lastError | There's no native module here: Expo Go, the web build, Jest, or an old build. Use a development build. |
| Flutter or React Native: no Bubbl logs in the Dart or JavaScript console | Bubbl logs natively: Logcat (tag BubblSDK) or the iOS unified log (tech.bubbl.sdk). |
| Flutter iOS: Xcode reports a dependency cycle after adding the notification service extension | In Runner › Build Phases, drag "Embed Foundation Extensions" above "Thin Binary". |
Expo: prebuild fails on cleartextHosts | Your app already has a network security config. Add the hosts to it and leave android.cleartextHosts out. |
Still stuck? Collect Bubbl.diagnostics() and the native log at debug level before contacting Bubbl support.