Player object for talking to it over postMessage. This guide builds a BunnyPlayer component that renders the iframe, emits its events, and exposes that object.
The component also works under Nuxt server rendering. player.js is imported in onMounted, because it reads window when imported, and the iframe renders only after the library is available, because player.js has to be loaded before the iframe finishes loading.
Vue example on GitHub
A Vite app built around this component, with custom controls and an event log.
Nuxt example on GitHub
The same component in a Nuxt 4 app, reading the video IDs from
runtimeConfig.Quickstart
1
Install player.js
tsconfig.json includes, for example player.js.d.ts. It covers the methods and events the Bunny Player supports:player.js.d.ts
2
Create the component
components/BunnyPlayer.vue
components/ and it’s auto-imported. No <ClientOnly> wrapper is needed: the server renders the placeholder and the browser swaps in the iframe.3
Render a video
Pass the library ID and video GUID from the video’s page in the dashboard:
params accepts any player parameter, such as captions, t, or muted.Control playback
Theready event carries the Player. Keep it in a shallowRef, so Vue doesn’t wrap the instance in a deep reactive proxy, and call its methods from your own controls:
player.js package on npm (0.1.0) has no playback speed method, so send the command directly. The build bunny.net hosts adds setPlaybackRate(), getPlaybackRate() and the playbackratechange event from version 0.1.2; see Methods.
play() until the viewer has interacted with the page, so call mute() first if playback has to start without a click. Playback control API lists every method and event.
Track progress
timeupdate fires several times a second with { seconds, duration }. Throttle it before writing to your backend:
t parameter to resume from there.
Load player.js from the CDN instead
To skip the npm dependency, load the hosted build and readwindow.playerjs. In Nuxt, add it to nuxt.config.ts:
nuxt.config.ts
<script> tag to index.html. Replace the dynamic import in onMounted with playerjs.value = window.playerjs and declare the global:
Troubleshooting
ReferenceError: window is not defined
ReferenceError: window is not defined
player.js is being imported during server rendering. Keep
import("player.js") inside onMounted. A static import playerjs from "player.js" at the top of <script setup> runs on the server in Nuxt.The ready event never fires
The ready event never fires
The iframe finished loading before player.js was loaded. Render the iframe only after player.js has loaded, as the component above does. A
Player created after that still connects, because player.js caches the iframe’s ready message.ready is also delayed while the tab is hidden, and fires once it becomes visible.Nuxt warns that a type check failed for libraryId
Nuxt warns that a type check failed for libraryId
Nuxt parses
NUXT_PUBLIC_* variables when it loads them into runtimeConfig, so a numeric library ID such as 12345 reaches the component as a number. Convert the IDs to strings before you pass them on:Events fire twice after changing the video
Events fire twice after changing the video
Every
Player adds a message listener to window that is never removed. The active flag in the watcher cleanup keeps stale instances quiet, so check that yours flips it.The iframe shows a 403
The iframe shows a 403
The library’s allowed domains, direct access block, or token authentication is rejecting the embed. See Embedding restrictions.