Docs

Privacy & Consent

Gate the Grovs Flutter SDK on user consent, and see what it collects

The SDK collects nothing while it is disabled. The plugin configures the native SDKs when the app launches, before any Dart code runs, so the state for that launch has to come from the native config files. Set GrovsEnabled to false in Info.plist and grovs_enabled to false in AndroidManifest.xml:

XML
<!-- ios/Runner/Info.plist -->
<key>GrovsEnabled</key>
<false/>
XML
<!-- android/app/src/main/AndroidManifest.xml, inside <application> -->
<meta-data
    android:name="grovs_enabled"
    android:value="false" />

Then turn the SDK on or off from Dart as consent changes:

Dart
import 'package:grovs_flutter_plugin/grovs.dart';
 
final grovs = Grovs();
 
Future<void> userDidChangeConsent(bool granted) async {
  await ConsentStore.save(granted); // your own storage
  await grovs.setSDK(granted);
}

The flag is not persisted by the SDK. Store the user's decision yourself and, on every launch, call setSDK(true) once you have restored a positive one:

Dart
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  if (await ConsentStore.hasConsent()) {
    await Grovs().setSDK(true);
  }
  runApp(const App());
}

Leaving the config key at its default of true and calling setSDK(false) in main() is too late. By then the native SDK has been configured enabled and has started authenticating, and on a first launch it may already have read the clipboard. Always start disabled through the config key when you gate on consent.

Calling setSDK with the state the SDK is already in does nothing. On Android the consent state is shared by every Flutter engine in the process, because the native SDK is configured once per process.

While the SDK is disabled

What the native SDKs stop doing is the same as in a native app, and is listed in iOS Privacy & Consent and Android Privacy & Consent. In short:

  • Nothing leaves the device: no authentication, device lookup, events, screen views, or purchases.
  • Link generation fails, so generateLink throws a GrovsException.
  • Changes to the user identifier, user attributes, push token, and screen aliases are held as the latest desired values.
  • Events and purchases already queued stay on the device.

The plugin adds one rule of its own: deep links that arrive while disabled are not delivered on onDeeplinkReceived, and any links buffered for delivery are discarded.

Enabling again

When you call setSDK(true), the native SDK authenticates if needed and sends everything that was held or queued.

The plugin also replays the link that launched the app while it was disabled. On Android it re-runs the launch intent through Grovs.onStart; on iOS it hands the universal link or URL back to the SDK. Only the most recent launch link is kept, and it is delivered on onDeeplinkReceived once resolved.

On iOS, a link lookup that was still in flight when setSDK(false) was called is dropped by the plugin. If consent is granted again before that lookup completes, the native SDK may still deliver it.

What the SDK collects

The plugin collects nothing itself; everything below is collected by the native SDK for the platform the app runs on. The full per-platform tables are in iOS Privacy & Consent and Android Privacy & Consent. In summary:

DataWhen
App version and build, bundle ID or package name, device model, user agent, screen size, time zone, preferred languageWhen the SDK authenticates and looks up the device
A device identifier (IDFV and a keychain identifier on iOS; the Android ID and the Play install referrer on Android)Same
User identifier, user attributes, push tokenOnly if you set them
Installs, opens, time spent, reactivationsAutomatically
Custom events and screen viewsWhen you call track or trackScreenView, and through Grovs.navigatorObserver
PurchasesWhen you call logInAppPurchase or logCustomPurchase
Clipboard contentsRead once on the first launch after install, when your project has recent copy-to-clipboard link clicks and the clipboard holds a web URL. Sent only if it is a link on a Grovs host or one of your GrovsClipboardDomains / grovs_clipboard_domains. See clipboard-assisted deferred deep linking

Neither native SDK reads the advertising identifier, and iOS does not require App Tracking Transparency.

Store privacy declarations

Anything you put in user attributes or event properties, such as an email address or a name, is data you collect too and needs its own declaration.

Logs

setDebugLevel accepts 'info' or 'error'. Any other value is treated as 'error'. Pass 'info' while integrating:

Dart
await Grovs().setDebugLevel('info');

Where the logs appear and how to filter them is platform-specific: see iOS logs and Android logs.

Edit this page on GitHubLast updated 2026-09-15