How to add a custom video player to your Webflow site


Webflow's native Video element is great for embedding content from YouTube and Vimeo, but it lacks flexibility for customization and self-hosted videos. By following this guide, you'll have a fully customized video player that fits your brand and ensures full control over the user experience, built with HTML, CSS and JavaScript in a simple embed.
Before adding a video player, make sure your video is in MP4 and WebM formats for maximum compatibility.
Now that your video is ready, you need to insert it into Webflow using custom HTML, CSS, and JavaScript.
Insert this code in an embed element in Webflow:
<video class="video" width="100%" height="100%">
<source src="https://res.cloudinary.com/your-account/video.mp4" type="video/mp4">
<source src="https://res.cloudinary.com/your-account/video.webm" type="video/webm">
</video>Replace the URLs with the links from your Cloudinary Asset Manager.
Now, we'll add JavaScript to control video playback, pause, fullscreen, and progress tracking.
Insert this JavaScript in Webflow's custom code section:
<script>
document.addEventListener("DOMContentLoaded", () => {
document.querySelectorAll("video").forEach(video => {
const container = document.createElement("div");
container.classList.add("video-container");
video.parentNode.insertBefore(container, video);
container.appendChild(video);
const controls = document.createElement("div");
controls.classList.add("video-controls");
const playPauseBtn = document.createElement("button");
playPauseBtn.classList.add("video-button");
playPauseBtn.innerHTML = `
<svg id="pauseIcon" width="24" height="24" fill="white">
<path d="M8 19c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2s-2 .9-2 2v10c0 1.1.9 2 2 2m6-12v10c0 1.1.9 2 2 2s2-.9 2-2V7c0-1.1-.9-2-2-2s-2 .9-2 2"></path>
</svg>
<svg id="playIcon" width="24" height="24" fill="white" style="display: none;">
<path d="M8 6.82v10.36c0 .79.87 1.27 1.54.84l8.14-5.18a1 1 0 0 0 0-1.69L9.54 5.98A.998.998 0 0 0 8 6.82"></path>
</svg>
`;
controls.appendChild(playPauseBtn);
const progressContainer = document.createElement("div");
progressContainer.classList.add("video-progress-container");
const progressBar = document.createElement("div");
progressBar.classList.add("video-progress-bar");
progressContainer.appendChild(progressBar);
controls.appendChild(progressContainer);
const fullscreenBtn = document.createElement("button");
fullscreenBtn.classList.add("video-button");
fullscreenBtn.innerHTML = `
<svg width="24" height="24" fill="white">
<path d="M4 4h6v2H6v4H4V4m10 0h6v6h-2V6h-4V4m-6 10v4h4v2H4v-6h2m16 0v6h-6v-2h4v-4h2"></path>
</svg>
`;
controls.appendChild(fullscreenBtn);
container.appendChild(controls);
playPauseBtn.addEventListener("click", () => {
if (video.paused) {
video.play();
playPauseBtn.querySelector("#playIcon").style.display = "none";
playPauseBtn.querySelector("#pauseIcon").style.display = "block";
} else {
video.pause();
playPauseBtn.querySelector("#playIcon").style.display = "block";
playPauseBtn.querySelector("#pauseIcon").style.display = "none";
}
});
fullscreenBtn.addEventListener("click", () => {
if (video.requestFullscreen) {
video.requestFullscreen();
}
});
video.addEventListener("timeupdate", () => {
const percent = (video.currentTime / video.duration) * 100;
progressBar.style.width = `${percent}%`;
});
progressContainer.addEventListener("click", (e) => {
const rect = progressContainer.getBoundingClientRect();
const offsetX = e.clientX - rect.left;
video.currentTime = (offsetX / rect.width) * video.duration;
});
});
});
</script>
To make controls visible and responsive, add this CSS in Webflow's Custom Code → Head Section:
<style>
.video-container {
position: relative;
width: 100%;
max-width: 100%;
overflow: hidden;
}
.video-controls {
position: absolute;
bottom: 0;
width: 100%;
background: rgba(0, 0, 0, 0.7);
display: flex;
align-items: center;
padding: 8px;
opacity: 0;
transition: opacity 0.3s ease-in-out;
}
.video-container:hover .video-controls {
opacity: 1;
}
.video-button {
background: none;
border: none;
cursor: pointer;
}
.video-progress-container {
flex: 1;
height: 6px;
background: rgba(255, 255, 255, 0.3);
cursor: pointer;
position: relative;
}
.video-progress-bar {
width: 0%;
height: 100%;
background: white;
}
</style>
If you want your video to autoplay and loop without controls, use Finsweet's Auto Video Attributes (Finsweet Auto Video). This solution removes controls but ensures seamless video playback. And if your videos live in CMS items (portfolio, blog, case studies), our tutorial on adding videos to a Webflow CMS collection covers that workflow in detail.
By implementing a custom video player, you ensure GDPR compliance, improve branding, and gain full control over video behavior. If you want autoplay without controls, consider using Finsweet Auto Video Attributes. Now, your Webflow site can feature fully customized, self-hosted videos without relying on YouTube!
If you would rather have this kind of custom development handled for you, our Webflow agency integrates custom players, animations and embeds as part of every build: feel free to reach out.