Video Tracking API

This reference covers the current Video Tracking runtime: module bootstrap, canonical storage, AJAX/REST entry points, Bricks integration, and the services that track watch state.

Overview

The Video Tracking runtime lives under src/Modules/VideoWatch/. It adds tracked video playback to BRM content, hosted video selection, and a native brm-video Bricks element.

  • Admin surfaceBricksMembers → Video Tracking for global defaults and host connections
  • Editor surface — BRM meta box fields for brm_video_url, brm_video_duration, brm_video_image, and per-post watch policy overrides
  • Frontend surfaceBRM Video Bricks element plus watch-state AJAX sync and dynamic tags

Core Services

  • VideoWatchSystem — Module bootstrap. Registers cross-module hooks and BRM Video element refresh controls.
  • VideoConfigResolver — Resolves effective config for a post by merging global defaults, per-post policy, and the resolved video source.
  • VideoWatchService — Canonical read/write service for user watch state. Exposes get_watch_state(), get_effective_watch_state(), sync(), and related context helpers.
  • VideoSourceSync — Keeps canonical _brm_video_source in sync with legacy fields such as brm_video_url, brm_video_image, and brm_video_duration, stores an explicit provider hint for opaque values, and lazily backfills legacy rows on read.
  • VideoProviderRegistry — Detects the provider from raw URL/ID input and normalizes provider-specific source data.
  • VideoPickerService — Lists videos and groups from connected providers for admin picker flows and exposes get_connected_providers() for editor surfaces.
  • VideoRefreshService — Adds threshold-reached refresh controls to the brm-video element and enqueues the frontend refresh handler when needed.

Canonical Storage

Video Tracking uses a mix of options, post meta, and a dedicated watch-state table.

  • brm_video_watch_settings — Global defaults such as required percent, completion mode, gating, resume mode, seek policy, and thumbnail settings
  • brm_video_host_credentials — Provider credentials and access tokens for the video picker
  • brm_video_host_enabled — Per-provider admin enable flags
  • _brm_video_source — Canonical normalized source payload for a post
  • _brm_video_source_provider — Optional provider hint stored alongside legacy brm_video_url values so opaque IDs can resolve deterministically
  • _brm_video_watch_policy — Per-post overrides for required percent, completion mode, and next-navigation gating
  • brm_video_url, brm_video_duration, brm_video_image — Legacy-compatible editor fields kept in sync with the canonical source
  • {prefix}brm_user_video_watch — Per-user/per-post watch state including coverage, watched buckets, threshold flags, completion flags, duration, and last/max positions

VideoWatchService treats the watch table as the canonical runtime store for learner watch progress. The current row shape includes values such as coverage_map, watched_buckets, watched_percent, threshold_percent, threshold_reached, fully_watched, last_position_seconds, max_position_seconds, duration_seconds, and source_hash.

Effective Watch State vs Post Watch State

VideoWatchService::get_effective_watch_state() is the preferred read path for frontend logic. It can aggregate related child video posts when a lesson/template context should behave like a single tracked lesson rather than an isolated child video post.

$state = \BaselMedia\BricksMembers\Modules\VideoWatch\VideoWatchService::get_instance()
    ->get_effective_watch_state( get_current_user_id(), get_the_ID() );

if ( ! empty( $state['threshold_reached'] ) ) {
    // Reveal dependent UI or allow a next-step action.
}

Use get_watch_state() only when you explicitly need the raw row for a single post/video source.

AJAX Handlers

The main frontend/admin entry points are registered in src/Ajax/VideoWatchActions.php.

  • wp_ajax_brm_get_video_watch_state — Returns the raw watch-state row for the requested post plus required_percent after access/context validation. This handler does not call get_effective_watch_state().
  • wp_ajax_brm_sync_video_watch_state — Syncs client watch progress into the canonical watch table
  • wp_ajax_brm_test_video_host_connection — Admin-only connection test for configured hosts

The sync payload keys are source_hash, duration_seconds, current_time_seconds, max_position_seconds, and bucket_indexes. The service rejects stale payloads if the source hash no longer matches the canonical post source.

REST Endpoints

Hosted video browsing is exposed through the REST controller under /wp-json/bricksmembers/v1/video-picker/.

  • GET /wp-json/bricksmembers/v1/video-picker/{provider} — List videos for one provider
  • GET /wp-json/bricksmembers/v1/video-picker/{provider}/groups — List groups/folders for providers that support them

The current picker supports mux, wistia, gumlet, bunny, youtube, and vimeo. The routes are registered whenever the Video Tracking module is active. Requests require a logged-in user who can edit_posts plus a valid WordPress REST nonce. Successful responses still depend on the provider being enabled and connected. YouTube is considered connected when BRM has either a current access token or a refresh-token stack (refresh_token + client_id + client_secret). Vimeo requires a saved access token, and private libraries need the public and private scopes.

Bricks Integration

The frontend element is brm-video (BRM Video in the builder). It renders the canonical video source for the current post and handles tracked playback.

  • Display modesdirect_embed, click_to_load, lightbox
  • Threshold refresh control — Injected through brm/elements/brm-video/controls and backed by VideoRefreshService
  • Asset hookbrm/elements/brm-video/enqueue_assets
  • Threshold event namebrm:video:threshold-reached

The threshold refresh controls support no-op, partial AJAX refresh, or full page refresh with scroll/highlight restoration. This is the hook point that lets the video threshold reveal quizzes, refresh progress bars, or update wrapped BRM UI on the page.

Dynamic Tags

Video watch tags are registered through VideoWatchDynamicTags. These tags use VideoWatchService::get_effective_watch_state(), not the raw AJAX state handler, so lesson-level aggregate contexts can resolve differently from wp_ajax_brm_get_video_watch_state. Current tags:

  • {brm_video_watch:percent}
  • {brm_video_watch:required_percent}
  • {brm_video_watch:remaining_percent}
  • {brm_video_watch:threshold_reached}
  • {brm_video_watch:completed}
  • {brm_video_watch:last_position}
  • {brm_video_watch:resume_available}

Separate from the watch-state tags, the core BRM dynamic tags also expose the resolved video metadata for the current post. That includes {brm_video:url}, {brm_video:source}, {brm_video:image}, and {brm_video:duration}. {brm_video:source} returns the resolved provider key such as gumlet, vimeo, youtube, or html5.

Provider Normalization

VideoProviderRegistry::normalize_from_raw() is the normalization boundary between editor input and runtime playback. The canonical source payload contains provider-specific normalized data such as provider key, source value, source ID, embed URL, thumbnail ID, duration, and privacy mode.

Provider implementations also declare whether they support resume and seek-guard behavior. That allows the runtime to adapt playback UX without treating all video sources as identical.

Related

Early Bird Deal

Start Building Your Membership Site Today

Create, sell, and manage your content without limits. BricksMembers gives you everything you need to build membership and LMS sites with Bricks Builder.

Lifetime updates & bug fixes • Premium support • 0% transaction fees • 60-day money-back guarantee