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() for onFunction rules
  • 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:
    • organizationCode
    • propertyCode
    • (Optional) environment, region, jurisdiction, and identities configured

Using a tool like FVM (Flutter Version Manager) is recommended to manage Flutter versions across projects.

Installation

  1. Add the package to your pubspec.yaml:

    dependencies:
      ketch_flutter: ^x.y.z # Use the latest version published to pub.flutter-io.cn
    
  2. Fetch dependencies:

    flutter pub get
    
  3. (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:

  1. Create a KetchController with your organization / property codes and identities.
  2. Create KetchOptions describing environment, region, preferences UI behavior, and callbacks.
  3. Render a KetchView in 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.getCachedConsent();
                    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>> getCachedConsent() – Read the locally cached consent state, without a network call.
  • 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, getConsent, setConsent, invokeRight, getSubscriptions, setSubscriptions, getPreferenceQRUrl — for consent operations that need no WebView.

Most lifecycle events are delivered via callbacks you pass to KetchOptions, such as:

  • onEnvironmentUpdated
  • onRegionUpdated
  • onJurisdictionUpdated
  • onIdentitiesUpdated
  • onConsentUpdated
  • onPrivacyProtocolUpdated
  • onWillShowExperience
  • onHasShownExperience

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 KetchController and KetchOptions
  • 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:

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.

Libraries

ketch_flutter