Adding video to a web page used to mean Flash plugins and broken players. Today it is straightforward, but there are still decisions to make: embed a platform player, or serve the video yourself with HTML5 and HLS. The right choice depends on where your viewers are and how much control you want.
This guide covers both approaches, with working code.
Option 1: Embed from a video platform
The simplest path. Upload your video to a sharing platform, copy the embed code, paste it into your page.
For example, video pages on sharing sites like s.pub are designed to be linked and referenced directly, and most platforms generate an iframe snippet for you. The pattern is always the same:
<iframe src="https://example.com/embed/VIDEO_ID" width="640" height="360" frameborder="0" allowfullscreen></iframe>
The platform transcodes, adapts quality to each viewer, and handles the player interface. You write one line of HTML.
The trade-offs of iframes
Embeds are convenient but you inherit the platform's player, its branding, and occasionally its recommendations. Page weight also suffers: each embedded iframe pulls its own pile of JavaScript. For most blogs and marketing pages this is acceptable. For performance-critical pages, serve the video yourself.
Option 2: Self-host with HTML5 and HLS
Modern video serving uses HLS, the adaptive streaming format: the video is split into short segments at several quality levels, and the player switches levels as bandwidth changes. It is what YouTube and Netflix effectively do.
Safari plays HLS natively. For Chrome and Firefox you include a small player library such as hls.js. The page code looks like this:
<video id="video" controls></video> <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script> <script> const video = document.getElementById('video'); if (video.canPlayType('application/vnd.apple.mpegurl')) { video.src = '/video/master.m3u8'; // Safari: native HLS } else if (Hls.isSupported()) { const hls = new Hls(); // Everyone else: hls.js hls.loadSource('/video/master.m3u8'); hls.attachMedia(video); } </script>
Generating the HLS files
You produce the segments and playlist from your source video with FFmpeg:
ffmpeg -i source.mp4 -codec copy -start_number 0 -hls_time 4 -hls_list_size 0 -f hls master.m3u8
The codec copy variant is instant but serves one quality. For a real ladder, encode multiple renditions with different bitrates and resolutions and point a master playlist at them. Hosting is then just static files: any web server, object storage, or CDN can serve HLS, because it is plain files over HTTP.
Getting the details right
Always set a poster image
A poster frame shows before playback starts, so your page does not greet visitors with a black rectangle. Pick a frame that says something about the content.
<video controls poster="/images/preview.jpg">
Make it responsive
Wrap the video in a container and let CSS handle scaling:
.video-wrap { position: relative; padding-bottom: 56.25%; height: 0; } .video-wrap video, .video-wrap iframe { position: absolute; inset: 0; width: 100%; height: 100%; }
The 56.25 percent padding enforces a 16:9 shape on every screen size.
Do not autoplay with sound
Browsers block it anyway. If you want autoplay, add the muted attribute and provide clear controls. Nothing drives bounce rate like unexpected audio.
Lazy-load below-the-fold videos
If a page has several videos, load the first one and defer the rest until the user scrolls near them. Use the loading attribute for iframes, or initialize hls.js only on intersection. This keeps initial page load fast, which both visitors and search engines appreciate.
Which approach should you pick?
For blogs, docs, and most marketing sites: embed from a platform and spend your saved time on the content around the video. For landing pages, web apps, or anywhere you control the stack: self-hosted HLS with hls.js gives the best loading behavior and the cleanest look. And whichever you choose, keep a poster image and responsive sizing on your checklist, because those two details separate an embedded video that feels designed from one that feels pasted in.
No comments yet