Previously, we’ve learned how to create a simple app from the ground app in our Quickstart Guides (Android, iOS, Cordova, Capacitor, React Native, Flutter). In this guide, we will dive-in in the most common configuration steps you must follow to accomplish a successful Situm integration.
Permissions needed by Situm #
Situm positioning system uses the device sensors data to compute geolocation, so you must request the appropriate permissions in Android and iOS.
Info! Don’t you know how to request permissions? Follow our Android, iOS, React Native, Flutter or Cordova Quick Start Guide!
Info! Starting from Android Situm SDK version 3.22.0 and iOS Situm SDK version 3.26.0, a new class, UserHelperManager, has been introduced. This class handles requesting the necessary permissions and helps resolve potential issues related to permissions and sensors by providing feedback to the user through the UI.
Android #
Situm Android SDK declares a number of install-time permissions that are strictly required for its operation. These permissions are automatically included when you integrate the SDK. However, you must manually declare the ACCESS_FINE_LOCATION permission in your AndroidManifest.xml as it is not included by the SDK. Additionally, you must request this permission at runtime.
If your building is calibrated with BLE beacons, you will also need to request BLUETOOTH_SCAN & BLUETOOTH_CONNECT permissions at runtime. If your building does not use BLE beacons, you can skip requesting these permissions.
Finally, you can optionally request the POST_NOTIFICATIONS permission to display to the user the Situm foreground service notification.
Permission | Description | Action |
---|---|---|
ACCESS_FINE_LOCATION | Required to positioning with every geolocation mode Situm provides. Also called: Location. | Request at runtime & declare in your AndroidManifest.xml |
BLUETOOTH_SCAN & BLUETOOTH_CONNECT | To scan BLE and also to turn BLE ON/OFF in Android 12 and above. Also called: Nearby Devices. | Request at runtime |
POST_NOTIFICATIONS (OPTIONAL) | Allows to push our foreground service notification inside the notification drawer in Android 13 and above. If not granted, user won’t be able to know that we are running on the background. Nevertheless, notices pertaining to these foreground services will still be visible in the Task Manager, irrespective of the user’s decision on the notification permission. See Android docs for more info. | Request at runtime (optional) |
iOS #
As in Android, iOS apps running Situm will need certain permissions. These permissions can be configured from your App Info.plist in Xcode, by creating the following keys:
Permission | Description |
---|---|
NSLocationAlwaysAndWhenInUseUsageDescription. In XCode: “Privacy – Location Always and When In Use Usage Description”. | Required to positioning with every geolocation mode Situm provides. |
NSLocationWhenInUseUsageDescription. In XCode: “Privacy – Location When In Use Usage | Required to positioning with every geolocation mode Situm provides. |
NSMotionUsageDescription. In Xcode: “Privacy – Motion Usage Description”. | Required to access altimeter information from iOS 17.4. Optional from Situm Sdk version 3.14.1, from that version on, if you disable LocationRequest.useBarometer the permission wont be requested at the expense of lower quality in floor changes. |
You will also need to add a description to each key, which will be shown to the user at the time the app request each specific permission. For example, to ask for Location usage you can add the key “NSLocationWhenInUseUsageDescription” with the description “Location is required to find out where you are”
How to request Situm permissions #
Option A – Delegate the permission request to Situm SDK #
Starting from Android Situm SDK version 3.22.0 and iOS Situm SDK version 3.26.0, a new class, UserHelperManager, has been introduced. This class handles requesting the necessary permissions by providing crear explanations to the user about why these permissions are needed. Additionally, it helps resolve potential issues related to permissions and sensors by providing appropriate feedback through the UI to assist the user in solving these problems.



The image below illustrates the flow to follow when requesting permissions and starting positioning using UserHelperManager.

Using UserHelperManager is really easy:
SITUserHelperManager.sharedInstance().autoManage(true);
SitumSdk.init(context) SitumSdk.userHelperManager().autoManage(true)
var situmSdk = SitumSdk(); situmSdk.init(); situmSdk.enableUserHelper();
cordova.plugins.Situm.setApiKey(YOUR_API_USER, YOUR_API_KEY); cordova.plugins.Situm.enableUserHelper();
// Coming soon.
Please note! Please follow our Quick Start Guides and learn in more detail how to request the permissions for each framework in their code snippets section (Android, iOS, Flutter, React Native, Cordova, Capacitor). Remember to install the required packages specified in the guides code snippets.
Option B – Request the permissions yourself #
We recommend using UserHelperManager to let Situm SDK handle the request for permissions.
Here we provide a guide on how to manage the permission request manually if you don’t want to use UserHelperManager.
Enable the sensors #
Situm does require the location and bluetooth sensors of your device enabled to work properly.

NOTE: (Android) Our SDK is able to enable the bluetooth sensor of the user’s device in Android < 13, you may want to implement this feature by setting the “Auto enable BLE during positioning” to true in your positioning configuration.
NOTE: (iOS) By disabling the bluetooth in the iOS control center, our SDK will keep working fine. Only make sure you have enabled the bluetooth sensor in the system preferences as we show in the image.
The users may have these sensors disabled, so detect this issue in your app and notify about these requirement to the users. Make sure you are aware of the status of these sensors to provide a well-built user experience.
Handling location data, status and errors #
In case all is configured correctly and the user is within the building, you can start positioning and receiving the location of the user by the onLocationUpdate() method.
However, something might fail after starting positioning. To be able to diagnose the issue, you’ll also need to listen to the errors and statuses thrown by the onLocationError() and onLocationStatus() callbacks.
A good way to be aware of this is to implement the following callbacks before calling requestLocationUpdates() to correctly listen and notify all the positioning troubles your app might face. For a complete code example, please visit our Quickstart Guides (Android, iOS, Cordova, Capacitor, React Native, Flutter):
//The location listener is passed to SitumSdk.locationManager().addLocationListener(locationListener); LocationListener locationListener = new LocationListener() { @Override public void onLocationChanged(@NonNull Location location) { Log.d(TAG, "Location: " + location.toString()); } @Override public void onStatusChanged(@NonNull LocationStatus locationStatus) { Log.d(TAG, "Status: " + locationStatus.toString()); } @Override public void onError(@NonNull Error error) { Log.d(TAG, "Error: " + error.toString()); } };
// Delegate functions to receive location notifications func locationManager(_ locationManager: SITLocationInterface, didUpdate location: SITLocation) { print("*POSITION UPDATED*\nPosition was updated to:\n Latitude: \(location.position.coordinate().latitude)\n Longitude: (location.position.coordinate().longitude).") } func locationManager(_ locationManager: SITLocationInterface, didFailWithError error: Error?) { print("*POSITION UPDATED*\nThere was an error with the request: \(error?.localizedDescription ?? "")") } func locationManager(_ locationManager: SITLocationInterface, didUpdate state: SITLocationState) { print("*POSITION UPDATED*\nState was updated to \(state.rawValue)") }
// Implement these callbacks before calling SitumPlugin.requestLocationUpdates() SitumSdk().onLocationUpdate((location) { debugPrint("""onLocationUpdate()>: buildingIdentifier=${location.buildingIdentifier}, floorIdentifier=${location.floorIdentifier}, coordiantes=${location.coordinate.latitude.toStringAsFixed(5)}, ${location.coordinate.longitude.toStringAsFixed(5)} """); }); SitumSdk().onLocationStatus((status) { debugPrint("onLocationStatus()> $status"); }); SitumSdk().onLocationError((err) { debugPrint("ERR> onLocationError()> ${err.message}"); });
// Implement these callbacks before calling SitumPlugin.requestLocationUpdates() SitumPlugin.onLocationUpdate(location => { console.log( `onLocationUpdate()>:\n` + ` \tbuildingIdentifier=${location.position?.buildingIdentifier},\n` + ` \tfloorIdentifier=${location.position?.floorIdentifier},\n` + ` \tcoordinates=${location.position?.coordinate.latitude.toFixed( 5, )},${location.position?.coordinate.longitude.toFixed(5)}\n` ); }); SitumPlugin.onLocationStatus(status => { console.log( `onLocationStatus()> ${JSON.stringify(status.statusName)}`, ); }); SitumPlugin.onLocationError(err => { console.error(`ERR> onLocationError()> ${JSON.stringify(err)}`); });
cordova.plugins.Situm.onLocationUpdate((location) => { console.info( "onLocationUpdate() > \n" + "\tbuildingIdentifier=" + location.buildingIdentifier + ",\n " + "\tfloorIdentifier=" + location.floorIdentifier + ",\n " + "\tcoordinates=" + location.coordinate.latitude.toFixed(5) + ", " + location.coordinate.longitude.toFixed(5) ); }); cordova.plugins.Situm.onLocationStatus((status) => { console.info("onLocationStatus() > " + status); }); cordova.plugins.Situm.onLocationError((err) => { console.error("ERR > onLocationError() > " + err); });
Callback | Description | Documentation |
---|---|---|
onLocationUpdate() | This callback returns back the user location data, only if: 1. Your project is correctly configured. 2. Your positioning configuration fits the requirements of your building. 3. The user’s device is physically inside the building (or simulating its location inside it). | onLocationUpdate: Android, iOS, Flutter, React Native, Cordova Location object: Android, iOS, Flutter, React Native, Cordova |
onLocationStatus() | This callback notifies the current status of the positioning system. The most common ones are STARTING, CALCULATING, STOPPED and USER_NOT_IN_BUILDING. Not all the platforms throw the same statuses. | onLocationStatus: Android, iOS, Flutter, React Native, Cordova LocationStatus object: Android, iOS, Flutter, React Native, Cordova |
onLocationError() | This callback notifies the posible errors that our SDK might face while trying to locate the user. We explain the most common errors in the “Why did n’t work?” section of this guide. | onLocationError: Android, iOS, Flutter, React Native, Cordova LocationError object: Android, iOS, Flutter, React Native, Cordova |
All together #
Finally, now you can start locating the users of your app in your building. You can do it by calling requestLocationUpdates(). In the following code snippet we demonstrate you all the steps of this guide together, so you can copy & paste it in your files. For a complete code example, please visit our Quickstart Guides (Android, iOS, Cordova, Capacitor, React Native, Flutter):
import 'dart:io'; import 'package:flutter/material.dart'; // Remember that you need to install the permission_handler package // to execute this code snippet import 'package:permission_handler/permission_handler.dart'; import 'package:situm_flutter/sdk.dart'; import 'package:situm_flutter/wayfinding.dart'; // Input here your API key ... const situmApiKey = "YOUR_APIKEY"; // ... and the building you want visualize const buildingIdentifier = "YOUR_BUILDING_IDENTIFIER"; // Make logs more visible var white = '\x1B[0m'; var green = '\x1B[32m'; var red = '\x1B[31m'; void initializeSitum(MapViewController controller, BuildContext context) async { var situmSdk = SitumSdk(); situmSdk.init(); situmSdk.setApiKey(situmApiKey); situmSdk.setConfiguration(ConfigurationOptions(useRemoteConfig: true)); setPositioningCallbacks(situmSdk, context); await requestPermissions().then((_) { situmSdk.requestLocationUpdates(LocationRequest( buildingIdentifier: buildingIdentifier, useDeadReckoning: false)); }).catchError((err) { debugPrint( "$red ERR> requestPermission()> ${err.toString()} $white"); }); } void setPositioningCallbacks(SitumSdk situmSdk, BuildContext context) { situmSdk.onLocationUpdate((location) { debugPrint("""$green onLocationUpdate()>: buildingIdentifier=${location.buildingIdentifier}, floorIdentifier=${location.floorIdentifier}, coordiantes=${location.coordinate.latitude.toStringAsFixed(5)}, ${location.coordinate.longitude.toStringAsFixed(5)} $white"""); }); situmSdk.onLocationStatus((status) { debugPrint("$green onLocationStatus()> $status $white"); }); situmSdk.onLocationError((err) { debugPrint("$red ERR> onLocationError()> ${err.message} $white"); }); } /// Example of a function that request permissions and check the result: Future<bool> requestPermissions() async { var permissions = <Permission>[ Permission.locationWhenInUse, ]; if (Platform.isAndroid) { permissions.addAll([ Permission.bluetoothConnect, Permission.bluetoothScan, ]); } Map<Permission, PermissionStatus> statuses = await permissions.request(); return statuses.values.every((status) => status.isGranted); }
// 1. Import our plugin import SitumPlugin, {requestPermission} from '@situm/react-native'; // Call this method whenever you want to start positioning const initializeSitum = async () => { // 2. Remember to initialize our SDK and authenticate SitumPlugin.init(); SitumPlugin.setApiKey('YOUR_APIKEY'); SitumPlugin.setUseRemoteConfig(true); // 3. Listen to all the possible errors & statuses SitumPlugin.onLocationStatus(status => { console.log( `onLocationStatus()> ${status.statusName}`, ); }); SitumPlugin.onLocationError(err => { console.error(`ERR> onLocationError()> ${JSON.stringify(err)}`); alert(`${err.message}`); }); // 4. Request the permissions to the user, // then request location updates. // // WARNING! this requestPermission() request both location and bluetooth permissions in Android. // In case you don't use beacons in your building, create your custom method without the bluetooth permissions await requestPermission() .then(() => { SitumPlugin.requestLocationUpdates(); }) .catch(err => { console.error(`ERR> requestPermission()> ${JSON.stringify(err)}`); }); }
document.addEventListener("deviceready", onDeviceReady, false); // Set here your credentials const YOUR_SITUM_EMAIL = 'YOUR_EMAIL'; const YOUR_SITUM_API_KEY = 'YOUR_APIKEY'; const YOUR_BUILDING_IDENTIFIER = 'YOUR_BUILDING_IDENTIFIER'; // Make logs more visible var white = "\x1B[0m"; var green = "\x1B[32m"; var red = "\x1B[31m"; function onDeviceReady() { // 1. Authenticate in our SDK. cordova.plugins.Situm.setApiKey(YOUR_SITUM_EMAIL, YOUR_SITUM_API_KEY); // 2. Set onLocationUpdate(), onLocationStatus() and onLocationError() the callbacks. cordova.plugins.Situm.onLocationUpdate((location) => { console.info( `${green}onLocationUpdate() > \n` + "\tbuildingIdentifier=" + location.buildingIdentifier + ",\n " + "\tfloorIdentifier=" + location.floorIdentifier + ",\n " + "\tcoordinates=" + location.coordinate.latitude.toFixed(5) + ", " + location.coordinate.longitude.toFixed(5) ); }); cordova.plugins.Situm.onLocationStatus((status) => { console.info(`${green}onLocationStatus() > ` + status); }); cordova.plugins.Situm.onLocationError((err) => { console.error(`${red}ERR > onLocationError() > ` + err); }); // 3. Ask the user for permission before positioning. _requestPermissions( () => { cordova.plugins.Situm.requestLocationUpdates({ buildingIdentifier: YOUR_BUILDING_IDENTIFIER, }); }, (errorMessage) => { console.error("ERR> ", JSON.stringify(errorMessage)); } ); } // WARNING! Remember to install the cordova.plugins.diagnostic npm package // Permission request logic. function _requestPermissions(successCb, errorCb) { var isAndroid = navigator.userAgent.match(/Android/i) && navigator.userAgent.match(/Android/i).length > 0; var isIOS = /iPhone|iPad|iPod/i.test(navigator.userAgent); if (isAndroid) { cordova.plugins.diagnostic.requestRuntimePermissions( function (permissions) { console.log("EXAMPLE> permissions statuses: ", permissions); successCb(); }, function (error) { errorCb(JSON.stringify(error)); }, [ cordova.plugins.diagnostic.permission.ACCESS_FINE_LOCATION, cordova.plugins.diagnostic.permission.BLUETOOTH_CONNECT, cordova.plugins.diagnostic.permission.BLUETOOTH_SCAN, ] ); } else if (isIOS) { cordova.plugins.diagnostic.getLocationAuthorizationStatus( (status) => { if (status == "authorized") { successCb(); } }, () => { // Do nothing } ); cordova.plugins.diagnostic.requestLocationAuthorization( function (status) { switch (status) { case cordova.plugins.diagnostic.permissionStatus.NOT_REQUESTED: errorCb("Permission not requested"); break; case cordova.plugins.diagnostic.permissionStatus.DENIED_ALWAYS: errorCb("Permission denied"); break; case cordova.plugins.diagnostic.permissionStatus.GRANTED: console.log("Permission granted always"); successCb(); break; case cordova.plugins.diagnostic.permissionStatus.GRANTED_WHEN_IN_USE: console.log("Permission granted only when in use"); successCb(); break; } }, function (error) { errorCb(JSON.stringify(error)); }, cordova.plugins.diagnostic.locationAuthorizationMode.ALWAYS ); } }
After implementing these methods and executing this code in your app, you should be able to see logs with the location of the device:

Troubleshooting #
Here are the most common positioning troubles your app may face while locating the user inside your building:
Reason | Codes | Solution |
---|---|---|
Location permission is not granted | Android: MISSING_LOCATION_PERMISSION iOS: 11(kSITLocationErrorLocationAccuracy AuthorizationStatusReducedAccuracy) 10(kSITLocationErrorLocationAuthStatusNotDetermined), 8 (kSITLocationErrorLocationDisabled) Flutter: LOCATION_PERMISSION_DENIED React Native: LOCATION_PERMISSION_DENIED | To fix this problem, remember to ask for the location permission before requesting location updates. In case the user actively denied this permission, explain that we won’t be able to locate or guide him through the building without this permission. |
Bluetooth permission is not granted | Android: MISSING_BLUETOOTH_PERMISSION iOS: (iOS devices do no need the BLE permission) Flutter: BLUETOOTH_PERMISSION_DENIED React Native: BLUETOOTH_PERMISSION_DENIED | To fix this problem, remember to ask for the Bluetooth permission before requesting location updates. In case the user actively denied this permission, explain that we won’t be able to locate or guide him through the building without this permission. |
Location sensor was disabled by the user | Android: LOCATION_DISABLED Flutter: LOCATION_DISABLED React Native: LOCATION_DISABLED | The user has disabled de Location sensor of his device. Try to convice the user to enable it, so the positioning system works as expected. |
Bluetooth sensor was disabled by the user | Android: BLUETOOTH_DISABLED iOS: 6 (kSITLocationErrorBluetoothIsOff) Flutter: BLUETOOTH_DISABLED React Native: BLUETOOTH_DISABLED | The user has disabled de Bluetooth sensor of his device. Try to convice the user to enable it, so the positioning system is able to use beacons to locate the user. |
User is out of the building | Android: USER_NOT_IN_BUILDING iOS: kSITLocationUserNotInBuilding Flutter: USER_NOT_IN_BUILDING React Native: USER_NOT_IN_BUILDING | This status is only returned when using building mode. The positioning system can’t locate you in the building based on the WiFi/BLE/GPS signals. This either means you’re actually not in the building, or that the SDK can’t scan those signals correctly. In this latter case: – Check if your app has all the required permissions – Check if your phone has all the required sensors enabled – Check if your Remote Configuration is correct. NOTE: Unlike the errors received in onLocationError(), this status is returned by the onLocationStatus(). |
Stopped | Android: STOPPED iOS: kSITLocationStopped Flutter: STOPPED React Native: STOPPED | This usually indicates that there has been a critical positioning error (check onLocationError logs) or that you have manually stopped Situm SDK. |
For pointers to the documentation where you can review all the errors / status, go here. On hybrid platforms, you might be able to see these errors / status in the Android Studio / Xcode logs.