Skip to main content

endpoint_lens 0.2.1 copy "endpoint_lens: ^0.2.1" to clipboard
endpoint_lens: ^0.2.1 copied to clipboard

Inspect recent API calls in debug builds, and in internal QA releases when you opt in. Attach Dio once, then long-press anywhere.

API Lens #

Created and maintained by Nehal Elsamoly

Add API Lens once. Run your Flutter app in debug, or send an internal QA build. Long-press anywhere to inspect recent API activity.

API Lens is a network inspector for Flutter apps that use Dio. It helps Flutter developers, backend engineers, and QA engineers see the requests the app just made without searching the codebase and without wrapping individual widgets.

API Lens runs automatically in debug builds and can be explicitly enabled in internal QA release builds. It stays disabled in normal production releases.

No widget wrapping is required for basic usage. Debug sessions turn the tool on with no extra flag. A normal production release leaves it off. An internal QA release turns it on only when you pass --dart-define=API_LENS=true.

Global mode shows recent API traffic, and the current route when you opt in. It cannot know which arbitrary widget owns an endpoint. A call may have been started by a Bloc, use case, or repository long before the long press.

Installation #

dependencies:
  endpoint_lens: ^0.2.1
import 'package:dio/dio.dart';
import 'package:endpoint_lens/endpoint_lens.dart';

final dio = Dio();

void main() {
  ApiLens.init(dio: dio);
  runApp(const MyApp());
}

Use that same dio instance everywhere the app makes requests. API Lens does not create a second client.

Then:

flutter run

Long-press anywhere in the app for about 700ms.

API Lens

Recent requests

GET /notifications
200 • 121 ms
Last: 2s ago

That is the whole basic setup. API Lens runs automatically in debug builds and can be explicitly enabled in internal QA release builds. It stays disabled in normal production releases.

QA / Backend APK #

A Flutter developer can build an internal APK and send it to a backend developer, QA engineer, or tester. They install it and inspect the APIs without the Flutter source and without asking which endpoint a screen uses.

flutter build apk --release --dart-define=API_LENS=true

The same flag works for an app bundle:

flutter build appbundle --release --dart-define=API_LENS=true

Send app-release.apk. After install, a long press anywhere opens API Lens. Recent requests show the method, endpoint, status code, duration, and full URL. Copy endpoint, copy full URL, and copy cURL work the same way they do in a debug session. No ApiLensWidget and no feature id are required.

A normal production build leaves the tool off:

flutter build apk --release
Build API Lens
Debug build Enabled automatically
QA release with API_LENS=true Enabled
Normal release Disabled

QA builds with API Lens enabled are internal/testing builds. Do not distribute an API-Lens-enabled QA build publicly unless you intentionally want the inspector available. Authorization tokens, cookies, API keys, and similar values stay [REDACTED].

Production safety #

API Lens runs automatically in debug builds and can be explicitly enabled in internal QA release builds. It stays disabled in normal production releases.

Command API Lens
flutter run On
flutter test On
flutter build apk --debug On
flutter run --profile Off
flutter run --release Off
flutter build apk --release Off
flutter build appbundle --release Off
flutter build apk --release --dart-define=API_LENS=true On
flutter build appbundle --release --dart-define=API_LENS=true On

You do not remove the ApiLens.init call before shipping. The developer opts in to a QA release with --dart-define=API_LENS=true.

When the tool is off it does not store history, does not install a pointer listener, does not add an interceptor, and does not build inspector UI. ApiLens.init returns immediately. A Dio interceptor that is already attached returns immediately.

What you will see #

The sheet lists recent calls, newest first. Each row shows the method, path, status, duration, and how long ago it finished. Repeats of the same method and path collapse into one row with a call count.

Filters: All, GET, POST, PUT, PATCH, DELETE, and Errors.

Open a row for the full URL, status, duration, timestamp, query parameters, and the route name if one was known when the request started. Copy the endpoint, the full URL, or a cURL command. Secrets are redacted. Request and response bodies are not stored, so they are not copied.

If nothing finished in the last 15 seconds, the sheet shows earlier history instead of an empty screen.

A request that starts within 1.5 seconds of a tap can be labeled Likely related. That is a hint about timing. It is not proof that a widget triggered the call.

Optional route names #

Basic inspection works without a navigator observer. Add one when you want the current screen name and a split between requests that started on that route and other recent requests:

MaterialApp(
  navigatorObservers: [ApiLensNavigatorObserver()],
  home: const HomePage(),
)

Only RouteSettings.name is shown. Unnamed routes stay blank. API Lens does not invent a class name such as HomeScreen.

GoRouter, auto_route, and other Router setups should pass ApiLensNavigatorObserver to the navigator they actually use. Tab switches inside one route do not change the route name. Long press still shows recent requests without the observer.

If the app's navigator is hard to find, pass the key you already give MaterialApp:

final navigatorKey = GlobalKey<NavigatorState>();

ApiLens.init(dio: dio, navigatorKey: navigatorKey);

MaterialApp(
  navigatorKey: navigatorKey,
)

Most MaterialApp and CupertinoApp trees do not need the key. API Lens looks up the navigator when the long press completes.

More than one Dio client #

ApiLens.init(dio: apiDio);
ApiLens.attach(uploadDio);

Attaching the same client twice does nothing.

Configuration #

Defaults are enough for normal use. Override them only when you need to:

ApiLens.init(
  dio: dio,
  config: const ApiLensConfig(
    longPressDuration: Duration(milliseconds: 700),
    recentWindow: Duration(seconds: 15),
    maxHistory: 200,
  ),
);

A pointer that moves more than 18 logical pixels cancels the long press, so taps, scrolls, and drags keep working.

Redaction #

Authorization, proxy authorization, cookies, API keys, passwords, passcodes, OTPs, access tokens, refresh tokens, and similar fields are replaced with [REDACTED] before anything is stored. Extra names are added to those defaults; they cannot turn the defaults off.

ApiLens.init(
  dio: dio,
  config: ApiLensConfig(
    redactHeaders: <String>['X-Custom-Secret'],
    redactFields: <String>['pin'],
  ),
);

cURL is built from the redacted URL and headers. It does not include a request body. Response bodies are never read.

Path segments are kept, so /users/123 stays visible. Do not put secrets in the path.

Advanced: exact mapping #

You do not need this for the global inspector. Use it only when you want a specific call tagged with a feature id.

await ApiLens.track(
  feature: 'profile',
  request: () => dio.get('/users/1'),
);

dio.get('/users/1', options: ApiLens.options('profile'));

ApiLens.track follows async/await that starts inside the callback. It does not follow a Bloc or Cubit handler, a Riverpod rebuild, or an isolate. For those, tag the repository method that calls Dio, or pass ApiLens.options.

ApiLensWidget is an optional long-press target for one feature. It is not required around cards, buttons, or screens.

Migrating from 0.1.x #

0.1.x asked you to tag features and wrap widgets, and it required an API_LENS dart-define. 0.2.0 records the Dio client you pass to ApiLens.init and opens from a long press anywhere while the app is running in debug mode. Wrappers are still optional. From 0.2.1, --dart-define=API_LENS=true is only for an internal QA or backend release build. Debug builds do not need it.

FAQ #

Does a normal release include the inspector?

No. API Lens runs automatically in debug builds and can be explicitly enabled in internal QA release builds. It stays disabled in normal production releases.

How does a backend developer or QA engineer use it?

Install the APK built with flutter build apk --release --dart-define=API_LENS=true, then long-press anywhere.

Do I wrap widgets?

No. ApiLens.init(dio: dio) is enough for debug and for a QA release.

Example #

cd example
flutter run

The example loads Home, Products, and Profile through one Dio client and a local mock. Long-press any screen. The Advanced page is the only place that uses exact feature mapping.

An internal QA build of the same example:

flutter build apk --release --dart-define=API_LENS=true

Author & Maintainer #

Nehal Elsamoly

Creator and maintainer of API Lens.

0
likes
160
points
575
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Inspect recent API calls in debug builds, and in internal QA releases when you opt in. Attach Dio once, then long-press anywhere.

Repository (GitHub)
View/report issues

Topics

#flutter #debugging #api #dio #developer-tools

License

MIT (license)

Dependencies

dio, flutter

More

Packages that depend on endpoint_lens