React Native Consent UI
The Transcend React Native UI SDK provides a consent management banner API for iOS and Android apps. Import the package as @transcend-io/cm-mobile-ui-react-native. All Transcend API calls are accessed through the useConsent or useConsentUI hooks inside a ConsentProvider.
Requirements: React Native 0.75+, React 18+, react-native-svg
ConsentProvider keeps only two pieces of React state on top of headless usage — consent and isReady. All other SDK methods (setConsent, getSdkConsentStatus, etc.) are passthroughs to the native Transcend Headless SDK.
Install the package and its peer dependency:
yarn add @transcend-io/cm-mobile-ui-react-native react-native-svg
# or
npm install @transcend-io/cm-mobile-ui-react-native react-native-svgInstall pods after adding the package:
cd ios && pod installThe native iOS Headless SDK is pulled in automatically via Swift Package Manager.
No extra repository configuration is required. The native Android Headless SDK (io.transcend.sdk.headless:headless) is included as a transitive dependency. INTERNET and ACCESS_NETWORK_STATE permissions are declared automatically.
Wrap your app in ConsentProvider and pass a config object. The provider initializes the native SDK on mount and exposes readiness through isReady.
import { ConsentProvider } from '@transcend-io/cm-mobile-ui-react-native';
export default function App() {
return (
<ConsentProvider
config={{
bundleId: 'YOUR_BUNDLE_ID', // Required — Transcend bundle ID
mobileAppId: 'com.example.myapp', // Required — your app's mobile identifier from https://app.transcend.io/consent-manager/native/applications
isTest: false, // Use test or production deployment
cdnUrl: 'https://transcend-cdn.com', // Optional — defaults to Transcend's CDN
token: 'AUTH_TOKEN', // Optional — auth token for backend sync
settingsOverrides: {
// Optional — override remote settings at init
country: 'EU',
regime: 'GDPR',
},
}}
onError={(error) => {
// Fires when SDK initialization fails
console.error('Consent SDK init failed:', error);
}}
>
<YourApp />
</ConsentProvider>
);
}Pass an onError callback to ConsentProvider to be notified when initialization fails (e.g. invalid config, network error, or native SDK init rejection). When onError fires, isReady remains false and consent APIs should not be called.
<ConsentProvider
config={{ bundleId: '...', mobileAppId: '...' }}
onError={(error) => {
// Log, report to your error tracker, or show a fallback UI
reportError('consent_init_failed', error);
}}
>
<YourApp />
</ConsentProvider>onError is invoked once per failed init attempt, use it alongside the isReady check in child components. isReady tells you when it is safe to proceed; onError tells you why initialization did not succeed.
| Field | Required | Description |
|---|---|---|
bundleId | Yes | Transcend bundle ID. |
mobileAppId | Yes | Native app identifier registered in Transcend. |
isTest | No | Use test deployment. Default: false. |
cdnUrl | No | CDN base URL. Default: https://transcend-cdn.com. |
token | No | Auth token for backend sync. Required for sync to work. |
settingsOverrides | No | Runtime overrides for remote settings (see Registering Overrides). |
destroyOnClose | No | Tear down the native SDK when the provider unmounts. Default: false. |
Use the isReady signal from useConsent to know when the SDK has finished loading settings and (optionally) completed its initial sync. Do not call consent APIs until isReady is true.
import { useEffect } from 'react';
import { useConsent } from '@transcend-io/cm-mobile-ui-react-native';
function TrackerLoader() {
const { isReady, getSdkConsentStatus } = useConsent();
useEffect(() => {
if (!isReady) return;
void getSdkConsentStatus('analytics_sdk').then((status) => {
if (status === 'ALLOW') {
// Safe to initialize the analytics tracker
}
});
}, [isReady, getSdkConsentStatus]);
return null;
}If initialization fails, isReady remains false and the onError callback passed to ConsentProvider is invoked with the error. Use onError to log or surface the failure; gate all consent and tracker logic on isReady.
Read the current consent from the consent object exposed by useConsent. This is React state kept in sync after initialization, sync, and after setConsent calls.
const { consent } = useConsent();
// consent.confirmed — boolean
// consent.prompted — boolean
// consent.purposes — Record<string, boolean>
// consent.timestamp — ISO 8601 string of when consent was givenPass a map of purpose names to boolean values. Syncs to the backend by default when a token was provided at init.
const { setConsent } = useConsent();
const success = await setConsent(
{
Analytics: true,
Functional: true,
Advertising: false,
},
{
autoSync: true, // Sync to backend after setting (default: true)
confirmed: true, // Mark consent as confirmed (default: true)
timestamp: undefined, // ISO Timestamp associated with the consent change (default: now)
updated: true, // Mark consent as updated (default: true)
}
);After setConsent resolves, the consent object in context is refreshed automatically.
Pass overrides in config.settingsOverrides at initialization to test specific regimes, disable sync, or force configuration values.
<ConsentProvider
config={{
bundleId: 'YOUR_BUNDLE_ID',
mobileAppId: 'com.example.myapp',
settingsOverrides: {
regime: 'GDPR',
},
}}
>
<YourApp />
</ConsentProvider>Common override keys include: "partition", "regime", "defaultRegime".
Backend sync requires an auth token. Pass token in config at init, otherwise sync is skipped and consent is not pushed to or pulled from the backend. Generate a token on your backend server following the Transcend preference store docs.
<ConsentProvider
config={{
bundleId: 'YOUR_BUNDLE_ID',
mobileAppId: 'com.example.myapp',
token: 'AUTH_TOKEN', // Required for sync
}}
>
<YourApp />
</ConsentProvider>The native SDK syncs consent automatically in two cases:
- During initialization using the
tokenfromconfig. - After
setConsentwhenautoSyncistrue(the default).
There is no separate public sync() method. To trigger a sync, call setConsent with autoSync: true and ensure a valid token was provided at init.
Sync is also skipped when SYNC_DISABLED is true in an override.
After a successful sync during init, isReady becomes true and consent reflects any remote changes.
Use these APIs to determine whether a third-party SDK (identified by a service ID) is allowed to run given the current consent state. Gate tracker initialization on isReady, then check status before loading each SDK.
import { useEffect } from 'react';
import { useConsent } from '@transcend-io/cm-mobile-ui-react-native';
function AnalyticsTracker() {
const { isReady, getSdkConsentStatus } = useConsent();
useEffect(() => {
if (!isReady) return;
void getSdkConsentStatus('analytics_sdk').then((status) => {
if (status === 'ALLOW') {
// Initialize analytics SDK
}
});
}, [isReady, getSdkConsentStatus]);
return null;
}Re-run tracker checks whenever isReady transitions to true (e.g. after init) or when consent changes and you need to re-evaluate SDK permissions.
const { getSdkConsentStatus } = useConsent();
const status = await getSdkConsentStatus('analytics_sdk');
switch (status) {
case 'ALLOW':
// SDK may run
break;
case 'BLOCK':
// User denied required purpose(s)
break;
case 'NO_SDK_FOUND':
// Service ID not in purpose map
break;
case 'INTERNAL_ERROR':
// Error occurred
break;
}Pass an array of service IDs to evaluate multiple SDKs at once:
const { batchGetSdkConsentStatuses } = useConsent();
const statusMap = await batchGetSdkConsentStatuses([
'analytics_sdk',
'ads_sdk',
]);
// e.g. { analytics_sdk: 'ALLOW', ads_sdk: 'BLOCK' }| Status | Meaning |
|---|---|
ALLOW | All required purposes for this SDK are granted (or SDK is Essential). |
BLOCK | At least one required purpose was explicitly denied. |
NO_SDK_FOUND | The service ID is not in the SDK purpose map. |
INTERNAL_ERROR | Consent resolution encountered an error while reconciling the service ID's purposes. |
The SDK purpose map is loaded from settings and cached by the native SDK (refreshed every 3 hours).
const {
showConsentManager, // Open the bundled consent UI
hideConsentManager, // Close the bundled consent UI
autoShowConsentManager, // Show UI if auto-prompt conditions are met
} = useConsent();
showConsentManager(); // Opens default experience
showConsentManager({ viewState: 'banner-into-modal' }); // Opens a specific experienceFor direct native access without the React context (advanced usage), import NativeConsent from the package. This bypasses the consent / isReady React state and should only be used when you manage state yourself.
| Scenario | Behavior |
|---|---|
Missing bundleId or mobileAppId | onError invoked; isReady stays false. |
| Native init failure | onError invoked with the error; also logged to console; isReady stays false. |
| API called before ready | Native SDK may throw; always gate on isReady first. |
useConsent outside ConsentProvider | Throws: "useConsent must be used inside ConsentProvider". |