@vitraun/react-native
v0.2.9
Published
Vitraun Try-On React Native adapter (WebView + embed-init bridge)
Readme
@vitraun/react-native
Official Vitraun Virtual Try-On adapter for React Native apps.
Embeds try-on via WebView. The integrator does not hardcode the try-on URL — the SDK calls embed-init, receives vtoUrl, and loads that URL in a WebView.
For web storefronts, use @vitraun/webar instead.
Install
npm install @vitraun/react-native react-native-webviewPeer dependencies: react (≥18), react-native (≥0.72), react-native-webview (≥13).
Depends on @vitraun/core for embed-init HTTP helpers.
Quick start
import { VitraunTryOn } from '@vitraun/react-native'
export const TryOnScreen = () => (
<VitraunTryOn
merchantId="vtrn-mch-key-00000000-0000-4000-8000-000000000001"
widgetId="vtrn-wdg-key-00000000-0000-4000-8000-000000000002"
lang="en-US"
platform="ios"
bundleId="com.your.store"
packageName="com.your.store"
isolatedSku="8028997081552"
basketOpensIn="event"
checkoutOpensIn="event"
onEvent={(event) => {
switch (event.type) {
case 'addToCart':
break
case 'redirectToCart':
break
default:
break
}
}}
/>
)Ecommerce modal (VitraunTryOnModal)
For PDP flows with a Try on button, use VitraunTryOnModal — the React Native equivalent of widget.open() on web:
import { useState } from 'react'
import { Button } from 'react-native'
import { VitraunTryOnModal } from '@vitraun/react-native'
export const ProductTryOn = () => {
const [isOpen, setIsOpen] = useState(false)
return (
<>
<Button title="Try on" onPress={() => setIsOpen(true)} />
<VitraunTryOnModal
visible={isOpen}
onRequestClose={() => setIsOpen(false)}
merchantId="vtrn-mch-key-..."
widgetId="vtrn-wdg-key-..."
isolatedSku="8028997081552"
basketOpensIn="event"
checkoutOpensIn="event"
closeButtonAccessibilityLabel="Close virtual try-on"
onEvent={(event) => console.log(event.type, event.detail)}
/>
</>
)
}| Scenario | Recommendation |
|----------|----------------|
| PDP with CTA button | VitraunTryOnModal |
| Dedicated try-on screen / tab | VitraunTryOn fullscreen in navigation |
| Retailer / QR modes | Behavior stays inside the WebView |
Props embedModalDesktop* and embedModalMobile* mirror panel modal appearance. embedModalBreakpoint defaults to mobile; use auto for tablet landscape desktop layout.
How it works
- The app renders
VitraunTryOn(or callsinitializeVitraunSession). - The SDK triggers try-on by calling embed-init before the WebView loads.
- A WebView loads
vtoUrlonly; an injected bridge forwardspostMessageevents toonEvent.
Shared embed-init logic lives in @vitraun/core.
Navigation & external links
The managed WebView keeps in-app navigation on the VTO origin. External links
(checkout/cart with basketOpensIn/checkoutOpensIn="blank", target="_blank", or window.open)
open in the system browser automatically — you do not need a custom
onShouldStartLoadWithRequest. For native cart/checkout, prefer "event" and handle in onEvent.
Session persistence (optional)
tryonSessionId is generated per mount by default. Pass a storage adapter (e.g. AsyncStorage)
via sessionStorage (and an optional sessionInstanceId to scope it) to keep it stable across opens:
import AsyncStorage from '@react-native-async-storage/async-storage'
const sessionStorage = {
getItem: (key) => AsyncStorage.getItem(key),
setItem: (key, value) => AsyncStorage.setItem(key, value),
}
<VitraunTryOn merchantId="..." widgetId="..." sessionStorage={sessionStorage} sessionInstanceId="pdp-main" />Panel prerequisites
- Register merchant ID and widget ID in the Vitraun panel
- Enable
allowWebViewon the channel - Register iOS bundle ID and/or Android package name
- Add camera permission:
- iOS:
NSCameraUsageDescriptioninInfo.plist - Android:
CAMERAinAndroidManifest.xml
- iOS:
Configuration
| Option | Required | Description |
|--------|----------|-------------|
| merchantId | Yes | Public merchant key (vtrn-mch-key-…) |
| widgetId | Yes | Public widget key (vtrn-wdg-key-…) |
| lang | No | Locale (default en-US) |
| env | No | Environment segment (empty = production; e.g. staging) |
| isolatedSku | No | Single-product (PDP) mode |
| basketOpensIn | No | blank, self, or event |
| checkoutOpensIn | No | blank, self, or event |
| platform | No | Sent in embed-init app.platform (e.g. ios, android) |
| bundleId | No | iOS bundle ID (panel allowlist) |
| packageName | No | Android package name (panel allowlist) |
| sessionStorage | No | Storage adapter (e.g. AsyncStorage) to persist tryonSessionId |
| sessionInstanceId | No | Scopes the session storage per instance |
| onEvent | No | Cart / checkout / ready callbacks |
| onError | No | Embed-init or load failure |
| onReady | No | Called when WebView URL is ready |
Events
| Event | Typical use |
|-------|-------------|
| addToCart | Add SKU to cart |
| removeFromCart | Remove line item |
| redirectToCart | Open checkout |
| analysisFinished | Camera / analysis ready |
<VitraunTryOn
merchantId="..."
widgetId="..."
onEvent={(event) => {
console.log(event.type, event.detail)
}}
/>import { VITRAUN_VTO_DEFAULT_EVENT_TYPES } from '@vitraun/react-native'Advanced usage
Init without the built-in component (custom WebView wrapper or preload):
import { initializeVitraunSession } from '@vitraun/react-native'
const session = await initializeVitraunSession({
state: {
merchantId: 'vtrn-mch-key-...',
widgetId: 'vtrn-wdg-key-...',
lang: 'en-US',
app: { platform: 'android', packageName: 'com.your.store' },
},
})
// session.vtoUrl — load in your WebView
// session.sessionToken — embed session JWT when required by channelLower-level hook:
import { useVitraunInit } from '@vitraun/react-native'Distribution
Published via npm only (npm install @vitraun/react-native). There is no CDN script bundle for this package.
Package exports
| Export | Description |
|--------|-------------|
| VitraunTryOn | WebView component with embed-init |
| VitraunTryOnModal | Native modal wrapper for ecommerce PDP flows |
| useVitraunInit | Embed-init hook (loading / error / session) |
| initializeVitraunSession | Init without UI (re-export from core) |
| handleVitraunWebViewMessage | Parse WebView onMessage payload |
| buildInjectedJavaScriptBeforeContentLoaded | Bridge + optional native config inject |
