Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
@vidyard/embed-code
Advanced tools
Vidyard Player embed and API
Table of Contents
The Vidyard embed code helps embed Vidyard players into web pages and applications. It provides programmatic playback control, the ability to listen on playback events, GDPR consent control and integration with third party MAP platforms.
In addition, the Vidyard Embed code is fully responsive (filling the width of the container element by default), it enhances SEO with JSON-LD tags and it improves the accessibility of the player on your page.
By default the Vidyard embed code has 2 components, the embed script and the placeholder image:
<img />
tag that displays the thumbnail of the video and contains data attributes
that control how the player is rendered. Each player uses a separate placeholder image.The Vidyard Embed code is designed to be lightweight and asynchronous. The placeholder image reserves a place in the layout for the video player while minimizing impact on the loading performance of the page.
The Vidyard Embed code can be bundled as an NPM dependency into your project:
npm install --save @vidyard/embed-code
# or using Yarn
yarn add @vidyard/embed-code
Then imported directly in your JavaScript:
import VidyardEmbed from '@vidyard/embed-code';
// render all players from placeholder images in the document
VidyardEmbed.api.renderDOMPlayers();
// render a player programmatically, see method documentation below
VidyardEmbed.api.renderPlayer({...})
Served from the Vidyard Global Content Delivery Network at https://play.vidyard.com/embed/v4.js
.
The script tag is auto executing. This means that on script load it will scan the document for Vidyard embed placeholder images and will replace them with Vidyard players.
<!-- The script tag should live in the head of your page if at all possible -->
<script src="https://play.vidyard.com/embed/v4.js" type="text/javascript" async></script>
<!-- Put this wherever you would like your player to appear -->
<img
style="max-width: 100%;"
class="vidyard-player-embed"
src="https://play.vidyard.com/UUID.jpg"
data-uuid="UUID"
data-v="4"
data-type="inline"
/>
The UMD is also available from the Vidyard Global Content Delivery Network at https://play.vidyard.com/embed/v4.umd.js
. It will not auto execute when imported, requiring the client to render the players by calling vidyardEmbed.api.renderPlayer
or vidyardEmbed.api.renderDOMPlayers
.
<!-- The script tag should live in the head of your page if at all possible -->
<script src="https://play.vidyard.com/embed/v4.umd.js" type="text/javascript" async></script>
<!-- Put this wherever you would like your player to appear -->
<img
style="max-width: 100%;"
class="vidyard-player-embed"
src="https://play.vidyard.com/UUID.jpg"
data-uuid="UUID"
data-v="4"
data-type="inline"
/>
<script>
window['onVidyardAPI'] = (vidyardEmbed) => {
vidyardEmbed.api.renderDOMPlayers();
};
</script>
Included as data attributes on the placeholder image (options must be prepended with data-
):
data-type
: specifies the type of embedlightbox
or inline
data-uuid
: the unique identifier string of the playerdata-aspect
: the aspect ratio of the player landscape
, portrait
, height / width * 100
(custom value)Note: This only applies to the Embed Script and UMD module embed types (not the NPM Package).
By default, the Embed Script Tag is loaded asynchronously by using the async
attribute on the script tag. The client code is notified when the embed code has loaded and is ready to be used using the following methods.
For Internet Explorer 9 we dispatch an onVidyardAPI
custom event on document
that can be listened to instead of using the global callback:
// initApp is the client's function that interacts with the Vidyard API
window.vidyardEmbed
? initApp(window.vidyardEmbed)
: document.addEventListener('onVidyardAPI', ({ detail: vyApi }) => initApp(vyApi));
Or by adding assigning a callback onto the global onVidyardAPI
value that will be called once the embed script is loaded
// initApp is the client's function that interacts with the Vidyard API
// this needs to be defined before the v4 embed script is added to the page
window['onVidyardAPI'] = (vyApi) => initApp(vyApi);
It is a good idea to check for the presence of the API global and fallback to the onVidyardAPI
// initApp is the client's function that interacts with the Vidyard API
// this can be defined anywhere in the client code
window.vidyardEmbed
? initApp(window.vidyardEmbed)
: (window.onVidyardAPI = (vyApi) => initApp(vyApi));
Or with promises:
// this can be defined anywhere in the client code
new Promise(res => window.vidyardEmbed
? res(window.vidyardEmbed)
: (window['onVidyardAPI'] = (vyApi) => res(vyApi))
).then((vyApi) => {
console.log('The Vidyard API is ready ', vyApi);
});
To pass unstructured metadata to the player, use the data-vydata
attribute. Data attributes use the DOMStringMap
format which limits the characters we can use for the key, so all complex nested data is passed as a stringified and URI encoded JSON.
const placeholderImg = document.querySelector("[data-uuid='UUID']");
placeholderImg.setAttribute(
"data-vydata",
encodeURIComponent(
JSON.stringify({
location: "here",
more: "yes"
})
)
);
By default the embed code is pointing at the production instance of play.vidyard.com
, this can be overridden by using the data-playbackurl
attribute on the script tag.
<script src="https://play.vidyard.com/embed/v4.js" data-playbackurl="play-staging.vidyard.com" type="text/javascript" async ></script>
Or by setting a global variable before including the embed script.
window.VIDYARD_PLAYBACK_URL = 'play-staging.vidyard.com';
Or by calling the debug method
window.vidyardEmbed._debug.setPlaybackURL('play-staging.vidyard.com');
The vidyardEmbed
named export and the window.VidyardV4
object expose the following APIs:
import vidyardEmbed from '@vidyard/embed-code';
const {
api: {
GDPR: { consent, hasConsentOnReady },
addReadyListener,
getPlayerMetadata,
getPlayersByUUID,
progressEvents,
renderDOMPlayers,
renderPlayer,
}
} = vidyardEmbed;
GDPR.consent([true|false])
true
or false
.import vidyardEmbed from '@vidyard/embed-code';
userHasGivenConsent() { // client page code
vidyardEmbed.api.GDPR.consent(true);
}
GDPR.hasConsentOnReady(callback)
true
or false
upon all player ready.import vidyardEmbed from '@vidyard/embed-code';
vidyardEmbed.api.GDPR.hasConsentOnReady((consent) => {
if (!consent) {
showConsentPrompt(); // client page code
} else {
greet(); // client page code
}
});
addReadyListener(callback[data, UUID])
data
object is undefined
for the ready
event.UUID
is optional filter for individual players.import vidyardEmbed from '@vidyard/embed-code';
vidyardEmbed.api.addReadyListener((data, player) => {
console.log('the player is ready', player);
player.seek(20);
player.play();
});
getPlayersByUUID(UUID)
UUID
.play()
, resume()
, seek()
, ready()
etc. For more details about player API, please visit the Vidyard Knowledgebaseimport vidyardEmbed from '@vidyard/embed-code';
const players = vidyardEmbed.api.getPlayersByUUID('UUID');
players[0].ready();
progressEvents(callback)
{ player, chapter, event } = result
object.import vidyardEmbed from '@vidyard/embed-code';
vidyardEmbed.api.addReadyListener((data, player) => {
vidyardEmbed.api.progressEvents(({ chapter, event, player }) => {
const { name } = player.metadata.chapters_attributes[chapter].video_attributes;
console.log(`${name}: ${event}%`);
if (event === 4) {
player.pause();
}
}, [1, 2, 3, 4, 25, 50, 75, 100]);
}, 'UUID');
renderDOMPlayers([container])
document
.import vidyardEmbed from '@vidyard/embed-code';
vidyardEmbed.api.renderDOMPlayers();
Or player in a specific container:
import vidyardEmbed from '@vidyard/embed-code';
const playersContainer = document.getElementById('video-content');
vidyardEmbed.api.renderDOMPlayers(playersContainer);
renderPlayer(options)
options
can either be an HTMLImageElement
in the DOM or a configuration object.uuid
and a container
properties.Note: The renderPlayer
API method will not work inside the ready event
as described above when using the standard v4.js
script.
It will, however, work inside the ready event when using the UMD module or NPM package,
or using the standard v4.js
script outside of the ready event (in which case, do not use the async attribute on the v4.js
script tag).
import vidyardEmbed from '@vidyard/embed-code';
const placeholderImage = document.querySelectorAll('img.vidyard-player-embed')[0];
vidyardEmbed.api.renderPlayer(placeholderImage);
Or using a data object:
import vidyardEmbed from '@vidyard/embed-code';
vidyardEmbed.api.renderPlayer({
uuid: 'UUID',
container: document.getElementById('player-container');
// optional
type: 'lightbox',
aspect: 'landscape',
vydata: encodeURIComponent(JSON.stringify({location: 'here', more: 'yes'}),
// ...
// any additional parameters
});
destroyPlayer(player)
window.Vidyard.players()
.const player = api.getPlayersByUUID('pZovJVPRGJWs2scm3EZckY')[0];
api.destroyPlayer(player);
getPlayerMetadata(UUID)
UUID
for the player.UUID
is not valid the promise is rejected.import vidyardEmbed from '@vidyard/embed-code';
vidyardEmbed.api.getPlayerMetadata('UUID')
.then((metadata) => {
console.log(metadata);
})
.catch((e) => {
console.log('error fetching player metadata');
});
The schema of the Player Metadata object:
interface Metadata {
chapters_attributes: Array<{
video_attributes: {
captions: any[];
description: string | null;
length_in_milliseconds: number;
length_in_seconds: number;
name: string;
sd_url: string;
status: string;
tags: any[];
thumbnail_urls: {
normal: string;
play_button: string;
play_button_small: string;
small: string;
};
};
}>;
custom_attributes: any[];
description: string;
height: number;
length_in_seconds: number;
name: string;
tags: any[];
uuid: string;
width: number;
}
Once a player is selected with any of the Embed API methods, the player API allows for control of the player and adding handlers for player events. Full documentation of the Vidyard Player API can be found in the Vidyard Knowledge Base.
const players = VidyardEmbed.api.getPlayersByUUID(UUID);
const firstPlayer = players[0];
firstPlayer.play();
firstPlayer.on('playerComplete', () => {
console.log('the video was watched in full, hurray!');
});
The Vidyard Embed code is licensed under the MIT License.
Copyright 2021 Buildscale Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
FAQs
The Vidyard player embed code, also known as Embed V4
We found that @vidyard/embed-code demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 16 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.