Skip to content

Freecaster Player Guide for Developers

Welcome! This guide shows you how to embed the Freecaster video player on your website and customize it using simple HTML and JavaScript.

Target Audience

This documentation is intended for front-end developers familiar with HTML, CSS, and JavaScript.

Statistics & GDPR Compliance

Heads up! By default, the player does not track statistics. To enable analytics modules (like Google Analytics, Mux, Youbora, etc.), you must set the stats attribute to true (see configuration). Remember, obtaining user consent is mandatory under GDPR.
You can find here the best integration practices.

Getting Started: Embedding the Player

There are two ways to embed the player. We recommend using the JavaScript integration method, as it provides easier access to the Player API and greater flexibility for customizing styles with CSS.

  1. Include the Player Script: Add this script tag to your page (ideally in the <head> or before your closing </body> tag). You only need it once, even for multiple players.

    <script async src="https://player.freecaster.com/freecaster/stable/fcplayer.js"></script>
    

  2. Add the Player Placeholder: Insert a <div> where you want the player. Use the freecaster-player class and the data-video-id attribute with your video's ID. The script will automatically replace this div with the player.

    <!-- Basic Example -->
    <div class="freecaster-player" data-video-id="YOUR_VIDEO_ID"></div>
    
    <!-- Example with Customizations -->
    <div class="freecaster-player" 
         data-video-id="YOUR_VIDEO_ID" 
         data-width="640" 
         data-autoplay="true" 
         data-muted="true" 
         data-lang="fr-be" 
         data-stats="true">
    </div>
    

Embed an <iframe> using this URL structure: https://player.freecaster.com/embed/VIDEO_ID.html. Add configuration options as query parameters.

<!-- Responsive Iframe Wrapper -->
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
    <iframe 
        src="https://player.freecaster.com/embed/YOUR_VIDEO_ID.html?width=640&autoplay=true&muted=true&stats=true&lang=fr-be" 
        style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0;" 
        frameborder="0" 
        scrolling="no" 
        allowfullscreen>
    </iframe>
</div>
Note: The div wrapper provides a common way to make the iframe responsive (16:9 aspect ratio). Adjust padding-bottom for different aspect ratios.

Testing Environment

When testing against our acceptance environment, use player.freecaster-uat.com instead of player.freecaster.com in the URLs.

Essential HTML Setup

For the player to work correctly, especially regarding responsiveness and character display, ensure these <meta> tags are present in the <head> of your HTML document:

<head>
  <meta charset="UTF-8"> 
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <!-- Other head elements -->
</head>
  • charset="UTF-8": Prevents potential character encoding issues (weird symbols).
  • viewport: Ensures the player scales correctly on different devices.

Configuring the Player

You can customize the player's behavior and appearance using attributes.

  • JavaScript Embed: Use data-* attributes on the <div> tag (e.g., data-autoplay="true").
  • Iframe Embed: Append query parameters to the src URL (e.g., ?autoplay=true).

Attribute Naming Convention

For iframe query parameters, use camelCase instead of hyphens.

  • JS Embed: data-my-attribute="value"
  • Iframe Embed: ?myAttribute=value

Here are the available configuration options:

Attribute (data-*) / Parameter (?param=) Expected Value Default Description
audio_only / audioOnly boolean false Hides video-specific UI elements for an audio-focused experience. See note below.
autopause boolean true Automatically pauses the video when it scrolls out of the viewport.
autoplay boolean false Starts playback automatically. Requires muted=true in most modern browsers. See Google's Autoplay Policy.
cast boolean false Enables Chromecast / AirPlay buttons.
chapters.enabled / chaptersEnabled boolean false Enables the chapters feature.
chapters.list / chaptersList []<Chapter> (JSON) [] Provides chapter data. See note below for format.
chapters.style / chaptersStyle hidden, dot, full_width hidden How chapter markers appear on the timeline.
controls boolean true Shows or hides the player control bar.
float_on_scroll / floatOnScroll boolean false Displays a mini-player that sticks to the viewport when the main player is scrolled out of view.
height number Sets the player's height in pixels (e.g., 360). Use 100% with width="100%" for stretching.
lang language-country Sets the player UI language (e.g., en-us, fr-be). Follows RFC 5646.
loop boolean false Restarts the video automatically when it ends.
multiplay boolean false If true, pauses this player if another Freecaster player on the page starts playing. Useful for pages with multiple players.
muted boolean false Mutes the player audio by default. Required for autoplay to work reliably.
noads boolean false Disables advertising.
poster Image URL (string) Specifies a custom poster image URL to show before playback starts.
preload auto, metadata, none auto How the video should be loaded: auto (loads video data), metadata (loads only dimensions, duration, etc.), none (doesn't preload). See Multi instance section.
speed.labels / speedLabels string Comma-separated custom labels for speed options (e.g., "Slow,Normal,Fast"). Must match the number of speed.options.
speed.options / speedOptions string "0.2,0.5,1,2,10" Comma-separated playback speed factors (e.g., "0.5,1,1.5,2").
stats boolean false Crucial: Enables all tracking and analytics (Google Analytics, Mux, Youbora, etc.). Requires user consent (GDPR).
stretching fill, cover, none none How the video and poster resize to fit player dimensions. Requires width="100%" and height="100%.
fill: Stretches, ignoring aspect ratio.
cover: Zooms/crops to fill, maintains aspect ratio.
none: Original size (may show black bars).
subtitles.default_lang / subtitlesDefaultLang lang (ISO 639-1) Sets the initially active subtitle track by its 2-letter language code (e.g., en, fr).
subtitles.lang / subtitlesLang lang (ISO 639-1) Filters the subtitle menu to only show the specified language (e.g., es).
subtitles.native / subtitlesNative boolean false Uses the browser's native subtitle rendering (supports VTT styling).
thumbnails.src / thumbnailsSrc Thumbnails URL URL for the video timeline preview thumbnails (VTT format).
trackers.ga.enabled / trackersGaEnabled boolean false Specifically enables Google Analytics 4 (GA4) tracking. Requires stats=true. Events pushed to window.dataLayer.
trackers.ga.tag_ids / trackersGaTagIds string Comma-separated list of GA4 Measurement IDs (e.g., "G-XXXXXXXXXX,G-YYYYYYYYYY") to send events to.
volume number (0.0 to 1.0) 1 Sets the initial volume (0 = silent, 1 = full volume). User's manual mute action takes precedence on subsequent loads. Browser autoplay policies may affect this.
watermark.enabled / watermarkEnabled boolean false Shows or hides the watermark overlay.
width number Sets the player's width in pixels (e.g., 640). Use 100% with height="100%" for stretching.

Notes

dnt Deprecated

The old dnt attribute is deprecated. Please use stats for clarity. dnt still works for backward compatibility.

audio_only Usage

If you are embedding audio content and don't want a poster image displayed, set audio_only to true for a minimal UI.

Chapter List Format (chapters.list)

Provide a JSON array of chapter objects:

[
  {
    "id": "chapter-1-unique-id", 
    "start": 0,         // Start time in milliseconds
    "end": 15000,       // End time in milliseconds
    "title": "Introduction",
    "description": "Overview of the topic",
    "customData": { "key": "value" } // Optional: Your custom data
  },
  {
    "id": "chapter-2-unique-id",
    "start": 15000,
    "end": 45000,
    "title": "Deep Dive" 
  }
]
  • start and end are in milliseconds.
  • customData is passed through to chapter-related events.

Chapter Events

When using chapters, the player emits events you can listen for (see Player Instance API and Events):

  • fc_chapter_user_enter: User enters a chapter's time range.
  • fc_chapter_user_leave: User leaves a chapter's time range.
  • fc_chapter_user_mark: Fires at the start time of each chapter.

    Example using the Player API:

    playerInstance.on('fc_chapter_user_enter', (payload) => {
      console.log(`Entered chapter: ${payload.data.title}`);
      console.log('Custom data:', payload.data.customData); 
    });
    

Accessing Player Instances

Using window.fcplayer

You can use the globally available window.fcplayer() function to get references to active fcplayer instances within your application.

How it Works:

The function's behavior depends on whether you provide an ID:

  • Retrieve the First Instance: If you call the function without any arguments (window.fcplayer()), it will return the very first fcplayer instance that was created on the page. If no players exist yet, it returns null.
  • Retrieve by ID: If you pass a string argument representing the unique ID of a player (window.fcplayer('mySpecificPlayerId')), the function will search for the player instance associated with that ID. If found, it returns that specific instance. If no player with that ID exists, it returns null.

Parameters:

  • playerId (String | undefined):
    • Optional. The ID of the player instance you want to target.
    • If omitted, the function retrieves the first available instance.

Returns:

  • An fcplayer instance (object) if a match is found (or if retrieving the first instance and one exists).
  • null if no instances exist or the specified playerId does not correspond to an active player.

Usage Examples:

// Scenario 1: Only one player expected, or need the default one
const player = window.fcplayer();
if (player) {
  // Interact with the player API
  console.log('Player found:', player.id);
} else {
  console.error('No fcplayer instances found!');
}

// Scenario 2: Need to control a specific player among potentially many
const bannerPlayer = window.fcplayer('promo-video-player');
if (bannerPlayer) {
  bannerPlayer.mute();
} else {
  console.log('Promo video player not ready or does not exist.');
}

Using Player Callback

The window._fcpr array provides a mechanism to execute your code whenever an fcplayer instance is initialized. You push callback functions onto this array.

Setup:

First, ensure the array is initialized, preferably early in your page execution:

window._fcpr = window._fcpr || [];
Usage:

Push a function that accepts the player instance as an argument. This function will run for all existing instances and any future instances as they are created.

window._fcpr.push(playerInstance => {
  // Code to run for each player instance
  console.log('Detected player:', playerInstance.id);
  // Example: Attach an event listener
  playerInstance.on('error', (err) => {
    console.error(`Player ${playerInstance.id} encountered an error:`, err);
  });
});

Example: Autoplay When Visible

This demonstrates the automatic play of a video using the viewenter event, which is only triggered once per player.

Example:

// Add this script once to your page
window._fcpr = window._fcpr || [];
window._fcpr.push(playerInstance => {
  // Play the video only when it becomes visible the first time
  playerInstance.once('viewenter', () => {
    // Use togglePlay(true) or play() - togglePlay avoids errors if already playing
    playerInstance.togglePlay(true); 
    console.log(`Player ${playerInstance.id || ''} entered view and started playing.`);
  });
});

You can create links that start (and optionally stop) video playback at specific times using query parameters start_time and end_time. Values are in seconds.

Example: https://player.freecaster.com/embed/VIDEO_ID.html?start_time=120&end_time=300

This link will start the video at 2 minutes (120s) and automatically pause it at 5 minutes (300s).

Limitation

This feature only works for Video On Demand (VOD), not live streams.

Getting Current Time

You can get the current playback time in seconds using the Player API: playerInstance.currentTime.

Player Instance API (JavaScript Embed Only)

To control the player programmatically (play, pause, seek, listen to events, etc.), you need its instance. You can only get the instance when using the JavaScript embed method.

Iframe Limitation

You cannot directly access the player instance or its API when using the iframe embed.

Here's how to get the player instance:

  1. By Element ID: Assign a unique id to your player <div>.

    <div id="my-player" class="freecaster-player" data-video-id="VIDEO_ID"></div>
    
    Then, use the global fcplayer() function:
    // Wait for the player script to load and initialize the player
    // A simple way is to wait for the DOMContentLoaded event or use the callback below
    document.addEventListener('DOMContentLoaded', () => {
      const playerInstance = fcplayer('my-player');
      if (playerInstance) {
        // Now you can use the instance
        playerInstance.play(); 
      }
    });
    

  2. Using the window._fcpr Callback: This array receives a callback function for every player instance created on the page. This is useful if you don't know the ID beforehand or want to handle multiple players.

    window._fcpr = window._fcpr || []; // Initialize if it doesn't exist
    
    window._fcpr.push((playerInstance) => {
      console.log(`Player ready: ${playerInstance.id || 'No ID'}`);
    
      // Example: Attach an event listener to a specific player
      if (playerInstance.id === 'my-special-player') {
        playerInstance.on('play', () => console.log('Special player started!'));
      }
    
      // Example: Attach listener to ALL players
      playerInstance.on('error', (err) => console.error(`Player error:`, err));
    });
    

Get All Instances: You can get an array of all initialized player instances at any time using:

const allPlayers = window.fcplayers(); 

Handling Multiple Players on a Page

If you have multiple players visible simultaneously, default browser behavior (especially with preload="auto" or autoplay="true") can lead to excessive bandwidth usage and performance issues as multiple videos might try to load at once.

Recommendation:

  1. Set preload="none" and autoplay="false" on your player divs.
  2. Use the Player API to start playback only when the player enters the viewport.
  3. Consider using data-multiplay="true" to automatically pause other players when one starts.

Example Implementation:

<!-- Player 1 -->
<div class="freecaster-player"
     data-video-id="VIDEO_ID_1"
     data-multiplay="true" 
     data-preload="none"
     data-muted="true" 
     data-autoplay="false">
</div> 

<!-- Player 2 -->
<div class="freecaster-player"
     data-video-id="VIDEO_ID_2"
     data-multiplay="true"
     data-preload="none"
     data-muted="true"
     data-autoplay="false">
</div> 

// Add this script once to your page
window._fcpr = window._fcpr || [];
window._fcpr.push(playerInstance => {
  // Play the video only when it becomes visible the first time
  playerInstance.once('viewenter', () => {
    // Use togglePlay(true) or play() - togglePlay avoids errors if already playing
    playerInstance.togglePlay(true); 
    console.log(`Player ${playerInstance.id || ''} entered view and started playing.`);
  });

  // Optional: Pause when it leaves view (if not using autopause attribute)
  // playerInstance.on('viewleave', () => {
  //   playerInstance.pause();
  //   console.log(`Player ${playerInstance.id || ''} left view and paused.`);
  // });
});
This approach provides a smoother "autoplay-like" experience without overloading the browser on page load.

Player Properties (API)

Access these properties on a player instance:

Property Description Example Usage Return Type Example Return Value
audioTracks List of available audio tracks. See MDN player.audioTracks AudioTrackList AudioTrackList {length: 2, 0: AudioTrack, 1: AudioTrack}
blackBarsHeight Returns the total height in pixels of the black bars (if any) shown due to a mismatch between the container and video ratio. player.blackBarsHeight number 100 (if black bars exist) / 0 (if no black bars exist)
config The current configuration object of the player. player.config object { autoplay: false, muted: true, ... }
container The main HTMLElement container of the player. player.container HTMLElement <div class="freecaster-player...">
controlbar The HTMLElement of the player's control bar. player.controlbar HTMLElement <div class="fp-controls...">
currentAudioTrack The currently active/playing audio track, if any. player.currentAudioTrack AudioTrack | null AudioTrack {id: 'en', kind: 'main', label: 'English', language: 'en'} / null
currentTime Current playback position in seconds. See MDN player.currentTime number 123.456
currentTimecode Current playback position as a formatted timecode string (HH:MM:SS:FF or HH:MM:SS.ms). player.currentTimecode string "00:02:03:15" or "00:02:03.500"
currentTimestamp Current playback position as a UTC timestamp in milliseconds (Live DASH/HLS only, requires specific setup). player.currentTimestamp number | null 1678886400123
duration The total duration of the video in seconds. Returns Infinity for live streams. player.duration number 600.5 or Infinity
id The id attribute of the player's container element, if set. player.id string | null "my-player"
live Boolean indicating if the current video source is a live stream. player.live boolean true / false
muted Boolean indicating if the player is currently muted. player.muted boolean true / false
paused Boolean indicating if the player is currently paused. player.paused boolean true / false
subtitlesEnabled Boolean indicating whether subtitles/captions are currently enabled on the player. player.subtitlesEnabled boolean true / false
version The player's version string. player.version string "freecaster-player x.y.z (core v...)
volume Current volume level (0.0 to 1.0). player.volume number 0.75

Deprecated Properties

These are older attributes/properties. Please use the current alternatives listed in the main configuration table.

Deprecated Use Instead
mute muted (attribute)
repeat loop (attribute)
aspectratio Handled via CSS/container
playbackRateControls speed.options etc.
localization lang (attribute)
displaytitle (No direct equivalent)
displaydescription (No direct equivalent)
fc-token data-video-id
locale lang (attribute)
dnt stats (attribute)

Player Methods (API)

Call these methods on a player instance:

Method Description Example Usage
play() Starts or resumes playback. player.play()
pause() Pauses playback. player.pause()
togglePlay(force?) Toggles between play and pause. Optional boolean forces state (true=play, false=pause). player.togglePlay()
player.togglePlay(true)
seek(time) Jumps to a specific time (in seconds) or timestamp (milliseconds, live/VOD with start offset). player.seek(120) (jump to 2 mins)
player.seek(1678886400123) (jump to timestamp, if applicable)
setSrc(source) Loads a new video source. See note below for format. player.setSrc('new_video.mp4')
player.setSrc({ type: 'application/dash+xml', src: 'manifest.mpd' })
loadVideo(videoId) Loads a new video using its Freecaster Video ID, replacing the current one. player.loadVideo('NEW_VIDEO_ID')
destroy() Removes the player instance and its associated DOM elements. Cleans up event listeners. player.destroy()
toggleFullScreen() Enters or exits fullscreen mode. player.toggleFullScreen()
setConfig(key, value) Updates one or more configuration options after initialization. player.setConfig('volume', 0.5)
player.setConfig({ controls: false, loop: true })
goBackToLive() For live streams with DVR, seeks to the current live edge. player.goBackToLive()
mute(shouldMute) Mutes (true) or unmutes (false) the player. player.mute(true)
setVolume(level) Sets the volume (0.0 to 1.0). player.setVolume(0.8)
on(event, callback) Attaches an event listener. player.on('play', () => console.log('Playback started'))
off(event, callback) Removes an event listener. player.off('play', myPlayHandler)
once(event, callback) Attaches an event listener that runs only once. player.once('ended', () => console.log('Video finished'))

seek() with Timestamps

Using an absolute timestamp (milliseconds) with seek() requires:

  • Live: The timestamp must be within the available DVR window.
  • VOD: The player.config.start property (usually provided by the API) must be available for the player to map the timestamp to a video offset.

setSrc() Format

The source parameter for setSrc() can be:

  • A simple URL string: 'https://path/to/video.mp4'
  • A source object: { type: 'application/dash+xml', src: 'https://path/to/manifest.mpd' }
  • An array of source objects (the player picks the first compatible one):
[
  { type: 'application/x-mpegurl', src: 'https://path/to/playlist.m3u8' },
  { type: 'video/mp4', src: 'https://path/to/fallback.mp4' }
]

Google Analytics (GA4) Integration

To send player events to Google Analytics 4:

  1. Include GA Snippet: Make sure the standard Google Analytics gtag.js snippet is included on your page. (Google Docs)
  2. Enable Stats: Set the data-stats="true" attribute on your player div.
  3. Enable GA Tracker: Set data-trackers.ga.enabled="true".
  4. (Optional) Specify Tag IDs: If needed, provide your GA4 Measurement ID(s) using data-trackers.ga.tag_ids="G-XXXXXXXXXX,G-YYYYYYYYYY". If omitted, events might be sent to tags configured globally via gtag('config', 'GA_MEASUREMENT_ID').

<!-- Make sure GA script is loaded on the page -->

<div class="freecaster-player" 
     data-video-id="YOUR_VIDEO_ID"
     data-stats="true"  
     data-trackers.ga.enabled="true" 
     data-trackers.ga.tag_ids="G-XXXXXXXXXX"> 
</div>
Player events (like play, pause, seek, ended, error, etc.) will automatically be pushed to the window.dataLayer.

Events

You can listen for various events on the player instance using player.on('eventName', callback).

Standard HTML Media Events

These are common events based on the HTML5 video element standard.

Event Description
play Fired when playback begins or resumes.
pause Fired when playback is paused.
ended Fired when playback reaches the end of the media.
error Fired when an error occurs during loading or playback.
seeking Fired when a seek operation begins.
seeked Fired when a seek operation completes.
timeupdate Fired frequently as the currentTime progresses. (Use sparingly for performance).
volumechange Fired when the volume or muted state changes.
ratechange Fired when the playback rate changes.
waiting Fired when playback stops due to buffering.
playing Fired when playback resumes after buffering or seeking.
loadstart Fired when the browser begins looking for media data.
loadedmetadata Fired when the media's metadata (duration, dimensions) is loaded.
loadeddata Fired when the first frame of data is available.
canplay Fired when the player can start playing, but might need to buffer.
canplaythrough Fired when the player estimates it can play through to the end without buffering.
resize Fired when the player's dimensions change.

Freecaster Player Custom Events

These events are specific to the Freecaster player.

Event Description Payload Data Example
fullscreenenter Fired when the player enters fullscreen mode. -
fullscreenexit Fired when the player exits fullscreen mode. -
viewenter Fired when the player element becomes visible within the browser's viewport. -
viewleave Fired when the player element scrolls out of the browser's viewport. -
fcplayerDestroy Fired just before the player instance is completely removed. -
fcplayerSrcChanged Fired after the video source has been successfully changed via setSrc or loadVideo. { src: 'new_source_url_or_object' }
fcplayerConfigChanged Fired after configuration is updated via setConfig. { key: 'config_key', value: 'new_value' } or { changes: { key1: value1, ... } }
fc_chapter_user_enter Fired when playback enters the time range of a chapter (defined in chapters.list). { data: ChapterObject }
fc_chapter_user_leave Fired when playback leaves the time range of a chapter. { data: ChapterObject }
fc_chapter_user_mark Fired exactly at the start time of each chapter during playback. { data: ChapterObject }
fcplayerCountdownTick (If applicable) Fired every second during a pre-roll countdown. { remaining: number } (seconds)
fcplayerCountdownEnabled (If applicable) Fired when a countdown starts. -
fcplayerCountdownDisabled (If applicable) Fired when a countdown is stopped or finishes naturally. -
fcplayerCountdownZero (If applicable) Fired exactly when the countdown hits zero. -

Example Listener:

playerInstance.on('viewenter', () => {
  console.log('Player is now visible!');
});

playerInstance.on('fcplayerSrcChanged', (payload) => {
  console.log('New video source loaded:', payload.src);
});

playerInstance.on('fc_chapter_user_enter', (payload) => {
  console.log(`Entering chapter: ${payload.data.title}`);
});

The Freecaster player uses cookies and HTML Local Storage for necessary functionality and, if enabled, for analytics. Third-party services integrated with the player (like Youbora) also use these technologies.

What are Cookies & Local Storage?

  • Cookies: Small files stored by your browser, often used for session tracking or preferences.
  • Local Storage: A web storage mechanism allowing sites to store data persistently in the browser.

Disabling Non-Essential Storage

You can prevent the player from setting analytics-related cookies and local storage items by setting the stats attribute to false:

<div class="freecaster-player" data-video-id="YOUR_VIDEO_ID" data-stats="false"></div> 
This will disable analytics tracking but may impact our ability to analyze player performance and issues. Essential functional storage (like to) will still be used.

Storage Items Used

Freecaster (Necessary Functionality)

Name Storage Purpose Expiry
to Local Storage Stores time offset calculation data needed for accurately displaying countdowns for live events. 30 minutes

Youbora (Analytics - Only if stats=true)

Name Storage Purpose Expiry
youbora.accCode Local Storage Stores Youbora account code. Permanent
youbora.data Local Storage Caches Youbora API settings. Permanent
youbora.dataTime Local Storage Timestamp for the cached settings. Permanent
youbora.host Local Storage Host endpoint for sending Youbora analytics. Permanent
youbora.offlineViews Local Storage Stores unsent analytics pings (if offline). Permanent
youbora.session Local Storage Unique identifier for the current viewing session. Permanent
youbora.sessionExpire Local Storage Expiry timestamp for the session identifier. Permanent
youbora.youboraDeviceUUID Local Storage Randomly generated unique device ID for tracking. Permanent

(Note: "Permanent" means the data persists until manually cleared by the user or the website.)

Best Practices for Statistics Integration (GDPR Compliant)

To comply with GDPR, player statistics must only be enabled after obtaining explicit user consent.

Recommended Workflow:

  1. Gather Consent: Before initializing the player with statistics enabled, display a consent UI (e.g., banner, popup) to the user.
  2. Handle User Choice:
    • Consent Given: Mark the consent (e.g., set data-stats="true" on the player's container element).
    • Consent Denied / No Choice Yet: Leave the player's container element as is (do not add data-stats="true").
  3. Initialize Player: Insert the <div class="freecaster-player"></div> into the document, fcplayer.js will take over and load the video player.