Skip to main content
Github Repository: https://github.com/KlipFit/kleep-rn A thin WebView wrapper around drawer.kleep.ai. The SDK exposes one component + two methods, mirroring the iOS surface.

Installation


Each release is published as an npm tarball on cdn.kleep.ai. Two URL shapes are available: Latest stable (auto-updates with every new stable release — pre-releases never move this pointer):
npm install https://cdn.kleep.ai/react-native-sdk/latest.tgz \
  react-native-webview \
  @react-native-async-storage/async-storage
Pin a specific version (recommended for production — fully immutable):
npm install https://cdn.kleep.ai/react-native-sdk/releases/v1.0.0/kleep-react-native-1.0.0.tgz \
  react-native-webview \
  @react-native-async-storage/async-storage
Replace v1.0.0 and 1.0.0 with the desired release tag. The two listed packages are peer dependencies — the SDK requires them but lets you control the version. The published tarball includes a SHA-256 alongside (<tarball>.sha256 / latest.tgz.sha256) if you want to verify integrity before installing.

Expo

Both peer deps are pre-bundled in Expo Go (SDK 54+). No extra setup needed in dev. For production builds, expo prebuild picks them up automatically.

Bare React Native

cd ios && pod install

Permissions


For the footwear flow (camera scan), add to ios/<App>/Info.plist:
<key>NSCameraUsageDescription</key>
<string>Used to scan your shoe size</string>
And to android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />

Configure once at app boot


import { Kleep } from '@kleep/react-native';

Kleep.configure({
  publicId: 'YOUR_KLEEP_PUBLIC_ID',  // UUID provided by Kleep
  language: 'fr',                      // optional, default UI language
});
FieldRequiredDescription
publicIdyesUUID identifying your retailer (provided by Kleep)
languageno'fr' | 'en' | 'de' | 'it' | 'es' | 'nl' | 'pt' | 'ja' | 'ko' | 'pl' | 'br' | 'dk' | 'fi' | 'se' | 'gb'

Usage


Method 1: Kleep.checkProduct

Call this on PDP mount. The result drives the “Find my size” CTA — whether to render it, and what label to show.
parameterprioritydescription
productIdrequiredYour product ID at the retailer
Returns
{
  recommendable: boolean;
  productFound: boolean;
  category?: 'clothing' | 'lingerie' | 'footwear' | 'children';
  recommendedSize?: string;   // e.g. "M", "38"
}
Logic schema
recommendablerecommendedSizeWhat to render
falseHide the CTA (product not eligible for Kleep)
trueabsentCTA: “Trouver ma taille”
true"M"CTA: “Taille recommandée: M”
The SDK caches the result for 5 min in memory, keyed on (publicId, productId) for the gate and (publicId, productId, mid) for the recommended size. Re-rendering the PDP or navigating back is free. Implementation example
import { useEffect, useState } from 'react';
import { Pressable, Text } from 'react-native';
import { Kleep, KleepFindSizeView, type KleepCheckProductResult } from '@kleep/react-native';

function ProductPage({ product }) {
  const [check, setCheck] = useState<KleepCheckProductResult | null>(null);
  const [open, setOpen] = useState(false);

  useEffect(() => {
    Kleep.checkProduct({ productId: product.id }).then(setCheck);
  }, [product.id]);

  if (!check?.recommendable) return <ProductContent />;

  return (
    <>
      <ProductContent />
      <Pressable onPress={() => setOpen(true)}>
        <Text>
          {check.recommendedSize
            ? `Taille recommandée : ${check.recommendedSize}`
            : 'Trouver ma taille'}
        </Text>
      </Pressable>
      <KleepFindSizeView
        visible={open}
        productId={product.id}
        variantId={selectedVariant?.id}
        onAddToCart={(e) => cart.add(e.variantId)}
        onSelectSize={(e) => pdp.setSize(e.size)}
        onDismiss={() => setOpen(false)}
      />
    </>
  );
}

Method 2: <KleepFindSizeView>

Mount this component to open the size-finder drawer in a fullscreen Modal+WebView. Controlled-component pattern: you own the visible state, the SDK requests close via onDismiss.
propprioritydescription
visiblerequiredControls Modal visibility
productIdrequiredSame as in checkProduct
onDismissrequiredFired when the user closes the drawer (X / swipe / back). Host MUST flip visible to false
variantIdoptionalPre-selects a variant for the recommendation
customerIdoptionalCRM identifier for cross-session linking
languageoptionalOverrides the SDK-level language for this open
countryCodeoptionale.g. "FR", "US" — drives unit system + bra-size defaults
stocksoptional{ [variantId]: number | boolean } — drawer renders unavailable / partial-stock UI
mockoptionaltrue → drawer skips real recommendation API calls (QA only)
forceStateoptional'outOfRange' | 'unavailable' | 'error' | 'qrcode' — QA hatch to render an end-state directly
warmRestoreoptional{ mid, uid } — pre-load an existing measurement (skip intro flow). Same-device restore is already automatic via AsyncStorage
extraParamsoptionalRaw Record<string, string> appended to the drawer URL (escape hatch)
onAddToCartoptional(event: { variantId, size? }) => void — user tapped the in-drawer “Add to cart” CTA. Host adds the variant to its cart
onSelectSizeoptional(event: { size }) => void — user picked a size on the Result screen. Host should sync its PDP size picker
onMessageoptionalDebug hook — fires for every inbound postMessage parsed from the drawer
styleoptionalStyleProp<ViewStyle> — container style override
webViewPropsoptionalForwarded to react-native-webview for advanced customisation
Auto-wired by the SDK (you don’t need to do anything):
  • Bridges the drawer’s iframe-style window.parent.postMessage to the React Native bridge
  • Persists mid / uid to AsyncStorage when the drawer pushes them
  • Responds to getMid / getUid / getSizes postMessages from the drawer
  • Calls Kleep.checkProduct on open to resolve the flow (clothing / lingerie / footwear / children) — uses the same 5-min cache as your CTA call, so it’s free if you’ve already invoked checkProduct

Method 3: Kleep.track

Fire-and-forget analytics. Never throws.
parameterprioritydescription
eventNamerequiredName of the event
options.customerIdoptionalCRM identifier
options.parametersoptionalRecord<string, unknown> — arbitrary event data
import { Kleep } from '@kleep/react-native';

await Kleep.track('product_viewed', {
  parameters: { productId: product.id },
});

await Kleep.track('product_added_to_cart', {
  customerId: user.id,
  parameters: {
    productId: product.id,
    variantId: selectedVariant.id,
    cart: cart.items,
  },
});

await Kleep.track('checkout_completed', {
  customerId: user.id,
  parameters: { orderId: order.id, cart: order.items },
});
We want to track 3 events:
eventNameTrigger
product_viewedUpon PDP viewed
product_added_to_cartUpon product added to the cart
checkout_completedUpon order confirmation after the payment
product_viewed example
{
  productId: "123ABC456"
}
product_added_to_cart example
{
  productId: "123ABC456",
  variantId: "123ABC456-00R",
  cart: [
    {
      productId: "123ABC456",
      variantId: "123ABC456-00R",
      sku: "XYZ",
      size: "S",
      quantity: 2,
      price: { amount: "50", currencyCode: "EUR" }
    }
  ]
}
checkout_completed example
{
  orderId: "000001",
  cart: [
    {
      lineItemId: "000001#1",
      productId: "123ABC456",
      variantId: "123ABC456-00R",
      sku: "XYZ",
      size: "S",
      quantity: 2,
      price: { amount: "50", currencyCode: "EUR" }
    }
  ]
}

Cache invalidation


The SDK keeps two in-memory caches (5 min TTL each):
  • Product gate(publicId, productId) → { recommendable, category, productFound }
  • Recommended size(publicId, productId, mid) → size label
Both invalidate automatically. If you need to force-refresh (user logged out, retailer switched, manual refresh button):
Kleep.clearCheckProductCache();