Why choose ngrok_flutter?
The ngrok_flutter package brings the official ngrok binary directly into your Flutter code via Dart FFI. It lets you create public tunnels from mobile or desktop apps without leaving the IDE, making it ideal for testing webhooks, deep links, push notifications, and remote debugging.
Installation
Add the plugin to your pubspec.yaml with the standard Flutter command:
flutter pub add ngrok_flutterAfter the command finishes, run flutter pub get to fetch the native binaries for the supported platforms (Android, iOS, macOS, Windows, Linux).
Initial configuration
Ngrok requires an authentication token that you obtain from your ngrok dashboard. Store the token securely (e.g., in .env or a secret manager) and pass it to the plugin during initialization.
import 'package:ngrok_flutter/ngrok_flutter.dart';
Future initNgrok() async {
await Ngrok.initialize(authToken: 'YOUR_NGROK_AUTHTOKEN');
}Choosing a region
Ngrok supports multiple regions (e.g., us, eu, ap). You can specify the region when starting a tunnel. If omitted, the default region defined in your ngrok account is used.
Starting and stopping a tunnel
The API is fully asynchronous, fitting Flutter’s reactive model. Below is the minimal code to start a tunnel on port 8080 and later stop it.
Future startMyTunnel() async {
// Returns a public URL like https://abcd1234.ngrok.io
final url = await Ngrok.startTunnel(port: 8080, region: 'us');
return url;
}
Future stopMyTunnel() async {
await Ngrok.stopTunnel();
}Full example – a tiny UI to control the tunnel
import 'package:flutter/material.dart';
import 'package:ngrok_flutter/ngrok_flutter.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Replace with your real token before running the app.
await Ngrok.initialize(authToken: 'YOUR_NGROK_AUTHTOKEN');
runApp(const NgrokDemoApp());
}
class NgrokDemoApp extends StatelessWidget {
const NgrokDemoApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ngrok_flutter Demo',
home: const TunnelHomePage(),
);
}
}
class TunnelHomePage extends StatefulWidget {
const TunnelHomePage({Key? key}) : super(key: key);
@override
State createState() => _TunnelHomePageState();
}
class _TunnelHomePageState extends State {
String _status = 'Tunnel not started';
Future _startTunnel() async {
try {
final url = await Ngrok.startTunnel(port: 8080, region: 'us');
setState(() => _status = 'Running: $url');
} catch (e) {
setState(() => _status = 'Error: $e');
}
}
Future _stopTunnel() async {
await Ngrok.stopTunnel();
setState(() => _status = 'Tunnel stopped');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('ngrok_flutter Demo')),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(_status),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _startTunnel,
child: const Text('Start Tunnel'),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: _stopTunnel,
child: const Text('Stop Tunnel'),
),
],
),
),
);
}
}Best practices & common pitfalls
- Bundle size: The native ngrok binary is added to each platform’s bundle. Keep an eye on the final APK/IPA size, especially for release builds.
- Development‑only usage: ngrok_flutter is designed for testing and debugging. Do not expose production services through a tunnel without proper security review.
- First‑run download: On the first launch the plugin may download missing binaries. Ensure the device has internet access, or ship the binaries manually if you need an offline workflow.
- FFI limitation: The plugin cannot run on Flutter Web because Web lacks native FFI support.
- Token safety: Never hard‑code your auth token in a public repository. Use environment variables or secure storage.
Tip: When testing webhooks, point the external service to the URL returned by
Ngrok.startTunnel. The tunnel will forward requests to your local server running on the same device, eliminating the need for a separate cloud endpoint.
When to use ngrok_flutter
Use this package when you need a quick, programmatic way to expose a local development server from a Flutter app running on mobile or desktop. Typical scenarios include:
- Testing push‑notification callbacks that require a public URL.
- Debugging deep‑link handling on a physical device.
- Running end‑to‑end integration tests that depend on external services.
- Sharing a preview of a desktop UI with remote teammates.
If you need a production‑grade, always‑on tunnel, consider dedicated services (e.g., Cloudflare Tunnel) instead of embedding ngrok in the app.
Frequently Asked Questions
Do I need an ngrok account to use ngrok_flutter?
Yes. The plugin requires an ngrok authentication token, which you obtain from a free ngrok account. The token is passed to <code>Ngrok.initialize</code>.
Can I use ngrok_flutter on Flutter Web?
No. The package relies on Dart's FFI to load native binaries, and FFI is not supported in the web runtime. Use a cloud‑based tunnel service for web projects.
Will the ngrok binary increase my app size significantly?
The binary adds a few megabytes to each platform bundle. For most development builds this is acceptable, but you may want to strip unused architectures or use a separate build flavor for production.
How do I change the tunnel region after initialization?
Specify the desired region each time you call <code>Ngrok.startTunnel</code> (e.g., <code>region: 'eu'</code>). The region is not stored globally, so you can switch per‑tunnel.
Is it safe to ship ngrok_flutter with my production app?
The package is intended for development and testing. Exposing a public tunnel from a production app can create security risks and unnecessary bandwidth usage. Use it only in debug or internal builds.