LerixBlog
ArticlesChangelogChangelogDocs
العربية
Dashboard
Lerix

The Lerix blog: guides for app developers, and news of every release of Lerix and its SDKs.

Blog

ArticlesChangelog RSS feed

Lerix

HomePricingDocsRefund policy

© 2026 Lerix · All rights reserved

LerixBlog
ArticlesChangelogChangelogDocs
العربية
Dashboard
  1. Lerix Blog
fluttercrash reportinggetting started

Crash reporting for Flutter apps: a practical setup guide

Most users never report a crash, they just leave. Set up crash reporting in a Flutter app in minutes: what gets caught, how to add context, and how to cut the noise.

The Lerix team

30 October 20266 min read

A Flutter checkout screen failing, its stack trace, and the grouped issue in the Lerix dashboard
On this page
  1. 1. Add the package
  2. 2. Initialise it in main()

Read next

One user in the centre, receiving the same notification on an iPhone, an Android phone, Chrome and a Mac
pushع

Send a push notification to a person, not a device

Your users have a phone, a laptop and a browser tab. Stop storing device tokens: link devices to your own user ID and send once to iOS, Android, web and macOS.

30 October 20266 min read

An 'Update required' screen, the release control settings, and a 'Back soon' maintenance screen
release controlع

Force an app update or turn on maintenance mode, without shipping a release

Lerix

The Lerix blog: guides for app developers, and news of every release of Lerix and its SDKs.

Blog

ArticlesChangelog RSS feed

Lerix

HomePricingDocsRefund policy

© 2026 Lerix · All rights reserved

  • 3. What gets caught automatically
  • 4. Report the errors you handle
  • 5. Know who was affected
  • 6. Cut the noise before it reaches you
  • 7. Flutter Web needs one more step
  • 8. What you see in the dashboard
  • Checklist
  • Most people who hit a crash never tell you. They close the app, try once more, and if it happens again they uninstall it or leave a one-star review that says "doesn't work". By the time you hear about it, the bug has been live for days.

    Crash reporting turns that around: every uncaught error reaches you with the stack trace, the device and the app version, grouped so a bug that fires ten thousand times shows up once. This guide sets it up in a Flutter app with the lerix_flutter package, and explains what is caught, what isn't, and how to keep the reports useful.

    1. Add the package

    Add lerix_flutter to pubspec.yaml and fetch it:

    dependencies:
      lerix_flutter: ^0.7.0
    
    flutter pub get
    

    Crash reporting only needs this one package. Push notifications (lerix_messaging) and Google Play in-app updates (lerix_app_update) are separate packages, so apps that don't use them don't ship their code. If you add them later, keep all three on the same version.

    The SDK runs on Android, iOS, macOS, Windows and the web.

    2. Initialise it in main()

    Create a project in the Lerix dashboard and copy its API key and slug from the project settings. Then hand your runApp call to Lerix.init:

    import 'package:flutter/material.dart';
    import 'package:lerix_flutter/lerix_flutter.dart';
    
    void main() {
      Lerix.init(
        url: 'https://api.lerix.dev/v1/your-project-slug',
        apiKey: 'your-api-key',
        projectId: 'your-project-slug',
        builder: () => runApp(const MyApp()),
      );
    }
    

    Two details that save time:

    • projectId is the project's slug, the short name you see in the dashboard's address bar, not its long id.
    • You don't need runZonedGuarded. Lerix.init sets up the error zone and WidgetsFlutterBinding itself, then calls your builder. If initialisation fails (no network on first launch, for example), your app still starts.

    3. What gets caught automatically

    Once init has run, three kinds of uncaught errors are reported as crashes, on every platform including Flutter Web:

    • Framework errors through FlutterError.onError: build, layout and paint errors. They are still printed to the console in debug builds, so your workflow doesn't change.
    • Errors outside the framework through PlatformDispatcher.onError, such as an exception in an async callback nobody awaited.
    • Errors in the app's zone that escape everything else.

    Every report carries the device model, OS and version, CPU architecture, time zone, country and your app's version and build number, read from the app itself. Reports also carry the current session, which is how the dashboard shows crash-free sessions and users per app version.

    Be aware of the edges: errors thrown inside another isolate, and crashes in native Kotlin or Swift code, are not caught automatically. Wrap isolate work in a try/catch and report it yourself (next section).

    4. Report the errors you handle

    A caught exception is often the most useful one, because you know what the user was doing. Report it with Lerix.throwError and attach whatever helps you reproduce it:

    try {
      await payments.charge(cart);
    } catch (e, stack) {
      await Lerix.throwError(
        e,
        stack,
        bugSeverity: BugSeverity.high,
        metaData: {
          'cartItems': cart.items.length,
          'paymentMethod': 'card',
        },
      );
      showPaymentFailed();
    }
    

    throwError never throws. If the report can't be sent, it is logged and your app carries on. Severity can be critical, high, medium or low; you can also set a bugType such as BugType.networkError or BugType.validationError to filter by it later.

    5. Know who was affected

    "312 users hit this" is a different priority from "one tester hit this". Tell Lerix who is signed in, and clear it on sign-out:

    // After sign-in
    await Lerix.setUser(user.id);
    
    // On sign-out
    await Lerix.clearUser();
    

    Use your own stable user id, never an email or a phone number. Every report from that device is then linked to the person, and the same id lets you send them a push notification on all their devices later.

    6. Cut the noise before it reaches you

    Some errors aren't worth an alert: a dropped connection on a train, a third-party package that logs instead of failing. Two options in Lerix.init handle that on the device:

    Lerix.init(
      url: 'https://api.lerix.dev/v1/your-project-slug',
      apiKey: 'your-api-key',
      projectId: 'your-project-slug',
      ignoreErrors: [
        'SocketException',                // case-insensitive "contains"
        RegExp(r'^HttpException: 40[13]'),
      ],
      beforeSend: (event) {
        // Drop reports from your own test runs.
        if (event.metadata?['test'] == true) return null;
        // Remove tokens that ended up in a message.
        return event.copyWith(
          message: event.message.replaceAll(RegExp(r'token=\S+'), 'token=***'),
        );
      },
      builder: () => runApp(const MyApp()),
    );
    

    ignoreErrors runs first, then beforeSend. The text you match against is the issue title, which includes the error class. Returning null from beforeSend drops the report silently. If your beforeSend itself throws, the original report is sent, so a bug in a filter never hides a crash.

    The server adds a few rules of its own. For example, Flutter's A RenderFlex overflowed by… is still recorded, but as a low-severity UI bug instead of a critical crash.

    7. Flutter Web needs one more step

    Release builds of Flutter Web are minified, so stack traces read like main.dart.js:1:48213. Build with --source-maps and upload the maps after each build; the source maps guide walks through it. Android and iOS release builds need no extra setup.

    8. What you see in the dashboard

    Reports don't arrive as a flood of duplicates. Lerix groups them into issues by the first line of the message (with numbers, ids, emails and URLs masked) and the first stack frame in your own code, ignoring line numbers. So Order 1234 not found and Order 5678 not found from the same function are one issue.

    Each issue shows its occurrences, affected users, first seen and last seen, and the full stack trace with the device and app details. From there you can:

    • Assign it to a teammate and keep notes on it.
    • Resolve it. If the same error comes back in a later version, the issue reopens by itself and you get an email, so regressions don't slip through.
    • Ignore it. It keeps counting but stops notifying you.
    • Read the AI summary of what went wrong, and open a GitHub issue from it if your repository is connected.

    Checklist

    1. lerix_flutter: ^0.7.0 in pubspec.yaml.
    2. Lerix.init in main() with your API key and project slug, and runApp inside builder.
    3. Lerix.throwError in the catch blocks that matter.
    4. Lerix.setUser after sign-in, Lerix.clearUser on sign-out.
    5. ignoreErrors / beforeSend for the noise you already know about.
    6. Source maps for Flutter Web.

    Then crash the app on purpose once, with a button that throws, and check that it shows up. It takes five minutes and it's the only way to be sure the next real crash will reach you.

    fluttercrash reportinggetting started
    Share X LinkedIn

    On this page

    1. 1. Add the package
    2. 2. Initialise it in main()
    3. 3. What gets caught automatically
    4. 4. Report the errors you handle
    5. 5. Know who was affected
    6. 6. Cut the noise before it reaches you
    7. 7. Flutter Web needs one more step
    8. 8. What you see in the dashboard
    9. Checklist

    An old version breaks against your new API, or the backend needs an hour offline. Set update rules and maintenance windows from the dashboard and every app follows within minutes.

    30 October 20267 min read

    A minified stack trace next to the same error mapped back to TypeScript source
    source mapsع

    Readable stack traces from minified JavaScript: source maps and error grouping

    index-8f3a1c.js:1:48213 tells you nothing. Upload source maps from your build so every error points at your own file, line and function, and see how errors become issues.

    30 October 20266 min read

    Catch your next crash before your users report it

    Crash reporting, push, analytics and an AI assistant that reads your code. Free to start.

    Start free