How to Add a Confetti Animation When a Vimeo Video Starts Playing

There's something about confetti that just works. It's celebratory, unexpected, and when it's timed right, it feels like the page is reacting to something the user did. Not just decoration sitting on a screen.
This post walks you through how to trigger a canvas confetti animation the moment a Vimeo video starts playing. We'll use the Vimeo Player API to hook into the play event, wait a beat, then fire the confetti. The result feels intentional and polished rather than random.
If you haven't worked with the Vimeo Player API before, I wrote a full breakdown of the basics here. This post will cover enough to get you up and running on its own, but that one goes deeper on the fundamentals.
What You're Building
A Vimeo video plays. About a third of a second later, confetti bursts across the screen. That's it. Simple concept, but the implementation has a few moving parts worth understanding.
Here's what you need:
- A Vimeo video embedded on your page
- The Vimeo Player SDK loaded via CDN
- The canvas-confetti library loaded via CDN
- A small JavaScript block wiring them together
Loading Your Dependencies
Add both of these script tags before your closing </body> tag. Order matters here. Both need to be available before your script runs.
<script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.2/dist/confetti.browser.min.js"></script>
<script src="https://player.vimeo.com/api/player.js"></script>Setting Up Your Vimeo Iframe
Place your Vimeo iframe on the page and give it an ID. That ID is how your JavaScript will find it.
<iframe
id="my-video"
src="https://player.vimeo.com/video/YOUR_VIDEO_ID?h=YOUR_HASH"
frameborder="0"
allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media"
allowfullscreen>
</iframe>If you want the video to autoplay when the page loads, add muted=1&autoplay=1 to the URL. Browsers block autoplay with sound by default, so muted is required for it to work.
Creating the Player Instance
Once the SDK is loaded and the iframe is on the page, you create a player instance by passing the iframe element to Vimeo.Player:
const iframe = document.getElementById('my-video');
const player = new Vimeo.Player(iframe);You now have a JavaScript object that can communicate with the embedded video.
Hooking Into the Play Event
The Vimeo Player API fires a play event every time the video starts or resumes playing. You listen for it using player.on():
player.on('play', function() {
// this runs every time the video plays
});This is the hook. Instead of guessing when the video starts or using a timer from page load, you're reacting to the actual moment playback begins. That's what makes the timing feel right.
Why a 300ms Delay Before the Confetti
You could fire the confetti the instant the play event fires. But in practice, firing it immediately can feel slightly off. The video frame is just starting to render, the browser is doing a few things at once, and the confetti ends up competing for attention before the video has had a chance to settle.
A 300ms delay gives the video just enough time to actually start showing on screen. By the time the confetti fires, the video is visible and playing, so the celebration feels like a reaction to something rather than something that happened alongside it. It's a small thing but it makes a noticeable difference to how polished the interaction feels.
player.on('play', function() {
setTimeout(function() {
confetti({
particleCount: 150,
spread: 80,
origin: { y: 0.4 },
zIndex: 9999
});
}, 300);
});Controlling the Confetti
The canvas-confetti library gives you a few key options worth knowing:
particleCount controls how many confetti pieces fire. 150 is a solid burst without being overwhelming. Crank it up to 300 for something more dramatic, drop it to 80 for something subtle.
spread controls how wide the burst fans out. 80 gives you a natural arc. Higher numbers spread it wider across the screen.
origin controls where the burst comes from. The default is the center of the screen. { y: 0.4 } pushes it slightly above center, which tends to look better when there's content below it.
zIndex makes sure the confetti renders on top of everything else on the page. 9999 is a safe bet.
One Thing to Watch Out For
The play event fires every time the video plays, not just the first time. If your user pauses and resumes the video, the confetti fires again. For a lot of use cases that's fine. But if you only want it to fire once, you can remove the confetti listener after the first time it runs.
The way to do that is with player.off(). When you register a listener with player.on(), Vimeo stores a reference to that specific function internally. player.off() tells Vimeo to find that function and deregister it. After that, the event still fires when the video plays, but there's nothing listening for it anymore.
For this to work, the function needs a name. If you write it as an anonymous function, you have nothing to pass to player.off() and no way to remove it. By naming it onPlay, you can pass that same reference to both player.on() and player.off():
function onPlay() {
setTimeout(function() {
confetti({
particleCount: 150,
spread: 80,
origin: { y: 0.4 },
zIndex: 9999
});
}, 300);
// Remove this listener so confetti only fires once
// The video will still play normally — this only stops the confetti
player.off('play', onPlay);
}
player.on('play', onPlay);The comments in the code do the heavy lifting here. Anyone reading this later knows exactly what player.off() is doing and why it's there. Without them, it reads like a line that came from nowhere.
The Full Code
Here's everything together in one clean block. If you're working in Webflow, add the two CDN script tags and this script block before your closing </body> tag:
window.Webflow = window.Webflow || [];
window.Webflow.push(function() {
const iframe = document.getElementById('my-video');
const player = new Vimeo.Player(iframe);
function onPlay() {
setTimeout(function() {
confetti({
particleCount: 150,
spread: 80,
origin: { y: 0.4 },
zIndex: 9999
});
}, 300);
// Remove this listener so confetti only fires once
// The video will still play normally — this only stops the confetti
player.off('play', onPlay);
}
player.on('play', onPlay);
});Clean, readable, and the confetti only fires once no matter how many times the user interacts with the video.
This Is the Kind of Detail That Sticks
Confetti is small. But small interactions done well are what separate a website that feels professionally built from one that just looks professionally built.
The Vimeo Player API makes it possible to react to what's actually happening in the video rather than guessing with timers. Combined with canvas-confetti, you can add moments of delight that feel earned rather than random.
If you want to go deeper on the Vimeo Player API itself, including how to control multiple videos on the same page, read How to Use the Vimeo Player API to Control Video on Your Website.
If you're building something like this for your business and want to talk through the approach, I offer free strategy sessions. We can look at what you're working on and figure out the best way to bring it to life. Book a call here.
End to End Webflow Design and Development Services
From Web Design and SEO Optimization to Photography and Brand Strategy, we offer a range of services to cover all your digital marketing needs.

Webflow Web Design
We design custom Webflow websites that are unique, SEO optimized, and designed to convert.
Webflow Support
Get dedicated design and development support from a Webflow Professional Partner without the overhead of a full-time hire or the hassle of one-off project quotes.
Claim Your Design Spot Today
We dedicate our full attention and expertise to a select few projects each month, ensuring personalized service and results.






