Events

The player emits events during playback that you can listen to for analytics, integration, or UI updates.

Listening for events

const player = lightbox({
  id: 'YOUR_MODULE_ID',
  targetElement: '#play-button',
})

player.on('ready', (event) => {
  console.log('Player is ready', event)
})

player.on('complete', (event) => {
  console.log('Video completed', event)
})

Event object

Every event callback receives an object with the following shape:

{
  event: 'complete',         // the event name
  id: 'YOUR_MODULE_ID',     // the content module ID
  data: { ... }             // event-specific payload (may be undefined)
}

Event types

ready

Fired when the player has loaded and is ready for user interaction.

start

Fired when the user plays the video for the first time. Fires before the first play event. Includes the full configuration context:

{
  event: 'start',
  data: {
    content: { vA: '03/15/2026' },
    manifestVersion: 2.1,
    mode: 'watch',
    recapEnabled: true,
    variantsRecap: 'a',
    variantsSlides: 'bbabba',
  },
}

play

Fired whenever the video starts playing. Includes the current timestamp.

pause

Fired whenever the video is paused. Includes the current timestamp.

end

Fired when the user reaches the end of the video, or when a chapter finishes after returning from the Recap.

recap

Fired whenever the user performs an action during the Recap stage — whether answering a question, clicking a button, or completing a step. Includes detailed progress and step content:

// Question answered
{
  event: 'recap',
  data: {
    meta: {
      currentQuestionNumber: 1,
      currentStepNumber: 2,
      percentCompletedQuestions: 25,
      percentCompletedSteps: 33.33,
      recapCompleted: false,
      totalQuestions: 4,
      totalSteps: 6,
    },
    stepType: 'question',
    stepContent: {
      statement: {
        question: 'VC3 supports _BLANK_ audio and visual content.',
        answer: 'personalised',
        userAction: {
          selectedAnswer: 'personalised',
          isAnswerCorrect: true,
        },
      },
    },
  },
}

return-to-chapter

Fired when the user chooses to return to a chapter from the Recap. Followed by a play event as the video starts playing from the beginning of the selected chapter.

quit-recap

Fired when the user chooses to exit the Recap and return to the player.

complete

Fired when the user has reached the end of the journey — usually when all Recap steps have been completed and Next Steps are displayed. If there is no Recap, fires when the video ends.

next-steps

Fired when the user clicks a Next Steps button. Includes the button text and action:

{
  event: 'next-steps',
  data: {
    text: 'Visit our website',
    type: 'url',
    url: 'https://example.com',
  },
}

restart

Fired when the user clicks the "replay video" button from the Next Steps stage.

quit-player

Fired when the user clicks the Exit Player button or closes an Unrecoverable Error. Includes detailed progress information:

{
  event: 'quit-player',
  data: {
    journeyComplete: false,
    mode: 'watch',
    slideCurrent: 3,
    slideTotal: 6,
    slidePercentComplete: 50,
    recapEnabled: true,
    recapStarted: false,
    variantSlides: 'bbabba',
  },
}

error

Fired when an unrecoverable error occurs. We recommend capturing these events and contacting support if you receive many in a short time.

{
  event: 'error',
  data: {
    message: 'This application has encountered an error...',
    type: 'unrecoverableErrorGeneric',
  },
}

event

A catch-all that fires for every event above. Useful for logging:

player.on('event', (event) => {
  console.log('New event:', event)
})

Example: analytics integration

const player = lightbox({
  id: 'YOUR_MODULE_ID',
  targetElement: '#play-button',
})

player.on('start', ({ id }) => {
  analytics.track('video_started', { moduleId: id })
})

player.on('complete', ({ id }) => {
  analytics.track('video_completed', { moduleId: id })
})

player.on('quit-player', ({ id, data }) => {
  analytics.track('video_exited', {
    moduleId: id,
    percentComplete: data?.slidePercentComplete,
  })
})