Creating Private Videos

By default, all videos uploaded have the public attribute set to “true.” This means that anyone with the video url can watch the video.

If you’d like to make your videos private, simply toggle public to false, and each video will be served with a unique token good for one viewing.

You can read more in our new tutorial: Creating Private Videos

Keep on streaming!

1 Like

Hi Doug,

If I understood correctly, it means that each time we create a video and want it to be private we will need to change its public attribute to false.

But if we know for sure that all our videos will be private and we don’t want to change the public attribute for each video created, could we just change the default value once for all ? (same question with mp4support attribute)


You can upload the video together with both properties (public: false, …) in one step/operation, so the default isn’t probably necessary at all.

1 Like

Thanks @mlapis for the reply! You’re correct - if you are creating the video as part of the process - you may select a player, you’ll add a title, and you can set the video to private/disable the mp4.

That said @nicolasheugas - it is a good idea to allow for account defaults (player, private, and other parameters). I’ll put this idea in our backlog and we’ll see if it makes sense allowing to add this feature as we grow our APIs.


Hi both, thank you for your answers.

Just to be be sure, do you confirm that even when uploading a video using a delegated token you can in one step upload the video and set its parameters (public: false) ?
So far the solution I found is create first the metadata of the video, get the videoId just created, upload the video with a delegated token under that videoId.

Thanks !

Hi @nicolasheugas,

Using a delegated token (currently) complicates this flow a bit.

The solution you have:

So far the solution I found is create first the metadata of the video, get the videoId just created, upload the video with a delegated token under that videoId.

is great - you can to set the public/mp4 settings when you create the metadata.


1 Like

If you are interested, I’ve created an app (using NodeJS) that creates the videoID before the delegated upload, and gives yo the option to set the video to ‘private’ or disable the mp4 file creation.

Hi there

Funnily enough I was trying to do this yesterday. In the end I worked it the other way around, I updated a delegated video and set its various properties including metadata and privacy. I hadn’t noticed the create method.


1 Like

Hi @doug,

I’m having an issue using the private video setting. I’m creating the video as private and retrieving the token from the asset url for each new page load. If I load the player url directly in the browser the video loads once as expected. However when I add the hls url to a custom video.js player It doesn’t work. I’m adding the header token as directed. I think the issue is due to the browser making a preflight options request to the url, this gets returned correctly with a 204 so when the request to the get the actual url you get a 404. I can see the token in the request header and I can see the the matching token in the url. I’ve tested the player and it is definitely only initialising once fyi. Is there something i’m missing?

Hi @Seth,

In order to play private video you have to include a session token in all requests that are made by the player (manifests, segments, etc). The method is explained in this article: .
When using a videojs player, you can use videojs.Vhs.xhr.beforeRequest in order to customize all these requests.
Since the above article has been published, a new way to add the session token has been released. You’re no longer required to add a custom “X-Token-Session” header in each request, you can now add a query parameter called “avh” that will contains the value of the session token.

You can find a working sample of private videos using videojs here: videojs-private-video - JSFiddle - Code Playground .

Please note that with some browsers the videojs.Vhs.xhr.beforeRequest won’t work (especially on Safari IOS). In that case you’ll have to modify the requests made by the player in another way (you can use service workers).

Managing private video with a custom player is quite boring. That’s why we recommand using the player that handles it natively.


Olivier - ecosystem team

Hi @olivier,

Yes, i’d read the tutorial and had included the token header. I tried the same solution as before but with the MP4 version instead of the m3u8 and it does work fine. As you say it still doesn’t work on for any ios device or safari though. I really need to use a custom player as it’s impossible to style player to match our designs, I’ve already built a poster uploader which will need modifying to upload to your servers instead, which again I can’t style how the poster is displayed (i.e. no black columns either side!). I also need to build a save for later functionality to support offline viewing which will require I have custom video player as well. I will have to include your player sdk to respond to additional functionality that is also a requirement of the build. I did check that video api service could support private videos before selecting this service but that is clearly not the case. It states that the embedded player is recommended for private videos but it seems like it is more or a requirement. Mine is a simple use case where by videos can only be watched when logged in on a given site. Do you have any plans to make a simpler solution where by I can just whitelist a domain from the admin? I’m looking into the service worker option but I’m not seeing a nice way to dynamically update the token in the headers with each request. Guessing i’ll need to write to cookie and then read that in service worker. Any information you can offer for this would be appreciated, i’m feeling quite frustrated with this service at present! Thanks in advance.

1 Like

Hi @Seth

Sorry to hear you’re having trouble with private videos.

There is a fairly simple way to use the service workers to add the header. If you use a code similar to the one I shared in the jsfiddle in my previous answer, the ?avh parameter is added to the manifest url, even on IOS.

You can get the value of this parameter in your service worker and add it as a header to all subsequent requests.

Here is a service worker code sample that does this:

let sessionToken = {};

self.addEventListener('activate', (event) => {

self.addEventListener('fetch', function (event) {

   // if we're not on IOS, exit
   if (["iPad", "iPhone"].indexOf( === -1) {

   const iframeId = event.clientId || "-";

   // if requesting player.json, clear the value of the x-token-session
   if (event.request.url.indexOf("player.json") !== -1) {
      sessionToken[iframeId] = undefined;

   // if we don't yet know the x-token-session value, try to retrieve it from the avh query param
   if (!sessionToken[iframeId]) {
      const re = /\?avh=([A-Za-z0-9-]+)/gm
      const reExec = re.exec(event.request.url);
      if (!!reExec) {
         sessionToken[iframeId] = reExec[1];

   if (!!sessionToken[iframeId] &&
      (event.request.url.startsWith("") ||
   ) {
      event.respondWith(fetch(event.request, {
         headers: {
            "X-Token-Session": sessionToken[iframeId]

Hope this helps,


I’m having issues playing private videos on iOS as well, see How to use hls with private videos in native suported browser that does not support mediaSource? - #3 by simeon

The service workers solution is interesting but, in my humble opinions, somewhat involved if one’s worked with service workers and a serious time sink if one hasn’t.

Have you considered performing the authentication through an URL query parameter instead of a header? I’d expect that to work out-of-the-box on iOS but may be mistaken.

I saw that that’s how Mux does it (Use Video.js with Mux | Mux). They use JWT tokens, though. I can’t judge whether that’s a requirement for authentication through query parameters.

Curious to hear more about this topic as it seems to be impacting several of us.