encatch_flutter
Official Flutter SDK for Encatch — in-app feedback.
Features
- Initialize the SDK with your API key
- Identify users with traits and secure HMAC verification
- Track custom events and screens
- Display feedback forms as a native WebView modal overlay with animations
- Render forms inline in your layout with
EncatchInlineForm - Offline-resilient retry queue with exponential backoff
- 30-second session ping to maintain engagement sessions
- Pre-fill form responses programmatically
- AI-powered text refinement for long-text questions
- Listen to form lifecycle events
- Full feature parity with the Encatch React Native SDK
Installation
Install encatch_flutter:
flutter pub add encatch_flutter
Android Setup
Add internet permission to android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
iOS Setup
No additional setup required. The SDK uses flutter_inappwebview which works out of the box.
Usage
For detailed usage, see the Flutter SDK reference.
1. Wrap your app with EncatchProvider
import 'package:encatch_flutter/encatch_flutter.dart';
void main() {
runApp(
EncatchProvider(
apiKey: 'your-api-key',
child: MyApp(),
),
);
}
2. Identify users
await Encatch.identifyUser(
'user@example.com',
traits: UserTraits(
set: {'name': 'Jane Doe', 'plan': 'pro'},
),
);
3. Track events
await Encatch.trackEvent('button_clicked');
4. Track screens
await Encatch.trackScreen('HomeScreen');
Add EncatchNavigatorObserver for automatic tracking:
MaterialApp(
navigatorObservers: [EncatchNavigatorObserver()],
// ...
)
5. Show a form manually
await Encatch.showForm('your-form-slug');
6. Listen to form events
final unsubscribe = Encatch.on((eventType, payload) {
print('Event: $eventType, payload: ${payload.data}');
});
// Later, to stop listening:
unsubscribe();
7. Pre-fill responses
Encatch.addToResponse('question_id', 'pre-filled value');
await Encatch.showForm('your-form-slug');
Configuration
EncatchProvider(
apiKey: 'your-api-key',
config: EncatchConfig(
theme: EncatchTheme.system,
debugMode: true,
isFullScreen: false,
apiBaseUrl: 'https://app.encatch.com', // override for self-hosted
),
child: MyApp(),
)
Inline forms
EncatchInlineForm renders a form directly inside your widget tree instead of as a full-screen modal overlay. Place it anywhere — in a Column, SingleChildScrollView, Card, etc.
Quick start
// In your screen's widget tree:
SingleChildScrollView(
child: Column(
children: [
// ... content above ...
EncatchInlineForm(
formId: 'your-form-slug', // exact match; omit for wildcard
enabled: ModalRoute.of(context)?.isCurrent ?? true,
),
// ... content below ...
],
),
)
Then trigger the form from anywhere:
await Encatch.showForm('your-form-slug');
Routing rules
When showForm is called, the SDK resolves the presenter in this order:
- Exact match — first registered
EncatchInlineFormwhoseformIdmatches the payload wins. - Wildcard — first registered
EncatchInlineFormwith noformIdcatches anything not exact-matched. - Modal fallback —
EncatchWebViewshows the form as the default overlay when no inline slot is registered or none match.
Tab / navigation focus
A background tab with EncatchInlineForm mounted will intercept showForm calls even when it is not visible. To prevent this:
Option A — pass enabled from ModalRoute:
EncatchInlineForm(
formId: 'your-form-slug',
enabled: ModalRoute.of(context)?.isCurrent ?? true,
)
Option B — only mount EncatchInlineForm on the active route (e.g. using IndexedStack with conditional rendering).
When enabled: false the slot is unregistered, so showForm falls through to the modal or another active slot.
ScrollView embedding
The WebView's internal scroll is disabled. The host SingleChildScrollView (or CustomScrollView) provides scrolling. The widget height grows automatically via form:resize messages from the web form.
SingleChildScrollView(
child: Column(
children: [
EncatchInlineForm(formId: 'my-form'),
],
),
)
Keyboard handling
The host app controls keyboard avoidance. Wrap the scroll view in MediaQuery inset handling or use Scaffold's resizeToAvoidBottomInset to slide content above the keyboard.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
formId |
String? |
null |
Exact form slug/id to match. null = wildcard. |
enabled |
bool |
true |
When false, unregisters the slot — use for tab/route focus. |
minHeight |
double |
0 |
Minimum height floor applied after form:resize. |
decoration |
BoxDecoration? |
null |
Outer container decoration. |
onOverlayOpenChange |
ValueChanged<bool>? |
null |
Called when a QnA/Scheduler overlay opens or closes. |
Custom Native Forms
Use buildSubmitRequest to submit responses from your own native UI:
final request = buildSubmitRequest(
options: BuildSubmitRequestOptions(
formConfigurationId: 'config-id',
triggerType: TriggerType.manual,
),
responses: [
NativeFormResponse(questionId: 'q1', type: 'rating', value: '5'),
NativeFormResponse(questionId: 'q2', type: 'short_answer', value: 'Great!'),
],
);
await Encatch.submitForm(request);
License
MIT License. See LICENSE for details.
Libraries
- encatch_flutter
- Encatch Flutter SDK