Skip to main content

Using Shaka Player

Quickstart

Add your HTML

Shaka player works by transforming a regular video tag into an HLS player, (widely supported by browsers)[https://caniuse.com/stream].

There are three important parts of this code below:

Caution

TODO: For videos we should give the recommended aspect ratio to make embedding possible without a flash of content

  1. The aspect ratio within the style tag. This tells the browser what size the video should be.
  2. The links. The poster is your thumbnail and the data-src is your video link
  3. The video controls like controls or playsinline. Take a look at the video player cheat sheet for more on these.
<div class="shaka-player" style="width:100%; position:relative; aspect-ratio:16/9; background:#000;">
<video
poster="https://worker.hesedvid.com/v1/thumbnail/org_01KAYN8RMNAEF0N243CYJCM9HR/env_A3TTAVN02AQHJTBLP7UTQ3V56ZYLNZ4/vid_K7VDWQKBCE06N0AK1O0LWDT2FQSS9A.png?width=1920&timeStamp=30"
data-src="https://worker.hesedvid.com/v1/edge_EVNENCJS37003VO58NNFZQTMWG7S66YA9TUY78/master.m3u8"
controls
playsinline
style="position:absolute; inset:0; width:100%; height:100%;"
></video>
</div>

Add your javascript

Shaka player relies on Javascript to work. Below is the minimal javascript/typescript code to use to get started.

import shaka from 'shaka-player/dist/shaka-player.compiled.js';
// Because HLS streaming isn't natively supported by some browsers,
// shaka starts with a polyfill
shaka.polyfill.installAll();
// Transparent error handling for very very old browsers
if (shaka.Player.isBrowserSupported()) {
// There can be multiple shaka player instances on a page,
// so we loop through them
document.querySelectorAll('.shaka-player video[data-src]').forEach(async (video: HTMLVideoElement) => {
// create and configure the player
const player = new shaka.Player();
// Full docs here: https://shaka-player-demo.appspot.com/docs/api/tutorial-config.html
player.configure({
streaming: {
// After seeking, how many seconds should be
// buffered before playing again?
rebufferingGoal: 0.1,
// How many seconds into the future
// should be buffered?
bufferingGoal: 15,
// How many seconds of previous video
// should be kept
bufferBehind: 10, // how much buffer to leave in the past
},
});
try {
await player.attach(video);
await player.load(video.dataset.src as string);
} catch (e) {
console.error('Error loading video', e);
}
});
} else {
console.error('Browser does not support Shaka Player');
}

Demo Video

Here’s what Shaka Player looks like based on the above code


Client-Side Ad Insertion (CSAI)

Shaka Player supports Client-Side Ad Insertion (CSAI) using the Google IMA SDK. The recommended approach is to use VMAP (Video Multi-Ad Playlist) tags, which define the complete ad schedule in a single URL.

Why VMAP?

A VMAP tag acts like a playlist for ads. It tells the player exactly when to play ads:

  • Pre-roll: Before the content starts
  • Mid-roll: At specific timestamps during playback
  • Post-roll: After the content ends

Shaka + IMA handle all the pausing, ad playback, and UI overlay (like “Skip Ad” buttons) automatically. This is far more reliable than manually pausing the video and swapping sources with JavaScript timers.

Demo

This demo uses a Google sample VMAP tag configured with a pre-roll, mid-roll, and post-roll:

Requirements

To add ads to Shaka Player, you need:

  1. Shaka Player UI build - The UI version (shaka-player.ui.js), not the compiled version
  2. Google IMA SDK - Loaded before your player code
  3. A VMAP/VAST tag URL - From your ad server (e.g., Google Ad Manager)

Step 1: Add the Scripts

<!-- Google IMA SDK (must be loaded first) -->
<script src="//imasdk.googleapis.com/js/sdkloader/ima3.js"></script>
<!-- Shaka Player UI build -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/shaka-player/4.3.0/shaka-player.ui.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/shaka-player/4.3.0/controls.min.css">

Or with npm:

import shaka from 'shaka-player/dist/shaka-player.ui';
import 'shaka-player/dist/controls.css';

Caution

You must use the UI build (shaka-player.ui.js) for ads. The compiled build (shaka-player.compiled.js) does not include the ad manager.

Step 2: Set Up the HTML

The UI overlay needs a container div wrapping the video:

<div id="video-container" style="width:100%; max-width:800px; position:relative;">
<video id="video" style="width:100%; height:100%;"></video>
</div>

Step 3: Initialize the Player with Ads

const video = document.getElementById('video');
const container = document.getElementById('video-container');
// Create player and UI overlay
const player = new shaka.Player();
const ui = new shaka.ui.Overlay(player, container, video);
await player.attach(video);
// Get the ad manager
const adManager = player.getAdManager();
// Initialize client-side ads
// Use the container so ads render on top of the video
adManager.initClientSide(container, video);
// Create the ad request with your VMAP tag
const adsRequest = new google.ima.AdsRequest();
adsRequest.adTagUrl = 'https://your-ad-server.com/vmap-tag';
adsRequest.linearAdSlotWidth = video.clientWidth;
adsRequest.linearAdSlotHeight = video.clientHeight;
// Request ads - Shaka parses the VMAP and schedules all ad breaks
adManager.requestClientSideAds(adsRequest);
// Load your video content
await player.load('https://your-video-url/master.m3u8');

Waiting for User Interaction

If you don’t want ads to autoplay, wait for user interaction before requesting ads:

// Initialize the ad manager
adManager.initClientSide(container, video);
// Load the video first
await player.load('https://your-video-url/master.m3u8');
// Request ads only when user clicks play
video.addEventListener('play', () => {
const adsRequest = new google.ima.AdsRequest();
adsRequest.adTagUrl = 'https://your-ad-server.com/vmap-tag';
adManager.requestClientSideAds(adsRequest);
}, { once: true });

Getting a VMAP Tag

Your ad server (like Google Ad Manager / DFP) generates VMAP URLs. The URL contains parameters that define:

  • Which ads to play
  • When to play them (pre-roll, mid-roll timestamps, post-roll)
  • Targeting information

For testing, you can use Google’s sample tags:

  • Pre-roll only: https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_preroll_skippable&sz=640x480&ciu_szs=300x250&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator=
  • Pre + Mid + Post: https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpost&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator=

Listening for Ad Events

const adManager = player.getAdManager();
adManager.addEventListener('ad-started', () => {
console.log('Ad started playing');
});
adManager.addEventListener('ad-stopped', () => {
console.log('Ad finished, content resuming');
});
adManager.addEventListener('ad-error', (event) => {
console.error('Ad error:', event);
});