Ir al contenido

SDK de Expo / React Native

@kilden-io/expo es el SDK cliente de Kilden para apps de Expo y React Native: captura de eventos, tracking de pantallas, identidad persistida y feature flags. Es la contraparte móvil del SDK web — misma semántica, adaptada a React Native (AsyncStorage en lugar de localStorage, un flush en background en lugar de sendBeacon). Para browsers usa @kilden/sdk; para tu backend usa un SDK de servidor.

Autocapture, session replay y plugins son solo web por ahora; este SDK no los incluye.

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

Bare React Native (sin Expo) también funciona: cada binding de plataforma es una dependencia blanda. Sin expo-crypto el SDK cae a cualquier polyfill global de crypto.getRandomValues (p. ej. react-native-get-random-values); sin AsyncStorage loguea un warning y mantiene la identidad en memoria, así que los ids no sobreviven un reinicio de la 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 });

El export por defecto es un singleton — llama a init una vez e impórtalo donde quieras. Las llamadas hechas antes de init se guardan y se reproducen en orden; las lecturas de flags antes de init se resuelven a su default. Si necesitas clientes aislados (tests, múltiples proyectos), usa createClient(writeKey, options).

Usa la write key pública de tu proyecto (wk_…). Jamás incluyas una key secreta (sk_…) en una app: todo lo que va dentro de un bundle puede extraerse, y una key secreta filtrada le permite a cualquiera escribir eventos de servidor verificados en tu proyecto. El constructor rechaza las keys secretas de plano — la imagen espejo de los SDKs de servidor, que rechazan las públicas. El modelo completo está en niveles de confianza.

Método Qué hace
init(writeKey, options?) Inicializa el singleton. Ver Configuración
track(event, properties?, options?) Encola un evento. options acepta timestamp y uuid explícitos
screen(name, properties?, options?) Registra una vista de pantalla: un evento $screen con $screen_name
identify(distinctId, traits?, options?) Vincula al usuario anónimo con tu id de usuario. Ver Identidad
alias(aliasId) Vincula otro id conocido a la identidad actual (emite $alias)
reset() Logout: id anónimo nuevo, token de identidad y cache de flags limpiados
getDistinctId() Distinct id actual. Async — espera la hidratación del storage
setIdentityToken(token) Setea o limpia el JWT de verificación de identidad
isFeatureEnabled(key, options?) / getFeatureFlag(key, options?) Feature flags, evaluados remotamente. Async — ver Feature flags
flush() Fuerza el envío de la cola
close() Flush final con deadline de 10 segundos, después el cliente queda inerte

Las garantías son las del SDK web: la API pública nunca lanza después de la construcción, tus datos nunca se mutan, y cada evento lleva un UUID v7 generado en el cliente para que los reintentos sean idempotentes. El formato de wire, la política de retry y el comportamiento del payload siguen kilden-sdk-spec — la misma autoridad contra la que se testean los SDKs de servidor.

Los usuarios empiezan anónimos: un id anon_ + UUID v7, generado en el primer arranque y persistido en AsyncStorage. Cuando inician sesión:

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

identify vincula la historia anónima con tu id de usuario, con la misma semántica del grafo de personas que en la web. En el logout:

kilden.reset();

reset rota a una identidad anónima nueva y descarta el token de identidad y el cache de flags. Si lo omites, el siguiente login en ese dispositivo queda vinculado al rastro anónimo del usuario anterior.

A diferencia del SDK web, este SDK también expone alias(aliasId): emite $alias, vinculando otro id conocido a la identidad actual sin cambiar el estado local. La mayoría de las apps solo necesita identify.

Los eventos de cliente son no verificados por defecto — cualquiera puede extraer tu write key pública del bundle de la app. Para obtener eventos verified: true (requeridos por el messenger, respetados por los triggers de campañas), tu backend firma un JWT de vida corta para el usuario logueado y el SDK lo lleva con cada batch:

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

El SDK refresca el token unos 60 segundos antes de que expire y una vez ante un 401. Los SDKs de servidor te dan el endpoint de firma en tres líneas — kilden/laravel trae POST /kilden/identity listo. Modelo completo: verificación de identidad.

Evaluación remota contra /decide, con cache de 30 segundos por identidad:

if (await kilden.isFeatureEnabled("new_checkout")) {
renderNewCheckout();
}
const variant = await kilden.getFeatureFlag("checkout_test", {
personProperties: { plan: "pro" }, // solo esta evaluación; evita el cache
default: "control", // se devuelve cuando Kilden no puede responder
});

Las lecturas de flags nunca lanzan y nunca reintentan — una respuesta tardía de un flag no sirve, así que una lectura fallida devuelve tu default (false si no seteaste uno). identify() y reset() invalidan el cache, así que los valores convergen a la nueva identidad de inmediato. La primera lectura de cada flag emite un evento de exposición $feature_flag_called. La semántica de targeting y bucketing está en la guía de feature flags.

Los eventos se encolan en memoria y se flushean cada 5 segundos, al llegar a 20 eventos encolados, y cuando la app deja el primer plano (vía AppState — React Native no tiene sendBeacon, así que el flush en background es el reemplazo móvil). El envío reintenta con backoff exponencial y respeta Retry-After. La cola está acotada a 10.000 eventos; al llegar al tope se descarta el evento nuevo, nunca la historia.

Por defecto la cola vive en memoria: los eventos aún encolados cuando el OS mata la app se pierden (React Native no expone una señal de “la app va a terminar” — el flush en background es el último hook confiable). Setea persistQueue: true para escribir la cola write-through a AsyncStorage: los eventos no entregados se restauran y se envían en el siguiente launch. La entrega es at-least-once — Kilden dedupea por uuid del evento, así que un batch que estaba en vuelo durante un kill jamás se cuenta doble. Llama a flush() en checkpoints naturales, y a close() si tu app tiene un punto de shutdown real — drena la cola con un deadline de 10 segundos y deja el cliente inerte.

Todas las opciones con sus defaults:

kilden.init("YOUR_WRITE_KEY", {
apiHost: "https://ingest.kilden.io",
flushAt: 20, // largo de cola que dispara un flush
flushIntervalMs: 5000, // flush periódico
maxQueueSize: 10000, // tope duro; al tope se descarta el evento NUEVO
requestTimeoutMs: 10000, // por request HTTP
debug: false, // logging verboso + warnings de prefijo $
enabled: true, // false convierte todo el cliente en un no-op
persistQueue: false, // true = la cola sobrevive a que el OS mate la app (se restaura y entrega en el siguiente launch)
});

El resto son puntos de inyección y plomería de identidad:

Opción Qué hace
identityToken JWT de identidad inicial, si ya tienes uno en el init
getIdentityToken Fetcher async del token, llamado 60 s antes de expirar y ante un 401. Ver verificación de identidad
context () => Properties que se mezcla en cada evento como properties de sistema extra (las properties explícitas del evento ganan)
storage Override de KeyValueStorage; por defecto AsyncStorage
transport Override de Transport; por defecto fetch
getRandomValues Override de entropía; por defecto expo-crypto, después el crypto.getRandomValues global
appState Override de la fuente de ciclo de vida; por defecto el AppState de React Native

Los puntos de inyección existen para que el core corra en cualquier lado — bare React Native, Expo Web, tests en Node. Por defecto cada evento lleva contexto del dispositivo: $os, $os_version, $device_type, $screen_width, $screen_height, más $lib y $lib_version.