mobile · 2 min read

FCM Token Not Refreshing After App Reinstall — Flutter Firebase Fix

Push notifications silently stopped after users reinstalled the app. Here is how we fixed stale FCM token registration in production.

Vikash Kumar

Vikash Kumar

· 2 min read

Problem

Push notifications fail silently after app reinstall due to stale FCM tokens

Solution

Listen to onTokenRefresh, always call getToken() on startup, upsert tokens server-side with deviceId

FlutterFirebaseFCMNode.js

Problem

Users who uninstalled and reinstalled our food delivery app stopped receiving order status push notifications. Backend logs showed valid-looking tokens, but FCM returned NotRegistered for roughly 18% of reinstall users within the first session.

Environment

  • Flutter 3.13, firebase_messaging 14.x, firebase_core 2.x
  • Backend: Node.js storing one FCM token per userId
  • Android 12–14, iOS 16–17

Root Cause

We only fetched the FCM token once during onboarding and never listened for onTokenRefresh. Reinstall generates a new token, but our app sent the old cached token from SharedPreferences on login because the cache key survived backup restore on some Android OEM skins.

Solution

class PushTokenService {
  Future<void> initialize() async {
    final messaging = FirebaseMessaging.instance;
    await messaging.requestPermission();

    // Always fetch fresh token on app start
    final token = await messaging.getToken();
    if (token != null) await _syncToken(token);

    FirebaseMessaging.instance.onTokenRefresh.listen(_syncToken);
  }

  Future<void> _syncToken(String token) async {
    final prefs = await SharedPreferences.getInstance();
    final last = prefs.getString('fcm_token');
    if (last == token) return;

    await api.registerPushToken(token);
    await prefs.setString('fcm_token', token);
  }
}

Backend change: upsert tokens in a user_tokens table (userId + deviceId) instead of overwriting a single column. Mark tokens NotRegistered when FCM says so.

Prevention

  • Register onTokenRefresh on every app cold start
  • Never trust locally cached tokens without comparing to getToken()
  • Handle FCM NotRegistered in your sender worker and prune dead tokens
  • QA checklist: uninstall → reinstall → verify push within 60 seconds

Result

Push delivery rate for reinstall cohort went from 82% to 99.1%. Order-tracking notification complaints dropped by 74% in two weeks.