A beautiful in-app viewer for the network logs your Flutter app already collects.
What Peek is. A presentation layer. Your app already has a logger — Dio's interceptors, Talker — and that logger already sees every call. Peek takes what it sees and turns it into a console you can open inside the app: searchable, filterable, one call at a time down to the last header, with export as cURL, HAR, Markdown or text.
What Peek is not. Another network logger. Peek never performs,
intercepts, delays or changes a request. It does not create an
HttpClient, does not wrap Dio, does not touch HttpOverrides, and does
not print to the console. package:http is the one client with nowhere to
watch from, so peek_http wraps the client the app already has — and hands
every call to it as it came, the response back as it arrived. An adapter is
a pair of eyes, not a pair of hands — and if anything inside Peek fails, the
failure reaches PeekOptions.onError, never your app.
Inspired by Pulse. Peek is inspired by Pulse, the network logger for Apple platforms. It is an independent project, written from scratch for Flutter.
Quick start
With Dio, two lines where the client is built and one wherever you want a button:
final dio = Dio(BaseOptions(baseUrl: 'https://api.example.com'));
dio.interceptors.add(PeekDioInterceptor(Peek.instance));
// Later, from any widget:
showPeek(context);
With Talker, one line next to the Talker you already have — the calls its loggers see are Peek's:
final peek = Peek();
peek.attach(PeekTalkerAdapter(peek, talker: talker));
dio.interceptors.add(TalkerDioLogger(talker: talker));
showPeek(context, peek: peek);
With Chopper, one interceptor in the chain:
final client = ChopperClient(
baseUrl: Uri.parse('https://api.example.com'),
interceptors: [PeekChopperInterceptor(Peek.instance)],
);
showPeek(context);
With package:http, which has no interceptors, one client around the one you
have:
final client = PeekHttpClient(Peek.instance, http.Client());
showPeek(context);
Prefer a floating button that is always there? Wrap the app once:
MaterialApp(
builder: (context, child) => PeekOverlay(
enabled: kDebugMode,
child: child!,
),
);
These lines are compiled, not just quoted: they live in
example, an app that makes real
calls all four ways and drives every screen.
Packages
| Package | What it is | Depends on |
|---|---|---|
peek |
The core model, store and exporters (package:peek/core.dart, pure Dart) and the Flutter UI (package:peek/peek.dart) |
flutter, meta |
peek_chopper |
PeekChopperInterceptor: reports what a Chopper client does |
peek, chopper, http |
peek_dio |
PeekDioInterceptor: reports what a Dio client does |
peek, dio |
peek_http |
PeekHttpClient: reports what a package:http client does |
peek, http |
peek_talker |
PeekTalkerAdapter: reads what Talker logs, talker_dio_logger understood out of the box |
peek, peek_dio, talker, talker_dio_logger |
Configuration
Everything is set once, on the Peek instance, and applies to every
adapter:
final peek = Peek(
options: PeekOptions(
enabled: kDebugMode,
limits: const PeekLimits(maxEntries: 500, maxBodyBytes: 256 * 1024),
redaction: PeekRedactionPolicy(
headerNames: {...PeekRedactionPolicy.defaultHeaderNames, 'x-session'},
),
onError: (error, stackTrace) => log('peek: $error'),
),
);
enabled— passkDebugModeto switch Peek off in release builds without touching the adapters.limits— how many calls are kept, how many bytes of a body, how many calls may be pinned. What a body limit costs ismaxEntriesof them, so raise one with the other in mind.redaction— nothing is masked until asked.PeekRedactionPolicy()covers the usual names (Authorization,Cookie,token,passwordand their relatives); each set replaces the built-in one, so extend a set by spreading the defaults back in.- Theme — Peek brings its own look and takes only the brightness from
the app. Register an override on the app's theme to change any token:
ThemeData(extensions: [PeekTheme.light().copyWith(accent: Colors.teal)]). - Strings — subclass
PeekStrings, override what you translate, and pass it toshowPeek(context, strings: ...). - Sharing — Peek depends on no sharing package. Hand it a
PeekShareDelegatewired to the one you use; the example shows it withshare_plus.
Writing your own adapter
An adapter watches a logger and reports PeekEvents into a PeekSink. It
needs one import — package:peek/core.dart — and about a screen of code;
doc/adapters.md is the guide, from the contract to the
package layout, with a checklist at the end.
Contributing
Bugs and ideas go through the issue templates; pull requests through
CONTRIBUTING.md, which has the setup, the scripts and
the definition of done. Security reports are private: see
SECURITY.md.
License
MIT © 2026 Dmitrii Medyannik. The icon outlines come from
Lucide (ISC); see NOTICE.