Skip to main content
Scripts

YouTube Player

YouTube hosts videos and provides an iframe player API.

Nuxt Scripts provides a useScriptYouTubePlayer() composable and a headless <ScriptYouTubePlayer> component for controlling the YouTube player.

YouTube Player

View source

Nuxt Config Setup

Add this to your nuxt.config.ts to load YouTube Player globally. Alternatively you can use the useScriptYouTubePlayer composable for more control.

export default defineNuxtConfig({
  scripts: {
    registry: {
      youtubePlayer: {
        trigger: 'onNuxtReady',
      }
    }
  }
})

This config automatically enables first-party mode (bundle + proxy). See below to customise.

useScriptYouTubePlayer()

The useScriptYouTubePlayer composable lets you have fine-grain control over when and how YouTube Player is loaded on your site.

const { proxy } = useScriptYouTubePlayer()

const { YT } = await proxy

Please follow the Registry Scripts guide to learn more about advanced usage.

First-Party Mode: Privacy Focused Proxy

No extra config needed. The script is bundled from your domain (faster loads, no extra DNS lookup) and runtime requests are reverse-proxied through your server with automatic anonymisation (user IPs stay hidden from YouTube Player, works with ad blockers). Learn more.

Mode
Bundle Proxy
Privacy
User IP addresses are anonymised. Other request data passes through.
export default defineNuxtConfig({
  scripts: {
    // ✅ First-party mode: bundled + proxied
    registry: {
      youtubePlayer: {
        trigger: 'onNuxtReady',
      },
    },
  },
})

Example

Using YouTube Player in a component with the proxy to send events .

<script setup lang="ts">
const { proxy } = useScriptYouTubePlayer()

// noop in development, ssr
// just works in production, client
function handleAction() {
  const { YT } = await proxy
}
</script>

<template>
  <div>
    <button @click="handleAction">
      Send Event
    </button>
  </div>
</template>

Types

Install @types/youtube for full TypeScript support.

pnpm add -D @types/youtube

<ScriptYouTubePlayer>

<ScriptYouTubePlayer> wraps useScriptYouTubePlayer() with a lazy thumbnail and a headless player UI.

An Element Event Trigger delays the iframe API and player until the configured event fires.

The default event is mousedown.

Demo

Play video
Click to load
Clicking the video will load the YouTube iframe and start the video.

Privacy

The <ScriptYouTubePlayer> component uses YouTube's privacy-enhanced https://www.youtube-nocookie.com host by default. See YouTube's embed instructions for details.

To use the standard cookie-enabled host, set the cookies prop.

<ScriptYouTubePlayer video-id="d_IFKP1Ofq0" cookies />

Placeholder

The YouTube Player placeholder is a 1280x720 WebP image that is lazy-loaded by default.

Set thumbnailSize to change the placeholder size. Set webp to false for a JPEG thumbnail.

<ScriptYouTubePlayer video-id="d_IFKP1Ofq0" thumbnail-size="maxresdefault" />

For finer control, set placeholderAttrs or replace the image through the #placeholder slot.

Eager Loading

For an above-the-fold video, load the thumbnail eagerly or replace it through the #placeholder slot.

<ScriptYouTubePlayer above-the-fold />

Component API

See the Facade Component API for full props, events, and slots.

Events

The component forwards the six events below. At runtime, each handler receives only the event object shown here. A failure while loading the iframe API also emits error with no arguments. The component's current TypeScript declaration lists a second YT.Player argument for five events, but that argument is not emitted. The YouTube API defines onAutoplayBlocked too, but the component does not currently forward it. See Player Events for payload details.

const emits = defineEmits<{
  'ready': [e: YT.PlayerEvent]
  'state-change': [e: YT.OnStateChangeEvent]
  'playback-quality-change': [e: YT.OnPlaybackQualityChangeEvent]
  'playback-rate-change': [e: YT.OnPlaybackRateChangeEvent]
  'error': [e: YT.OnErrorEvent]
  'api-change': [e: YT.PlayerEvent]
}>()

Slots

Use the slots to control the facade around the player.

default

Always visible.

<template>
  <ScriptYouTubePlayer video-id="d_IFKP1Ofq0">
    <div class="bg-blue-500 text-white p-5">
      Video by Nuxt
    </div>
  </ScriptYouTubePlayer>
</template>

awaitingLoad

Shown while the component waits for its element trigger.

<template>
  <ScriptYouTubePlayer video-id="d_IFKP1Ofq0">
    <template #awaitingLoad>
      <div class="bg-blue-500 text-white p-5">
        Click to play!
      </div>
    </template>
  </ScriptYouTubePlayer>
</template>

loading

Shown while the iframe API loads.

<template>
  <ScriptYouTubePlayer video-id="d_IFKP1Ofq0">
    <template #loading>
      <div class="bg-blue-500 text-white p-5">
        Loading...
      </div>
    </template>
  </ScriptYouTubePlayer>
</template>

placeholder

Replaces the default YouTube thumbnail. The slot receives the computed placeholder URL.

<template>
  <ScriptYouTubePlayer video-id="d_IFKP1Ofq0">
    <template #placeholder="{ placeholder }">
      <img :src="placeholder" alt="Video Placeholder">
    </template>
  </ScriptYouTubePlayer>
</template>

useScriptYouTubePlayer()

Use useScriptYouTubePlayer() when you need to load the iframe API and create a player programmatically.

export function useScriptYouTubePlayer<T extends YouTubePlayerApi>(_options: YouTubePlayerInput) {}

For triggers, proxying, and other script options, see Registry Scripts.

export interface YouTubePlayerApi {
  YT: MaybePromise<{
    Player: YT.Player
    PlayerState: YT.PlayerState
    get: (k: string) => any
    loaded: 0 | 1
    loading: 0 | 1
    ready: (f: () => void) => void
    scan: () => void
    setConfig: (config: YT.PlayerOptions) => void
    subscribe: <EventName extends keyof YT.Events>(
      event: EventName,
      listener: YT.Events[EventName],
      context?: any,
    ) => void
    unsubscribe: <EventName extends keyof YT.Events>(
      event: EventName,
      listener: YT.Events[EventName],
      context?: any,
    ) => void
  }>
}

Example

Loading the YouTube Player SDK and interacting with it programmatically.

<script setup lang="ts">
const video = ref()
const { onLoaded } = useScriptYouTubePlayer({})

const player = ref(null)
onLoaded(async ({ YT }) => {
  // we need to wait for the internal YouTube APIs to be ready
  const YouTube = await YT
  await new Promise<void>((resolve) => {
    if (typeof YouTube.Player === 'undefined')
      YouTube.ready(resolve)
    else
      resolve()
  })
  // load the API
  player.value = new YouTube.Player(video.value, {
    videoId: 'd_IFKP1Ofq0'
  })
})
function play() {
  player.value?.playVideo()
}
</script>

<template>
  <div>
    <div ref="video" />
    <button @click="play">
      Play
    </button>
  </div>
</template>