Emitrace

One-tap Flutter debugging for QA and developers.
Capture logs, network calls, routes, errors, screenshots, and shareable reports from inside your app.

Emitrace Flutter debugging banner

pub version pub points GitHub stars Flutter ready No backend required

Safe for real apps

TestFlight uses release mode, so do not rely only on kReleaseMode. Use an explicit flag:

final emitraceConfig = Emitrace.initialize(
  enabled: const bool.fromEnvironment(
    'EMITRACE_ENABLED',
    defaultValue: false,
  ),
).copyWith(
  appName: 'My App',
  navigatorKey: navKey,
);

Enable for QA/TestFlight:

flutter build ipa --dart-define=EMITRACE_ENABLED=true

Disable for public production builds:

flutter build ipa --dart-define=EMITRACE_ENABLED=false

Why Emitrace?

Flutter bugs are hard to reproduce when QA only sends: "App crashed on checkout."

Emitrace gives you the missing context:

  • what user tapped
  • which route they were on
  • which API failed
  • what logs happened before the issue
  • screenshot at the time of failure
  • shareable markdown report

What Emitrace captures

Area What you get
Logs Manual logs, breadcrumbs, pretty logger output
Network Dio requests, responses, failures
Routes Push/pop/replace/remove transitions
Errors Flutter/platform/manual errors + crash context summary
Screenshots Auto screenshot capture on errors
Reports Markdown debug bundle, report preview/copy/share, GitHub issue export
Integrations Slack and Discord webhook summaries

2-Minute Quickstart

dependencies:
  emitrace: ^1.3.0
import 'package:emitrace/emitrace.dart';
import 'package:flutter/material.dart';

final navKey = GlobalKey<NavigatorState>();

final emitraceConfig = Emitrace.initialize(
  enabled: const bool.fromEnvironment(
    'EMITRACE_ENABLED',
    defaultValue: false,
  ),
).copyWith(
  appName: 'My App',
  navigatorKey: navKey,
);

void main() {
  runApp(
    EmitraceScope(
      config: emitraceConfig,
      child: MaterialApp(
        navigatorKey: navKey,
        home: const HomePage(),
      ),
    ),
  );
}

Open the floating E button, inspect logs/network/device context, then generate/copy/share report artifacts. The panel keeps familiar tabs (Logs, Network, Device) with searchable grouped timeline cards.

Pretty Logger

Emitrace.log() and EmitraceLogger solve different needs:

  • Emitrace.log() -> records entries in Emitrace timeline/report.
  • EmitraceLogger -> pretty console logging with optional timeline storage.

Sample logger output:

🐛 TRACE DEBUG │ 12:30:41 │ Auth │ User session restored
⚠ TRACE WARN  │ 12:30:42 │ API │ Slow response
⛔ TRACE ERROR │ 12:30:43 │ Checkout │ Payment failed

Logger color modes:

  • EmitraceColorMode.never -> safe no-color logs
  • EmitraceColorMode.auto -> recommended (only colors in ANSI-safe terminals)
  • EmitraceColorMode.always -> force ANSI colors

Use EmitraceColorMode.always only in terminals that support ANSI colors. Flutter debug console, VS Code debug console, Android Studio console, and Xcode may show raw escape codes.

More logger examples: doc/pretty-logger.md

Emitrace vs normal debugging

Without Emitrace With Emitrace
QA sends vague bug message QA shares full debug report
Logs scattered in console Logs grouped in app timeline
API failures hard to trace Failed network calls captured
Route history unknown Navigation timeline included
Manual screenshots Auto screenshot on error

Production safety matrix

Build type Recommended
Debug Enabled
QA/Internal Enabled
TestFlight Enabled with dart-define
App Store/Play Store Disabled
Production monitoring Use with Crashlytics/Sentry

Integration snippets

Route tracking

final routeObserver = EmitraceRouteObserver();

MaterialApp(
  navigatorObservers: [routeObserver],
)

Manual API examples

Emitrace.log('User opened checkout', data: {'cartItems': 3});
Emitrace.event('checkout_started', data: {'flow': 'guest'});
Emitrace.action('tap_pay_now', data: {'buttonId': 'pay_now'});
Emitrace.breadcrumb('Reached payment screen');

try {
  // risky call
} catch (e, st) {
  await Emitrace.error(e, st, data: {'feature': 'payment'});
}

await Emitrace.captureScreenshot(reason: 'before_submit');
await Emitrace.captureReport();

Dio interceptor

final dio = Dio();
dio.interceptors.add(EmitraceDioInterceptor());

Slack and Discord webhooks

final emitraceConfig = Emitrace.initialize(
  enabled: Emitrace.enabledFromEnvironment,
).copyWith(
  enableSlackIntegration: true,
  slackWebHookUrl: 'https://hooks.slack.com/services/xxx/yyy/zzz',
  enableDiscordIntegration: true,
  discordWebhookUrl: 'https://discord.com/api/webhooks/xxx/yyy',
);

Notes:

  • Slack and Discord sends are optional and independent.
  • Local file paths in report are device-local references.

Reporting workflows

Timeline search and filters

  • Use the Logs tab search box to match message/route/url/method/metadata text.
  • Use filters to narrow timeline by type (all, log, event, action, navigation, network, error).
  • Tap cards to expand details inline or open full detail view.

Copy Debug Bundle

Use Device tab actions -> Copy Debug Bundle to copy a markdown bundle containing:

  • app + timestamp overview
  • route timeline
  • recent actions/events
  • recent errors
  • network failures
  • screenshot references
  • device/app metadata

GitHub issue export

final markdown = EmitraceController().generateGitHubIssueMarkdown();

Or Device tab actions -> Copy GitHub Issue Markdown.

Platform notes

  • navigatorKey is recommended for reliable panel presentation.
  • iOS gallery save requires photo library usage descriptions when host app implements save.
  • Android gallery save requires proper media/storage permissions in host app.
  • Host-app gallery save contract uses MethodChannel('emitrace/gallery') with saveToGallery.

Docs

Coming next

  • HTML report export
  • GitHub issue sync
  • Crashlytics enrichment guide
  • Team dashboard exploration

See ROADMAP.md for longer-term plans.

Contributing

See CONTRIBUTING.md.

If Emitrace helps your workflow

  • Star the repo
  • Like it on pub.dev
  • Share feedback
  • Open issues or feature requests

License

MIT License. See LICENSE.

Libraries

emitrace