Docs
grovs.io Start for free

Privacy & consent

Gate the Grovs React Native SDK on user consent, and see what it collects.

Call setSDK(false) when the user declines analytics and setSDK(true) when they accept:

typescript
import Grovs from 'react-native-grovs-wrapper';
 
async function applyConsent(granted: boolean) {
  await consentStore.save(granted);
  Grovs.setSDK(granted);
}

The native SDKs don't persist this flag, so the wrapper does. setSDK stores it (SharedPreferences on Android, UserDefaults on iOS) and forwards it to the native SDK. Before anything is stored, it's true.

Start the next launch disabled

The native SDK is configured in MainApplication and AppDelegate, before any JavaScript runs, and configure starts collecting. A JavaScript setSDK(false) is too late for that launch unless native configure reads the stored value. Pass it as enabled, as the Quick Start and the Expo config plugin do:

Kotlin
import com.grovswrapper.GrovsConsent
 
Grovs.configure(
    this, "your-api-key", useTestEnvironment = false, baseURL = null,
    autoTrackScreenViews = false, clipboardDomains = null,
    enabled = GrovsConsent.isEnabled(this)
)
Swift
import react_native_grovs_wrapper
 
Grovs.configure(
    APIKey: "your-api-key", useTestEnvironment: false,
    autoTrackScreenViews: false, clipboardDomains: nil,
    enabled: GrovsWrapperSwift.isSDKEnabled(), delegate: GrovsWrapperSwift.shared
)

A user who declined then stays opted out from the first frame of the next cold start. Without it, every launch starts enabled until JavaScript calls setSDK(false).

GrovsConsent.isEnabled and GrovsWrapperSwift.isSDKEnabled() return true until setSDK is first called, so the first launch starts enabled. To opt out before the user answers, call Grovs.setSDK(false) as early as possible in JavaScript on that launch. Collection stops there and the next cold start begins disabled.

While the SDK is disabled

The wrapper checks the stored flag before calling native for backend features:

  • generateLink, linkDetails, displayMessages and numberOfUnreadMessages reject with code 'SDK_DISABLED' and a message ending Grovs SDK is disabled. Call setSDK(true) first.
  • track, trackScreenView, logInAppPurchase and logCustomPurchase are forwarded; the native SDK sends nothing while disabled.
  • setIdentifier, setAttributes, setPushToken and setScreenAliases are forwarded; the native SDK holds the latest values and syncs them once enabled.
  • Deep links aren't resolved, so onDeeplinkReceived doesn't fire. Push taps deliver nothing and no opens are reported.
  • In-app messages don't show.
typescript
try {
  const link = await Grovs.generateLink({ title: 'Invite' });
} catch (error) {
  if ((error as { code?: string }).code === 'SDK_DISABLED') {
    // ask for consent, then Grovs.setSDK(true)
  }
}

Natively, no authentication, device lookup, clipboard read, events, screen views or purchases leave the device, and outstanding requests are cancelled. Full lists: Android and iOS.

Re-enabling

setSDK(true) stores the value and enables the native SDK, which authenticates if needed and sends everything held. On Android the wrapper re-forwards onStart for the current Activity, so a launch link from while disabled reaches your listener. On iOS it isn't replayed.

What the SDK collects

The wrapper collects nothing itself: it stores the consent flag locally and forwards your calls. What leaves the device, including the clipboard read for clipboard-assisted deferred deep linking, is per platform:

Anything in setAttributes or event properties (an email or name, say) is data you collect too and needs its own declaration.

Logs

setDebug('info') turns on verbose native logging; setDebug('error') restores the default. Native logs go through Logcat and os_log (see Android and iOS). The wrapper's JavaScript logs (which bridge it uses, listener registration) go to the Metro console prefixed 🔗GROVS JS.

Last updated 2026-10-27
Was this page helpful?