redacto_consent_sdk 2.0.0 copy "redacto_consent_sdk: ^2.0.0" to clipboard
redacto_consent_sdk: ^2.0.0 copied to clipboard

Flutter SDK for integrating Redacto consent notices.

redacto_consent_sdk #

Flutter SDK for integrating Redacto consent notices and a self-service Privacy Center into your app.

Installation #

flutter pub add redacto_consent_sdk

Requirements #

  • Dart >=3.3.0 <4.0.0
  • Flutter >=3.19.0

Architecture #

The SDK follows a client-server architecture pattern:

  1. Your Backend Server acts as a proxy between your Flutter application and Redacto's API, handling token generation and refresh.
  2. Your Flutter Application uses SDK widgets to display consent notices and collect user choices.
  3. SDK Widgets fetch consent content, render UI, and submit consent records.

Before You Start #

You need three UUIDs from your Redacto Console and a CMS API Key.

Where to Find Your UUIDs #

Value Where to find it
Organisation UUID Console → Settings → Organization → Copy UUID (or from the URL: /org/{ORG_UUID}/...)
Workspace UUID Console → Settings → Workspaces → Select your workspace → Copy UUID (or from the URL: /org/.../workspace/{WORKSPACE_UUID}/...)
Notice UUID Console → Consent Management → Notices → Click on your notice → Copy UUID (or from the URL: .../notices/{NOTICE_UUID})

CMS API Key #

Your backend needs a CMS API Key to call the Redacto token API. This key must never appear in frontend code.

Important: You need to obtain your CMS API Key from the Redacto Dashboard. Store this key securely in your environment variables and never expose it to the frontend.

  1. Go to Console → Settings → API Keys.
  2. Click Create API Key.
  3. Copy the key — you will not see it again.
  4. Store it as an environment variable on your server:
export CMS_API_KEY="your-api-key-here"

Required App Configuration #

Store the following values in your app configuration (for example, Dart defines, secure config, or remote config):

Config Value Required Used For
BACKEND_URL Yes Your backend endpoint for consent token and refresh token APIs
NOTICE_UUID Yes (modal flows) Notice rendered by RedactoNoticeConsent
ORGANISATION_UUID Yes (inline flows) Loading consent content and token requests
WORKSPACE_UUID Yes (inline flows) Loading consent content and token requests
BASE_URL No Override the default Redacto consent API base URL

How to wire these values:

  1. Set these values in your app's runtime/build configuration.
  2. Send ORGANISATION_UUID, WORKSPACE_UUID, and optional BASE_URL to your backend token endpoint.
  3. Use returned accessToken and refreshToken with RedactoNoticeConsent, or pass UUIDs (and tokens when available) to RedactoNoticeConsentInline.

Components #

RedactoNoticeConsent #

Modal consent component for initial consent and reconsent flows.

Best for: Initial consent collection, standalone consent flows

Key Characteristics:

  • Requires tokens upfront (must be provided before rendering)
  • Displays as a modal overlay
  • Blocks UI interaction by default
Parameter Type Required Default Description
noticeId String Yes - Notice UUID
accessToken String Yes - JWT access token
refreshToken String Yes - JWT refresh token
baseUrl String? No https://api.redacto.io/consent Override consent API base URL (notice fetch, tokens, legacy writes)
ledgerBaseUrl String? No - Go ledger base URL. When set, consent writes and prior-consent checks route through the ledger (falls back: ledger → baseUrl → default). Omit to keep the legacy consent-server path.
settings ConsentSettings? No - UI styling overrides
language String No "en" Initial language
blockUI bool No true Prevents back-dismiss
onAccept VoidCallback Yes - Called on accept
onDecline VoidCallback Yes - Called on decline
onError ValueChanged<Object>? No - Error callback
applicationId String? No - Application/user-specific UUID
validateAgainst ValidateAgainst No ValidateAgainst.all Validation mode
includeFullyConsentedData bool No false Include review payload for already-consented users
reviewModeButtonText String? No "Update Consent" UI path Custom review CTA text
onPrivacyCenterTap VoidCallback? No - Called instead of opening the privacy center URL in an external browser; use for in-app Privacy Center navigation

When onPrivacyCenterTap is set, tapping the privacy center link in the notice routes to your handler (for example, Navigator.push to a screen hosting RedactoPrivacyCenter). See Privacy Center.

RedactoNoticeConsentInline #

Embedded consent component for inline form contexts.

Best for: Registration forms, checkout flows, multi-step processes

Key Characteristics:

  • Renders inline within your form
  • Auto-submits consent when all conditions are met

Auth paths: The inline widget supports two mutually exclusive auth paths — provide either noticeId + accessToken (post-token) OR orgUuid + workspaceUuid + noticeUuid (pre-token: render the widget while you fetch tokens). Params marked No* in the table below are conditionally required: exactly one of the two combos must be provided.

Parameter Type Required Default Description
noticeId String? No* - Notice UUID (post-token path)
accessToken String? No* - JWT access token (post-token path)
orgUuid String? No* - Organisation UUID (pre-token path)
workspaceUuid String? No* - Workspace UUID (pre-token path)
noticeUuid String? No* - Notice UUID (pre-token path)
baseUrl String? No https://api.redacto.io/consent Override consent API base URL (notice fetch, legacy writes)
ledgerBaseUrl String? No - Go ledger base URL. When set, consent writes and already-consented checks route through the ledger. Applies to the post-token path only (both require an accessToken). Omit for legacy behavior.
settings ConsentSettings? No - UI styling overrides
language String No "en" Initial language
onAccept VoidCallback? No - Called after auto-submit
onDecline VoidCallback? No - Decline callback
onError ValueChanged<Object>? No - Error callback
onValidationChange ValueChanged<bool>? No - Emits validation state
applicationId String? No - Application/user-specific UUID
validateAgainst ValidateAgainst No ValidateAgainst.required Validation mode
includeFullyConsentedData bool No false Include review payload for already-consented users

Usage Example #

import "package:flutter/material.dart";
import "package:redacto_consent_sdk/redacto_consent_sdk.dart";

class ConsentDemo extends StatelessWidget {
  const ConsentDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () {
        showModalBottomSheet<void>(
          context: context,
          isScrollControlled: true,
          builder: (_) => RedactoNoticeConsent(
            noticeId: NOTICE_UUID,
            accessToken: accessToken,
            refreshToken: refreshToken,
            validateAgainst: ValidateAgainst.all,
            onAccept: () => Navigator.of(context).pop(),
            onDecline: () => Navigator.of(context).pop(),
            onError: (error) => debugPrint(error.toString()),
          ),
        );
      },
      child: const Text("Open consent"),
    );
  }
}

Styling (ConsentSettings) #

ConsentSettings supports:

  • Base properties: link, borderRadius, backgroundColor, headingColor, textColor, borderColor, font
  • Buttons:
    • button.accept (backgroundColor, textColor)
    • button.decline (backgroundColor, textColor)
    • button.language (backgroundColor, textColor, selectedBackgroundColor, selectedTextColor)

Privacy Center #

A self-service Privacy Center widget for managing consents, submitting data subject access requests (DSAR), and tracking activity. Renders as a mobile-first single column (matching React Native): top navbar (page title, email, language selector, theme toggle), page content, bottom tab bar (Consents | Requests | Activities | Receipts), and a "Powered by Redacto" footer. Case details is an internal overlay reached from the Requests tab—not a bottom-tab page.

baseUrl is the consent API base URL (same as notice flows, for example https://api.redacto.io/consent), not a separate privacy center URL.

Import #

import "package:redacto_consent_sdk/redacto_consent_sdk.dart";

RedactoPrivacyCenter, PrivacyCenterPage, and related Privacy Center exports are available from the main library entry—no separate import path (unlike React Native's /privacy-center subpath).

Dependencies #

Privacy Center features rely on packages bundled as direct SDK dependencies: intl, file_picker, share_plus, open_filex, and path_provider. Receipt download/share and DSAR file upload use the platform share sheet and file picker; follow standard Flutter iOS and Android setup for those plugins. You do not need to add these packages separately when using redacto_consent_sdk.

RedactoPrivacyCenter #

Parameter Type Required Default Description
baseUrl String Yes - Consent API base URL for Privacy Center requests
ledgerBaseUrl String? No - Go ledger base URL. When set, user consents, receipts, and manage-consent route through the ledger. Omit to use the legacy /dsar/privacy-center/* routes. See the note below on the DSAR form picker.
accessToken String Yes - JWT access token
refreshToken String Yes - JWT refresh token
onError void Function(Object error) Yes - Error handler
theme Brightness No Brightness.light Visual theme (Brightness.light or Brightness.dark); user can toggle from the navbar
initialPage PrivacyCenterPage No PrivacyCenterPage.consentManager Initial tab: consentManager, form, activity, or receipt. Do not use caseDetails—it is internal and opened from the Requests list
language String No "en" Initial language code (for example en, hi); drives UI strings and the API language query param; user can change from the navbar
contactEmail String? No - User contact email for case history and forms when the JWT does not embed it (common with backend-issued consent tokens)
onBack VoidCallback? No - When set, the navbar shows a back arrow that invokes this callback (for example Navigator.of(context).pop())

Usage Example #

import "package:flutter/material.dart";
import "package:redacto_consent_sdk/redacto_consent_sdk.dart";

class PrivacyCenterScreen extends StatelessWidget {
  const PrivacyCenterScreen({
    super.key,
    required this.accessToken,
    required this.refreshToken,
    this.userEmail,
  });

  final String accessToken;
  final String refreshToken;
  final String? userEmail;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: RedactoPrivacyCenter(
        baseUrl: BASE_URL,
        accessToken: accessToken,
        refreshToken: refreshToken,
        contactEmail: userEmail,
        theme: Brightness.light,
        initialPage: PrivacyCenterPage.consentManager,
        onBack: () => Navigator.of(context).pop(),
        onError: (error) => debugPrint(error.toString()),
      ),
    );
  }
}

Ledger mode #

Passing ledgerBaseUrl routes consent-bearing reads and writes to the Go ledger:

  • Notice widgetssubmit-consent goes to the ledger, and the already-consented check uses the ledger's check-consent endpoint instead of the legacy HTTP 409 signal. Notice content and tokens always stay on baseUrl.
  • Privacy Center — user consents, receipts (including the /download PDF path), and manage-consent (sent as a partial: true write) route to the ledger. DSAR form, cases, activities, uploads, and OTP stay on baseUrl.

ledgerBaseUrl is independent of baseUrl — you still pass both. Every ledger read degrades to the legacy path on failure, so a ledger outage does not break the consent flow.

Known limitation. The DSAR form is not ledger-aware. It sources its purpose list from Python's form/data flat purposes array and has no product-grouped picker (the React and React Native SDKs group DSAR targets by product and, in ledger mode, source that picker from ledger-served consents — Flutter has no equivalent, and form/data's direct_groups / nominated_groups are not parsed). Setting ledgerBaseUrl does not change the form. If your backend's form/data stops returning purposes for a workspace cut over to the ledger, the form's purpose list will be empty.

Headless API #

For fully custom UIs, the package also exports headless building blocks on top of the same backend:

  • PrivacyCenterApi and PrivacyCenterAuthManager — API client and token refresh
  • PrivacyCenterPage, PCScope, PcTheme — navigation scope and theming
  • Models from privacy_center_models.dart (cases, consents, activities, receipts, etc.)

See the example app for a runnable integration.

Sandbox Mode (No Backend Required) #

Sandbox mode lets you build and test a full consent PoC — notice → Privacy Center → DSAR — straight from your app, with no backend and no token minting. You paste a static sandbox token into the widget instead of your server minting a JWT. Everything is recorded as test data, isolated from live records. Going live is a config swap, not a rewrite.

Sandbox is available on the modal RedactoNoticeConsent and on RedactoPrivacyCenter. The inline RedactoNoticeConsentInline widget has no sandbox mode.

1. Get your sandbox credentials #

Redacto Dashboard → API Keys → Sandbox tab: copy the Sandbox token (static, never expires). Copy your Organization ID and Workspace ID from the same page under Workspace identifiers.

Pass the sandbox token plus org/workspace and a test identity to RedactoNoticeConsent — no accessToken, no refreshToken:

import "package:flutter/material.dart";
import "package:redacto_consent_sdk/redacto_consent_sdk.dart";

showModalBottomSheet<void>(
  context: context,
  isScrollControlled: true,
  builder: (_) => RedactoNoticeConsent(
    noticeId: NOTICE_UUID,
    token: SANDBOX_TOKEN,
    organisationUuid: ORGANISATION_UUID,
    workspaceUuid: WORKSPACE_UUID,
    email: "test.user@example.com", // or mobile / ucic
    onAccept: () => Navigator.of(context).pop(),
    onDecline: () => Navigator.of(context).pop(),
    onError: (error) => debugPrint(error.toString()),
  ),
);

Give RedactoPrivacyCenter the same token, org, workspace, and test identity. The same test user can review their consent, withdraw it, and file a DSAR — all recorded as test data:

import "package:flutter/material.dart";
import "package:redacto_consent_sdk/redacto_consent_sdk.dart";

Scaffold(
  body: RedactoPrivacyCenter(
    baseUrl: BASE_URL,
    token: SANDBOX_TOKEN,
    organisationUuid: ORGANISATION_UUID,
    workspaceUuid: WORKSPACE_UUID,
    email: "test.user@example.com", // or mobile / ucic — same identity as step 2
    onBack: () => Navigator.of(context).pop(),
    onError: (error) => debugPrint(error.toString()),
  ),
);

Sandbox props #

These are added to both RedactoNoticeConsent and RedactoPrivacyCenter. In sandbox mode, accessToken and refreshToken are omitted.

Parameter Type Required Description
token String? Yes Static sandbox token. Its presence activates sandbox mode.
organisationUuid String? Yes Organization ID (replaces the JWT-decoded org in sandbox mode).
workspaceUuid String? Yes Workspace ID (replaces the JWT-decoded workspace in sandbox mode).
email String? One of email/mobile/ucic Test subject email.
mobile String? One of email/mobile/ucic Test subject mobile (used when email is absent).
ucic String? One of email/mobile/ucic Client's own user id (org_user_id). Takes precedence: ucic > email > mobile.

How it works #

  • The sandbox token is sent as the single X-Consent-Token header; its presence marks the request as test data. There is no Authorization: Bearer and no JWT refresh, so a 401 fails fast instead of retrying.
  • The acting identity rides each request's own payload — query params (org_user_id / primary_email / primary_mobile) on reads, the JSON body on writes — resolved in precedence order ucic > email > mobile.
  • The server records everything under environment=test, namespaced and isolated. Test data never mixes with, or reads from, your live records.
  • Sandbox always talks to the consent server; it never routes to the Go ledger, so ledgerBaseUrl has no effect in sandbox mode.

Going live #

Use the same widgets. Remove the sandbox props (token, organisationUuid, workspaceUuid, and the test identity) and pass a real accessToken / refreshToken JWT minted by your backend. Records then write as environment=live.

Localization #

  • Set initial locale with language on RedactoNoticeConsent or RedactoNoticeConsentInline.
  • UI labels and text content are loaded from notice translations.
  • Users can switch languages via the built-in selector when translations are available.

Privacy Center #

  • Set initial locale with language on RedactoPrivacyCenter.
  • Privacy Center ships built-in UI strings for many locales; users switch language from the navbar selector.
  • language drives both UI strings and API-backed labels where applicable (request types, statuses, purposes).
  • Date and relative-time formatting uses intl internally; the SDK initializes locale data as needed—no extra app setup required.

Troubleshooting #

  • No modal data: verify noticeId, accessToken, and refreshToken.
  • Inline submit not firing: ensure required selections are complete and onValidationChange becomes true.
  • HTTP errors: check backend token generation and baseUrl value.
  • Empty case history or case API errors: pass contactEmail when your JWT does not include the user's email.
  • Wrong language on case details after toggle: the SDK refetches case data on language change; verify tokens are valid and baseUrl is correct.
  • Receipt download or export failures: check platform file and share permissions (iOS share sheet, Android storage where applicable).

Development #

cd packages/consent-sdk-flutter
flutter pub get
dart analyze
flutter test
0
likes
110
points
325
downloads

Documentation

API reference

Publisher

verified publisherredacto.ai

Weekly Downloads

Flutter SDK for integrating Redacto consent notices.

Repository (GitHub)

License

Apache-2.0 (license)

Dependencies

file_picker, flutter, flutter_svg, http, intl, just_audio, open_filex, path_provider, share_plus, url_launcher

More

Packages that depend on redacto_consent_sdk