Komo cards can be embedded into your React Native application through Komo’s package @komo-tech/react-native.

Installation

pnpm add @komo-tech/react-native react-native-webview react-native-safe-area-context
npm install @komo-tech/react-native react-native-webview react-native-safe-area-context
yarn add @komo-tech/react-native react-native-webview react-native-safe-area-context

Basic usage

  • Wrap embedded content in KomoClientProvider.
  • Use KomoCard inside the provider for the fastest setup. It combines metadata fetching, card cover display, and modal handling.
  • Preferred: pass cardId under KomoClientProvider. The provider’s App ID region prefix selects the regional metadata host. To find the card ID in Komo Portal:
    • Navigate to the settings of the card to be embedded.
    • Select the Embed tab and click React Native code in the right sidebar.
    • Copy the generated cardId from the card embed settings or the card actions.
  • Deprecated: embedMetaUrl still works inside or outside the provider for legacy, providerless, custom-host, and emulator flows. When both sources are supplied, cardId takes precedence.
import { KomoCard, KomoClientProvider } from '@komo-tech/react-native';

<KomoClientProvider
  appId="au1_00000000-0000-0000-0000-000000000000"
  getIdentityToken={async () => {
    const token = await getHostJwt();
    return token ? { type: 'jwt', token } : { type: 'anonymous' };
  }}
>
  <KomoCard
    cardId="00000000-0000-0000-0000-000000000000"
    containerStyle={{ maxWidth: '80%' }}
  />
</KomoClientProvider>;

Provider authentication

Use KomoClientProvider for all supported new React Native integrations. It creates the Komo session shared by KomoCard and direct KomoExperienceModal usage beneath it.

appId, getIdentityToken, and children are required.

import {
  KomoCard,
  KomoClientProvider,
  isKomoAuthError,
  useKomoSession
} from '@komo-tech/react-native';

<KomoClientProvider
  appId="au1_00000000-0000-0000-0000-000000000000"
  getIdentityToken={async () => {
    const token = await getHostJwt();
    return token ? { type: 'jwt', token } : { type: 'anonymous' };
  }}
  onAuthenticated={({ contactId, trustLevel }) => {
    trackKomoAuth(contactId, trustLevel);
  }}
  onIdentityChanged={({ previousContactId, contactId, reason }) => {
    trackKomoIdentityChange(previousContactId, contactId, reason);
  }}
  onSessionExpired={({ reason }) => {
    promptUserToSignInAgain(reason);
  }}
  onAuthError={(error) => {
    reportAuthError(error.code, error.retryable);
  }}
>
  <KomoCard cardId="00000000-0000-0000-0000-000000000000" />
</KomoClientProvider>;

const retryIdentify = async (
  komoSession: ReturnType<typeof useKomoSession>
) => {
  try {
    await komoSession.identify();
  } catch (error) {
    if (isKomoAuthError(error) && error.retryable) {
      showRetryPrompt();
    }
  }
};

App ID and identity results

Copy the SDK App ID from Komo Portal. It includes the region prefix in {region}_{appId} format, for example au1_00000000-0000-0000-0000-000000000000. See Workspace Apps for setup steps and identity result behavior. See When getIdentityToken runs for call frequency and refresh behavior.

Return one of these identity results from getIdentityToken:

  • { type: 'jwt', token } exchanges your host JWT for a Komo session.
  • { type: 'email', attributes: { email, ... } } exchanges verified host attributes, attributes.email is required. By default, attributes map to matching contact properties by key. Configure custom mappings in the Workspace App when host attribute keys do not match Komo contact property keys.
  • { type: 'anonymous' } creates an anonymous Komo session. Use this when no host JWT exists but embeds should work for visitors.
  • { type: 'none' } creates no Komo session. Session-backed SDK features will not work.
<KomoClientProvider
  appId="au1_00000000-0000-0000-0000-000000000000"
  getIdentityToken={async () => {
    const token = await getHostJwt();
    return token ? { type: 'jwt', token } : { type: 'anonymous' };
  }}
>
  <KomoCard cardId="00000000-0000-0000-0000-000000000000" />
</KomoClientProvider>

Provider callbacks

Use provider callbacks for session lifecycle UI and analytics:

  • onAuthenticated runs when Komo resolves a session.
  • onIdentityChanged runs when the provider resolves a different identity.
  • onSessionExpired runs when a session expires, refresh fails, or the user logs out.
  • onAuthError receives a KomoAuthError for authentication failures.
<KomoClientProvider
  appId="au1_00000000-0000-0000-0000-000000000000"
  getIdentityToken={getKomoIdentity}
  onAuthError={(error) => {
    switch (error.code) {
      case 'identity_provider_failed':
        showAuthServiceUnavailableMessage();
        break;
      case 'token_invalid':
        promptUserToSignInAgain();
        break;
      default:
        logAuthError(error.code, error.message, error.retryable);
        break;
    }
  }}
>
  <KomoCard cardId="00000000-0000-0000-0000-000000000000" />
</KomoClientProvider>

useKomoSession

Use useKomoSession under KomoClientProvider when app UI needs session state or explicit auth actions.

import { useKomoSession } from '@komo-tech/react-native';
import { Button } from 'react-native';

function SessionActions() {
  const {
    session,
    getSessionToken,
    getCurrentSession,
    identify,
    logout,
    appId,
    sdkInstanceId
  } = useKomoSession();

  return (
    <Button
      title={`Refresh Komo session for ${appId}`}
      onPress={async () => {
        await identify();
        await getSessionToken();
        console.log(getCurrentSession(), session.state, sdkInstanceId);
      }}
    />
  );
}

Prefilling form details

  • Pass information through to Komo forms with formPrefillValues.
  • Use a plain Record<string, string> object.
  • Object keys must match the Unique ID of the Komo form field or contact property.
<KomoCard
  cardId="00000000-0000-0000-0000-000000000000"
  containerStyle={{ maxWidth: '80%' }}
  formPrefillValues={{
    email: 'email@domain.com',
    first_name: 'Person',
    last_name: 'Doe'
  }}
/>

Advanced usage

Metadata fetching

Preferred: use useCardMetadataQuery with cardId under KomoClientProvider. The provider resolves the regional metadata URL from its App ID prefix.

Using cardId outside KomoClientProvider throws:

useCardMetadataQuery cardId must be used within a KomoClientProvider

Deprecated: pass embedMetaUrl for providerless, custom-host, or emulator-specific metadata URLs. When both sources are supplied, cardId takes precedence.

import { useCardMetadataQuery } from '@komo-tech/react-native';

// Preferred: under KomoClientProvider
const { data, isLoading, isError } = useCardMetadataQuery({
  cardId: '00000000-0000-0000-0000-000000000000'
});

// Deprecated compatibility (works without a provider):
// useCardMetadataQuery({ embedMetaUrl: KomoCardNativeEmbedUrl });

For custom fetching, call useKomoSession().buildCardEmbedMetaUrl(cardId) under the provider to derive the regional metadata URL, then fetch with your own data layer.

import { useKomoSession } from '@komo-tech/react-native';

const { buildCardEmbedMetaUrl } = useKomoSession();
const metadataUrl = buildCardEmbedMetaUrl(
  '00000000-0000-0000-0000-000000000000'
);
// e.g. https://api.au1.komo.site/api/v1/live/cards/.../embed-meta

buildCardEmbedMetaUrl validates the card ID, encodes it as one path segment, and uses the provider’s resolved region.

CardEmbedMetadata has the information required to render the cover image and the URL that KomoExperienceModal needs to render the embedded experience. You can use your own data-fetching layer if it produces compatible metadata.

Render a card cover

Use KomoCardCover to display the cover image of a Komo card.

import { KomoCardCover } from '@komo-tech/react-native';

<KomoCardCover
  imageUrl={metadata?.imageUrl}
  imageAspectRatio={metadata?.imageAspectRatio}
  isLoading={isLoading}
  isError={isError}
  onClick={() => setIsModalOpen(true)}
  metaButtonStyle={metadata?.buttonStyle}
  containerStyle={{ borderRadius: 8 }}
/>;

Use the experience modal directly

Use KomoExperienceModal when you want to control the trigger UI yourself. Render it under KomoClientProvider so provider session-token auth is applied.

import { KomoExperienceModal } from '@komo-tech/react-native';

<KomoExperienceModal
  isOpen={isModalOpen}
  onClose={() => setIsModalOpen(false)}
  embedUrl={metadata?.embedUrl}
  loadingTimeoutMs={15000}
/>;

Example without rendering a Komo cover:

const { data, isLoading } = useCardMetadataQuery({
  isEnabled,
  cardId: '00000000-0000-0000-0000-000000000000'
});
const [modalOpen, setModalOpen] = useState(false);

return (
  <>
    <Button
      title="Open Komo experience"
      disabled={isLoading}
      onPress={() => setModalOpen(true)}
    />
    <KomoExperienceModal
      isOpen={modalOpen}
      onClose={() => setModalOpen(false)}
      embedUrl={data?.embedUrl}
    />
  </>
);

Listening for events

  • Use onKomoEvent for User Interaction Events.
  • Use onWindowMessage for raw window.postMessage events from the embedded experience.
  • User Interaction Events also appear in onWindowMessage. onKomoEvent is usually more convenient.
<KomoExperienceModal
  isOpen={modalOpen}
  onClose={() => setModalOpen(false)}
  embedUrl={data?.embedUrl}
  onKomoEvent={(event) => {
    console.log('Komo event received:', event);
  }}
  onWindowMessage={(event) => {
    console.log('Window message received:', event);
  }}
/>

Handling Access Policy auth requests

KomoExperienceModal and KomoCard accept optional onAuthRequest. The embedded experience posts komo:requestAuth when an Access Policy Sdk condition needs host authentication. Show your host login UX, then call useKomoSession().identify().

import { useKomoSession } from '@komo-tech/react-native';

function ExperienceWithAuth() {
  const komoSession = useKomoSession();

  return (
    <KomoExperienceModal
      isOpen={modalOpen}
      onClose={() => setModalOpen(false)}
      embedUrl={data?.embedUrl}
      onAuthRequest={() => {
        void (async () => {
          await startHostLogin();
          await komoSession.identify();
        })();
      }}
    />
  );
}
import { KomoCard, useKomoSession } from '@komo-tech/react-native';

function CardWithAuth() {
  const komoSession = useKomoSession();

  return (
    <KomoCard
      cardId="00000000-0000-0000-0000-000000000000"
      onAuthRequest={() => {
        void (async () => {
          await startHostLogin();
          await komoSession.identify();
        })();
      }}
    />
  );
}

Extension data

KomoExperienceModal and KomoCard can set extension data on User Interaction Events. Avoid PII because extension data is passed to tag manager integrations.

<KomoCard
  cardId="00000000-0000-0000-0000-000000000000"
  extensionDataValues={{
    custom_unique_id: 'ABC123',
    custom_object: {
      some_id: 'ABC123',
      some_measure: 123456
    }
  }}
/>

Query parameters

Pass custom query parameters, such as UTM values, to embedded experiences with queryParams.

import { KomoCard } from '@komo-tech/react-native';

<KomoCard
  cardId="00000000-0000-0000-0000-000000000000"
  queryParams={{
    utm_source: 'mobile-app',
    utm_medium: 'widget',
    utm_campaign: 'summer-2024',
    utm_content: 'hero-banner'
  }}
/>;

These examples assume KomoCard and KomoExperienceModal render under KomoClientProvider.

UTM tracking example

<KomoCard
  cardId={cardId}
  queryParams={{
    utm_source: 'instagram',
    utm_medium: 'social',
    utm_campaign: 'product-launch',
    utm_term: 'keyword',
    utm_content: 'story-swipe-up'
  }}
/>

Dynamic campaign tracking

import { KomoCard } from '@komo-tech/react-native';
import { useRoute } from '@react-navigation/native';

function CampaignScreen() {
  const route = useRoute();
  const { campaignId, source } = route.params;

  return (
    <KomoCard
      cardId={cardId}
      queryParams={{
        utm_campaign: campaignId,
        utm_source: source,
        utm_medium: 'app'
      }}
    />
  );
}

User segment tracking

import { KomoCard } from '@komo-tech/react-native';
import { useUser } from './hooks/useUser';

function ContestScreen() {
  const { userSegment, subscriptionTier } = useUser();

  return (
    <KomoCard
      cardId={cardId}
      queryParams={{
        utm_source: 'app',
        utm_content: userSegment,
        user_tier: subscriptionTier
      }}
    />
  );
}

Combining with other props

Query parameters work alongside form prefill and extension data:

<KomoCard
  cardId={cardId}
  formPrefillValues={{
    email: user.email,
    first_name: user.firstName
  }}
  extensionDataValues={{
    user_id: user.id,
    account_type: user.accountType
  }}
  queryParams={{
    utm_source: 'app',
    utm_medium: 'home-screen',
    utm_campaign: 'welcome-flow'
  }}
/>

queryParams also works with KomoExperienceModal:

<KomoExperienceModal
  isOpen={isOpen}
  onClose={() => setIsOpen(false)}
  embedUrl={metadata?.embedUrl}
  queryParams={{
    utm_source: 'custom-modal',
    utm_medium: 'app'
  }}
/>

Track users coming from deep links:

import { KomoCard } from '@komo-tech/react-native';
import { useEffect, useState } from 'react';
import { Linking } from 'react-native';

function DeepLinkScreen() {
  const [queryParams, setQueryParams] = useState<Record<string, string>>({});

  useEffect(() => {
    Linking.getInitialURL().then((url) => {
      if (!url) return;

      const urlObj = new URL(url);
      const params: Record<string, string> = {};
      urlObj.searchParams.forEach((value, key) => {
        params[key] = value;
      });
      setQueryParams(params);
    });
  }, []);

  return (
    <KomoCard
      cardId={cardId}
      queryParams={{
        ...queryParams,
        utm_source: 'deep-link'
      }}
    />
  );
}

Multi-platform tracking

Detect and track the platform:

import { KomoCard } from '@komo-tech/react-native';
import { Platform } from 'react-native';

<KomoCard
  cardId={cardId}
  queryParams={{
    utm_source: 'react-native',
    utm_medium: 'app',
    platform: Platform.OS,
    app_version: getAppVersion()
  }}
/>;

Query parameters are added directly to the webview URL. All values must be strings. They can be combined with formPrefillValues and extensionDataValues.

Legacy Auth0 session transfer

This section applies only to older integrations that do not use KomoClientProvider. New integrations should use provider authentication.

  • Legacy integrations can pass Auth0 authentication through authPassthroughParams on KomoCard.
  • Legacy direct KomoExperienceModal usage can pass Auth0 authentication through embedAuthUrl and authPassthroughParams.
  • embedAuthUrl is typically obtained from CardEmbedMetadata.
  • Auth0 SSO must be configured on the Komo site, and Force Embed Auth must be enabled under Embed SDK settings.
  • The session transfer token must be obtained immediately before opening the modal because it has a short lifespan.
  • Specify webViewProps={{ incognito: true }} to clear session state when changing between authenticated users.
{/* Legacy providerless Auth0 transfer (deprecated embedMetaUrl path) */}
<KomoCard
  embedMetaUrl={KomoCardNativeEmbedUrl}
  authPassthroughParams={new URLSearchParams({
    session_transfer_token: 'ABC123'
  })}
  webViewProps={{ incognito: true }}
/>

<KomoExperienceModal
  isOpen={isModalOpen}
  onClose={() => setIsModalOpen(false)}
  embedUrl={metadata?.embedUrl}
  embedAuthUrl={metadata?.embedAuthUrl}
  authPassthroughParams={new URLSearchParams({
    session_transfer_token: 'ABC123'
  })}
  webViewProps={{ incognito: true }}
/>

Auth0 error handling

If the session_transfer_token is used, invalid, or expired, the modal shows its errorDisplay, including a built-in retry button. Provide a custom errorDisplay if you need to regenerate the token before retrying.

API reference

KomoClientProvider props

Name Type Required Description
appId string Yes Workspace App ID copied from Komo Portal, including region prefix
getIdentityToken () => Promise<IdentityResult> | IdentityResult Yes Returns identity used for session exchange
children ReactNode Yes Components that should share the provider session
fetch PortableFetch | RuntimeFetch No Custom fetch implementation. Defaults to globalThis.fetch
logger EmbedCoreLogger No Optional logger passed to the session manager
onAuthenticated ({ contactId, trustLevel }) => void No Called when provider session authenticates
onIdentityChanged (payload: IdentityChangedPayload) => void No Called when provider session resolves to a different identity
onSessionExpired ({ reason }) => void No Called when provider session expires, refresh fails, or logs out
onAuthError (error: KomoAuthError) => void No Called when provider authentication or refresh fails

useKomoSession return

Name Type Description
session CurrentSession Latest provider session snapshot
getSessionToken () => Promise<string | null> Returns the current bearer token and refreshes state
getCurrentSession () => CurrentSession Imperative current session snapshot read
identify () => Promise<CurrentSession> Forces identity exchange using latest identity result
logout () => void Logs out the current Komo session
buildCardEmbedMetaUrl (cardId: string) => string Derives the regional card metadata URL for custom fetching
appId string Resolved app ID segment used by the provider
sdkInstanceId string Stable SDK instance ID used by the provider

KomoAuthError

KomoAuthError is the stable error contract for provider authentication failures.

Name Type Description
name 'KomoAuthError' Error type discriminator
code KomoAuthErrorCode Stable machine-readable reason
source 'app' | 'komo' | 'sdk' Origin of the failure
retryable boolean Whether retrying may succeed
status number? HTTP status when Komo returned one
failureReason ExchangeFailureReason? Raw Komo auth failure reason when returned
message string Human-readable diagnostic message

CardEmbedMetadata

Name Type Description
title string? Title of the card
imageUrl string? URL of the card cover image
imageHeight number? Height of the cover image in pixels
imageWidth number? Width of the cover image in pixels
imageAspectRatio number? Aspect ratio of the cover image
embedUrl string? URL for the embedded experience
embedAuthUrl string? Legacy OAuth URL before showing the embedded experience
buttonStyle ButtonStyle? Styling for the card button

KomoCardCover props

Name Type Required Description
onClick () => void Yes Callback for when the cover is clicked
isLoading boolean Yes Whether the cover is loading
isError boolean? No Whether the cover is in an error state
loader ReactNode? No Override the default skeleton loader
errorDisplay ReactNode? No Override the default error display
metaButtonStyle ButtonStyle? No Button style returned from the embed metadata endpoint
overrideButtonStyle StyleProp<ViewStyle>? No Override the button style
overrideButtonTextStyle StyleProp<TextStyle>? No Override the button text style
containerStyle StyleProp<ViewStyle>? No Override the container style
coverImageStyle StyleProp<ImageStyle>? No Override the cover image style
hideCoverButton boolean? No Whether to hide the cover button
imageUrl string? No URL of the cover image
imageAspectRatio number? No Aspect ratio of the cover image

KomoExperienceModal props

Name Type Required Description
isOpen boolean Yes Whether the modal is open
onClose () => void Yes Callback for when close is requested
embedUrl string Yes URL of the embedded card experience
modalHeader ReactNode No Override the default modal header
shareClickUrl string No Override the share link redirect URL
appId string No Identifier for where the content is embedded
formPrefillValues Record<string, string> No Prefill values for the experience
extensionDataValues Record<string, string | number | boolean | object> No Extension data included with User Interaction Events
queryParams Record<string, string> No Query parameters to add to the webview URL
loadingIndicator ReactNode No Override the default loading indicator
modalProps ModalProps No Override the default modal props
safeAreaScrimColor ColorValue No Color used to fill safe area above modal content
loadingTimeoutMs number No Timeout before showing error state. Defaults to 15000ms
errorDisplay ({ onRetry }: { onRetry: () => void }) => ReactNode No Override the default error display
onFileDownload WebViewProps['onFileDownload'] No Callback for file downloads. Only applies to iOS
onKomoEvent (event: KomoEvent) => void No Callback for Komo events
onWindowMessage (event: any) => void No Callback for raw window messages
onAuthRequest OnAuthRequest No Optional. Fires on Access Policy Sdk komo:requestAuth. Then call identify()
embedAuthUrl string No Legacy authorization URL
authPassthroughParams URLSearchParams No Legacy authorization passthrough parameters
webViewProps WebViewProps No Props for react-native-webview
iframeProps IframeProps No Props for the web iframe
debugMode boolean No Enables development troubleshooting logs

KomoCard props

Name Type Required Description
cardId string No* Preferred. Card ID resolved through the provider’s regional metadata host
embedMetaUrl string No* Deprecated. Explicit metadata URL for legacy, providerless, or custom-host flows
appId string No Identifier for where the content is embedded
containerStyle StyleProp<ViewStyle> No Override the container style
coverImageStyle StyleProp<ImageStyle> No Override the cover image style
buttonStyle StyleProp<ViewStyle> No Override the button style
buttonTextStyle StyleProp<TextStyle> No Override the button text style
coverLoader ReactNode No Override the default loader for the cover
coverErrorDisplay ReactNode No Override the default error display for the cover
hideCoverButton boolean No Whether to hide the cover button
modalHeader ReactNode No Override the default modal header
onError (e: any) => void No Callback for metadata query errors
onModalClose () => void No Callback when the modal closes
onModalOpen () => void No Callback when the modal opens
shareClickUrl string No Override the share link redirect URL
formPrefillValues Record<string, string> No Prefill values for the experience
extensionDataValues Record<string, string | number | boolean | object> No Extension data included with User Interaction Events
queryParams Record<string, string> No Query parameters to add to the webview URL
authPassthroughParams URLSearchParams No Legacy authorization passthrough parameters
loadingTimeoutMs number No Timeout before showing modal error state
modalErrorDisplay ({ onRetry }: { onRetry: () => void }) => ReactNode No Override modal error display
onFileDownload WebViewProps['onFileDownload'] No Callback for file downloads. Only applies to iOS
onKomoEvent (event: KomoEvent) => void No Callback for Komo events
onWindowMessage (event: any) => void No Callback for raw window messages
onAuthRequest OnAuthRequest No Optional. Fires on Access Policy Sdk komo:requestAuth. Then call identify()
webViewProps WebViewProps No Props for react-native-webview
iframeProps IframeProps No Props for the web iframe
debugMode boolean No Enables development troubleshooting logs

*At least one of cardId or embedMetaUrl is required. When both are supplied, cardId takes precedence.

useCardMetadataQuery hook

Provide cardId (preferred, requires KomoClientProvider) or deprecated embedMetaUrl. At least one source is required; cardId wins when both are present.

Options

Name Type Required Description
cardId string No* Preferred. Card ID resolved through the provider’s regional metadata host
embedMetaUrl string No* Deprecated. Explicit metadata URL for legacy or providerless flows
isEnabled boolean No Whether the metadata query is enabled. Defaults to true
onError (e: any) => void No Callback for metadata query errors

*At least one of cardId or embedMetaUrl is required.

Result

Name Type Description
data CardEmbedMetadata? Embed metadata for the card
isLoading boolean Whether metadata is loading
isError boolean Whether metadata query failed
isSuccess boolean Whether metadata query succeeded
refetchAsync () => Promise<void> Function to refetch metadata

KomoEvent

Name Type Description
eventName string Name of the Komo event
eventData any Object containing event data
extensionData Record<string, string | number | boolean | object> Extension data raised along with the event
trackedData Record<string, string | number | boolean | object> Optional. Admin-configured contact properties included on the event