theprivacylabs_consent 0.2.1
theprivacylabs_consent: ^0.2.1 copied to clipboard
DPDP-compliant consent management SDK for Flutter apps. Manage user privacy preferences across iOS and Android.
Privacy Labs Flutter Consent SDK #
DPDP-compliant consent management SDK for Flutter apps.
Installation #
Add to your pubspec.yaml:
dependencies:
theprivacylabs_consent: ^0.1.1
Then run:
flutter pub get
Quick Start #
1. Initialize the SDK #
import 'package:theprivacylabs_consent/theprivacylabs_consent.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await PrivacyLabsConsent.init(ConsentConfig(
orgId: 'your-org-id', // From Privacy Labs dashboard
onConsentChange: (consent) {
print('Consent changed: ${consent.preferences.toJson()}');
// Enable/disable analytics based on consent
if (consent.preferences.analytics) {
Analytics.enable();
} else {
Analytics.disable();
}
},
onError: (error) {
print('Consent error: $error');
},
debug: kDebugMode, // Enable debug logs in development
));
runApp(MyApp());
}
2. Create Privacy Settings Screen #
import 'package:flutter/material.dart';
import 'package:theprivacylabs_consent/theprivacylabs_consent.dart';
class PrivacySettingsScreen extends StatefulWidget {
@override
_PrivacySettingsScreenState createState() => _PrivacySettingsScreenState();
}
class _PrivacySettingsScreenState extends State<PrivacySettingsScreen> {
List<ConsentCategory> _categories = [];
ConsentState? _consent;
bool _isLoading = true;
@override
void initState() {
super.initState();
_loadData();
}
Future<void> _loadData() async {
final categories = await PrivacyLabsConsent.getCategories(lang: 'en');
final consent = await PrivacyLabsConsent.getConsentStatus();
setState(() {
_categories = categories;
_consent = consent;
_isLoading = false;
});
}
Future<void> _updateConsent(String categoryId, bool value) async {
final current = _consent?.preferences ?? ConsentPreferences();
ConsentPreferences updated;
switch (categoryId) {
case 'analytics':
updated = current.copyWith(analytics: value);
break;
case 'marketing':
updated = current.copyWith(marketing: value);
break;
case 'performance':
updated = current.copyWith(performance: value);
break;
default:
return;
}
await PrivacyLabsConsent.setConsent(updated);
await _loadData(); // Refresh state
}
@override
Widget build(BuildContext context) {
if (_isLoading) {
return Scaffold(
appBar: AppBar(title: Text('Privacy Settings')),
body: Center(child: CircularProgressIndicator()),
);
}
return Scaffold(
appBar: AppBar(title: Text('Privacy Settings')),
body: ListView(
padding: EdgeInsets.all(16),
children: [
Text(
'Control how we use your data',
style: Theme.of(context).textTheme.bodyLarge,
),
SizedBox(height: 24),
// Category toggles
..._categories.map((category) => Card(
child: SwitchListTile(
title: Text(category.name),
subtitle: Text(category.description),
value: _getCategoryValue(category.id),
onChanged: category.required
? null
: (value) => _updateConsent(category.id, value),
),
)),
SizedBox(height: 24),
// Accept All button
ElevatedButton(
onPressed: () async {
await PrivacyLabsConsent.acceptAll();
await _loadData();
},
child: Text('Accept All'),
),
],
),
);
}
bool _getCategoryValue(String categoryId) {
if (_consent == null) return false;
switch (categoryId) {
case 'essential':
return true;
case 'analytics':
return _consent!.preferences.analytics;
case 'marketing':
return _consent!.preferences.marketing;
case 'performance':
return _consent!.preferences.performance;
default:
return false;
}
}
}
3. Link Identity After Login #
// After user logs in
Future<void> handleLogin(String email, String password) async {
final user = await authService.login(email, password);
// Link consent to user identity for cross-device sync
await PrivacyLabsConsent.linkIdentity(
email,
method: IdentityLinkMethod.login,
);
}
// After user signs up
Future<void> handleSignup(String email, String password) async {
final user = await authService.signup(email, password);
await PrivacyLabsConsent.linkIdentity(
email,
method: IdentityLinkMethod.signup,
);
}
4. iOS App Tracking Transparency (Optional) #
For iOS apps that use tracking, you need to request ATT permission:
import 'dart:io';
import 'package:theprivacylabs_consent/theprivacylabs_consent.dart';
Future<void> requestTrackingPermission() async {
if (Platform.isIOS) {
// Request ATT permission first
final attStatus = await PrivacyLabsConsent.requestATTPermission();
if (attStatus == ATTStatus.authorized) {
// User allowed tracking, show privacy settings
Navigator.pushNamed(context, '/privacy-settings');
} else {
// User denied tracking, set consent accordingly
await PrivacyLabsConsent.setConsent(ConsentPreferences(
analytics: false,
marketing: false,
));
}
} else {
// Android: just show privacy settings
Navigator.pushNamed(context, '/privacy-settings');
}
}
Note: ATT requires the app_tracking_transparency package for full support.
API Reference #
PrivacyLabsConsent #
| Method | Description |
|---|---|
init(config) |
Initialize the SDK |
getConsentStatus({syncWithServer}) |
Get current consent state |
hasConsent(category) |
Check if user consented to a category |
getCategories({lang}) |
Get available consent categories |
setConsent(preferences) |
Update consent preferences |
acceptAll() |
Accept all categories |
withdrawConsent() |
Withdraw all consent |
linkIdentity(userKey, {method}) |
Link consent to user identity |
syncFromServer(userId) |
Sync consent from another device |
requestATTPermission() |
Request iOS ATT permission |
getATTStatus() |
Get iOS ATT status |
clearLocalData() |
Clear local consent data |
Types #
ConsentConfig
ConsentConfig({
required String orgId,
String apiBaseUrl = 'https://app.theprivacylabs.com',
bool debug = false,
void Function(ConsentState)? onConsentChange,
void Function(Exception)? onError,
})
ConsentPreferences
ConsentPreferences({
bool essential = true,
bool analytics = false,
bool marketing = false,
bool performance = false,
})
ConsentState
ConsentState({
required bool hasConsent,
required ConsentPreferences preferences,
DateTime? timestamp,
DateTime? expiryDate,
String? platform,
String? deviceId,
bool isSynced = false,
})
Cross-Device Consent Sync #
When a user logs in on a new device, their consent preferences are automatically synced:
- User gives consent on Device A (web or mobile)
- User logs in on Device B (Flutter app)
- SDK calls
linkIdentity()with user's email - Backend finds existing consent and syncs to Device B
onConsentChangecallback fires with synced preferences
This ensures consistent consent across all user devices.
Integration Checklist #
Before Launch #
- ❌ Add SDK to pubspec.yaml
- ❌ Initialize SDK in main.dart with orgId
- ❌ Create Privacy Settings screen with category toggles
- ❌ Add "Withdraw Consent" button that calls
withdrawConsent()(clears local data + records to API) - ❌ Add "Privacy Settings" to app settings/profile menu
On User Events #
- ❌ First app launch: Check consent status, show settings if needed
- ❌ User login: Call
linkIdentity(email, method: IdentityLinkMethod.login) - ❌ User signup: Call
linkIdentity(email, method: IdentityLinkMethod.signup) - ❌ User logout: Optionally call
clearLocalData()
SDK Integration #
- ❌ Gate analytics/marketing SDKs based on consent state
- ❌ Implement
onConsentChangecallback to enable/disable SDKs dynamically - ❌ See SDK Integration Recipes below for per-SDK examples
SDK Integration Recipes #
Important: Mobile SDKs are compiled into your app — you cannot "not load" them at runtime. Instead, consent controls whether each SDK collects data or not. Your app owns execution; Privacy Labs owns consent state + policy.
Firebase Analytics #
import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:theprivacylabs_consent/theprivacylabs_consent.dart';
// On app launch — set initial state
final consent = await PrivacyLabsConsent.getConsentStatus();
await FirebaseAnalytics.instance
.setAnalyticsCollectionEnabled(consent?.preferences.analytics ?? false);
// On consent change — update dynamically
await PrivacyLabsConsent.init(ConsentConfig(
orgId: 'your-org-id',
onConsentChange: (state) async {
await FirebaseAnalytics.instance
.setAnalyticsCollectionEnabled(state.preferences.analytics);
},
));
Firebase Crashlytics #
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
// Gate on analytics (or performance) consent
await FirebaseCrashlytics.instance
.setCrashlyticsCollectionEnabled(consent?.preferences.analytics ?? false);
Mixpanel #
import 'package:mixpanel_flutter/mixpanel_flutter.dart';
final mixpanel = await Mixpanel.init('YOUR_TOKEN', trackAutomaticEvents: false);
// On consent change
if (consent.preferences.analytics) {
mixpanel.optInTracking();
} else {
mixpanel.optOutTracking();
}
Adjust (Marketing Attribution) #
import 'package:adjust_sdk/adjust.dart';
import 'package:adjust_sdk/adjust_config.dart';
final adjustConfig = AdjustConfig('APP_TOKEN', AdjustEnvironment.production);
// Only enable if marketing consent given
if (consent?.preferences.marketing ?? false) {
Adjust.start(adjustConfig);
} else {
Adjust.setEnabled(false);
}
// On consent change
onConsentChange: (state) {
Adjust.setEnabled(state.preferences.marketing);
}
AppsFlyer #
import 'package:appsflyer_sdk/appsflyer_sdk.dart';
// Gate on marketing consent
if (consent?.preferences.marketing ?? false) {
appsflyerSdk.startSDK();
} else {
appsflyerSdk.stop(true);
}
CleverTap / MoEngage (Marketing Push) #
// CleverTap
import 'package:clevertap_plugin/clevertap_plugin.dart';
if (consent?.preferences.marketing ?? false) {
CleverTapPlugin.setOptOut(false);
} else {
CleverTapPlugin.setOptOut(true);
}
// MoEngage
import 'package:moengage_flutter/moengage_flutter.dart';
if (consent?.preferences.marketing ?? false) {
MoEngageFlutter.enableDataTracking();
} else {
MoEngageFlutter.disableDataTracking();
}
Pattern: Consent-Gated Helper #
// utils/consent_gate.dart
import 'package:theprivacylabs_consent/theprivacylabs_consent.dart';
Future<void> ifConsented(String category, Future<void> Function() action) async {
final consent = await PrivacyLabsConsent.getConsentStatus();
final prefs = consent?.preferences;
bool allowed = false;
switch (category) {
case 'analytics':
allowed = prefs?.analytics ?? false;
break;
case 'marketing':
allowed = prefs?.marketing ?? false;
break;
case 'performance':
allowed = prefs?.performance ?? false;
break;
}
if (allowed) {
await action();
}
}
// Usage
await ifConsented('analytics', () => FirebaseAnalytics.instance.logEvent(name: 'purchase'));
await ifConsented('marketing', () => Adjust.trackEvent(adjustEvent));
License #
MIT