Использование пользовательских событий для улучшения отслеживания
Пользовательские события — это простая, но мощная концепция, которую предоставляет наш Tracker без необходимости добавлять что-либо дополнительно. Они могут расширить отслеживаемые данные всем, что вам нужно, будь то пользовательские ошибки, связанные с вашей бизнес-логикой, или даже простые события, чтобы понимать, что делают ваши пользователи.
По умолчанию наш трекер отслеживает множество различных вещей, включая некоторые полезные ошибки, но их может оказаться недостаточно, поэтому у нас есть пользовательские события.
Добавление пользовательских событий
Section titled Добавление пользовательских событийДля этого примера возьмём типичный сайт электронной коммерции и добавим несколько событий, чтобы понимать, когда наш пользователь добавляет товар в корзину покупок.
По умолчанию OpenReplay не отслеживает эту информацию. Однако с помощью пользовательских событий вы можете легко это отслеживать.
Создание Tracker Provider
Section titled Создание Tracker ProviderВсё, что вам нужно знать сейчас, — это то, что мы создаём провайдер контекста, который позволит вам взаимодействовать с трекером через несколько функций.
В частности, нас будут интересовать logIssue и logEvent, которые позволяют отправлять пользовательскую проблему или событие на платформу.
- События предназначены для регистрации действий, специфичных для пользователя. В нашем случае, например, мы будем регистрировать добавление товара в корзину.
- Проблемы, с другой стороны, предназначены для регистрации ошибок, которые наш трекер не определяет автоматически. В нашем случае мы смоделируем сетевую ошибку, которая не позволяет нам получить доступ к стороннему API. Когда это произойдёт, мы зарегистрируем проблему на платформе.
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>
)
}
Функции logEvent и logIssue имеют одинаковую сигнатуру; мы передадим объект со свойствами name и data. name будет использоваться для идентификации нашей записи в интерфейсе OpenReplay, а data будет содержать регистрируемую информацию.
Помните: свойство data должно содержать сериализуемый объект.
Затем мы можем настроить этого провайдера в нашем файле _app.tsx следующим образом:
//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>
)
}
Покончив с этим, мы можем перейти к запуску событий.
Регистрация пользовательских проблем и событий
Section titled Регистрация пользовательских проблем и событийДля этого мы воспользуемся нашим интерфейсом:

Мы будем записывать новое событие каждый раз, когда пользователь добавляет товар в нашу корзину (по сути, когда он нажимает кнопку «ADD TO CART»).
И мы зарегистрируем проблему, если он сделает это, не выбрав сначала размер.
Вы можете ознакомиться с полным исходным кодом этого компонента прямо здесь, но давайте сосредоточимся на логике, которую мы добавим.
В начале нашего компонента мы будем использовать хук useContext:
//outside the component
import { TrackerContext } from '../../../context/trackerProvider'
//inside the component
const { logEvent, logIssue } = useContext(TrackerContext)
Внутри функции addToCart мы добавим следующую логику для проверки того, что не выбран допустимый размер:
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,
},
})
}
Ключевая часть кода — это последний IF: когда мы понимаем, что допустимый размер не выбран, мы вызываем функцию logIssue, которую получили из предыдущего вызова useContext.
А для события мы углубимся в ту же функцию и добавим:
logEvent({
name: 'product_added',
data: {
id: product.id,
date_added: new Date(),
},
})
Это всё, что нам нужно; затем мы можем перейти в OpenReplay, найти нашу запись сессии и просмотреть раздел Events:

И если нам нужны подробности, мы можем нажать на ссылку «DETAILS», которая появляется при наведении курсора на одну из строк:

Это те подробности, которые мы записали при добавлении товара.
И если вы хотите изучить полный исходный код этого примера, вы можете найти его здесь.
Есть вопросы?
Section titled Есть вопросы?Если у вас возникнут какие-либо проблемы с пользовательскими событиями в вашем проекте, свяжитесь с нами в нашем сообществе Slack и задайте вопросы нашим разработчикам напрямую!