The Formbricks Flutter SDK allows you to integrate surveys into native iOS and Android applications built with Flutter.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/formbricks/formbricks/llms.txt
Use this file to discover all available pages before exploring further.
The Flutter SDK uses WebView to render surveys. Make sure your app has the necessary permissions to display web content.
Installation
Add dependencies
Add the required packages to your
pubspec.yaml:dependencies:
flutter:
sdk: flutter
webview_flutter: ^4.0.0
http: ^1.0.0
Configure platform permissions
iOS (ios/Runner/Info.plist):Android (android/app/src/main/AndroidManifest.xml):
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>io.flutter.embedded_views_preview</key>
<true/>
<uses-permission android:name="android.permission.INTERNET" />
Core Implementation
Formbricks Service
Create a service to manage Formbricks functionality:// lib/services/formbricks_service.dart
import 'dart:convert';
import 'package:http/http.dart' as http;
class FormbricksService {
final String environmentId;
final String appUrl;
String? _userId;
String? _contactId;
Map<String, String> _attributes = {};
FormbricksService({
required this.environmentId,
required this.appUrl,
});
/// Initialize the SDK
Future<void> setup() async {
try {
// Fetch environment state
final response = await http.get(
Uri.parse('$appUrl/api/v1/client/$environmentId/environment'),
);
if (response.statusCode == 200) {
print('Formbricks initialized successfully');
} else {
print('Failed to initialize Formbricks: ${response.statusCode}');
}
} catch (e) {
print('Error initializing Formbricks: $e');
}
}
/// Set user ID
Future<void> setUserId(String userId) async {
_userId = userId;
await _updateUser();
}
/// Set user email
Future<void> setEmail(String email) async {
_attributes['email'] = email;
await _updateUser();
}
/// Set user attributes
Future<void> setAttributes(Map<String, String> attributes) async {
_attributes.addAll(attributes);
await _updateUser();
}
/// Set single attribute
Future<void> setAttribute(String key, String value) async {
_attributes[key] = value;
await _updateUser();
}
/// Set user language
Future<void> setLanguage(String language) async {
_attributes['language'] = language;
await _updateUser();
}
/// Track custom event
Future<void> track(String eventName) async {
if (_userId == null) {
print('Cannot track event: User ID not set');
return;
}
try {
final response = await http.post(
Uri.parse('$appUrl/api/v1/client/$environmentId/actions'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({
'userId': _userId,
'name': eventName,
'environmentId': environmentId,
}),
);
if (response.statusCode == 200) {
print('Event tracked: $eventName');
}
} catch (e) {
print('Error tracking event: $e');
}
}
/// Logout user
Future<void> logout() async {
_userId = null;
_contactId = null;
_attributes.clear();
}
/// Update user information on backend
Future<void> _updateUser() async {
if (_userId == null) return;
try {
final response = await http.post(
Uri.parse('$appUrl/api/v1/client/$environmentId/update/contacts/$_userId'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({
'userId': _userId,
'attributes': _attributes,
}),
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
_contactId = data['state']?['data']?['contactId'];
print('User updated successfully');
}
} catch (e) {
print('Error updating user: $e');
}
}
/// Get user ID
String? get userId => _userId;
/// Get contact ID
String? get contactId => _contactId;
}
Survey Display Widget
Create a widget to display surveys:// lib/widgets/formbricks_survey_widget.dart
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class FormbricksSurveyWidget extends StatefulWidget {
final String surveyUrl;
final VoidCallback? onComplete;
final VoidCallback? onClose;
const FormbricksSurveyWidget({
Key? key,
required this.surveyUrl,
this.onComplete,
this.onClose,
}) : super(key: key);
@override
State<FormbricksSurveyWidget> createState() => _FormbricksSurveyWidgetState();
}
class _FormbricksSurveyWidgetState extends State<FormbricksSurveyWidget> {
late WebViewController _controller;
bool _isLoading = true;
@override
void initState() {
super.initState();
_initializeWebView();
}
void _initializeWebView() {
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(
NavigationDelegate(
onPageStarted: (String url) {
setState(() {
_isLoading = true;
});
},
onPageFinished: (String url) {
setState(() {
_isLoading = false;
});
},
),
)
..loadRequest(Uri.parse(widget.surveyUrl));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Survey'),
leading: IconButton(
icon: const Icon(Icons.close),
onPressed: () {
widget.onClose?.call();
Navigator.of(context).pop();
},
),
),
body: Stack(
children: [
WebViewWidget(controller: _controller),
if (_isLoading)
const Center(
child: CircularProgressIndicator(),
),
],
),
);
}
}
Usage Examples
Initialize in Main App
// lib/main.dart
import 'package:flutter/material.dart';
import 'services/formbricks_service.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize Formbricks
final formbricks = FormbricksService(
environmentId: 'your-environment-id',
appUrl: 'https://app.formbricks.com',
);
await formbricks.setup();
runApp(MyApp(formbricks: formbricks));
}
class MyApp extends StatelessWidget {
final FormbricksService formbricks;
const MyApp({Key? key, required this.formbricks}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Formbricks Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(formbricks: formbricks),
);
}
}
User Authentication
// lib/screens/login_screen.dart
import 'package:flutter/material.dart';
import '../services/formbricks_service.dart';
class LoginScreen extends StatelessWidget {
final FormbricksService formbricks;
const LoginScreen({Key? key, required this.formbricks}) : super(key: key);
Future<void> _handleLogin(String userId, String email) async {
// Your authentication logic
await authenticate(userId);
// Identify user in Formbricks
await formbricks.setUserId(userId);
await formbricks.setEmail(email);
await formbricks.setAttributes({
'loginDate': DateTime.now().toIso8601String(),
'platform': 'mobile',
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () => _handleLogin('user-123', 'user@example.com'),
child: const Text('Login'),
),
),
);
}
}
Track Events
// lib/screens/home_screen.dart
import 'package:flutter/material.dart';
import '../services/formbricks_service.dart';
class HomeScreen extends StatelessWidget {
final FormbricksService formbricks;
const HomeScreen({Key? key, required this.formbricks}) : super(key: key);
Future<void> _handleFeatureUsage(String feature) async {
// Your feature logic
// Track the event
await formbricks.track('feature_${feature}_used');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Home')),
body: Column(
children: [
ElevatedButton(
onPressed: () => _handleFeatureUsage('export'),
child: const Text('Export Data'),
),
ElevatedButton(
onPressed: () => _handleFeatureUsage('share'),
child: const Text('Share'),
),
],
),
);
}
}
Display Survey
// lib/screens/survey_screen.dart
import 'package:flutter/material.dart';
import '../widgets/formbricks_survey_widget.dart';
class SurveyScreen extends StatelessWidget {
final String surveyId;
const SurveyScreen({Key? key, required this.surveyId}) : super(key: key);
@override
Widget build(BuildContext context) {
final surveyUrl = 'https://app.formbricks.com/s/$surveyId';
return FormbricksSurveyWidget(
surveyUrl: surveyUrl,
onComplete: () {
print('Survey completed');
Navigator.of(context).pop();
},
onClose: () {
print('Survey closed');
},
);
}
}
// Show survey from anywhere
void showSurvey(BuildContext context, String surveyId) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SurveyScreen(surveyId: surveyId),
fullscreenDialog: true,
),
);
}
Provider Pattern
For state management with Provider:// lib/providers/formbricks_provider.dart
import 'package:flutter/foundation.dart';
import '../services/formbricks_service.dart';
class FormbricksProvider extends ChangeNotifier {
final FormbricksService _service;
FormbricksProvider({
required String environmentId,
required String appUrl,
}) : _service = FormbricksService(
environmentId: environmentId,
appUrl: appUrl,
);
Future<void> initialize() async {
await _service.setup();
notifyListeners();
}
Future<void> identifyUser(String userId, String email,
{Map<String, String>? attributes}) async {
await _service.setUserId(userId);
await _service.setEmail(email);
if (attributes != null) {
await _service.setAttributes(attributes);
}
notifyListeners();
}
Future<void> trackEvent(String eventName) async {
await _service.track(eventName);
}
Future<void> logout() async {
await _service.logout();
notifyListeners();
}
String? get userId => _service.userId;
String? get contactId => _service.contactId;
}
import 'package:provider/provider.dart';
import 'providers/formbricks_provider.dart';
void main() {
runApp(
ChangeNotifierProvider(
create: (_) => FormbricksProvider(
environmentId: 'your-environment-id',
appUrl: 'https://app.formbricks.com',
)..initialize(),
child: const MyApp(),
),
);
}
// In a widget
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final formbricks = Provider.of<FormbricksProvider>(context);
return ElevatedButton(
onPressed: () => formbricks.trackEvent('button_clicked'),
child: const Text('Track Event'),
);
}
}
Environment Configuration
Create environment-specific configurations:// lib/config/environment.dart
class Environment {
static const String formbricksEnvId = String.fromEnvironment(
'FORMBRICKS_ENV_ID',
defaultValue: 'your-default-env-id',
);
static const String formbricksUrl = String.fromEnvironment(
'FORMBRICKS_URL',
defaultValue: 'https://app.formbricks.com',
);
}
flutter run --dart-define=FORMBRICKS_ENV_ID=your-env-id
Best Practices
- Error Handling: Always wrap API calls in try-catch blocks
- Loading States: Show loading indicators during network operations
- Offline Support: Cache user data locally for offline scenarios
- Permissions: Request necessary permissions before displaying surveys
- User Privacy: Only track essential user information
Troubleshooting
WebView Not Loading
Ensure you have the proper permissions and that the WebView package is properly initialized:import 'package:webview_flutter/webview_flutter.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
// Initialize WebView
if (Platform.isAndroid) {
WebView.platform = SurfaceAndroidWebView();
}
runApp(MyApp());
}
CORS Issues
If you encounter CORS errors, ensure your Formbricks instance allows requests from your app domain.Next Steps
JavaScript SDK
Learn about the core JavaScript SDK
React SDK
Integrate Formbricks with React applications