Рабочие процессы преподавателей музыкальных инструментов с автоматическим записыванием через PostHog и пользовательскими событиями
Разместите функции автозахвата PostHog, события исходов, воспроизведения сессий и временные линии пользователей так, чтобы продукты обучения с использованием ИИ могли отслеживать завершённые задания, а не только количество кликов.
Источники: **Instrumenting User Behaviour on KaushalSaathi with PostHog**
KaushalSaathi — это образовательная платформа, ориентированная на использование ИИ и предназначенная для учителей. Она может составлять планы уроков, направлять процесс обучения в режиме «Учить», формировать расписания и предоставлять возможность чат-консультаций. Поскольку значительная часть ценности продукта достигается за счёт асинхронной генерации контента, а не простого перехода между страницами, стратегия сбора данных требовала рассматривать завершённые задачи как важные сигналы — а не только клики и изменения маршрутов.
Разработка новых функций без анализа реального использования — это распространённая ловушка. Дополнительные экраны не обязательно приводят к лучшим результатам. Прежде чем добавлять новую функцию, команде необходимы доказательства того, с чем уже работают учителя, где они сталкиваются с трудностями и какие инструменты они вообще не используют. Возможность наблюдения за поведением пользователей превращает выбор функций из процесса угадывания в основанные на реальных данных решения. Именно эту проблему и было предложено решить с помощью PostHog: как на самом деле учителя используют уже существующий продукт?
Автозахват как бесплатная базовая функция
Автозахват обрабатывает действия на уровне DOM без необходимости настройки — клики, $pageview, $pageleave и изменения состояния сессии. Безусловное использование этого инструмента и рассмотрение отсутствия API-ключа как сигнала о выключении функций позволяют избежать необходимости настройки учётных записей и использования веток типа if (enabled) в процессе локальной разработки и работы с форками:
const POSTHOG_KEY = import.meta.env.VITE_POSTHOG_KEY ?? "phc_disabled_no_key_set";
const ENABLED = POSTHOG_KEY !== "phc_disabled_no_key_set";
<PostHogProvider
apiKey={POSTHOG_KEY}
options={{
api_host: POSTHOG_HOST,
autocapture: ENABLED,
capture_pageview: ENABLED,
session_recording: { maskAllInputs: true },
loaded: (ph) => { if (!ENABLED) ph.opt_out_capturing(); },
}}
Автозахват позволяет определить, куда произошло навигационное действие. Однако он не показывает, что именно было завершено. Обработчики кликов в DOM никогда не узнают о завершении асинхронных операций — например, о генерации учебного плана, окончании периода в режиме обучения или успешном экспорте PDF. Ни одно из этих завершений не приводит к событию клика в DOM, к которому можно было бы подключиться, поэтому автозахват по своей конструкции не может их обнаружить. Именно из-за этой проблемы существует второй уровень обработки.
Персонализированные события, превращающиеся в метрики
Значимые результаты передаются в виде пользовательских событий через простой трехфункциональный обёрточный модуль. Каждый вызов проверяет значение posthog.__loaded, поэтому остальная часть приложения никогда не проверяет наличие аналитики и не интересуется тем, активна ли функция сбора данных:
export function captureEvent(name: string, props?: Record<string, unknown>) {
if (!posthog.__loaded) return;
posthog.capture(name, props);
}
Два правила обеспечивают полезность этих событий при последующих запросах.
Передавайте события при успешном выполнении, а не при попытке. Обработка сбора данных происходит по асинхронному пути успешного завершения, а не внутри обработчика кнопки, поэтому графики отражают завершённую работу:
const plan = await generateLessonPlan(payload); // resolves only on success
captureEvent("lesson_plan_generated", {
grade: plan.grade, sector: plan.sector, language: plan.language,
});
Присоединяйте свойства, которые будут использоваться в разбивке по критериям. Поля такие как grade, language, sector и periodNumber передаются вместе с событием момент его отправки. В PostHog они превращаются в фильтры и элементы разбивки без дополнительных операций — одно событие может ответить на вопросы о разбивке по уровням, языкам или секторам.
Ключевым инструментом является функция identifyUser, которая запускается один раз из хука аутентификации после успешного входа. Этот вызов связывает временный анонимный идентификатор с авторизованным аккаунтом и добавляет поля, отражающие роль пользователя, что позволяет последующим записям наследовать те же атрибуты:
posthog.identify(user.id,
{ role: user.role, grade: user.grade, school: user.school });
// on logout: posthog.reset() ← must run before the redirect, or events leak to the next id
Порядок вызовов при выходе из системы имеет значение. Перенаправление до вызова reset() на общем устройстве может привести к тому, что следующая сессия будет ассоциироваться с предыдущей идентичностью. Сначала выполните сброс, затем переходите к другим действиям.
Каждое событие позволяет получить сохраненную информацию. Обычно используется подсчет событий с разбивкой по имени пользователя:
lesson_plan_generatedво всем окне, сгруппированный по часам, позволяет получить временную серию с указанием когда, а также таблицу с детальными результатами в порядке ранжирования, показывающую кто. Этот единый вид представления выявляет активных пользователей, случайные регистрации и места наибольшей интенсивности использования. По умолчанию лимит строк в разбивке составляет 25; его можно увеличить до 50, когда важна информация о редких случаях использования.chat_message_sent, ограниченный временными рамками прошлого дня и сгруппированный по часам, использует ту же самую запись с узкими временными рамками — например, пик активности днем около 15:00, связанный с одним учителем.
Одно и то же определение события, но разный диапазон дат и способ разбивки. Новый вопрос превращается в новый сохраненный вид представления, а не в новый код приложения.
Повторная отрисовка сессии для выяснения причин
Показатели отражают что и как часто, но не почему. Запись ведётся по умолчанию при настройке maskAllInputs: true, поскольку учителя вводят персональные данные учащихся и школы. Клики, навигация, глубина прокрутки и моменты заминок остаются видимыми; значения введённых данных маскируются при сохранении.
Ситуации, когда возможность перепросмотра оправдана:
- Локализация утечек в процессе работы. Когда срабатывает параметр
lesson_plan_generated, но неpdf_exportedдля определённой группы, показатели выявляют утечку, а перепросмотр показывает точный этап экспорта, на котором происходит сбой. - Беззвучные многократные сбои. Режим преподавания может работать некорректно без видимых сигналов; пользователи просто прекращают работу. Перепросмотр позволяет отделить сбой интерфейса от неоднозначных меток или медленной обработки, вызывающей тайм-аут.
Графики активности каждого пользователя
Как только идентификатор связывает записи действий с конкретным аккаунтом, экран с данными пользователя в PostHog отображается в виде временной шкалы для данного педагога: какие события произошли, какие функции были использованы, какие сессии сохранены. Практические применения включают проверку того, что после сигнала registration_completed следует первый сигнал lesson_plan_generated (для оценки успешности адаптации), просмотр временной шкалы активного пользователя перед разработкой решений с учетом его действий или воссоздание сообщенной ошибки на основе конкретной сессии вместо опоры на память.
Собирание всех компонентов воедино
Функция автоматического захвата предоставляет базовый сигнал бесплатно. Пользовательские события и метрики превращают результаты работы функций в ранжированные временные ряды с разбивкой по свойствам. Возможность воспроизведения сессий позволяет увидеть причинно-следственные связи, лежащие в основе тех или иных трендов на графиках. Линейные диаграммы, отражающие деятельность пользователей, позволяют увеличивать масштаб от общих данных до информации о конкретном преподавателе. Все эти элементы в совокупности позволяют определять, что следует разработать на основе наблюдаемого поведения, а не на основе предположений о том, как продукт «должен» использоваться.