Uninstall Tracking
Track app uninstalls to measure user retention and optimize re-engagement campaigns by integrating Firebase Cloud Messaging (FCM) with the Singular SDK.
Important: Google deprecated GCM APIs in April 2018. Use Firebase Cloud Messaging (FCM) for all uninstall tracking implementations.
Prerequisites
Configure Singular Platform
Before implementing uninstall tracking in your app, configure your app in the Singular platform and complete the Android SDK + FCM integration steps described in Setting Up Android Uninstall Tracking .
System Requirements
Uninstall tracking requires Firebase Cloud Messaging and specific device configurations.
FCM Requirements ( source ):
- Android Version: Devices must run Android 4.1 (API 16) or higher
- Google Play Services: Devices must have the Google Play Store app installed
- Emulator Support: Android 4.1+ emulators with Google APIs are supported
- Distribution: Apps can be distributed outside the Google Play Store while still supporting uninstall tracking
Note: Users on unsupported Android versions or devices without Google Play Services will not be tracked for uninstalls.
Implementation Steps
Step 1: Integrate Firebase Cloud Messaging
Set up Firebase Cloud Messaging in your app if not already configured.
Follow Google's official guide to Set up a Firebase Cloud Messaging client app on Android . This includes:
- Add Firebase to your Android project
-
Add the FCM SDK dependency to your
app/build.gradle - Create a Firebase Messaging Service class
- Request notification permissions (Android 13+)
Step 2: Confirm AndroidManifest.xml FCM Setup
Verify FCM Service and Permissions
Ensure your app is already integrated with Firebase Cloud Messaging and that the Android manifest declares a FirebaseMessagingService to receive FCM messages.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.your.package">
<!-- FCM Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application>
<!-- App Firebase Messaging Service -->
<service
android:name=".MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
</application>
</manifest>
Important: Replace
.MyFirebaseMessagingService
with the
fully
qualified name of your class that extends
FirebaseMessagingService
.
Only one service should handle the
com.google.firebase.MESSAGING_EVENT
intent in your app.
Step 3: Register FCM Device Token
Retrieve the FCM device token and send it to Singular for uninstall tracking.
Retrieve and Set Token
Get the FCM token and register it with Singular immediately after SDK initialization.
import com.google.firebase.messaging.FirebaseMessaging
import com.singular.sdk.Singular
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Initialize Singular SDK
val config = SingularConfig("SDK_KEY", "SDK_SECRET")
Singular.init(applicationContext, config)
// Retrieve and register FCM token
FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
if (!task.isSuccessful) {
Log.w("FCM", "Fetching FCM token failed", task.exception)
return@addOnCompleteListener
}
// Get FCM token
val token = task.result
// Register token with Singular
Singular.setFCMDeviceToken(token)
Log.d("FCM", "FCM token registered with Singular: $token")
}
}
}
import com.google.firebase.messaging.FirebaseMessaging;
import com.singular.sdk.Singular;
import com.singular.sdk.SingularConfig;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initialize Singular SDK
SingularConfig config = new SingularConfig("SDK_KEY", "SDK_SECRET");
Singular.init(getApplicationContext(), config);
// Retrieve and register FCM token
FirebaseMessaging.getInstance().getToken()
.addOnCompleteListener(new OnCompleteListener<String>() {
@Override
public void onComplete(@NonNull Task<String> task) {
if (!task.isSuccessful()) {
Log.w("FCM", "Fetching FCM token failed", task.getException());
return;
}
// Get FCM token
String token = task.getResult();
// Register token with Singular
Singular.setFCMDeviceToken(token);
Log.d("FCM", "FCM token registered with Singular: " + token);
}
});
}
}
Best Practice:
Register the FCM token immediately
after
Singular.init()
to ensure uninstall tracking is
enabled from the first app session.
Singular.setFCMDeviceToken()
silently no-ops if it is called before
Singular.init()
completes or if the token argument is
null
or empty. If your token registration appears to do nothing, confirm
that the SDK was initialized first and that the FCM token returned by
Firebase is a non-empty string.
Handle Token Refresh
Update the FCM token with Singular whenever it refreshes to maintain accurate uninstall tracking.
import com.google.firebase.messaging.FirebaseMessagingService
import com.singular.sdk.Singular
class MyFirebaseMessagingService : FirebaseMessagingService() {
override fun onNewToken(token: String) {
super.onNewToken(token)
// Send updated token to Singular
Singular.setFCMDeviceToken(token)
Log.d("FCM", "New FCM token registered: $token")
// Also send token to your server if needed
sendTokenToServer(token)
}
private fun sendTokenToServer(token: String) {
// Implement your server communication logic here
}
}
import com.google.firebase.messaging.FirebaseMessagingService;
import com.singular.sdk.Singular;
public class MyFirebaseMessagingService extends FirebaseMessagingService {
@Override
public void onNewToken(@NonNull String token) {
super.onNewToken(token);
// Send updated token to Singular
Singular.setFCMDeviceToken(token);
Log.d("FCM", "New FCM token registered: " + token);
// Also send token to your server if needed
sendTokenToServer(token);
}
private void sendTokenToServer(String token) {
// Implement your server communication logic here
}
}
Important:
FCM tokens can refresh at any time (app
updates, device restore, etc.). Always implement
onNewToken()
to keep Singular updated.
Alternative Configuration Method
Set Token During Initialization
If you have the FCM token available before SDK initialization, configure
it in the
SingularConfig
object.
// Get token synchronously (if cached)
val cachedToken = getStoredFCMToken() // Your caching logic
val config = SingularConfig("SDK_KEY", "SDK_SECRET")
.withFCMDeviceToken(cachedToken)
Singular.init(applicationContext, config)
// Get token synchronously (if cached)
String cachedToken = getStoredFCMToken(); // Your caching logic
SingularConfig config = new SingularConfig("SDK_KEY", "SDK_SECRET")
.withFCMDeviceToken(cachedToken);
Singular.init(getApplicationContext(), config);
Method Signature:
public SingularConfig withFCMDeviceToken(String fcmDeviceToken);
withFCMDeviceToken
only seeds the SDK with the token you have at initialization time. It
does not subscribe to token refreshes. You still need to implement
FirebaseMessagingService.onNewToken
and call
Singular.setFCMDeviceToken(newToken)
there to keep Singular's record current. The config method also no-ops
silently if the supplied token is
null
or empty.
Verification and Troubleshooting
Verify Implementation
Confirm uninstall tracking is working correctly.
- Check Logs: Verify FCM token registration appears in your logs
- Test Token Generation: Ensure tokens are generated on first app launch
- Monitor Dashboard: Check Singular dashboard for uninstall tracking data after 24-48 hours
- Test Token Refresh: Clear app data and verify token updates correctly
Common Issues
- Token Not Generated: Verify FCM dependencies are correctly added and Firebase is configured in your project
-
Token Not Updating:
Check that
onNewToken()callback is implemented in your FirebaseMessagingService - Missing Data: Ensure devices meet FCM requirements (Android 4.1+, Google Play Services installed)
- Configuration Error: Confirm uninstall tracking is enabled in Singular platform settings
Additional Resources: For detailed troubleshooting, see the Uninstall Tracking Setup Guide and Firebase Cloud Messaging Documentation .