Uso de eventos personalizados para mejorar tu seguimiento
Los eventos personalizados son un concepto sencillo pero potente que nuestro Tracker ofrece sin tener que añadir nada adicional. Pueden ampliar los datos rastreados con cualquier otra cosa que necesites, ya sean errores personalizados relacionados con tu lógica de negocio o incluso eventos simples, para saber qué están haciendo tus usuarios.
Nuestro tracker, de forma predeterminada, hará un seguimiento de muchas cosas diferentes, incluidos algunos errores útiles, pero es posible que no sean suficientes para ti, por lo que tenemos eventos personalizados.
Añadir eventos personalizados
Section titled Añadir eventos personalizadosPara este ejemplo, tomemos un sitio de comercio electrónico genérico y añadamos algunos eventos para entender cuándo nuestro usuario añade un producto al carrito de compra.
De forma predeterminada, OpenReplay no rastreará esa información. Sin embargo, mediante eventos personalizados, puedes hacer un seguimiento de esto fácilmente.
Crear el Tracker Provider
Section titled Crear el Tracker ProviderTodo lo que necesitas saber ahora es que se trata de un proveedor de contexto que estamos creando y que te permitirá interactuar con el tracker a través de múltiples funciones.
En particular, nos importarán logIssue y logEvent, que te permiten enviar una incidencia o un evento personalizado a la plataforma.
- Los eventos están pensados para registrar acciones específicas del usuario. En nuestro caso, por ejemplo, registraremos la adición de un producto al carrito.
- Las incidencias, por otro lado, están pensadas para registrar errores que nuestro tracker no detecta automáticamente. En nuestro caso, simularemos un error de red que nos impide acceder a una API de terceros. Cuando eso ocurra, registraremos una incidencia en la plataforma.
import { createContext, useCallback } from 'react'
import Tracker from '@openreplay/tracker'
import { v4 as uuidV4 } from 'uuid'
import { useReducer } from 'react'
export const TrackerContext = createContext()
function defaultGetUserId() {
return uuidV4()
}
function newTracker(config) {
const getUserId =
config?.userIdEnabled && config?.getUserId
? config.getUserId
: defaultGetUserId
let userId = null
const trackerConfig = {
projectKey:
config?.projectKey || process.env.NEXT_PUBLIC_OPENREPLAY_PROJECT_KEY,
}
if (config?.ingestPoint || process.env.NEXT_PUBLIC_OPENREPLAY_INGEST_POINT) {
trackerConfig.ingestPoint =
config?.ingestPoint || process.env.NEXT_PUBLIC_OPENREPLAY_INGEST_POINT
}
console.log('Tracker configuration: ')
console.log(trackerConfig)
const tracker = new Tracker(trackerConfig)
if (config?.userIdEnabled) {
userId = getUserId()
tracker.setUserID(userId)
}
return tracker
}
function reducer(state, action) {
switch (action.type) {
case 'init': {
if (!state.tracker) {
console.log('Instantiaing the tracker for the first time...')
let t = newTracker(state.config)
let pluginsReturnedValue = {}
if (state.config.plugins) {
state.config.plugins.forEach((p) => {
console.log('Using plugin...')
pluginsReturnedValue[p.name] = t.use(p.fn(p.config))
})
}
return {
...state,
pluginsReturnedValue: pluginsReturnedValue,
tracker: t,
}
}
return state
}
case 'start': {
console.log('Starting tracker...')
state.tracker.start()
return state
}
case 'logEvent': {
console.log('Logging event')
state.tracker?.event(action.payload?.name, action.payload?.data)
return state
}
case 'logIssue': {
console.log('Logging issue')
state.tracker?.issue(action.payload?.name, action.payload?.data)
return state
}
}
}
export default function TrackerProvider({ children, config = {} }) {
let [state, dispatch] = useReducer(reducer, {
tracker: null,
pluginsReturnedValue: {},
config,
})
let value = {
startTracking: () => dispatch({ type: 'start' }),
initTracker: () => dispatch({ type: 'init' }),
logEvent: (evnt) => dispatch({ type: 'logEvent', payload: evnt }),
logIssue: (evnt) => dispatch({ type: 'logIssue', payload: evnt }),
pluginsReturnedValues: { ...state.pluginsReturnedValue },
}
return (
<TrackerContext.Provider value={value}>{children}</TrackerContext.Provider>
)
}
Las funciones logEvent y logIssue tienen la misma firma; pasaremos un objeto con las propiedades name y data. El name se usará para identificar nuestro registro en la interfaz de OpenReplay y data contendrá la información registrada.
Recuerda: la propiedad data debe contener un objeto serializable.
Luego podemos configurar este proveedor en nuestro archivo _app.tsx de la siguiente manera:
//imports here...
export default function MyApp({ Component, pageProps }: AppProps) {
const Layout = (Component as any).Layout || Noop
useEffect(() => {
document.body.classList?.remove('loading')
}, [])
return (
<TrackerProvider config={{}}>
<Head />
<ManagedUIContext>
<Layout pageProps={pageProps}>
<Component {...pageProps} />
</Layout>
</ManagedUIContext>
</TrackerProvider>
)
}
Una vez resuelto esto, ya podemos pasar a disparar los eventos.
Registro de incidencias y eventos personalizados
Section titled Registro de incidencias y eventos personalizadosPara ello, aprovecharemos nuestra interfaz:

Registraremos un nuevo evento cada vez que el usuario añada un producto a nuestro carrito (esencialmente cuando pulse el botón “ADD TO CART”).
Y registraremos una incidencia si lo hace sin seleccionar antes una talla.
Puedes consultar el código fuente completo de este componente aquí mismo, pero centrémonos en la lógica que vamos a añadir.
Al inicio de nuestro componente usaremos el hook useContext:
//outside the component
import { TrackerContext } from '../../../context/trackerProvider'
//inside the component
const { logEvent, logIssue } = useContext(TrackerContext)
Dentro de la función addToCart, añadiremos la siguiente lógica para comprobar si no hay ninguna talla válida seleccionada:
const validSizes = product.options
.filter((o) => o.id == 'option-size')
.map((o) => o.values)[0]
let pickedSized = validSizes.find((s) => {
return selectedOptions.size == s.label.toLowerCase()
})
if (!pickedSized) {
logIssue({
name: 'Product added without a size',
data: {
product_id: product.id,
added_date: new Date(),
available_options: validSizes,
},
})
}
La parte clave del código es el último IF: cuando detectamos que no hay ninguna talla válida seleccionada, llamamos a la función logIssue, que obtuvimos de la llamada a useContext anterior.
Y para el evento, profundizaremos en la misma función y añadiremos:
logEvent({
name: 'product_added',
data: {
id: product.id,
date_added: new Date(),
},
})
Eso es todo lo que necesitamos; luego podemos ir a OpenReplay, encontrar nuestra grabación de sesión e inspeccionar la sección de Eventos:

Y si queremos ver los detalles, podemos hacer clic en el enlace “DETAILS” que aparece al pasar el cursor sobre una de las filas:

Esos son los detalles que registramos al añadir un producto.
Y si quieres revisar el código fuente completo de este ejemplo, puedes encontrarlo aquí.
¿Tienes preguntas?
Section titled ¿Tienes preguntas?Si tienes algún problema con los eventos personalizados en tu proyecto, ponte en contacto con nosotros en nuestra comunidad de Slack y pregunta directamente a nuestros desarrolladores.