HLSEmbeddingPlayer

How to Embed an HLS Video on Your Website (iframe and hls.js)

Step-by-step guide to putting an HLS video on a web page: the ready-made iframe player, responsive markup, URL parameters and your own hls.js setup.

HLS (HTTP Live Streaming) is the format most websites use today for on-demand video. Instead of one huge MP4 file, the video is described by a small text playlist that points at several versions of the same video, each cut into short segments. The player downloads a few segments ahead, measures how fast they arrive and switches between versions on the fly. Viewers on a phone connection get a light version, viewers on fibre get the sharp one, and nobody waits for a whole file to download before the first frame appears.

This guide shows two ways to put an HLS video from UFOLOAD on your own web page: the ready-made player in an iframe, which takes about a minute, and your own <video> element driven by hls.js, which gives you full control over the page. Both use the same stream, so you can start with the iframe and move to hls.js later without re-uploading anything.

What an HLS stream from UFOLOAD looks like

After you upload a file, the converter encodes it with H.264 video and AAC stereo audio into one to four versions, called renditions: 360p, 720p, 1080p and 2160p (4K). A rendition is never larger than your source, so a 720p upload produces 720p and 360p, never an upscaled 1080p. The highest rendition you actually get also depends on your plan; the pricing page lists the current limits. If you want the full background on how the rungs are chosen, read adaptive bitrate ladders explained.

Each rendition is stored as a regular MP4 with the index at the front of the file. When a viewer starts playback, the storage layer packages those MP4 files into HLS on the fly: a master playlist (master.m3u8) lists every rendition with its peak bandwidth, resolution and codecs, and every rendition has its own playlist of four-second segments. Keyframes are placed so that they line up with segment boundaries, which is what lets the player switch quality cleanly in the middle of a video.

The playlist and the segments are served from cache nodes with an Access-Control-Allow-Origin: * header, so a player running on your domain can request them directly. Every URL is signed and has an expiry time, which matters later when we talk about the hls.js approach.

Step 1: upload the video and wait until it is ready

Upload from the dashboard by dropping the file or pasting a direct link, or use FTP, WebDAV or the API (see uploading videos via API for curl, Python and Node.js examples). A file moves through the statuses uploading, queued, processing and ready; failed is reported with a reason and can be retried from the dashboard. Short clips are ready within minutes, long films take longer, and paid plans have a priority encoding queue.

You do not have to wait for the page to be finished. If someone opens the player while the file is still processing, it shows a processing notice with the progress and switches to the video by itself when processing finishes. Still, check that the status is ready before you publish the page, so you do not ship a page whose first visitors see a progress bar.

You will need the video identifier. The dashboard shows it in the share panel, and the API returns it as public_id, a short code of 11 characters. That code is what goes into the embed address.

Step 2: embed the player with an iframe

The dashboard hands out an iframe snippet right after an upload and in the share panel of every video. It looks like the first block below. Replace VIDEO_ID with the identifier of your video. The player page itself is not indexed by search engines, which is what you want for an embed: your page ranks, not the player frame.

Snippet from the dashboard · html
<iframe width="640" height="360"
  src="https://ufoload.com/e/VIDEO_ID"
  title="My video"
  frameborder="0"
  allow="autoplay; fullscreen; picture-in-picture"
  allowfullscreen></iframe>

Fixed pixel sizes break on phones. For a responsive page wrap the iframe in a box that keeps the 16:9 ratio and let the frame fill it. The player fills the whole frame, so the video scales cleanly.

Responsive embed · html
<div style="position:relative;aspect-ratio:16/9;max-width:960px">
  <iframe src="https://ufoload.com/e/VIDEO_ID"
    title="My video"
    style="position:absolute;inset:0;width:100%;height:100%;border:0"
    loading="lazy"
    allow="autoplay; fullscreen; picture-in-picture"
    allowfullscreen></iframe>
</div>

Parameters you can add to the address

  • autoplay=1 starts playback when the player loads. Browsers block autoplay with sound in most cases, so combine it with mute=1.
  • mute=1 starts the video muted; the viewer can unmute at any moment.
  • loop=1 starts the video over when it ends.
  • t=30 starts playback 30 seconds in, handy for deep links to a moment in a longer video.

A parameter in the address always wins over the same setting in Player studio. Use Player studio for defaults that apply everywhere, such as the skin, accent color, logo and button layout, and use parameters when one page needs to behave differently. You can even keep a separate player profile per embedding domain.

Tip

If the player shows a message that embedding is not allowed, the domain of your page is probably missing from the list of allowed embed domains. See domain locking and geo-restrictions to understand how that list works.

Step 3 (optional): play the stream with hls.js

The iframe is the shortest path, but sometimes you want your own markup: a custom control bar, the video inside a carousel, analytics events from your own code. Then you need the playlist address and a player library. Browsers other than Safari cannot play HLS natively, so the usual choice is hls.js, a JavaScript library that feeds HLS segments into a standard <video> element. Safari and iOS play HLS natively and do not need it.

The playlist address is the links.playback field of the video object. Request it from your server with an API key, because the key must never appear in browser code. The same call returns links.expires_at, and links are signed and time-limited, so ask for a fresh link each time you render the page rather than storing one in your database.

Server side (Node.js 18+): get a signed playlist link · js
const BASE = 'https://ufoload.com/api/v1'

export async function playbackUrl(fileId) {
  const res = await fetch(`${BASE}/files/${fileId}`, {
    headers: { Authorization: `Bearer ${process.env.UFOLOAD_API_KEY}` },
  })
  if (!res.ok) throw new Error(`UFOLOAD API: ${res.status}`)
  const { file, links } = await res.json()
  if (file.status !== 'ready') return null // still processing
  return links.playback // signed master.m3u8 URL
}

If you need a lifetime other than the default, POST /files/{id}/links accepts a ttl from 60 seconds to 30 days and can bind the link to an IP address or a cookie. The API documentation covers it in full. There is also a public endpoint, GET /api/v1/public/files/{id}, which needs no key; the watch and embed pages use it, and its links are valid for six hours.

On the page, create the player. The block below uses hls.js where it is supported, falls back to native playback on Safari and shows a plain message otherwise. Self-host the library file or pin a version instead of loading whatever is latest.

Client side · html
<video id="player" controls playsinline preload="metadata"
       poster="POSTER_URL" style="width:100%;aspect-ratio:16/9;background:#000"></video>
<script src="/vendor/hls.min.js"></script>
<script>
  const video = document.getElementById('player')
  const src = 'PLAYLIST_URL_FROM_YOUR_SERVER'

  if (window.Hls && Hls.isSupported()) {
    const hls = new Hls()
    hls.loadSource(src)
    hls.attachMedia(video)
    hls.on(Hls.Events.ERROR, (_, data) => {
      if (!data.fatal) return
      if (data.type === Hls.ErrorTypes.NETWORK_ERROR) hls.startLoad()
      else if (data.type === Hls.ErrorTypes.MEDIA_ERROR) hls.recoverMediaError()
      else hls.destroy()
    })
  } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
    video.src = src // Safari, iOS
  } else {
    video.outerHTML = '<p>This browser cannot play HLS video.</p>'
  }
</script>

The video object also carries links.poster for the cover image and links.sprite for hover preview thumbnails, which you can use if you build your own seek bar. With hls.js you give up the things the UFOLOAD player does for you: the quality menu, chapters, subtitle selection, ads and the logo overlay. That is the real trade-off, and the table below sums it up.

iframe or hls.js: which one to use

Questioniframe playerhls.js on your page
Setup timeOne minute, copy and pasteAn hour or more, plus a small server endpoint
Player featuresQuality menu, chapters, subtitles, hover previews, logo, adsWhatever you build yourself
MonetizationAds from the player are shown and countedNot available, because the ad layer lives in the UFOLOAD player
StylingSkin, colors, logo and buttons in Player studioAny HTML and CSS you like
Link expiryHandled for youYou request a fresh link on every page render
Domain lockAllowed embed domains are enforcedNot applicable to a link you serve yourself, so use short TTL and IP or cookie binding

Troubleshooting checklist

  • Black frame or endless spinner. Open the browser network panel and look for master.m3u8. A 403 means the link expired or the viewer is blocked by a country or IP rule; request a fresh link.
  • Blocked by the browser on an HTTPS page. Everything must be HTTPS. Never paste an http:// address into the iframe or into hls.js.
  • Autoplay does nothing. Autoplay with sound is blocked by browsers. Add mute=1, or in hls.js set video.muted = true before calling play().
  • Processing notice instead of video. The file is not ready yet. Poll GET /files/{id} until status is ready.
  • Only a low quality plays. The player starts conservatively and climbs as soon as it has measured throughput. Your plan and your source also cap the top rendition; compare with pricing and the features page.

Once your page works, you may want to protect it from hotlinking or to earn from it. Both are covered in the next guides: restrict where your video can be embedded and monetize your video site with ads in the player. If you are still deciding where to host, the video hosting checklist lists what to compare.

Try it with a free account

Upload a video, get an HLS player and an API key in minutes. Plan limits are listed on the pricing page.