Custom event tracking
Subscribe to contract events with useMoviieEvent and onEvent to drive your own analytics.
The player emits the same contract events as the
window.Moviie Player API. Subscribe to them to drive
analytics, sync your UI, or trigger downstream behaviour. The full event list and
payloads are in the Events reference.
One event with useMoviieEvent
useMoviieEvent(handle, event, listener) subscribes to a single event. Get the
handle from <MoviieVideo>'s onReady (or a ref), keep it in state, and pass
it to the hook:
"use client"
import { useState } from "react"
import { MoviieVideo, useMoviiePlayer, useMoviieEvent } from "@moviie/player-react"
import type { MoviiePlayerHandle } from "@moviie/player-react"
function Player({ embedId }: { embedId: string }) {
const moviie = useMoviiePlayer({ embedId })
const [handle, setHandle] = useState<MoviiePlayerHandle | null>(null)
useMoviieEvent(handle, "play", () => analytics.track("video_play", { embedId }))
useMoviieEvent(handle, "ended", () => analytics.track("video_complete", { embedId }))
return <MoviieVideo {...moviie} onReady={setHandle} aspectRatio={16 / 9} />
}The subscription re-binds when the handle changes and cleans up on unmount.
Many events with onEvent
To handle every event in one place, use the onEvent prop. It fires for each
contract event with the event name and its payload:
<MoviieVideo
{...moviie}
aspectRatio={16 / 9}
onEvent={(event, detail) => {
if (event === "timeupdate") return // skip the high-frequency one
analytics.track(`moviie_${event}`, { embedId, ...((detail as object) ?? {}) })
}}
/>Reading payloads
Some events carry a payload. For example timeupdate reports the current time:
useMoviieEvent(handle, "timeupdate", (detail) => {
const { currentTime } = detail as { currentTime: number }
progressBar.value = currentTime
})Throttle high-frequency handlers
timeupdate fires frequently. Coalesce expensive work (analytics flushes,
layout reads) before reacting, or skip it in onEvent as shown above.
Combine with getState()
Events tell you when something happens; getState() tells you what the
player looks like at that moment. Read a coherent snapshot from the handle:
useMoviieEvent(handle, "pause", () => {
const state = handle?.getState()
analytics.track("video_pause", { at: state?.currentTime })
})See getState and the Properties reference.