BunnyPlayer component that renders the Bunny Player iframe, emits its events, and exposes a player.js Player for controlling playback.
Nuxt can server-render it as is. player.js reads window on import, which is why the component imports it in onMounted, and the iframe waits for the library before it renders.
Vue example on GitHub
A Vite app with custom controls and an event log.
Nuxt example on GitHub
The same component in a Nuxt 4 app.
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. Skip <ClientOnly>: the server renders the placeholder and the browser swaps in the iframe.3
Render a video
The library ID and video GUID are on the video’s page in the dashboard.
params takes any player parameter, such as captions, t, or muted.Control playback
Theready event carries the Player. Keep it in a shallowRef, which stops Vue wrapping it in a deep reactive proxy.
send() covers the gap. The build we host adds setPlaybackRate(), getPlaybackRate() and playbackratechange (Methods).
play() before the viewer has clicked anything. Call mute() first if playback has to start on its own. The Playback control API lists every method and event.
Track progress
timeupdate fires several times a second. Throttle it before it reaches your backend.
t parameter to resume.
Load player.js from the CDN instead
To drop the npm dependency, load our hosted build from the component.lib/load-playerjs.ts
onMounted for the loader.
components/BunnyPlayer.vue
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 loaded before player.js. Render it only once player.js has loaded, as the component above does.A hidden tab also holds
ready back until the viewer switches to it.Nuxt warns that a type check failed for libraryId
Nuxt warns that a type check failed for libraryId
Nuxt parses
NUXT_PUBLIC_* variables as it loads them, and a numeric library ID such as 12345 arrives as a number. Convert the IDs to strings first.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.