ketch-flutter
This repository contains the Ketch Flutter package in the /lib folder and an example app in the /example folder.
Features
- Drop-in UI via
KetchView(WebView-based) - Imperative control with
KetchController - Consent & Preference experiences
- Live updates to org/property/lang/region/jurisdiction/env/identities
- API region/CDN switching (US, EU, UAT)
- Read consent state & IAB/USP/GPP protocols
- Rule triggers via
trigger()foronFunctionrules - Headless HTTP API for consent operations that need no WebView
- Programmatic CSS override (safe, ≤ 1KB)
- Event callbacks:
environment,region,jurisdiction,identities,consent,privacyProtocol,willShowExperience,hasShownExperience,hideExperience, and errors
Getting started
Prerequisites
- Flutter SDK (3.x or newer recommended)
- Dart 3.x
- A working Android and/or iOS development environment
See the official Flutter docs for platform setup. - A Ketch account with:
organizationCodepropertyCode- (Optional) environment, region, jurisdiction, and identities configured
Using a tool like FVM (Flutter Version Manager) is recommended to manage Flutter versions across projects.
Installation
-
Add the package to your
pubspec.yaml:dependencies: ketch_flutter: ^x.y.z # Use the latest version published to pub.flutter-io.cn -
Fetch dependencies:
flutter pub get -
(Optional) If you plan to run the example app in this repo:
cd example flutter pub get
Enabling AAID (Android advertising ID)
ketch_flutter never adds the Android Advertising ID (AAID) dependency, permission, or Play Data
Safety burden to your app on its own — nothing changes unless you opt in. To enable AAID
resolution for a property that requests it, add both of the following to your own app (not to
ketch_flutter):
// app/build.gradle
dependencies {
implementation "com.google.android.gms:play-services-ads-identifier:18.3.0"
}
<!-- android/app/src/main/AndroidManifest.xml -->
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
Both steps are required — the Gradle dependency makes the identifier available at runtime, and the
manifest permission is what Android and Play Console require to read it. Without either one,
ketch_aaid resolves to null, the same as if AAID weren't requested at all.
Usage
For a working, end-to-end example, see the /example directory.
The typical integration has three steps:
- Create a
KetchControllerwith your organization / property codes and identities. - Create
KetchOptionsdescribing environment, region, preferences UI behavior, and callbacks. - Render a
KetchViewin your widget tree and trigger experiences with the controller.
1. Create a controller
import 'package:flutter/material.dart';
import 'package:ketch_flutter/ketch_flutter.dart';
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late final KetchController _ketchController = KetchController(
organizationCode: 'YOUR_ORGANIZATION_CODE',
propertyCode: 'YOUR_PROPERTY_CODE',
languageCode: 'en', // optional
identities: const {
'email': 'user@example.com',
},
);
late KetchOptions _options = _buildOptions();
KetchOptions _buildOptions() {
final pref = PreferenceExperienceOptions(
tab: PreferenceTab.overviewTab,
showOverviewTab: true,
showConsentsTab: true,
showSubscriptionsTab: true,
showRightsTab: true,
);
return KetchOptions(
organizationCode: 'YOUR_ORGANIZATION_CODE',
propertyCode: 'YOUR_PROPERTY_CODE',
identities: const {
'email': 'user@example.com',
},
languageCode: 'en',
regionCode: 'US', // optional
jurisdictionCode: 'US', // optional
environmentName: null, // or 'uat', etc.
dataCenter: KetchDataCenter.us, // us / eu / uat
preferenceExperienceOptions: pref,
// Event callbacks
onEnvironmentUpdated: (env) => debugPrint('env: $env'),
onRegionUpdated: (r) => debugPrint('region: $r'),
onJurisdictionUpdated: (j) => debugPrint('jurisdiction: $j'),
onIdentitiesUpdated: (ids) => debugPrint('identities: $ids'),
onConsentUpdated: (c) => debugPrint('consent: ${c.toJson()}'),
onPrivacyProtocolUpdated: (p, v) =>
debugPrint('protocol $p: $v'),
onHasShownExperience: () => debugPrint('hasShownExperience'),
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(
controller: _ketchController,
options: _options,
),
);
}
}
2. Add KetchView to your UI
KetchView is a WebView-based widget that renders Ketch consent and preference experiences.
You can embed it full-screen, in a sheet, or in any other layout container.
class MyHomePage extends StatefulWidget {
final KetchController controller;
final KetchOptions options;
const MyHomePage({
super.key,
required this.controller,
required this.options,
});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _isSheetVisible = false;
@override
Widget build(BuildContext context) {
const sheetHeight = 380.0;
return Scaffold(
appBar: AppBar(title: const Text('Ketch Flutter Example')),
body: Stack(
children: [
// Your app content
Center(
child: Wrap(
spacing: 12,
runSpacing: 12,
children: [
OutlinedButton(
onPressed: () => widget.controller.showConsentExperience(),
child: const Text('Show Consent'),
),
OutlinedButton(
onPressed: () {
widget.controller.showPreferenceExperience(
options: widget.options.preferenceExperienceOptions,
);
setState(() => _isSheetVisible = true);
},
child: const Text('Show Preferences'),
),
OutlinedButton(
onPressed: () async {
final consent = await widget.controller.getConsent();
debugPrint('Consent: $consent');
},
child: const Text('Log Consent'),
),
OutlinedButton(
onPressed: () async {
final protocols = await widget.controller.getProtocols();
debugPrint('Protocols: $protocols');
},
child: const Text('Log Protocols'),
),
OutlinedButton(
onPressed: () {
widget.controller.setCssOverride(
'#ketch-banner-button-primary { display: none !important; }',
);
},
child: const Text('Apply CSS Override'),
),
OutlinedButton(
onPressed: () => widget.controller.setCssOverride(null),
child: const Text('Clear CSS Override'),
),
],
),
),
// Bottom sheet containing the KetchView
Align(
alignment: Alignment.bottomCenter,
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
curve: Curves.easeOut,
height: _isSheetVisible ? sheetHeight : 0,
width: double.infinity,
child: ClipRect(
child: SizedBox.expand(
child: KetchView(
controller: widget.controller,
options: widget.options,
),
),
),
),
),
],
),
);
}
}
3. API overview
KetchController exposes imperative methods to control the experience:
showConsentExperience()– Show the consent experience.showPreferenceExperience({PreferenceExperienceOptions? options})– Show the preference experience.dismissExperience()– Hide the current experience.load()– Initialize / reload the experience with the current options.Future<Map<String, dynamic>> getConsent()– Read the current consent state.Future<Map<String, dynamic>> getProtocols()– Read IAB/USP/GPP protocol state.setCssOverride(String? css)– Apply or clear a small CSS override (≤ 1KB).
Resolved values, preferring anything you set explicitly over a network lookup:
Future<String?> getRegion()Future<String?> getJurisdiction()
IAB privacy strings, as written to native storage by the tag:
Future<String> getTCFTCString()Future<String> getUSPrivacyString()Future<String> getGPPHDRGppString()Future<String> getSavedString(String key)
Rule triggers:
await controller.trigger(TriggerName.custom, 'managePrivacy');
Returns false if the function name is invalid or an experience is already
showing. Calls made before the tag finishes loading are queued and fired once
it is ready.
The controller also exposes headless HTTP methods — getBootstrapConfiguration,
getFullConfiguration, fetchConsent, setConsentOnServer, invokeRight,
getSubscriptions, setSubscriptions, preferenceQRUrl — for consent
operations that need no WebView.
Most lifecycle events are delivered via callbacks you pass to KetchOptions, such as:
onEnvironmentUpdatedonRegionUpdatedonJurisdictionUpdatedonIdentitiesUpdatedonConsentUpdatedonPrivacyProtocolUpdatedonWillShowExperienceonHasShownExperience
For additional, more advanced usage examples, see the code in /example/lib/main.dart.
Additional information
Example app / Running locally
To run the included example app:
cd example
flutter pub get
flutter run
The example demonstrates:
- Configuring
KetchControllerandKetchOptions - Switching between API regions (
KetchDataCenter.us,.eu,.uat) - Setting identities
- Showing consent vs. preference experiences
- Reading consent and protocol state
- Applying CSS overrides safely
Where to learn more
For more information about Ketch concepts (organizations, properties, identities, environments, regions, jurisdictions, etc.) and general SDK usage, see the Ketch developer documentation:
- Ketch docs: https://developers.ketch.com/
Contributing
Contributions are welcome!
- If you find a bug or have a feature request, please open an issue in this repository.
- For larger changes, open an issue first to discuss what you’d like to change.
- Follow the existing code style and add tests where appropriate.
Support
If you need help integrating Ketch with your Flutter app:
- File an issue with steps to reproduce, expected behavior, and actual behavior.
- Include your Flutter version, platform (iOS/Android), and any relevant logs.
- For account- or configuration-specific questions, reach out through your standard Ketch support channel.