Jump to content

User manual: VidPly Player

A practical guide for web developers on how to integrate VidPly into their websites.

VidPly Logo

Brief overview

VidPly is a universal, accessible media player that supports the following:

FeaturesSupport
VideoMP4, WebM, OGG
AudioMP3, OGG, WAV
YouTubeEmbedded with standardised controls
VimeoEmbedded with standardised controls
SoundCloudEmbedded via widget API with standardised controls
HLSAdaptive bitrate streaming (hls.js in most browsers, native on iOS / iPadOS)
DASHMPEG-DASH streaming via dash.js
Buffer spinnerCentred loading spinner whilst waiting/searching
Download buttonOptional controls with support for custom URLs
PlaylistsAudio, video and mixed media with thumbnails
AccessibilityWCAG 2.2 AA compliant
TypeScriptStrict TS sources + bundled .d.ts declarations
LanguagesEN, ES, FR, DE, JA + custom

Installation

1. Create the player

 
npm install
npm run build
 

This will create files in the dist/:

  • prod/vidply.esm.min.js - ES module (recommended)
  • legacy/vidply.min.js - IIFE for script tag (global VidPly)
  • vidply.min.css - Styles

2. Embed it into your page

ES module (recommended):

 
<link rel="stylesheet" href="dist/vidply.min.css">
<script type="module">
  import Player from './dist/prod/vidply.esm.min.js';
</script>
 

Traditional script tag:

 
<link rel="stylesheet" href="dist/vidply.min.css">
<script src="dist/legacy/vidply.min.js"></script>
 

Basic usage

Video player

 
<video data-vidply width="800" height="450">
  <source src="video.mp4" type="video/mp4">
  <source src="video.webm" type="video/webm">
</video>
 

The data-vidply attribute automatically initialises the player.

Audio player

 
<audio data-vidply>
  <source src="audio.mp3" type="audio/mpeg">
  <source src="audio.ogg" type="audio/ogg">
</audio>
 

With poster image

 
<video data-vidply poster="thumbnail.jpg" width="800" height="450">
  <source src="video.mp4" type="video/mp4">
</video>
 

External services

YouTube

 
<video data-vidply src="https://www.youtube.com/watch?v=VIDEO_ID"></video>
 

Or with the full URL:

 
<video data-vidply src="https://youtu.be/VIDEO_ID"></video>
 

Vimeo

 
<video data-vidply src="https://vimeo.com/VIDEO_ID"></video>
 

SoundCloud

 
<audio data-vidply src="https://soundcloud.com/artist/track-name"></audio>
 

The SoundCloud widget API is automatically detected for any URL soundcloud.com. The widget is loaded on demand and can be integrated with the standard VidPly controls for play, pause, seek and volume.

When used mpc-vidply in TYPO3, the privacy layer displays a GDPR consent overlay before the SoundCloud iframe is loaded – visitors must first consent to the loading of external content.

HLS streaming

 
<video data-vidply src="https://example.com/stream.m3u8"></video>
 

hls.js is automatically loaded from the CDN as soon as .m3u8 URLs are detected. Behaviour varies by platform:

PlatformHLS engineSubtitles / Transcript / Quality
Chrome / Firefox / Edgehls.jsFull VidPly user interface
Desktop macOS Safarihls.js (for compatibility with other browsers)Full VidPly user interface
iOS / iPadOS SafariNative <video> HLSFull VidPly user interface via the native TextTrack API bridge
 

Even on iOS, where hls.js cannot be run (no MSE), VidPly still integrates the subtitle menu, interactive transcript and quality menu into the browser’s native HLS text tracks – you lose no UI controls.

 

DASH streaming

 
<video data-vidply src="https://example.com/manifest.mpd"></video>
 

dash.js is automatically loaded from the CDN as soon as .mpd URLs are detected. DASH streams support:

  • Adaptive bitrate selection
  • TTML subtitles (rendered natively by dash.js)
  • WebVTT subtitles (processed by VidPly’s subtitle system with transcript support)

DASH + HLS + MP4 fallback

 
<video data-vidply width="800" height="450">
  <source src="dash/manifest.mpd" type="application/dash+xml">
  <source src="hls/master.m3u8" type="application/x-mpegURL">
  <source src="fallback.mp4" type="video/mp4">
  <track kind="subtitles" src="subtitles.en.vtt" srclang="en" label="English">
</video>
 

Adding subtitles

Simple subtitles

 
<video data-vidply width="800" height="450">
  <source src="video.mp4" type="video/mp4">
  <track kind="subtitles" src="captions-en.vtt" srclang="en" label="English">
  <track kind="subtitles" src="captions-de.vtt" srclang="de" label="Deutsch">
</video>
 

Track types

TypePurpose
subtitlesTranslation of dialogue
captionsDialogue + sound effects (for the deaf/hard of hearing)
descriptionsText descriptions of visual content
chaptersChapter markers for navigation

Subtitles on by default

 
<track kind="subtitles" src="captions.vtt" srclang="en" label="English" default>
 

Chapter

Add chapter navigation with a chapter track:

 
<video data-vidply>
  <source src="video.mp4" type="video/mp4">
  <track kind="chapters" src="chapters.vtt" srclang="en">
</video>
 

chapters.vtt:

 
WEBVTT

00:00:00.000 --> 00:02:30.000
Introduction

00:02:30.000 --> 00:08:00.000
Main Topic

00:08:00.000 --> 00:12:00.000
Examples

00:12:00.000 --> 00:15:00.000
Conclusion
 

Configuration options

About data attributes

 
<video 
  data-vidply
  data-vidply-autoplay="false"
  data-vidply-loop="false"
  data-vidply-muted="false"
  data-vidply-volume="0.8"
  data-vidply-language="en"
  data-vidply-keyboard="true"
  data-vidply-responsive="true"
  src="video.mp4">
</video>
 

About JavaScript

 
const player = new Player('#my-video', {
  // Display
  width: 800,
  height: 450,
  poster: 'poster.jpg',
  responsive: true,
  
  // Playback
  autoplay: false,
  loop: false,
  muted: false,
  volume: 0.8,
  playbackSpeed: 1.0,
  
  // Controls
  controls: true,
  hideControlsDelay: 3000,
  
  // Buttons (show/hide individual controls)
  playPauseButton: true,
  progressBar: true,
  volumeControl: true,
  speedButton: true,
  captionsButton: true,
  fullscreenButton: true,
  pipButton: true,
  downloadButton: false,        // Show a download button in the control bar
  downloadUrl: null,            // Optional explicit download URL (defaults to current src)

  // Custom Floating Player (in-page miniplayer / "own PiP")
  floating: false,                          // Enable the custom floating player; also disables native browser PiP
  floatingPosition: 'bottom-right',         // 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'
  floatingMinViewportWidth: 768,            // Floating feature is hidden below this viewport width (px)

  // Language
  language: 'en',
  
  // Keyboard
  keyboard: true,
  
  // Accessibility
  screenReaderAnnouncements: true,
  focusHighlight: true
});
 

Reference of all options

OptionTypeDefaultDescription
widthNumber800Player width
heightNumber450Player height
posterStringnullURL of the poster image
responsivebooltrueResponsive resizing
autoplayboolfalseStart playback automatically
loopboolfalseLoop playback
mutedboolfalseStart muted
volumeNumber0.8Default volume (0–1)
playbackSpeedNumber1.0Default speed
controlsbooltrueShow controls
hideControlsDelayNumber3000Delay before automatic fading (ms)
keyboardbooltrueEnable keyboard shortcut
languageString'en'UI language
captionsbooltrueEnable subtitle support
captionsDefaultboolfalseShow subtitles by default
transcriptboolfalseShow subtitle window
debugboolfalseDebug logging
preloadString'metadata''none', 'metadata', 'auto'
deferLoadboolfalseAvoid starting the network loading process during initialisation; only load when the user plays the content / explicit loading
initialDurationNumber0Initial duration in seconds (UI only, before media metadata is loaded)
requirePlaybackForAccessibilityTogglesboolfalseIf true: AD/SL displays a prompt before playback, rather than loading/playing implicitly

Download button

Displays an optional download button in the control bar:

 
<video
  data-vidply
  data-vidply-download-button="true"
  data-vidply-download-url="/files/lecture.mp4"
  src="/streams/lecture/manifest.mpd">
</video>
 
const player = new Player('#video', {
  downloadButton: true,
  downloadUrl: '/files/lecture.mp4' // optional; falls back to current src
});
 

The button can be operated via the keyboard, is fully internationalised (player.download translation key) and uses aria-label , so that screen readers announce it correctly.

 

Note for streaming sources: downloadUrl is usually the URL of an MP4/MP3 fallback, as users generally do not .mpd or .m3u8 manifest as a single file.

 

Custom floating player (mini-player)

VidPly includes an optional, in-page floating player (‘custom PiP’) that appears in a configurable corner of the viewing area, can be moved and resized, and retains VidPly’s own subtitle display, transport controls and full-screen function within the floating shell.

As long as floating it is enabled, the browser’s native Picture-in-Picture API is automatically suppressed (disablepictureinpicture + disableremoteplayback), ensuring the user receives a consistent user experience across all browsers.

Behaviour

  • Automatic display on scrolling out – When the original player is scrolled out of the viewport, the video appears in the floating shell. When it is scrolled back in, the video re-docks to its original container.
  • Manual docking/undocking – The PiP button in the control bar manually docks the floating shell. Manual docking/undocking overrides scroll-based automatic floating until the next user-triggered play.
  • Close button – The X button in the floating shell pauses the video, returns it to its original container and suppresses automatic floating for the remainder of the playback session.
  • Drag & Resize – The floating shell can be dragged by the header and resized using the corner/edge handles. The geometry is retained per player via local storage.
  • Reduced control bar – Only the essential controls are displayed within the floating shell: Play/Pause, Rewind, Fast-forward, Volume, Subtitles, PiP and Full Screen. Tooltips open above the buttons; the size of the subtitles is 90% and limited to 95% width.
  • Audio players are skipped – The floating function applies only to <video> players.
  • By default, only on the desktop – Below floatingMinViewportWidth (default 768 px), the feature is disabled and the floating PiP button is hidden in the main control bar (it never appears in the overflow menu).

Enabling via HTML (data-vidply-options JSON)

The floating options are controlled via the data-vidply-options JSON blob (the same channels as TYPO3 / mpc_vidply is used):

 
<video
  data-vidply
  data-vidply-options='{"floating": true, "floatingPosition": "bottom-right", "floatingMinViewportWidth": 768}'
  src="video.mp4"
  width="800" height="450">
  <track kind="subtitles" src="captions.vtt" srclang="en" label="English">
</video>
 

Enabling via JavaScript

 
const player = new Player('#video', {
  floating: true,
  floatingPosition: 'bottom-right', // or 'bottom-left' | 'top-right' | 'top-left'
  floatingMinViewportWidth: 768
});
 

Accessibility

  • The floating shell is role="dialog" with a translated aria-label (player.floatingPlayerDialog).
  • The PiP switch uses aria-pressed to indicate the pinned status.
  • The focus returns to the original button when the floating shell is closed using the keyboard.
  • All built-in languages (en, de, es, fr, ja) contain translations for player.floatingPlayer, player.floatingPlayerClose, player.floatingPlayerEnter, player.floatingPlayerExit and player.floatingPlayerDialog.

Buffering spinner

A centred loading spinner appears automatically whilst the media is being buffered (waiting / seeking / initial loadstart) and disappears when canplay / playing. It works for HTML5, HLS and DASH renderers and takes into account prefers-reduced-motion.

You can customise the design using CSS variables:

 
.vidply-player {
  --vidply-spinner-color: #ffffff;
  --vidply-spinner-size: 56px;
  --vidply-z-buffering: 1; /* sits below the play overlay */
}
 

The container provides a .vidply-buffering class that you can use for styling or integration:

 
.vidply-player.vidply-buffering .my-skin-overlay {
  opacity: 0.3;
}
 

Playlists

Audio playlist

 
<div id="audio-player"></div>

<script type="module">
  import { Player, PlaylistManager } from './dist/prod/vidply.esm.min.js';
  
  // When you pass a non-media element, VidPly will create the media element for you.
  const player = new Player('#audio-player', { mediaType: 'audio' });
  const playlist = new PlaylistManager(player, {
    autoAdvance: true,
    loop: false,
    showPanel: true
  });
  
  playlist.loadPlaylist([
    {
      src: 'track1.mp3',
      title: 'Track 1',
      artist: 'Artist Name',
      poster: 'cover1.jpg'
    },
    {
      src: 'track2.mp3',
      title: 'Track 2',
      artist: 'Artist Name',
      poster: 'cover2.jpg'
    }
  ]);
</script>
 

Video playlist

 
<div id="video-player"></div>

<script type="module">
  import { Player, PlaylistManager } from './dist/prod/vidply.esm.min.js';
  
  const player = new Player('#video-player');
  const playlist = new PlaylistManager(player, {
    autoAdvance: true,
    showPanel: true
  });
  
  playlist.loadPlaylist([
    {
      src: 'video1.mp4',
      title: 'Video 1',
      poster: 'thumb1.jpg',
      tracks: [
        { src: 'captions1.vtt', kind: 'captions', srclang: 'en', label: 'English' }
      ]
    },
    {
      src: 'video2.mp4',
      title: 'Video 2',
      poster: 'thumb2.jpg'
    }
  ]);
</script>
 

Playlist options

OptionDefaultDescription
autoAdvancetrueAutomatically play next track
autoPlayFirsttrueAutomatically play first track loadPlaylist() (if false: The first track is loaded/selected, but not played)
loopfalseRepeat playlist
showPaneltrueShow playlist window

Playlist controls

 
playlist.next()           // Next track
playlist.previous()       // Previous track
playlist.goToTrack(2)     // Jump to track index
playlist.hasNext()        // Check if next exists
playlist.hasPrevious()    // Check if previous exists
 

Accessibility features

Audio description

Provide an alternative video with audio description:

 
const player = new Player('#my-video', {
  audioDescription: true,
  audioDescriptionSrc: 'video-with-description.mp4'
});
 

Users can switch using the AD button.

Sign language

Add a sign language interpretation overlay:

 
const player = new Player('#my-video', {
  signLanguage: true,
  signLanguageSrc: 'sign-language.mp4',
  signLanguagePosition: 'bottom-right'
});
 

Positioning options: bottom-right, bottom-left, top-right, top-left

Interactive transcripts

 
const player = new Player('#my-video', {
  transcript: true,
  transcriptPosition: 'external',
  transcriptContainer: '#transcript-panel'
});
 

Features:

  • Click on any line to jump to that point
  • Automatic scrolling during playback
  • Searchable text
  • Window can be moved and resized

Keyboard shortcuts

VidPly offers comprehensive keyboard control:

KeyAction
Space bar / P / KPlay/Pause
FToggle full screen
MMute/Unmute
/ Increase/decrease volume
/ Skip forward/backward ±10 seconds
CTurn subtitles on/off
ASubtitle style menu
<** / **>Decrease/increase speed
SSpeed menu
QQuality menu
JChapter menu
TShow/hide transcript
DDrag mode (transcript/characters)
RResize mode
HomeReset position
EscExit mode/Close menu

Custom keyboard shortcuts

 
const player = new Player('#my-video', {
  keyboardShortcuts: {
    'play-pause': [' ', 'p', 'k'],
    'seek-forward': ['ArrowRight', 'l'],
    'seek-backward': ['ArrowLeft', 'j'],
    'volume-up': ['ArrowUp'],
    'volume-down': ['ArrowDown'],
    'mute': ['m'],
    'fullscreen': ['f'],
    'captions': ['c']
  }
});
 

Design & Themes

CSS variables

 
.vidply-player {
  /* Colors */
  --vidply-primary-color: #3b82f6;
  --vidply-background: rgba(0, 0, 0, 0.8);
  --vidply-text-color: #ffffff;
  
  /* Sizing */
  --vidply-button-size: 40px;
  --vidply-icon-size: 20px;
  
  /* Spacing */
  --vidply-gap-sm: 4px;
  --vidply-gap-md: 8px;
  --vidply-gap-lg: 12px;
  
  /* Border radius */
  --vidply-radius-sm: 4px;
  --vidply-radius-md: 8px;
  --vidply-radius-lg: 12px;
  
  /* Transitions */
  --vidply-transition-fast: 150ms;
  --vidply-transition-normal: 300ms;
}
 

Custom progress bar

 
.vidply-progress-played {
  background: linear-gradient(90deg, #667eea, #764ba2);
}
 

Custom buttons

 
.vidply-button:hover {
  background: rgba(59, 130, 246, 0.2);
}

.vidply-button:focus {
  outline: 2px solid var(--vidply-primary-color);
  outline-offset: 2px;
}
 

Internationalisation

Integrated languages

  • English (en)
  • Spanish (es) – Español
  • French (fr) – Français
  • German (de) - Deutsch
  • Japanese (ja) – 日本語

Set language

 
const player = new Player('#my-video', {
  language: 'de'  // German
});
 

Detect automatically from HTML

 
<html lang="de">
  <!-- Player auto-detects German -->
</html>
 

Load custom language

Via data attribute:

 
<video 
  data-vidply 
  data-vidply-language-files='{"pt": "languages/pt.json"}'
  src="video.mp4">
</video>
 

Via JavaScript (options):

 
import Player from './dist/prod/vidply.esm.min.js';

const player = new Player('#my-video', {
  language: 'pt',
  languageFiles: { pt: 'languages/pt.json' }
});
 

Language file format

languages/pt.json:

 
{
  "player": {
    "play": "Reproduzir",
    "pause": "Pausar",
    "mute": "Silenciar",
    "unmute": "Ativar som",
    "fullscreen": "Tela cheia",
    "captions": "Legendas",
    "settings": "Configurações"
  },
  "time": {
    "currentTime": "Tempo atual",
    "duration": "Duração"
  }
}
 

API Reference

Playback

 
player.play()              // Start playback
player.pause()             // Pause playback
player.stop()              // Stop and reset
player.toggle()            // Toggle play/pause
player.seek(30)            // Seek to 30 seconds
player.seekForward(10)     // Skip forward 10s
player.seekBackward(10)    // Skip backward 10s
 

Volume

 
player.setVolume(0.5)      // Set volume (0-1)
player.getVolume()         // Get volume
player.mute()              // Mute
player.unmute()            // Unmute
player.toggleMute()        // Toggle mute
 

Speed

 
player.setPlaybackSpeed(1.5)   // Set speed (0.25-2.0)
player.getPlaybackSpeed()      // Get speed
 

Full screen

 
player.enterFullscreen()   // Enter fullscreen
player.exitFullscreen()    // Exit fullscreen
player.toggleFullscreen()  // Toggle fullscreen
 

Subtitles

 
player.enableCaptions()    // Enable captions
player.disableCaptions()   // Disable captions
player.toggleCaptions()    // Toggle captions
 

Status

 
player.getCurrentTime()    // Current time in seconds
player.getDuration()       // Total duration
player.isPlaying()         // Is playing?
player.isPaused()          // Is paused?
player.isEnded()           // Has ended?
player.isMuted()           // Is muted?
player.isFullscreen()      // Is fullscreen?
 

Events

 
player.on('ready', () => {})
player.on('play', () => {})
player.on('pause', () => {})
player.on('ended', () => {})
player.on('timeupdate', (time) => {})
player.on('volumechange', (volume) => {})
player.on('fullscreenchange', (isFullscreen) => {})
player.on('captionsenabled', (track) => {})
player.on('error', (error) => {})
 

Clean-up

 
player.destroy()           // Remove player
 

Browser support

BrowserVersion
Chrome90+
Firefox88+
Safari14+
Edge90+
iOS Safari14+
Android Chrome90+

Troubleshooting

Video won't play

ProblemSolution
Black screenCheck whether the video URL is accessible
CORS errorEnsure that the CORS headers on the server are correct
Format not supportedProvide an MP4 fallback
Autoplay blockedAutoplay muted: true for autoplay

Subtitles are not displayed

ProblemSolution
VTT is not loadingCheck the file URL; validate the VTT syntax
CORS errorServe VTT from the same domain or enable CORS
Incorrect encodingSave the VTT as UTF-8

YouTube/Vimeo not working

ProblemSolution
Does not loadCheck video URL format
API errorEnsure that the videos are embeddable
Controls missingVidPly uses native service players

HLS is not playing

ProblemSolution
Stream is not loadingCheck whether the .m3u8 URL is accessible
CORS issuesConfigure CORS on the streaming server
Segments are failingCheck the segment URLs in the manifest

DASH is not playing

ProblemSolution
Stream is not loadingCheck whether the .mpd URL is accessible
CORS issuesConfigure CORS on the streaming server
No quality levelsCheck whether MPD has multiple renditions
TTML subtitles are missingdash.js renders TTML natively; ensure that the tracks are included in the manifest
Transcript not availableTTML tracks do not support transcripts; use WebVTT for transcripts

Best practice

Performance

  • ✅ Use responsive: true for fluid layouts
  • ✅ Provide poster images
  • ✅ Use appropriate video resolutions
  • ✅ Compress videos for web delivery

Accessibility

  • ✅ Always provide subtitles
  • ✅ Use meaningful titles
  • ✅ Test using only the keyboard
  • ✅ Test with screen readers

Cross-browser

  • ✅ Provide MP4 and WebM sources
  • ✅ Test on mobile devices
  • ✅ Take into account differences in full-screen mode on iOS

Live demos

Try VidPly in action:

Need help? Check the API documentation or create a ticket on GitHub.

Share page