useMediaEvents
useMediaEvents hook: track play, pause, complete, and seek events from embedded media for analytics integration in tours
Overview
useMediaEvents provides event handlers for tracking media engagement. Use it to measure how users interact with videos in your onboarding tours, send data to analytics platforms, or trigger actions based on playback events.
Why Track Media Events?
- Measure engagement: See which videos users watch and how much
- Optimize content: Identify where users drop off
- Analytics integration: Send events to your analytics platform
- Conditional flows: Proceed to next step after video completion
- A/B testing: Compare video performance
Basic Usage
import { useMediaEvents } from '@tour-kit/media'
import { TourMedia } from '@tour-kit/media'
function TrackedVideo() {
const handlers = useMediaEvents({
mediaType: 'youtube',
mediaSrc: 'dQw4w9WgXcQ',
tourId: 'onboarding',
stepId: 'welcome'
})
return (
<TourMedia
src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
alt="Welcome video"
{...handlers}
/>
)
}Options
Prop
Type
Return Value
Returns an object with event handler functions to spread onto media components:
{
onLoaded: () => void
onPlay: () => void
onPause: () => void
onComplete: () => void
onError: (error: Error) => void
onTimeUpdate: (currentTime: number, duration: number) => void
}Examples
Basic Analytics Integration
Send events to your analytics platform:
import { useMediaEvents } from '@tour-kit/media'
import analytics from './analytics'
function AnalyticsVideo() {
const handlers = useMediaEvents({
mediaType: 'youtube',
mediaSrc: 'dQw4w9WgXcQ',
onPlay: (event) => {
analytics.track('Video Played', {
videoId: event.mediaSrc,
mediaType: event.mediaType
})
},
onComplete: (event) => {
analytics.track('Video Completed', {
videoId: event.mediaSrc,
mediaType: event.mediaType
})
}
})
return (
<TourMedia
src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
alt="Product demo"
{...handlers}
/>
)
}Track Watch Progress
Monitor how much users watch:
function WatchProgressTracking() {
const [progress, setProgress] = useState<number[]>([])
const handlers = useMediaEvents({
mediaType: 'video',
mediaSrc: '/videos/tutorial.mp4',
onTimeUpdate: (event) => {
const { currentTime, duration } = event
const percentComplete = (currentTime / duration) * 100
// Track 25%, 50%, 75% milestones
if (percentComplete >= 25 && !progress.includes(25)) {
setProgress([...progress, 25])
analytics.track('Video 25% Complete')
}
if (percentComplete >= 50 && !progress.includes(50)) {
setProgress([...progress, 50])
analytics.track('Video 50% Complete')
}
if (percentComplete >= 75 && !progress.includes(75)) {
setProgress([...progress, 75])
analytics.track('Video 75% Complete')
}
}
})
return (
<TourMedia
src="/videos/tutorial.mp4"
alt="Tutorial video"
{...handlers}
/>
)
}Conditional Tour Progression
Only allow proceeding after watching video:
import { Tour, TourStep } from '@tour-kit/react'
import { useMediaEvents } from '@tour-kit/media'
function GatedTourStep() {
const [videoCompleted, setVideoCompleted] = useState(false)
const { nextStep } = useTour()
const handlers = useMediaEvents({
mediaType: 'youtube',
mediaSrc: 'dQw4w9WgXcQ',
tourId: 'onboarding',
stepId: 'training-video',
onComplete: () => {
setVideoCompleted(true)
// Auto-advance to next step
setTimeout(() => nextStep(), 1000)
}
})
return (
<TourStep id="training-video">
<h2>Required Training Video</h2>
<TourMedia
src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
alt="Required training content"
{...handlers}
/>
{videoCompleted ? (
<p className="success">✓ Training complete! Proceeding...</p>
) : (
<p className="info">Please watch the video to continue</p>
)}
</TourStep>
)
}Error Tracking
Monitor video loading failures:
function ErrorTracking() {
const handlers = useMediaEvents({
mediaType: 'video',
mediaSrc: '/videos/demo.mp4',
onError: (event) => {
console.error('Video failed to load:', event)
analytics.track('Video Error', {
videoSrc: event.mediaSrc,
error: event.error?.message
})
// Send to error tracking service
Sentry.captureException(event.error, {
tags: {
mediaType: event.mediaType,
mediaSrc: event.mediaSrc
}
})
}
})
return (
<TourMedia
src="/videos/demo.mp4"
alt="Demo video"
{...handlers}
/>
)
}Engagement Heatmap
Track when users replay sections:
function EngagementHeatmap() {
const seekEvents = useRef<number[]>([])
const handlers = useMediaEvents({
mediaType: 'youtube',
mediaSrc: 'dQw4w9WgXcQ',
onTimeUpdate: (event) => {
seekEvents.current.push(event.currentTime)
},
onComplete: (event) => {
// Analyze seek patterns
const heatmap = calculateHeatmap(seekEvents.current)
analytics.track('Video Heatmap', {
videoId: event.mediaSrc,
heatmap
})
}
})
return (
<TourMedia
src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
alt="Product demo"
{...handlers}
/>
)
}Multiple Event Handler
Use generic event handler for all events:
function UnifiedEventTracking() {
const handlers = useMediaEvents({
mediaType: 'vimeo',
mediaSrc: '123456789',
tourId: 'product-tour',
stepId: 'intro',
onEvent: (event) => {
// Log all events to analytics
analytics.track('Media Event', {
eventName: event.eventName,
mediaType: event.mediaType,
mediaSrc: event.mediaSrc,
tourId: event.tourId,
stepId: event.stepId,
timestamp: event.timestamp,
currentTime: event.currentTime,
duration: event.duration
})
// Also log to console in development
if (process.env.NODE_ENV === 'development') {
console.log('Media event:', event)
}
}
})
return (
<TourMedia
src="https://vimeo.com/123456789"
alt="Intro video"
{...handlers}
/>
)
}Session Replay Integration
Capture video events for session replay tools:
import { useMediaEvents } from '@tour-kit/media'
import { LogRocket } from 'logrocket'
function SessionReplayTracking() {
const handlers = useMediaEvents({
mediaType: 'video',
mediaSrc: '/videos/onboarding.mp4',
onPlay: (event) => {
LogRocket.track('Video Played', {
mediaSrc: event.mediaSrc
})
},
onPause: (event) => {
LogRocket.track('Video Paused', {
mediaSrc: event.mediaSrc,
currentTime: event.currentTime
})
},
onComplete: (event) => {
LogRocket.track('Video Completed', {
mediaSrc: event.mediaSrc,
duration: event.duration
})
}
})
return (
<TourMedia
src="/videos/onboarding.mp4"
alt="Onboarding guide"
{...handlers}
/>
)
}MediaEvent Type
All event handlers receive a MediaEvent object:
interface MediaEvent {
eventName: 'media_loaded' | 'media_play' | 'media_pause' | 'media_complete' | 'media_error'
mediaType: MediaType
mediaSrc: string
tourId?: string
stepId?: string
timestamp: number
currentTime?: number
duration?: number
error?: Error
}Event Types
media_loaded
Fired when media finishes loading and is ready to play:
onLoaded: (event) => {
console.log('Video loaded:', event.mediaSrc)
console.log('Duration:', event.duration)
}media_play
Fired when playback starts:
onPlay: (event) => {
console.log('Video started playing')
console.log('Current time:', event.currentTime)
}media_pause
Fired when playback pauses:
onPause: (event) => {
console.log('Video paused at:', event.currentTime)
}media_complete
Fired when playback reaches the end:
onComplete: (event) => {
console.log('Video finished')
console.log('Total duration:', event.duration)
}media_error
Fired when media fails to load or play:
onError: (event) => {
console.error('Video error:', event.error?.message)
}media_time_update
Fired periodically during playback (typically every second):
onTimeUpdate: (event) => {
const progress = (event.currentTime / event.duration) * 100
console.log(`Progress: ${progress}%`)
}Analytics Platform Examples
Segment
const handlers = useMediaEvents({
mediaType: 'youtube',
mediaSrc: 'dQw4w9WgXcQ',
onPlay: (event) => {
window.analytics.track('Video Played', {
video_id: event.mediaSrc,
platform: event.mediaType
})
}
})Mixpanel
const handlers = useMediaEvents({
mediaType: 'vimeo',
mediaSrc: '123456789',
onComplete: (event) => {
mixpanel.track('Video Completed', {
'Video ID': event.mediaSrc,
'Media Type': event.mediaType,
'Duration': event.duration
})
}
})Google Analytics 4
const handlers = useMediaEvents({
mediaType: 'video',
mediaSrc: '/videos/demo.mp4',
onPlay: (event) => {
gtag('event', 'video_start', {
video_title: 'Product Demo',
video_url: event.mediaSrc
})
},
onComplete: (event) => {
gtag('event', 'video_complete', {
video_title: 'Product Demo',
video_url: event.mediaSrc
})
}
})Amplitude
const handlers = useMediaEvents({
mediaType: 'loom',
mediaSrc: 'abc123',
onEvent: (event) => {
amplitude.track(event.eventName, {
media_type: event.mediaType,
media_src: event.mediaSrc,
tour_id: event.tourId,
step_id: event.stepId
})
}
})TypeScript
Full type safety for event handlers:
import type { MediaEvent, MediaEventHandlers } from '@tour-kit/media'
const handlers: MediaEventHandlers = useMediaEvents({
mediaType: 'youtube',
mediaSrc: 'dQw4w9WgXcQ',
onPlay: (event: MediaEvent) => {
// event is fully typed
console.log(event.eventName) // 'media_play'
console.log(event.currentTime) // number | undefined
}
})See Also
- TourMedia - Media component with event support
- MediaHeadless - Headless media with events
- usePrefersReducedMotion - Motion preference detection