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-svg

Install pods after adding the package:

cd ios && pod install

The 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.

FieldRequiredDescription
bundleIdYesTranscend bundle ID.
mobileAppIdYesNative app identifier registered in Transcend.
isTestNoUse test deployment. Default: false.
cdnUrlNoCDN base URL. Default: https://transcend-cdn.com.
tokenNoAuth token for backend sync. Required for sync to work.
settingsOverridesNoRuntime overrides for remote settings (see Registering Overrides).
destroyOnCloseNoTear 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 given

Pass 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:

  1. During initialization using the token from config.
  2. After setConsent when autoSync is true (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' }
StatusMeaning
ALLOWAll required purposes for this SDK are granted (or SDK is Essential).
BLOCKAt least one required purpose was explicitly denied.
NO_SDK_FOUNDThe service ID is not in the SDK purpose map.
INTERNAL_ERRORConsent 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 experience

For 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.

ScenarioBehavior
Missing bundleId or mobileAppIdonError invoked; isReady stays false.
Native init failureonError invoked with the error; also logged to console; isReady stays false.
API called before readyNative SDK may throw; always gate on isReady first.
useConsent outside ConsentProviderThrows: "useConsent must be used inside ConsentProvider".