pub version License GitHub stars Coverage

Production Safety workflow Test and Analyze workflow Deploy Web Logs Viewer workflow

Pub likes Pub points Pub downloads

Latest benchmark result

ISpect is a pre-release diagnostics toolkit for Flutter and Dart. It runs inside internal builds (developer machines, QA, staging) and gives testers and engineers a way to look at logs, network calls, database operations, BLoC events, navigation, and the widget tree without attaching a debugger. The toolkit is compile-time gated. Omit --dart-define=ISPECT_ENABLED=true and every entry point becomes a const-guarded no-op that Dart's tree-shaker can drop from release builds.

Live web demo. Drop an exported log file in to walk through a session in the browser.

Start here

Add the Flutter panel, paste this setup, and run an internal build. It is the smallest complete ispect integration: guarded startup, in-app panel, and navigation diagnostics.

dependencies:
  ispect: ^6.1.6
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:ispect/ispect.dart';

void main() => ISpect.run(() => runApp(const MyApp()));

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _observer = ISpectNavigatorObserver();

  @override
  Widget build(BuildContext context) => MaterialApp(
        localizationsDelegates: [
          GlobalMaterialLocalizations.delegate,
          GlobalCupertinoLocalizations.delegate,
          GlobalWidgetsLocalizations.delegate,
          ...ISpectLocalizations.delegate(),
        ],
        navigatorObservers: ISpectNavigatorObserver.observers(
          observer: _observer,
        ),
        builder: (_, child) => ISpectBuilder.wrap(
          child: child!,
          options: ISpectOptions(observer: _observer),
        ),
        home: const Scaffold(body: Center(child: Text('My app'))),
      );
}
# Internal build: diagnostics active.
flutter run --dart-define=ISPECT_ENABLED=true

# Public release: omit the flag so the toolkit is inactive.
flutter build apk

Choose the package you need

Need Package
Structured logging only, with no Flutter UI ispectify
In-app panel, navigator observer, and inspector ispect
Dio or http requests ispectify_dio or ispectify_http
WebSocket frames ispectify_ws
Database or storage operations ispectify_db
BLoC/Cubit lifecycle ispectify_bloc
Riverpod provider lifecycle ispectify_riverpod
Layout inspection only ispect_layout

Each adapter depends on ispectify; add ispect only when the Flutter UI is useful. See the package README for the focused setup.

Focused runnable examples

The ispect showcase keeps one target per integration, alongside the full complex_example.dart tour:

cd packages/ispect/example
flutter run -t lib/network/main.dart --dart-define=ISPECT_ENABLED=true
flutter run -t lib/ws/main.dart --dart-define=ISPECT_ENABLED=true
flutter run -t lib/db/main.dart --dart-define=ISPECT_ENABLED=true
flutter run -t lib/bloc/main.dart --dart-define=ISPECT_ENABLED=true
flutter run -t lib/riverpod/main.dart --dart-define=ISPECT_ENABLED=true
flutter run -t lib/routing/main.dart --dart-define=ISPECT_ENABLED=true

The standalone BLoC and Riverpod observer examples run without Flutter:

cd packages/ispectify_bloc/example && dart run -DISPECT_ENABLED=true main.dart
cd packages/ispectify_riverpod/example && dart run -DISPECT_ENABLED=true main.dart

Preview

ISpect desktop log viewer

Desktop log viewer and standalone web demo.

Inspector panel
Inspector
Render tree, layout, spacing, transforms.
Color picker
Color picker
Read on-screen colors and compare values.
JSON viewer
JSON viewer
Inspect structured payloads without leaving the app.
Settings panel
Settings
Tune filters, history, and debug flags.
Share sheet
Export and share
Send sessions and logs for debugging or QA.
Performance overlay
Performance overlay
Live frame misses and dropped-frame counts.
HTTP composer

HTTP composer — replay a captured request or build one from scratch, then send it through your registered client.

Typography inspector
Typography
Style, scaler, and overflow.
Rich text inspector
Rich text
Span-by-span style breakdown.
Borders and radii inspector
Borders & radii
Per-side borders and corner formatting.
Gradient inspector
Gradients
Stops, begin/end, tile mode.
Dark theme gradient inspector
Dark themes
Decoration against dark backgrounds.
Shadow and blur inspector
Shadows & blur
Box shadows and backdrop filters.
Network image inspector
Images
Source, raw pixels, fit, and alignment.
Transform and clip inspector
Transform & clip
Matrix decomposition and clip shape.
Compare two widgets
Compare
Pixel gaps between two widgets.
Zoom magnifier overlay
Zoom
Pixel-level magnifier overlay.

What it covers

The toolkit handles the diagnostics most projects rebuild by hand for every new app.

Capability What it does
Release gating kISpectEnabled is a compile-time constant. Disabled builds tree-shake the toolkit out, so production binaries do not carry it.
Debug panel Draggable in-app overlay with the log viewer, custom actions, and badges.
Widget inspector Tap a widget to read its render box, decoration, constraints, padding, transforms, and text style.
Structured logs Typed entries with severity, log-type keys, filters, bounded history, and JSON export/import.
Network capture Request/response/error capture for Dio, the http package, and WebSocket clients. Requests and responses are paired by correlation ID.
HTTP composer Replay a captured request or build one from scratch and send it through your registered Dio/http client, reusing its base URL, auth interceptors, and retries. Opt in with ISpect.registerSender; redacted values are re-added by the client at send time, not resent.
Database tracing One dbTrace extension wraps any storage call with timing, redaction, optional sampling, and a slow-query threshold.
BLoC observer Events, transitions, state changes, errors, and create/close hooks routed through the log pipeline.
Riverpod observer Provider add, update, dispose, and failure events routed through the log pipeline with the same redaction surface.
Redaction Auth headers, tokens, passwords, PII, and financial data masked before they reach logs, exports, observers, or the cURL helper.
Observer hooks Forward selected log categories to your own sink through an ISpectObserver adapter.
Localization 14 UI languages: en, ru, kk, zh, es, fr, de, pt, ar, ko, ja, hi, ckb, ku.

Compared to the obvious alternatives

Tool What it does well Where ISpect fits
Flutter DevTools Profiling, memory, CPU, debugger, widget inspector when the IDE is attached. DevTools needs an IDE connection. ISpect runs inside the app and lets a QA build export a session for offline inspection.
Sentry, Crashlytics Production crash reporting, release health, alerts, retention. ISpect captures detail before the app ships. It is not a production telemetry replacement.
Per-client interceptors Logging request bodies to the console. ISpect correlates network, logs, database calls, BLoC events, and navigation in one viewer that shares a single redaction pipeline.

Data handling

ISpect only captures what you enable. Logs, network metadata, optional bodies and headers, database trace arguments, BLoC events, navigation, and exports are all opt-in at the call site.

Redaction is on by default for every supported network and database interceptor. The shared engine masks auth headers, cookies, bearer tokens, passwords, API keys, common PII (emails, phone numbers, SSN-class IDs), and financial fields. Application-specific keys (tenant IDs, internal tokens, account numbers) live in your RedactionService configuration, because only your team knows what counts as sensitive in your data model.

The same redactor runs across every boundary that can leak. Interceptors, log export, clipboard helpers, cURL generation, and observer payloads all pass through it. A request masked in the viewer is also masked in the exported session, the cURL you paste into a ticket, and the payload an observer ships to an internal sink.

A few habits that pay off on shared internal builds:

  • Capture metadata first. Turn body and header logging on only for the bug you are chasing.
  • Register your domain-specific redaction keys before sharing exported sessions outside the engineering team.
  • Treat exported .json sessions according to the data class they contain. They are plain-text artifacts and travel through the same channels as any internal log.
  • Review observer adapters before pointing them at a centralized sink. An observer sees whatever category you choose to forward.
  • Keep release pipelines free of --dart-define=ISPECT_ENABLED=true. The flag is the only thing that turns the toolkit on.

docs/SECURITY.md has the full data-handling policy and a rollout checklist.

Minimal safe setup

Start with the UI shell and metadata-only diagnostics. Turn deeper capture on for the specific problem you are investigating.

  1. Add ispect and wrap the app with ISpect.run(...) and ISpectBuilder.wrap(...).
  2. Run internal builds with --dart-define=ISPECT_ENABLED=true.
  3. Keep production jobs free of that flag.
  4. Add network, database, BLoC, and Riverpod modules one at a time as you need them.
  5. Leave body and header capture off until a payload-level investigation needs it.
  6. Add your project's redaction keys before sharing exported sessions with anyone outside the team.

Rolling file history (opt-in)

Internal Flutter builds can keep a bounded, daily history across app launches:

final logger = ISpectFlutter.init(
  options: ISpectLoggerOptions(maxHistoryItems: 10_000),
  fileHistory: const FileLogHistoryOptions(
    maxSessionDays: 7,
    maxFileSize: 5 * 1024 * 1024,
    maxTotalSize: 50 * 1024 * 1024,
  ),
);

ISpect.run(() => runApp(const App()), logger: logger);

RollingFileLogHistory writes redacted JSON Lines to the application cache, rotates segments by their actual UTF-8 size, and bounds both retained days and total disk usage. Existing 4.x logs_YYYY-MM-DD.json files remain readable. ISpectFlutter.init(fileHistory: ...) falls back to normal in-memory history on web, and creates no directory, timer, or file when ISPECT_ENABLED is omitted.

Passing fileHistory: above is all it takes: the log viewer then automatically surfaces a Daily Sessions browser — reachable from the settings sheet or by tapping the app-bar title — where each retained day reopens in the same viewer for browsing and search. The browser appears whenever ISpect.logger.fileLogHistory is set; nothing else needs wiring. Optionally set onOpenFile/onShare on the builder's ISpectOptions to add open-in-file-manager and share buttons for those sessions.

Persistence activates only on non-web builds run with --dart-define=ISPECT_ENABLED=true (see Production safety); otherwise the file history stays inert.

The global redaction switch remains authoritative. Setting ISpectRedaction.enabled = false while file history is configured deliberately allows raw values to be persisted. Keep it enabled unless an isolated internal investigation explicitly requires unredacted diagnostics.

The ISpect toolkit

ISpect is a modular monorepo. Pick the packages your project needs. Each one works on its own.

Package What it does
ispect Flutter UI: debug panel, log viewer, navigation observer, inspector integration.
ispect_layout Visual layout inspector with sizes, constraints, decorations, compare mode, and a color picker.
ispectify Pure-Dart logging core: typed log entries, filtering, tracing, observers.
ispectify_dio Dio HTTP interceptor with automatic redaction.
ispectify_http http package interceptor with automatic redaction.
ispectify_ws Provider-agnostic WebSocket capture (any client) with automatic redaction.
ispectify_db Database operation tracing for SQL, ORMs, and KV stores.
ispectify_bloc BLoC event, state, transition, and error observer.
ispectify_riverpod Riverpod provider add, update, dispose, and failure observer.

Release channel

The 5.x line is the current stable channel and is the recommended pin for new integrations. If your dependency policy still requires the older API surface, the latest 4.x release remains available on pub.dev.

Project state

What you can verify from the repository today:

  • The current line is 5.x stable. 4.x stable is still available on pub.dev for teams that need it.
  • SDK baseline is Dart >=3.6.0 <4.0.0. Flutter packages are tested against the pinned Flutter SDK in CI, and the latest stable channel runs as an advisory signal.
  • A production_safety CI job builds a release APK without ISPECT_ENABLED and counts residual "ispect" strings in the binary.
  • Network capture, export, clipboard, cURL generation, and observer boundaries share the same RedactionService.
  • Deprecations come with replacements and removal targets in docs/DEPRECATIONS.md.

Linked policies:

Performance scope

The latest reproducible AOT hot-path and Android release-footprint data is published in benchmark-data. Startup and frame timing require a recorded physical-device profile pass and are not claimed by the current report. See Performance scope for the measurement method and controls.

Production safety

ISpect is flag-gated at compile time. When ISPECT_ENABLED is not defined, ISpect.run(), ISpectBuilder.wrap(...), and ISpectLocalizations.delegate() resolve to const-guarded no-ops. Because the disabled path is a compile-time constant, release builds let Dart's tree-shaker drop the inactive toolkit code.

The flag is a build-time decision, not a runtime toggle. ISpect does not enable itself in production. A release pipeline opts in only if it explicitly passes --dart-define=ISPECT_ENABLED=true.

# Internal build, toolkit active.
flutter run --dart-define=ISPECT_ENABLED=true

# Release build, toolkit inactive.
flutter build apk

For environment-aware control:

import 'package:flutter/foundation.dart';

class ISpectConfig {
  static const bool isEnabled = bool.fromEnvironment(
    'ISPECT_ENABLED',
    defaultValue: kDebugMode,
  );

  static const String environment = String.fromEnvironment(
    'ENVIRONMENT',
    defaultValue: 'development',
  );

  static bool get shouldInitialize => isEnabled && environment != 'production';
}

Release checklist:

  • Keep production jobs free of --dart-define=ISPECT_ENABLED=true.
  • Keep debug-only setup inside ISpect.run(...) and ISpectBuilder.wrap(...) entry points.
  • Add an environment guard (ENVIRONMENT != 'production') for internal staging builds that share the same pipeline as production.
  • Check the generated artifact if your compliance process needs binary evidence.

Measured footprint on an obfuscated release APK built without --dart-define=ISPECT_ENABLED: 6 residual "ispect" strings, compared to 276 in a development build. Treat the number as a release-footprint sanity check, not a guarantee that every textual reference disappears from the binary.

Repository

This is a monorepo. Every package above plus the standalone web log viewer lives in the same tree, with shared scripts for versioning, publishing, and doc sync. See bash/README.md for the automation stack and docs/VERSION_MANAGEMENT.md for the release workflow.

Documentation workflow

Package READMEs are generated. Sources live in docs/readme/<package>.md and shared fragments in docs/readme/_partials/. Run ./bash/build_readme.sh to regenerate, and ./bash/build_readme.sh --check in CI to catch drift. Hand-edits to packages/*/README.md get overwritten on the next build.

Contributing

Contributions are welcome. See CONTRIBUTING.md for guidelines, and open issues or pull requests at the ISpect repository.

License

MIT. See LICENSE.


Contributors

Libraries

ispect