Aller au contenu

SDK Expo / React Native

@kilden-io/expo est le SDK client de Kilden pour les apps Expo et React Native : capture d’événements, suivi d’écrans, identité persistée et feature flags. C’est le pendant mobile du SDK web — même sémantique, adaptée à React Native (AsyncStorage au lieu de localStorage, un flush en arrière-plan au lieu de sendBeacon). Pour les navigateurs, utilisez @kilden/sdk ; pour votre backend, un SDK serveur.

L’autocapture, le session replay et les plugins sont réservés au web pour l’instant ; ce SDK ne les inclut pas.

Terminal window
npx expo install @kilden-io/expo expo-crypto @react-native-async-storage/async-storage

Bare React Native (sans Expo) fonctionne aussi : chaque binding de plateforme est une dépendance souple. Sans expo-crypto, le SDK se rabat sur n’importe quel polyfill global de crypto.getRandomValues (par ex. react-native-get-random-values) ; sans AsyncStorage, il avertit et garde l’identité en mémoire, donc les ids ne survivent pas à un redémarrage de l’app.

import kilden from "@kilden-io/expo";
kilden.init("YOUR_WRITE_KEY");
kilden.track("order_completed", { revenue: 99.9, currency: "CLP" });
kilden.screen("Checkout", { step: 2 });

L’export par défaut est un singleton — appelez init une fois et importez-le où vous voulez. Les appels faits avant init sont mis en mémoire et rejoués dans l’ordre ; les lectures de flags avant init se résolvent vers leur default. Si vous avez besoin de clients isolés (tests, plusieurs projets), utilisez createClient(writeKey, options).

Utilisez la write key publique de votre projet (wk_…). N’embarquez jamais une clé secrète (sk_…) dans une app : tout ce qui se trouve dans un bundle peut être extrait, et une clé secrète fuitée permet à n’importe qui d’écrire des événements serveur vérifiés dans votre projet. Le constructeur rejette d’emblée les clés secrètes — l’image miroir des SDKs serveur, qui rejettent les publiques. Le modèle complet est dans niveaux de confiance.

Méthode Ce qu’elle fait
init(writeKey, options?) Initialise le singleton. Voir Configuration
track(event, properties?, options?) Met un événement en file. options accepte un timestamp et un uuid explicites
screen(name, properties?, options?) Enregistre une vue d’écran : un événement $screen avec $screen_name
identify(distinctId, traits?, options?) Relie l’utilisateur anonyme à votre id utilisateur. Voir Identité
alias(aliasId) Relie un autre id connu à l’identité courante (émet $alias)
reset() Déconnexion : id anonyme neuf, token d’identité et cache de flags effacés
getDistinctId() Distinct id courant. Async — attend l’hydratation du storage
setIdentityToken(token) Définit ou efface le JWT de vérification d’identité
isFeatureEnabled(key, options?) / getFeatureFlag(key, options?) Feature flags, évalués à distance. Async — voir Feature flags
flush() Force l’envoi de la file
close() Flush final avec un délai de 10 secondes, puis le client devient inerte

Les garanties sont celles du SDK web : l’API publique ne lance jamais après la construction, vos données ne sont jamais mutées, et chaque événement porte un UUID v7 généré côté client pour que les réessais soient idempotents. Le format de wire, la politique de retry et le comportement du payload suivent kilden-sdk-spec — la même autorité contre laquelle les SDKs serveur sont testés.

Les utilisateurs commencent anonymes : un id anon_ + UUID v7, généré au premier lancement et persisté dans AsyncStorage. Quand ils se connectent :

kilden.identify("user_42", { plan: "pro", email: "[email protected]" });

identify relie l’historique anonyme à votre id utilisateur, avec la même sémantique du graphe de personnes que sur le web. À la déconnexion :

kilden.reset();

reset bascule vers une identité anonyme neuve et abandonne le token d’identité et le cache de flags. Si vous l’omettez, la connexion suivante sur cet appareil est reliée à la trace anonyme de l’utilisateur précédent.

Contrairement au SDK web, ce SDK expose aussi alias(aliasId) : il émet $alias, reliant un autre id connu à l’identité courante sans changer l’état local. La plupart des apps n’ont besoin que d’identify.

Les événements client sont non vérifiés par défaut — n’importe qui peut extraire votre write key publique du bundle de l’app. Pour obtenir des événements verified: true (exigés par le messenger, respectés par les déclencheurs de campagnes), votre backend signe un JWT à courte durée de vie pour l’utilisateur connecté et le SDK le transporte avec chaque batch :

kilden.init("YOUR_WRITE_KEY", {
getIdentityToken: async () => {
const response = await fetch("https://your-backend.example/kilden/identity", {
method: "POST",
headers: { Authorization: `Bearer ${sessionToken}` }, // le token de session de votre app
});
if (!response.ok) return null;
const { token } = await response.json();
return token;
},
});

Le SDK rafraîchit le token environ 60 secondes avant son expiration et une fois sur un 401. Les SDKs serveur vous donnent l’endpoint de signature en trois lignes — kilden/laravel livre POST /kilden/identity prêt à l’emploi. Modèle complet : vérification d’identité.

Évaluation à distance contre /decide, avec un cache de 30 secondes par identité :

if (await kilden.isFeatureEnabled("new_checkout")) {
renderNewCheckout();
}
const variant = await kilden.getFeatureFlag("checkout_test", {
personProperties: { plan: "pro" }, // cette évaluation seulement ; contourne le cache
default: "control", // renvoyé quand Kilden ne peut pas répondre
});

Les lectures de flags ne lancent jamais et ne réessaient jamais — une réponse de flag tardive ne sert à rien, donc une lecture qui échoue renvoie votre default (false si vous n’en avez pas défini). identify() et reset() invalident le cache, donc les valeurs convergent tout de suite vers la nouvelle identité. La première lecture de chaque flag émet un événement d’exposition $feature_flag_called. La sémantique de ciblage et de bucketing est dans le guide des feature flags.

Les événements sont mis en file en mémoire et envoyés toutes les 5 secondes, à 20 événements en file, et quand l’app quitte le premier plan (via AppState — React Native n’a pas de sendBeacon, le flush en arrière-plan est le remplaçant mobile). La livraison réessaie avec un backoff exponentiel et honore Retry-After. La file est bornée à 10 000 événements ; au plafond, c’est le nouvel événement qui est écarté, jamais l’historique.

Par défaut, la file vit en mémoire : les événements encore en file quand l’OS tue l’app sont perdus (React Native n’expose aucun signal « l’app va se terminer » — le flush en arrière-plan est le dernier hook fiable). Réglez persistQueue: true pour écrire la file en write-through dans AsyncStorage : les événements non livrés sont restaurés et envoyés au lancement suivant. La livraison est at-least-once — Kilden déduplique par uuid d’événement, donc un batch en vol pendant un kill n’est jamais compté deux fois. Appelez flush() aux points de passage naturels, et close() si votre app a un vrai point d’arrêt — il draine la file avec un délai de 10 secondes et rend le client inerte.

Toutes les options avec leurs valeurs par défaut :

kilden.init("YOUR_WRITE_KEY", {
apiHost: "https://ingest.kilden.io",
flushAt: 20, // longueur de file qui déclenche un flush
flushIntervalMs: 5000, // flush périodique
maxQueueSize: 10000, // plafond dur ; au plafond le NOUVEL événement est écarté
requestTimeoutMs: 10000, // par requête HTTP
debug: false, // logs verbeux + avertissements de préfixe $
enabled: true, // false transforme tout le client en no-op
persistQueue: false, // true = la file survit quand l'OS tue l'app (restaurée et livrée au lancement suivant)
});

Le reste, ce sont des points d’injection et la plomberie d’identité :

Option Ce qu’elle fait
identityToken JWT d’identité initial, si vous en avez déjà un à l’init
getIdentityToken Récupérateur async du token, appelé 60 s avant l’expiration et sur un 401. Voir vérification d’identité
context () => Properties fusionné dans chaque événement comme propriétés système supplémentaires (les propriétés explicites de l’événement gagnent)
storage Override de KeyValueStorage ; par défaut AsyncStorage
transport Override de Transport ; par défaut fetch
getRandomValues Override d’entropie ; par défaut expo-crypto, puis le crypto.getRandomValues global
appState Override de la source de cycle de vie ; par défaut l’AppState de React Native

Les points d’injection existent pour que le cœur tourne partout — bare React Native, Expo Web, tests sous Node. Par défaut, chaque événement porte le contexte de l’appareil : $os, $os_version, $device_type, $screen_width, $screen_height, plus $lib et $lib_version.