Privacy & consent
Gate the Grovs React Native SDK on user consent, and see what it collects.
Gating collection on consent
Call setSDK(false) when the user declines analytics and setSDK(true) when they accept:
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:
import com.grovswrapper.GrovsConsent
Grovs.configure(
this, "your-api-key", useTestEnvironment = false, baseURL = null,
autoTrackScreenViews = false, clipboardDomains = null,
enabled = GrovsConsent.isEnabled(this)
)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,displayMessagesandnumberOfUnreadMessagesreject withcode'SDK_DISABLED'and a message endingGrovs SDK is disabled. Call setSDK(true) first.track,trackScreenView,logInAppPurchaseandlogCustomPurchaseare forwarded; the native SDK sends nothing while disabled.setIdentifier,setAttributes,setPushTokenandsetScreenAliasesare forwarded; the native SDK holds the latest values and syncs them once enabled.- Deep links aren't resolved, so
onDeeplinkReceiveddoesn't fire. Push taps deliver nothing and no opens are reported. - In-app messages don't show.
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:
- What the Android SDK collects, and the Google Play data safety categories to declare
- What the iOS SDK collects, the bundled privacy manifest, and the App Store privacy details to declare
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.