skip to content

FlutterFire Plugins

The FlutterFire plugins put Firebase behind Dart APIs: generated options, auth streams, Firestore snapshots, FCM handlers and Crashlytics. Interviewers probe setup order and background handling.

part ofFlutteroverview, primer and where to startread it →
on this pageshow

explore

questions

29

With Flutter's firebase_analytics, how do you log a custom funnel event and a user property, and which naming rules apply?

level: juniorimportance: must knowfreq 50%

answer

  1. logEvent(name:, parameters:)
  2. String or num values only
  3. firebase_ prefix is reserved
  4. setUserProperty: 24-character names
  5. recommended log* helpers exist

basics

~10 s

FirebaseAnalytics.instance.logEvent(name: 'lesson_completed', parameters: {...}) logs an event whose parameter values are String or num; setUserProperty(name:, value:) tags the user. Reserved names and the firebase_ prefix throw ArgumentError.

solid answer

~40 s

Call `FirebaseAnalytics.instance.logEvent(name: 'lesson_completed', parameters: {'lesson_id': 'es-a1-07', 'score': 92})`. Names are 1 to 40 letters, digits or underscores, start with a letter, and are case-sensitive. Parameter values must be `String` or `num`; a `bool` fails a debug assertion. The Dart layer throws `ArgumentError` for reserved event names and the `firebase_` prefix. The other limits come from the docs: 25 parameters per event, 500 distinct event names, and 100 characters per string value. For standard events, prefer the typed helpers such as `logTutorialBegin` or `logLevelUp(level: 3)`. `setUserProperty(name: 'learning_language', value: 'es')` attaches an attribute to the user rather than to one event. Its names are at most 24 characters, there can be up to 25 of them, values persist across sessions, and a `null` value removes the property.

code

dart · 29 lines
dart
import 'package:firebase_analytics/firebase_analytics.dart';

abstract final class LessonEvents {
  static const started = 'lesson_started';
  static const completed = 'lesson_completed';
}

Future<void> onLessonCompleted({
  required String lessonId,
  required int score,
  required bool perfect,
}) async {
  final analytics = FirebaseAnalytics.instance;
  await analytics.logEvent(
    name: LessonEvents.completed,
    parameters: {
      'lesson_id': lessonId,
      'score': score,
      'perfect': perfect ? 1 : 0, // bool values fail the String-or-num assert
    },
  );
}

Future<void> onLanguageChosen(String languageCode) async {
  await FirebaseAnalytics.instance.setUserProperty(
    name: 'learning_language',
    value: languageCode,
  );
}

go deeper

for a junior

Know logEvent(name:, parameters:) with String or num values, setUserProperty(name:, value:), and that the firebase_ prefix and reserved names are rejected.

for a middle

Explain which rules Dart enforces and which are only documented, the difference between parameters and user properties, and when to use the recommended log helpers.

for a senior

Show how you keep an event schema stable across releases: constants, type-safe wrappers, registered custom definitions, and no personal data in IDs or parameters.

for a principal

Own the tracking plan: which funnel steps matter, who may add events under the 500-name ceiling, and how analytics changes are reviewed like API changes.

## Events and user properties **firebase_analytics** is the FlutterFire plugin for Google Analytics for Firebase. Its data has two shapes: - **Events** record that something happened: a lesson started, a lesson completed, a subscription purchased. Each can carry **parameters**. - **User properties** describe the user across events, such as the language being learned or the plan tier. They persist until you change them. For a language-learning app's funnel, the events might be `lesson_started`, `lesson_completed` and `streak_extended`. A user property might be `learning_language`. ## logEvent and its rules `logEvent({required String name, Map<String, Object>? parameters, List<AnalyticsEventItem>? items, AnalyticsCallOptions? callOptions})` is the general method. The rules come from two places. **Enforced by the Dart layer:** 1. A reserved event name, such as `ad_click` and the other automatic events, throws `ArgumentError`. 2. A name starting with `firebase_` throws `ArgumentError`. 3. Parameter values must be `String` or `num`. This is an `assert`, so it fails in debug builds; a `bool` is not accepted. Log `1`/`0` or a string instead. **Documented, but not checked in Dart:** | Rule | Limit | |---|---| | Event name | 1 to 40 characters, letters, digits and underscores, starting with a letter | | Distinct event names | 500 per app | | Parameters per event | 25 | | Parameter name | up to 40 characters; `firebase_`, `google_`, `ga_` prefixes reserved | | String parameter value | up to 100 characters | | Case | `Lesson_Completed` and `lesson_completed` are two different events | Because Dart does not check these, a violation gives no error in your code. The event or parameter just may not show up as expected in reports. Keep event names in one constants file. ## Recommended events The plugin has typed helpers for Google's recommended events, and they use the prescribed parameter names: - `logTutorialBegin()` and `logTutorialComplete()` for onboarding. - `logLevelUp(level: 3)` when a learner moves up a level. - `logLogin`, `logSignUp` and `logPurchase` for account and revenue events. - `logScreenView(screenName: ...)` for screens. The docs recommend using these where they fit, because reports treat their parameters specially. Every helper also accepts extra `parameters`. ## Default parameters `setDefaultEventParameters({...})` attaches parameters to every later event. Values must be `String`, `num` or `null`, and `null` clears a key. A value passed to `logEvent` wins over a default. The docs note this method is not supported on web. ## setUserProperty `setUserProperty({required String name, required String? value})`: - The name must be 1 to 24 letters, digits or underscores, and start with a letter. Otherwise the call throws `ArgumentError`. - The `firebase_` prefix throws `ArgumentError`. - Up to 25 user property names are supported. - Values persist across sessions. Setting `null` removes the property. Use a user property when an attribute should segment **all** of a user's events, such as `learning_language` or `plan`. Use an event parameter when the value belongs to one occurrence, such as a lesson's score. `setUserId(id: ...)` sets the user ID; the API docs say it must be used in line with Google's privacy policy, so never send an email or a name. Custom parameters also need registering as custom definitions in the console before they appear in reports. That is product configuration, not client code.

  • When should a value be a user property rather than an event parameter?
    Use a user property when it describes the user and should segment all their events, such as `learning_language` or `plan`. It persists across sessions, and there are at most 25 of them. Use an event parameter when the value belongs to one occurrence, such as a lesson's score or ID. Duplicating a per-event value as a user property overwrites it on every event and loses history.
  • Your event name is 45 characters long. What happens in the Flutter code?
    Nothing in Dart: `logEvent` only throws for reserved names and the `firebase_` prefix. The 40-character limit is a documented rule the Dart layer does not check, so the event may simply not appear as expected in reports. Keep names in constants and review them against the documented limits.

saying these in an interview costs you the question

  • Boolean parameter values are logged as true or false.
  • logEvent throws for any name longer than 40 characters.
  • Event names are case-insensitive, so casing does not matter.
  • User properties reset at the start of each session.
  • Putting the user's email in setUserId is fine for debugging.
open as a page

With firebase_auth in Flutter, how do you sign a user in with signInWithEmailAndPassword and handle the FirebaseAuthException it can throw?

level: juniorimportance: must knowfreq 60%

basics

~10 s

Await FirebaseAuth.instance.signInWithEmailAndPassword(email:, password:) inside try, catch FirebaseAuthException and switch on e.code. With email enumeration protection, wrong email or password both arrive as invalid-credential, not user-not-found or wrong-password.

open as a page

With Flutter's firebase_remote_config, how does a parameter move from setDefaults through fetch and activate to what getBool returns?

level: juniorimportance: must knowfreq 52%

basics

~20 s

setDefaults supplies in-app values; fetch() downloads backend values into a cache without applying them; activate() makes them what getBool and the other getters return. fetchAndActivate() does both and returns true only when new values were activated.

open as a page

In Flutter's cloud_firestore plugin, what is the difference between get() and snapshots() on a DocumentReference or query, and when do you use each?

level: juniorimportance: must knowfreq 58%

basics

~20 s

get() returns a Future with one snapshot, trying the server, then the cache. snapshots() returns a Stream that emits current data at once and on every change, local writes included. Use get() for one-off reads, snapshots() for live screens.

open as a page

In a Flutter app using FlutterFire, why must main() await Firebase.initializeApp before runApp, and what breaks when that order slips?

level: juniorimportance: must knowfreq 72%

basics

~10 s

Every FlutterFire plugin looks up a FirebaseApp that exists only after Firebase.initializeApp completes. So main() calls WidgetsFlutterBinding.ensureInitialized(), awaits initializeApp with DefaultFirebaseOptions.currentPlatform, then calls runApp; otherwise the first plugin call throws [core/no-app].

open as a page

With Flutter's firebase_crashlytics, how do fatal and non-fatal reports differ, and how do log, setCustomKey and recordError add context?

level: middleimportance: must knowfreq 48%

basics

~10 s

FirebaseCrashlytics.instance.recordError(error, stack, fatal: false) records a non-fatal that is stored and sent with the next fatal report or launch; fatal: true reports immediately. setCustomKey and log attach state and breadcrumbs to later reports.

open as a page

In firebase_auth, how do authStateChanges, idTokenChanges and userChanges differ, and which one should drive sign-in versus home routing?

level: middleimportance: must knowfreq 62%

basics

~20 s

All three emit a User? on subscribe, sign-in and sign-out; idTokenChanges also fires on token refresh, and userChanges also on profile updates, linking and reload. Route between sign-in and home on authStateChanges, the only one limited to that decision.

open as a page

With Flutter's cloud_functions plugin, how do you call a callable Cloud Function and handle the errors it can return?

level: middleimportance: must knowfreq 44%

basics

~10 s

Get a reference with FirebaseFunctions.instance.httpsCallable('name'), await call(data), and read result.data; failures throw FirebaseFunctionsException, whose code, message and details come from the function or the client, such as deadline-exceeded after the 60-second default timeout.

open as a page

With Flutter's firebase_messaging, which API receives a message or notification tap when the app is foregrounded, backgrounded or terminated?

level: middleimportance: must knowfreq 62%

basics

~10 s

FirebaseMessaging.onMessage delivers messages in the foreground; onMessageOpenedApp fires when a tap resumes a backgrounded app; getInitialMessage() returns the tap that launched a terminated app; onBackgroundMessage registers a top-level handler for background or terminated delivery.

open as a page

With Flutter's firebase_storage plugin, how do you upload a photo with putFile, show progress, and obtain a download URL afterwards?

level: juniorimportance: should knowfreq 48%

basics

~10 s

Call ref.putFile(file) on a child Reference to get an UploadTask, listen to task.snapshotEvents for bytesTransferred and totalBytes, await the task (a Future<TaskSnapshot>), then call getDownloadURL() on the uploaded reference.

open as a page

In Flutter's firebase_messaging, what does requestPermission() do on iOS and on Android 13+, and how do you read its result?

level: juniorimportance: should knowfreq 46%

basics

~10 s

FirebaseMessaging.instance.requestPermission() shows the notification prompt on iOS, macOS, web and Android 13+, and returns NotificationSettings whose authorizationStatus is authorized, denied, notDetermined, provisional or deniedPermanently.

open as a page

What does the FlutterFire CLI's flutterfire configure command generate for a Flutter app, and when must you run it again?

level: juniorimportance: should knowfreq 55%

basics

~20 s

flutterfire configure registers a Firebase app per selected platform, writes lib/firebase_options.dart with a DefaultFirebaseOptions class, and adds Android Gradle plugins for Crashlytics or Performance Monitoring. Rerun it when you add a platform or start using a new Firebase product.

open as a page

In a Flutter app using firebase_analytics, why are screen views missing, and how do FirebaseAnalyticsObserver and logScreenView fix it?

level: middleimportance: should knowfreq 38%

basics

~10 s

Automatic screen tracking sees only the one native screen hosting Flutter, so routes need FirebaseAnalyticsObserver, which calls logScreenView with each PageRoute's RouteSettings.name, or manual logScreenView calls for tabs and unnamed routes.

open as a page

In a Flutter app using firebase_auth, why can FirebaseAuth.instance.currentUser be null at launch for a user who is still signed in?

level: middleimportance: should knowfreq 45%

basics

~20 s

currentUser is a snapshot, and at launch firebase_auth may still be restoring the persisted session, so it reads null. The first authStateChanges() event arrives only after restoration; route from it, or await authStateChanges().first, instead of reading currentUser early.

open as a page

In firebase_auth, how does signInWithProvider with Google or Apple behave across Android, iOS and web, and what platform traps should you expect?

level: middleimportance: should knowfreq 40%

basics

~10 s

signInWithProvider runs Google or Apple sign-in on Android and iOS; web uses signInWithPopup or signInWithRedirect, which throw UnimplementedError elsewhere. Apple is native on iOS, while Android runs every provider in a Chrome Custom Tab.

open as a page

In Flutter's firebase_remote_config, how does onConfigUpdated deliver live changes, and what must your listener do before new values take effect?

level: middleimportance: should knowfreq 36%

basics

~10 s

onConfigUpdated is a Stream<RemoteConfigUpdate>: listening opens a real-time connection, the SDK fetches each published template, and the event lists updatedKeys. The listener must call activate() before getters return the new values.

open as a page

In Flutter's cloud_firestore, how do Settings.persistenceEnabled and cacheSizeBytes shape offline behaviour, and when must those settings be applied?

level: middleimportance: should knowfreq 30%

basics

~10 s

persistenceEnabled chooses an on-disk or in-memory cache, and cacheSizeBytes sets the size that triggers cleanup of little-used data. Assign FirebaseFirestore.instance.settings before any other Firestore call; web uses memory unless persistence is enabled.

open as a page

In Flutter's cloud_firestore plugin, what does withConverter do on a collection or document reference, and why prefer typed references over raw maps?

level: middleimportance: should knowfreq 44%

basics

~10 s

withConverter<R>(fromFirestore:, toFirestore:) returns a reference typed to R, so reads yield model objects and writes accept them. The mapping runs client-side only; Firestore still stores ordinary map fields.

open as a page

With Flutter's firebase_messaging, how do you get a device's FCM token to your backend and keep it current as it changes?

level: middleimportance: should knowfreq 48%

basics

~10 s

Call FirebaseMessaging.instance.getToken() at startup or sign-in, send it to your backend, and subscribe to onTokenRefresh for later changes; on iOS the APNs token must exist first, and on web you pass a vapidKey.

open as a page

In FlutterFire, how do firebase_options.dart and the native google-services.json and GoogleService-Info.plist files interact when Firebase.initializeApp runs?

level: middleimportance: should knowfreq 38%

basics

~20 s

firebase_core first adopts any default app the native SDK built from google-services.json or GoogleService-Info.plist, then compares Dart's FirebaseOptions with it: matching options return that app, a different apiKey throws [core/duplicate-app]. Web has no native file, so Dart options are mandatory.

open as a page

Crashlytics shows unreadable Dart stack traces, or a Missing dSYM alert, for an obfuscated Flutter release; what symbol uploads are missing on iOS and Android?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Builds with --split-debug-info (and --obfuscate) need their symbols in Crashlytics: on iOS the firebase_crashlytics upload-symbols run script must exist as the last build phase; on Android run firebase crashlytics:symbols:upload with the Firebase App ID and the symbols directory.

open as a page

In a Flutter app using firebase_auth, how do you attach the user's ID token to your own backend calls, and when does getIdToken return a refreshed token?

level: seniorimportance: should knowfreq 42%

basics

~20 s

Call await user.getIdToken() for each request and send it as a bearer token. It returns the cached token until expiry, then refreshes automatically; getIdToken(true) or getIdTokenResult(true) forces a refresh, which is how new custom claims reach the client.

open as a page

A flag changed in the console hours ago still hasn't reached users of a Flutter app using firebase_remote_config; how do minimumFetchInterval and throttling explain it?

level: seniorimportance: should knowfreq 38%

basics

~10 s

minimumFetchInterval defaults to 12 hours, so fetches inside that window reuse the cached config. Lowering it in production risks backend throttling (code throttled, lastFetchStatus throttle); onConfigUpdated delivers published changes regardless of the interval.

open as a page

A Flutter app's callable works against the local emulator but fails in production with not-found; how do cloud_functions regions and instanceFor explain it?

level: seniorimportance: should knowfreq 28%

basics

~10 s

FirebaseFunctions.instance targets us-central1, so a function deployed elsewhere is not found; use FirebaseFunctions.instanceFor(region: 'europe-west1'), or httpsCallableFromUrl, while useFunctionsEmulator routes every call to the local emulator, whatever the region.

open as a page

In a Flutter app using cloud_firestore, why is calling snapshots() inside build() costly, and how do you keep Firestore listeners cheap?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Each snapshots() call creates a new stream whose first listen starts a native listener that re-runs the query. Calling it in build() restarts that listener on every rebuild; create the stream once, cancel manual subscriptions, and keep queries narrow.

open as a page

A firebase_messaging background handler runs in debug but never seems to run in an Android release build of the Flutter app; what do you check?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Check that the handler is a top-level function annotated @pragma('vm:entry-point') so release tree shaking keeps it, registered in main(), that it calls Firebase.initializeApp in its own isolate, and that its errors, which the plugin only prints, are reported.

open as a page

FCM pushes reach the Android build of a Flutter app using firebase_messaging but never the iOS build; what do you check?

level: seniorimportance: should knowfreq 34%

basics

~20 s

Check the APNs authentication key uploaded to Firebase, the Push Notifications capability and the Background fetch and Remote notifications modes in Xcode, granted permission, and an APNs token before getToken(). In the foreground, iOS shows nothing until presentation options are set.

open as a page

For a Flutter volunteer-scheduling app with separate dev and prod Firebase projects, how do you wire FlutterFire per build flavor, and what typically goes wrong?

level: seniorimportance: should knowfreq 34%

basics

~20 s

Run flutterfire configure once per Firebase project into per-flavor options files, pick the file at startup by entry point or appFlavor, and bundle each flavor's own google-services.json and GoogleService-Info.plist. Mismatches send dev data to prod or throw [core/duplicate-app].

open as a page