> ## Documentation Index
> Fetch the complete documentation index at: https://knowledge.komo.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# Mobile App Integration

> Complete guide to embedding Komo sites and cards in mobile apps - React Native SDK, WebView, and hybrid approaches

# Mobile App Integration

Complete guide to embedding Komo experiences in mobile applications.

> **Important Note:** Komo does **not** provide native iOS or Android SDKs. All mobile integration is done via **WebViews** - this is the recommended and only supported approach for embedding Komo in mobile apps.

Three WebView-based approaches available:

* **React Native SDK** (recommended for React Native apps) - Uses WebView under the hood
* **Direct WebView** (simplest for any platform) - Native iOS/Android WebView
* **Browser Embed SDK** (for advanced hybrid apps) - WebView with JavaScript bridge

## Overview

### Native iOS & Android Apps

For **native iOS (Swift/Objective-C)** and **native Android (Kotlin/Java)** apps, use the **Direct WebView** method. Komo experiences run in a WebView component - there is no native SDK to import.

**Why WebViews?**

* Komo experiences are web-based and optimized for mobile browsers
* WebViews provide full feature support without platform-specific SDKs
* Consistent experience across all platforms
* No app store approval delays for content updates

### Three Integration Methods

| Method | Best For | Complexity | Features |
| - | - | - | - |
| **React Native SDK** | React Native apps | Low | Full feature set, pre-built components |
| **Direct WebView** | Native iOS/Android, Flutter, etc. | Lowest | Basic embedding, minimal setup |
| **Browser Embed SDK** | Advanced WebView apps | Medium | Advanced features, JavaScript bridge |

**Platform Guide:**

* **React Native** → Use **React Native SDK** (Method 1)
* **Native iOS (Swift)** → Use **Direct WebView** (Method 2)
* **Native Android (Kotlin)** → Use **Direct WebView** (Method 2)
* **Flutter** → Use **Direct WebView** (Method 2)
* **Other frameworks** → Use **Direct WebView** (Method 2) or **Browser Embed SDK** (Method 3)

### Feature Comparison

| Feature | React Native SDK | Direct WebView | Browser Embed SDK |
| - | - | - | - |
| Card Covers | ✅ Built-in | ❌ Manual | ✅ Built-in |
| Form Prefilling | ✅ Native props | ⚠️ URL params | ✅ JavaScript API |
| Event Listening | ✅ Native callbacks | ❌ Limited | ✅ Full support |
| Auth0/SSO | ✅ Session transfer | ⚠️ Manual | ✅ Session transfer |
| UTM Tracking | ✅ Native props | ⚠️ URL params | ✅ Full support |
| Extension Data | ✅ Native props | ❌ No | ✅ JavaScript API |
| Custom Styling | ✅ Style props | ⚠️ Limited | ✅ CSS/JS |

## Method 1: React Native SDK (Recommended)

### What is it?

The official `@komo-tech/react-native` package provides pre-built React Native components for embedding Komo cards with full feature support including form prefilling, event listening, authentication, and analytics tracking.

**Requirements:**

* React Native app
* `react-native-webview` v13.x (peer dependency)
* `react-native-safe-area-context` v4.0+ (peer dependency)
* iOS 11+ / Android 5.0+

### Installation

```bash theme={null}
npm install @komo-tech/react-native react-native-webview react-native-safe-area-context
```

Or with pnpm:

```bash theme={null}
pnpm add @komo-tech/react-native react-native-webview react-native-safe-area-context
```

Wrap your app in `SafeAreaProvider` from `react-native-safe-area-context` (typically at your root component) so the SDK can read safe-area insets correctly.

**iOS Setup:**

```bash theme={null}
cd ios && pod install
```

### Quick Start: KomoCard

The `KomoCard` component combines everything - metadata fetching, card cover display, and modal handling.

```jsx theme={null}
import { KomoCard } from '@komo-tech/react-native';

function App() {
  return (
    <KomoCard
      embedMetaUrl="https://your-hub.komo.site/api/cards/your-card-id/embed/meta"
      containerStyle={{ maxWidth: '80%' }}
    />
  );
}
```

**Getting the embedMetaUrl:**

1. Go to Komo Portal → Card Settings → Embed tab
2. Click "React Native code" in sidebar
3. Copy "Card embed meta URL"

### Form prefilling

Pass user data to prefill forms in the embedded experience:

```jsx theme={null}
<KomoCard
  embedMetaUrl={embedUrl}
  formPrefillValues={{
    email: user.email,
    first_name: user.firstName,
    last_name: user.lastName,
    phone: user.phoneNumber
  }}
/>
```

**Important:** Object keys must match the Unique ID of form fields or contact properties in Komo.

### Event listening

Listen for user interactions and events:

```jsx theme={null}
<KomoCard
  embedMetaUrl={embedUrl}
  onKomoEvent={(event) => {
    console.log('Komo event:', event);
    // Handle prize won, form submitted, etc.
  }}
  onWindowMessage={(message) => {
    console.log('Raw message:', message);
  }}
/>
```

`onKomoEvent` is a convenience callback for [Komo user interaction events](https://developers.komo.tech/user-interaction-events). `onWindowMessage` exposes all raw `window.postMessage` events from the embedded experience.

**Common events** (kebab-case names from the embed event payload):

* `form-submission` - User submitted a form
* `card-finished` - User completed a card / gameplay experience
* `card-started` - User began interacting with a card
* `coupon-redeemed` - User redeemed a coupon

There is no prize-won embed event. For the full list, see [Events published to Tag Manager data layers](/account-settings/analytics/events-published-to-tag-manager-data-layers).

### UTM tracking & analytics

Track campaign attribution:

```jsx theme={null}
<KomoCard
  embedMetaUrl={embedUrl}
  queryParams={{
    utm_source: 'mobile-app',
    utm_medium: 'home-screen',
    utm_campaign: 'summer-2024',
    utm_content: 'hero-banner'
  }}
/>
```

**Dynamic campaign tracking:**

```jsx theme={null}
import { useRoute } from '@react-navigation/native';

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

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

### Extension data

Pass custom data to analytics integrations (no PII):

```jsx theme={null}
<KomoCard
  embedMetaUrl={embedUrl}
  extensionDataValues={{
    user_segment: 'premium',
    account_type: 'enterprise',
    custom_id: 'ABC123'
  }}
/>
```

### Shared authentication with KomoClientProvider

Wrap your app in `KomoClientProvider` when you want every `KomoCard` and `KomoExperienceModal` underneath it to share a single authenticated Komo session. Provider mode is the recommended approach for apps that already authenticate users (e.g., via your own JWT-issuing backend) and want a consistent identity inside Komo experiences.

```tsx theme={null}
import {
  KomoCard,
  KomoClientProvider
} from '@komo-tech/react-native';

function App() {
  return (
    <KomoClientProvider
      appId="au1_app-guid"
      getIdentityToken={async () => ({
        type: 'jwt',
        token: await getHostJwt()
      })}
      onAuthenticated={({ contactId, trustLevel }) => {
        console.log('Komo session authenticated', contactId, trustLevel);
      }}
      onSessionExpired={({ reason }) => {
        console.log('Komo session expired', reason);
      }}
    >
      <KomoCard embedMetaUrl={KomoCardNativeEmbedUrl} />
    </KomoClientProvider>
  );
}
```

**Required props:**

* `appId` - Workspace app ID copied from the Komo Portal, including region prefix (for example `au1_<app-guid>`).
* `getIdentityToken` - Returns the identity payload used for session exchange. Supported identity types include `{ type: 'jwt', token }`, `{ type: 'anonymous' }`, and `{ type: 'email', attributes: { email, ... } }`.

**Behavior notes:**

* Provider mode appends `komo_session` to embedded experience URLs.
* Legacy per-open `embedAuthUrl` and `authPassthroughParams` flows are **ignored** under `KomoClientProvider`. A development-only warning is logged if you pass them.
* Apps that do not use `KomoClientProvider` keep existing behavior, including Auth0 session transfer.

**Reading the provider session:**

Use `useKomoSession` inside the provider to read the current session, force re-identification, or log out.

```tsx theme={null}
import { useKomoSession } from '@komo-tech/react-native';

function AccountActions() {
  const { session, identify, logout } = useKomoSession();

  const isAuthenticating = session.state === 'AUTHENTICATING';

  return (
    <>
      <Button
        title="Refresh Komo session"
        disabled={isAuthenticating}
        onPress={() => identify()}
      />
      <Button title="Log out of Komo" onPress={logout} />
    </>
  );
}
```

### Auth0 session transfer (no provider)

If you are **not** using `KomoClientProvider`, the SDK still supports per-open Auth0 session transfer:

```jsx theme={null}
<KomoCard
  embedMetaUrl={embedUrl}
  authPassthroughParams={new URLSearchParams({
    session_transfer_token: 'ABC123' // Fresh token, 60s lifespan
  })}
  webViewProps={{ incognito: true }}
/>
```

**Prerequisites:**

* Auth0 SSO configured on Komo Hub
* "Force Embed Auth" enabled in Embed SDK settings
* Session transfer token obtained immediately before opening (60s lifespan)

We recommend `webViewProps={{ incognito: true }}` so user session state is cleared correctly when switching between authenticated users.

### Advanced: Custom implementation

Use individual components for full control:

```jsx theme={null}
import {
  useCardMetadataQuery,
  KomoCardCover,
  KomoExperienceModal
} from '@komo-tech/react-native';
import { useState } from 'react';
import { Button } from 'react-native';

function CustomImplementation() {
  const [isModalOpen, setIsModalOpen] = useState(false);

  // Fetch card metadata
  const { data, isLoading, isError } = useCardMetadataQuery({
    embedMetaUrl: 'https://your-hub.komo.site/api/cards/xxx/embed/meta'
  });

  return (
    <>
      {/* Custom trigger button */}
      <Button
        title="Open Contest"
        onPress={() => setIsModalOpen(true)}
      />

      {/* Or use KomoCardCover component */}
      <KomoCardCover
        imageUrl={data?.imageUrl}
        imageAspectRatio={data?.imageAspectRatio}
        isLoading={isLoading}
        isError={isError}
        onClick={() => setIsModalOpen(true)}
        metaButtonStyle={data?.buttonStyle}
      />

      {/* Experience Modal */}
      <KomoExperienceModal
        isOpen={isModalOpen}
        onClose={() => setIsModalOpen(false)}
        embedUrl={data?.embedUrl}
        embedAuthUrl={data?.embedAuthUrl}
        formPrefillValues={{ email: user.email }}
        queryParams={{ utm_source: 'custom-modal' }}
      />
    </>
  );
}
```

### Styling & customization

Customize the appearance:

```jsx theme={null}
<KomoCard
  embedMetaUrl={embedUrl}
  containerStyle={{
    borderRadius: 12,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.25
  }}
  coverImageStyle={{ borderRadius: 8 }}
  buttonStyle={{ backgroundColor: '#FF6B6B' }}
  buttonTextStyle={{ fontSize: 18, fontWeight: 'bold' }}
/>
```

### Error handling

Handle loading and error states:

```jsx theme={null}
<KomoCard
  embedMetaUrl={embedUrl}
  onError={(error) => {
    console.error('Embed failed:', error);
    // Show error UI, retry button, etc.
  }}
  coverErrorDisplay={<CustomErrorComponent />}
  modalErrorDisplay={({ onRetry }) => (
    <ErrorView onRetry={onRetry} />
  )}
/>
```

### Debug mode

Both `KomoCard` and `KomoExperienceModal` accept a `debugMode` prop that logs the component lifecycle, URL construction, WebView events, and the iOS/Android/web message handshake to the console. Use it while diagnosing form prefill issues, stuck loading states, or platform-specific problems.

```jsx theme={null}
<KomoCard
  embedMetaUrl={KomoCardNativeEmbedUrl}
  formPrefillValues={{ email: 'user@example.com', first_name: 'John' }}
  debugMode={__DEV__} // React Native's development flag
/>
```

**Only enable `debugMode` during development.** Debug logs may include sensitive data and can impact performance — always disable in production builds.

***

## Method 2: Direct WebView (Simplest)

### What is it?

The simplest approach - embed Komo using a standard WebView component with the site or card URL. This is the **recommended approach for native iOS and Android apps** (Swift, Kotlin, Java) as well as Flutter and other frameworks.

> **Note:** There is no native iOS SDK or native Android SDK for Komo. WebView is the standard and only approach for embedding in native mobile apps.

**Best for:**

* **Native iOS apps (Swift/Objective-C)** ← Primary use case
* **Native Android apps (Kotlin/Java)** ← Primary use case
* Flutter apps
* Quick prototyping
* Simple embedding needs
* When you don't need advanced features

### React Native WebView

```jsx theme={null}
import { WebView } from 'react-native-webview';

function SimpleEmbed() {
  return (
    <WebView
      source={{ 
        uri: 'https://your-hub.komo.site/?card=your-card-id&singleCard=true'
      }}
      style={{ flex: 1 }}
    />
  );
}
```

**With UTM Parameters:**

```jsx theme={null}
<WebView
  source={{ 
    uri: 'https://your-hub.komo.site/?card=your-card-id&singleCard=true&utm_source=mobile-app&utm_medium=webview'
  }}
/>
```

### iOS (Swift) - Native App Integration

**This is the standard way to embed Komo in native iOS apps.** There is no separate iOS SDK - WebView is the official integration method.

```swift theme={null}
import WebKit

class ViewController: UIViewController {
    @IBOutlet weak var webView: WKWebView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let url = URL(string: "https://your-hub.komo.site/?card=your-card-id&singleCard=true")!
        let request = URLRequest(url: url)
        webView.load(request)
    }
}
```

### Android (Kotlin) - Native App Integration

**This is the standard way to embed Komo in native Android apps.** There is no separate Android SDK - WebView is the official integration method.

```kotlin theme={null}
import android.webkit.WebView
import android.webkit.WebViewClient

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        val webView: WebView = findViewById(R.id.webview)
        webView.webViewClient = WebViewClient()
        webView.settings.javaScriptEnabled = true
        
        webView.loadUrl("https://your-hub.komo.site/?card=your-card-id&singleCard=true")
    }
}
```

### Flutter

```dart theme={null}
import 'package:webview_flutter/webview_flutter.dart';

class KomoEmbed extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return WebView(
      initialUrl: 'https://your-hub.komo.site/?card=your-card-id&singleCard=true',
      javascriptMode: JavascriptMode.unrestricted,
    );
  }
}
```

### URL Structure

**Single Card (Recommended):**

```text theme={null}
https://your-hub.komo.site/?card=CARD_ID&singleCard=true
```

**Full Hub:**

```text theme={null}
https://your-hub.komo.site/
```

**With Query Parameters:**

```text theme={null}
https://your-hub.komo.site/?card=CARD_ID&singleCard=true&utm_source=app&utm_campaign=spring
```

### Limitations of Direct WebView

❌ **Form prefilling** - Limited to URL parameters only\
❌ **Event listening** - No native callback support\
❌ **Auth0 session transfer** - Must implement manually\
❌ **Extension data** - Not supported\
✅ **UTM tracking** - Works via URL parameters\
✅ **Basic display** - Full Komo experience renders

***

## Method 3: Browser Embed SDK (Advanced)

### What is it?

For advanced use cases, use the Browser Embed SDK within a WebView. Provides JavaScript API for form prefilling, event listening, and authentication - even in mobile WebViews.

**Best for:**

* Hybrid apps with WebView
* Advanced WebView implementations
* When you need JS bridge communication

### Setup

Include the embed script in HTML loaded by WebView:

```html theme={null}
<!DOCTYPE html>
<html>
<head>
    <script>
    (function (n, r, t, c, u, e, f) {
      n[u] = n[u] || (function (q) {
        return new Proxy(q, {
          get(y, s) {
            return s === 'q' ? y[s] || [] : function (...B) {
              (n[u].q = n[u].q || []).push([s, ...B]);
            };
          }
        });
      })({});
      e = r.createElement(t);
      f = r.getElementsByTagName(t)[0];
      e.async = 1;
      e.src = c;
      f.parentNode.insertBefore(e, f);
    })(window, document, 'script', 'https://your-hub.komo.site/assets/embed/embed.js', 'komoEmbed');
    </script>
</head>
<body>
    <div data-komo-embed-card-cover 
         data-komo-embed='{"cardId":"YOUR_CARD_ID"}'>
    </div>
</body>
</html>
```

### JavaScript API in WebView

Once loaded, use the `komoEmbed` object:

```javascript theme={null}
// Prefill forms
komoEmbed.setFormPrefillValues({
  email: 'user@example.com',
  first_name: 'John'
});

// Listen for events
komoEmbed.listenToKomoEvents((event) => {
  console.log('Event:', event);
  // Send to native app via WebView bridge
});

// Set extension data
komoEmbed.setExtensionDataValues({
  user_id: '12345'
});

// Open programmatically
komoEmbed.openExperience({ 
  type: 'card', 
  id: 'YOUR_CARD_ID' 
});
```

### React Native WebView with JS Bridge

```jsx theme={null}
import { WebView } from 'react-native-webview';
import { useRef } from 'react';

function AdvancedWebView() {
  const webViewRef = useRef(null);
  
  const html = `
    <!DOCTYPE html>
    <html>
    <head>
      <script src="https://your-hub.komo.site/assets/embed/embed.js"></script>
    </head>
    <body>
      <div id="komo-container"></div>
      <script>
        // Initialize and listen for events
        komoEmbed.listenToKomoEvents((event) => {
          // Send to React Native
          window.ReactNativeWebView.postMessage(JSON.stringify({
            type: 'komo-event',
            data: event
          }));
        });
        
        // Prefill from native app
        window.prefillForm = (values) => {
          komoEmbed.setFormPrefillValues(values);
        };
      </script>
    </body>
    </html>
  `;
  
  return (
    <WebView
      ref={webViewRef}
      source={{ html }}
      onMessage={(event) => {
        const message = JSON.parse(event.nativeEvent.data);
        if (message.type === 'komo-event') {
          console.log('Komo event:', message.data);
        }
      }}
      injectedJavaScript={`
        window.prefillForm(${JSON.stringify({ email: 'test@test.com' })});
      `}
    />
  );
}
```

***

## Platform-Specific Considerations

### iOS

**App Transport Security (ATS):** Ensure your hub domain is allowed:

```xml theme={null}
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>
```

**Safe Area Insets:** Handle notches and home indicators:

```jsx theme={null}
<SafeAreaView style={{ flex: 1 }}>
  <KomoCard embedMetaUrl={embedUrl} />
</SafeAreaView>
```

### Android

**Hardware Acceleration:** Enable for smooth WebView performance:

```xml theme={null}
<application android:hardwareAccelerated="true" ...>
```

**Back Button Handling:**

```kotlin theme={null}
override fun onBackPressed() {
    if (webView.canGoBack()) {
        webView.goBack()
    } else {
        super.onBackPressed()
    }
}
```

### Performance Tips

**Optimize Loading:**

* Use single card pages (not full hub) for faster load
* Enable caching in WebView settings
* Preload metadata when possible

**Memory Management:**

* Dispose WebViews when not visible
* Limit concurrent embedded experiences
* Monitor memory usage on low-end devices

***

## Authentication & SSO

### Auth0 in React Native

```jsx theme={null}
<KomoCard
  embedMetaUrl={embedUrl}
  authPassthroughParams={new URLSearchParams({
    session_transfer_token: auth0SessionToken
  })}
  webViewProps={{ incognito: true }}
/>
```

**Token Lifecycle:**

1. Detect user needs authentication
2. Obtain fresh session transfer token from Auth0
3. Pass to Komo widget
4. Token valid for 60 seconds only

### Custom Authentication

For non-Auth0 setups, use form prefilling:

```jsx theme={null}
<KomoCard
  embedMetaUrl={embedUrl}
  formPrefillValues={{
    user_id: currentUser.id,
    auth_token: currentUser.token
  }}
/>
```

***

## Testing & Debugging

### Development Tips

**Enable Debug Mode:**

```jsx theme={null}
<KomoCard
  embedMetaUrl={embedUrl}
  webViewProps={{
    allowsInlineMediaPlayback: true,
    mediaPlaybackRequiresUserAction: false,
    allowsAirPlayForMediaPlayback: true
  }}
/>
```

**Console Logging:**

```jsx theme={null}
<WebView
  onMessage={(event) => {
    console.log('WebView message:', event.nativeEvent.data);
  }}
  injectedJavaScript={`
    console.log = (function(oldLog) {
      return function(...args) {
        oldLog.apply(this, args);
        window.ReactNativeWebView.postMessage(JSON.stringify({
          type: 'console',
          data: args
        }));
      };
    })(console.log);
  `}
/>
```

### Common Issues

**White Screen:**

* Check URL is correct and accessible
* Verify network permissions
* Enable WebView debugging

**Slow Loading:**

* Use single card mode
* Enable WebView caching
* Optimize images in Komo

**Form Prefill Not Working:**

* Verify field Unique IDs match
* Check data types (strings only)
* Ensure form is loaded before prefilling

**Authentication Fails:**

* Session token must be fresh (\< 60s)
* Enable incognito mode for clean sessions
* Check Auth0 configuration in Komo

***

## Best Practices

### Do:

* ✅ Use React Native SDK for React Native apps
* ✅ Implement error handling and retry logic
* ✅ Test on real devices, not just simulators
* ✅ Handle authentication token lifecycle properly
* ✅ Use UTM parameters for attribution
* ✅ Optimize images in Komo for mobile
* ✅ Test network connectivity scenarios

### Don't:

* ❌ Hardcode authentication tokens
* ❌ Ignore loading and error states
* ❌ Use full hub URLs when single card will do
* ❌ Forget to handle back button (Android)
* ❌ Disable all WebView security features
* ❌ Assume desktop features work on mobile

***

## Examples by Use Case

### E-commerce App

**Product Page Contest:**

```jsx theme={null}
// Show contest entry on product pages
<KomoCard
  embedMetaUrl={productContestUrl}
  queryParams={{
    utm_source: 'app',
    utm_medium: 'product-page',
    utm_content: productId
  }}
  formPrefillValues={{
    product_id: productId,
    user_id: userId
  }}
/>
```

### Event App

**Live Trivia During Event:**

```jsx theme={null}
// Full-screen trivia experience
<KomoExperienceModal
  isOpen={triviaOpen}
  onClose={() => setTriviaOpen(false)}
  embedUrl={triviaEmbedUrl}
  queryParams={{
    utm_source: 'event-app',
    utm_campaign: eventId
  }}
  onKomoEvent={(event) => {
    if (event.eventName === 'card-finished') {
      showLeaderboard();
    }
  }}
/>
```

### Loyalty App

**Points Redemption:**

```jsx theme={null}
// Allow users to redeem points
<KomoCard
  embedMetaUrl={redemptionCardUrl}
  extensionDataValues={{
    points_balance: user.points,
    tier_level: user.tier
  }}
  onKomoEvent={(event) => {
    if (event.eventName === 'coupon-redeemed') {
      refreshUserPoints();
    }
  }}
/>
```

***

## Related Documentation

* [React Native Package](https://www.npmjs.com/package/@komo-tech/react-native) - NPM documentation
* [Developer Docs](https://developers.komo.tech/embedding/react-native) - Full API reference

***

**Need Help?** Contact [support@komo.tech](mailto:support@komo.tech) for mobile integration assistance.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.