skip to content

Analytics & Crashlytics

firebase_analytics logs events, user properties and screen views; firebase_crashlytics records fatal and non-fatal errors with custom keys. Interviewers probe how crashes get readable stack traces.

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

explore

questions

5

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 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 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

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