Key takeaways
- Load https://www.youtube.com/iframe_api once and create players in onYouTubeIframeAPIReady.
- Control playback with playVideo, pauseVideo, seekTo, mute and loadVideoById.
- React to onStateChange and onError to track plays and skip broken videos.
- The IFrame API needs no key; listing channel or playlist videos needs the YouTube Data API with a key and quotas.
Load the API and create a player
<div id="player"></div>
<script src="https://www.youtube.com/iframe_api"></script>
<script>
let player;
function onYouTubeIframeAPIReady() {
player = new YT.Player("player", {
videoId: "VIDEO_ID",
playerVars: { playsinline: 1, rel: 0 },
events: { onReady: e => e.target.mute().playVideo() }
});
}
</script>Common methods
| Method | Does |
|---|---|
| playVideo() / pauseVideo() | Play and pause |
| seekTo(seconds) | Jump to a time |
| mute() / unMute() | Sound control |
| loadVideoById(id) | Switch videos |
| getCurrentTime() | Current position |
Events
onReady, onStateChange (playing, paused, ended), onError. Use them to track views or start the next video.
When you don’t need the API
For a gallery, playlist or channel feed on marketing pages, the API is a lot of code to maintain.
Show YouTube videos in a player with playlist — no API code.
Try Elfsight Video Gallery →How the API loads
The IFrame API is a single script. When it finishes loading, it calls a global function named onYouTubeIframeAPIReady — create your players there. Load the script once per page, even if you have several players, and create each player on its own element.
const players = {};
function onYouTubeIframeAPIReady() {
document.querySelectorAll("[data-yt]").forEach((el) => {
players[el.id] = new YT.Player(el.id, {
videoId: el.dataset.yt,
playerVars: { rel: 0, playsinline: 1 }
});
});
}Player states
| Value | Constant | Meaning |
|---|---|---|
| -1 | — | Unstarted |
| 0 | YT.PlayerState.ENDED | Ended |
| 1 | YT.PlayerState.PLAYING | Playing |
| 2 | YT.PlayerState.PAUSED | Paused |
| 3 | YT.PlayerState.BUFFERING | Buffering |
| 5 | YT.PlayerState.CUED | Video cued |
Listen to onStateChange and compare event.data with these constants.
Build a custom play button
<div id="player"></div>
<button id="play">Play</button>
<script>
let player;
function onYouTubeIframeAPIReady() {
player = new YT.Player("player", { videoId: "VIDEO_ID", playerVars: { controls: 0 } });
}
document.getElementById("play").onclick = () => {
const s = player.getPlayerState();
s === YT.PlayerState.PLAYING ? player.pauseVideo() : player.playVideo();
};
</script>Hiding YouTube’s controls means you take responsibility for accessible controls — keyboard support and labels.
Track plays and completions
events: {
onStateChange: (e) => {
const title = e.target.getVideoData().title;
if (e.data === YT.PlayerState.PLAYING) gtag("event", "video_start", { video_title: title });
if (e.data === YT.PlayerState.ENDED) gtag("event", "video_complete", { video_title: title });
}
}Handle errors
| Code | Meaning | What to do |
|---|---|---|
| 2 | Invalid parameter (often a wrong video ID) | Check the ID |
| 5 | HTML5 player error | Retry or show a fallback |
| 100 | Video not found or private | Remove it from the list |
| 101 / 150 | Owner doesn’t allow embedding | Link to YouTube instead |
Listen to onError and skip to the next video in your list when an error occurs.
IFrame API vs. YouTube Data API
The IFrame API controls playback of videos you already know. To list a channel’s uploads or a playlist’s videos, you need the separate YouTube Data API — with an API key, daily quota limits and caching on your side. That’s the part most custom galleries underestimate.
Show a channel or playlist as a gallery without the Data API, keys or quotas.
Try Elfsight Video Gallery →A complete example: a playlist of product videos
A common use case: one player, a list of your product videos next to it, and analytics for each play. Create the player once, render your list as buttons with data-id attributes, and call loadVideoById on click. On ENDED, load the next ID in your list so the playlist continues. Send video_start and video_complete events to analytics with the video title. Everything else — thumbnails, titles, the order of videos — comes from your own data, which is exactly the part the Data API or a gallery widget provides.
Frequently asked questions
What is the YouTube IFrame API?
A JavaScript API that controls embedded YouTube players.
Do I need an API key?
No, the IFrame Player API doesn’t need a key. The YouTube Data API (for listing channel videos) does.
Can I use the IFrame API with several players?
Yes — load the script once and create one YT.Player per element.
Why doesn’t playVideo() start with sound on mobile?
Browsers block unmuted playback without a user gesture; call it from a click, or mute first.
Can I autoplay with the IFrame API?
Yes, if the player is muted (playerVars mute: 1 or player.mute()) — the same browser rules apply as for iframes.
How do I get the current time of the video?
Call player.getCurrentTime() — for example on an interval while the state is PLAYING.
How do I switch videos without reloading the player?
Use player.loadVideoById(id) to load and play, or cueVideoById(id) to load without playing.
Does the API work with Shorts?
Yes — Shorts have regular video IDs; use a 9:16 container.