Ir al contenido

Rastreo y senales

El rastreo es como Presage aprende sobre el comportamiento del usuario. Cada llamada a client.track() alimenta el pipeline de calculo de senales, que actualiza el UserContext y puede activar la reevaluacion de reglas.

Presage incluye un almacen de eventos integrado que mantiene los eventos en memoria. No se requiere ningun servicio externo.

const client = createAdaptiveClient({
tracker: {
builtIn: {
maxEvents: 1000, // Keep at most 1000 events (default)
maxAgeMs: 30 * 24 * 60 * 60 * 1000, // Prune events older than 30 days (default)
},
},
})

El tracker integrado automaticamente:

  • Asigna un sessionId (persistido en sessionStorage)
  • Agrega marca de tiempo a cada evento
  • Poda eventos antiguos para mantenerse dentro de los limites de memoria

Cada evento rastreado sigue esta estructura:

interface TrackerEvent {
name: string
properties?: Record<string, unknown>
timestamp: number // Auto-set to Date.now()
userId?: string // Set after client.identify()
sessionId: string // Auto-generated per browser session
}
// Feature usage — increments signals.featureUsage['dashboard-export']
client.track('feature_used', { featureId: 'dashboard-export' })
// Click tracking — increments signals.clickMap['sidebar-analytics']
client.track('click', { elementId: 'sidebar-analytics' })
// Custom signals — increments signals.customSignals['engagement'] by 5
client.track('custom_signal', { signalId: 'engagement', value: 5 })
// Generic event — counted in signals.totalEvents
client.track('page_view', { path: '/dashboard' })

Las senales se recalculan automaticamente despues de cada llamada a track() (con debounce de 100ms para evitar problemas de rendimiento). Asi es como los eventos se mapean a senales:

Nombre del eventoPropiedadesSenal actualizada
feature_used{ featureId: string }signals.featureUsage[featureId] += 1
click{ elementId: string }signals.clickMap[elementId] += 1
custom_signal{ signalId: string, value?: number }signals.customSignals[signalId] += value
Cualquier eventosignals.totalEvents += 1

Adicionalmente, estas senales se calculan a partir del historial completo de eventos:

SenalCalculo
sessionCountCantidad de valores unicos de sessionId
firstSeenAtMarca de tiempo del evento mas antiguo
lastSeenAtMarca de tiempo del evento mas reciente
daysSinceSignupDias entre traits.signupDate y ahora

Puede reenviar eventos a servicios de analitica externos implementando la interfaz TrackerAdapter:

interface TrackerAdapter {
name: string
track(event: TrackerEvent): void | Promise<void>
identify(userId: string, traits: UserTraits): void | Promise<void>
flush?(): Promise<void>
}
import posthog from 'posthog-js'
import type { TrackerAdapter, TrackerEvent, UserTraits } from '@presage-kit/core'
const posthogAdapter: TrackerAdapter = {
name: 'posthog',
track(event: TrackerEvent) {
posthog.capture(event.name, event.properties)
},
identify(userId: string, traits: UserTraits) {
posthog.identify(userId, traits)
},
async flush() {
// PostHog batches automatically, but you can force a flush here
},
}
import type { TrackerAdapter, TrackerEvent, UserTraits } from '@presage-kit/core'
const segmentAdapter: TrackerAdapter = {
name: 'segment',
track(event: TrackerEvent) {
window.analytics.track(event.name, {
...event.properties,
sessionId: event.sessionId,
})
},
identify(userId: string, traits: UserTraits) {
window.analytics.identify(userId, traits)
},
}

Pase los adaptadores en la configuracion del cliente:

const client = createAdaptiveClient({
tracker: {
adapters: [posthogAdapter, segmentAdapter],
},
// ...rules, persistence
})

Todos los adaptadores reciben cada llamada a track() e identify() junto con el almacen integrado.

El recalculo de senales tiene un debounce de 100ms. Si dispara multiples llamadas a track() en rapida sucesion (por ejemplo, durante una rafaga de clics), las senales solo se recalculan una vez despues de que la rafaga se estabilice.

El almacen de eventos integrado impone dos limites:

  • maxEvents (por defecto: 1000) — Cuando se excede, los eventos mas antiguos se podan
  • maxAgeMs (por defecto: 30 dias) — Los eventos mas antiguos que esto se descartan

Estos valores por defecto funcionan bien para la mayoria de las aplicaciones SaaS. Ajustelos si su caso de uso genera volumenes de eventos muy altos.

Una vez que las senales se calculan, uselas en condiciones de reglas igual que los atributos:

{
id: 'frequent-user-shortcut',
adaptationId: 'toolbar',
priority: 10,
conditions: {
all: [
{ field: 'signals.sessionCount', operator: 'gte', value: 20 },
{ field: 'signals.featureUsage.export', operator: 'gte', value: 5 },
],
},
action: { type: 'show', variantId: 'with-keyboard-shortcuts' },
}