Failed to execute 'postMessage' on 'DOMWindow': target/origin mismatch http vs https
Asked Answered
H

4

4

I apologize up front as I'm very confused by my problem. I'm really in a bind because this is causing a problem on my production site.

I have a javascript player on my site which plays through song lists which can be hosted on youtube, soundcloud or vimeo. Yesterday I noticed this error which generally arises anytime you try to load a new song through "skipping" with the player buttons. This error just started in the last day or two. I am not seeing anything new in the youtube api release notes and this error occurs using Chrome, Firefox and Safari, so it is most likely not related to a change in the browser. Something that I am using has changed though, as I have not pushed new code in 18 days.

An example playlist is here: http://www.muusical.com/playlists/programming-music

I think I have isolated the way to reproduce the error, here are the steps:

  1. Play a youtube hosted song.
  2. Skip to any other song in the list (whether by pressing the skip buttons or directly pressing the play button on the song's row item).

*Note, that if the first song in the playlist is a youtube song, simply skipping to another song even without playing the initially loaded youtube song will produce the error.

Essentially, the error seems to occur once you have loaded and/or played a youtube song and attempt to skip to another song.

Let me know if you find an exception to this behavior.

I see this error in the console:

Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('https://www.muusical.com') does not match the recipient window's origin ('http://www.muusical.com').

I load the player with using the youtube javascript api:

new YT.Player('playlist-player', {
      playerVars: { 'autoplay': 1, 'fs': 0 },
      videoId: "gJ6APKIjFQY",
      events: {
        'onReady': @initPlayerControls,
        'onStateChange': @onPlayerStateChange
      }
    })

Which produces this iframe:

<iframe id="playlist-player" frameborder="0" allowfullscreen="1" title="YouTube video player" width="640" height="360" src="https://www.youtube.com/embed/gJ6APKIjFQY?autoplay=1&amp;enablejsapi=1&amp;origin=http%3A%2F%2Fwww.muusical.com"></iframe>

After hitting skip from the above youtube song, this is what I see loaded in the iframe:

<iframe id="playlist-player" frameborder="0" allowfullscreen="1" title="YouTube video player" width="640" height="360" src=""></iframe>

I support youtube, soundcloud and vimeo songs. It seems like once a youtube song is loaded the "origin" changes from http to https. I don't think it is necessary to include the embedding methods for the other hosts as this error occurs even if the entire playlist is only youtube and it does not occur in a playlist which consists of only songs from soundcloud and vimeo.

Also, this is how I am loading the youtube javascript:

// Load the IFrame Player API code asynchronously.
  var tag = document.createElement('script');
  tag.src = "https://www.youtube.com/player_api";
  var firstScriptTag = document.getElementsByTagName('script')[0];
  firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

Please let me know if you need me to clarify anything and thanks in advance for taking a look.

Hydro answered 11/1, 2015 at 0:13 Comment(0)
H
3

@sodawillow's answer is partially correct but I'd like to give the details to the solution and what caused my code to stop calling the .destroy() method to remove the youtube player.

My site has a player which swaps out songs from various sites, one of them being Youtube. There can be different methods for removing a player depending on the type it is. My code checks for the existence of a youtube player and if passes the check then it uses the .destroy() method which only the youtube player has. The problem is that YouTube changed the names of some of the static variables on their player object. For example, if I created a player via:

var player = new YT.Player('playlist-player', {
      playerVars: { 'autoplay': 1, 'fs': 0 },
      videoId: "gJ6APKIjFQY",
      events: {
      }
    })

then there would be a variable player.L which held the string "player". So to check if the current player was a YouTube player and remove it I did this:

if (player.L == "player") {
  player.destroy();
} else {
//handle the removal of the Soundcloud or Vimeo player.
}

Sometime recently Youtube changed the location of the string "player" to now reside at player.M. I could change the above code to check player.M instead of player.L and that would work but to try to avoid this issue in the future I instead have implemented:

if (player.destroy) {
  player.destroy();
} else {
//handle the removal of the Soundcloud or Vimeo player.
}

As long as Youtube does not remove the .destroy() method unannounced this will not cause any issues.

So in summary, the issue was as @sodawillow guessed, I was not using the .destroy() method to remove the Youtube player. The reason was because Youtube made some unannounced changes to their api, changing the location of some of the static variables.

Hydro answered 14/1, 2015 at 1:17 Comment(1)
I have searched and tried many solutions. this one is simple but worked for me. tks very much.Yahrzeit
S
3

I have read a bit about this, some SO posts here and there and this link too : https://code.google.com/p/gdata-issues/issues/detail?id=5788

I was about to add a comment to your question, saying I was getting crazy over this ... but when I started to describe my setup, I found a way to avoid the issue ^^.

I start with an empty div element, and use the Youtube Iframe API to turn it into an iframe with all the necessary options.

I have multiple divs like this one, and usually use the same JS variable to store all those players, but one at a time (one replaces the other, and so on ... - it could be better, I know).

To fix the issue, I had the idea to destroy the player with youtubePlayer.destroy(); before building a new one from another element. No more JS errors bleeding in my Chrome console :).

Hope it helps, all the litterature I could read about http and https did not apply to my case, because I am not setting the iframe URL myself, and my website happens to be not https ...

I did restore an async call instead of a static script tag in my HTML but I do not think this was necessary.

EDIT : this error message is quite misleading in fact, it only vaguely means : you are not using the youtube API the proper way :)

Saintly answered 12/1, 2015 at 21:29 Comment(7)
Thanks for the response! I do actually run the destroy() method on the player when I get rid of it but I haven't actually read through all the discussion in the link you sent. I've tried various different combinations of setting http/https in the origin or not and the dynamically loaded script but I will go through this discussion a little more scientifically and hopefully it finally gives. :)Hydro
which of your projects were you having this issue on? Seems like you have a number of music related sites with players. :)Hydro
You actually went to my site lol :) Don't know if it's a good thing to post it here but hey ... it's already online :) manec.fr : each time you hit a planet, you open a section with a different youtube player (bottom right)Saintly
I think you are pretty free in comments to post links. And links are actually ok in answers too but they mainly want you to also post the relevant information in the answer as well in case the link goes dead later. At least that is my current understanding as to how to avoid getting busted by the stackoverflow police.Hydro
Wow, I figured it out. You were onto something! Youtube used to store the string "player" under the static variable player.L. So, I used this to check if the song was Youtube as I support a few different sites. If it was a Youtube player, then I called player.destroy() if not I had to handle it differently. So, Youtube quietly changed the static variable name to M so now player.M == "player". JEEZ! I will have to find a more robust way of checking if the player is indeed Youtube.Hydro
BTW, not totally sure how to handle this as far as answering the question. The fix is to change the variable name but you certainly had me on the road to finding it. :)Hydro
plusone'd your question because it helped me find the solution :)Saintly
H
3

@sodawillow's answer is partially correct but I'd like to give the details to the solution and what caused my code to stop calling the .destroy() method to remove the youtube player.

My site has a player which swaps out songs from various sites, one of them being Youtube. There can be different methods for removing a player depending on the type it is. My code checks for the existence of a youtube player and if passes the check then it uses the .destroy() method which only the youtube player has. The problem is that YouTube changed the names of some of the static variables on their player object. For example, if I created a player via:

var player = new YT.Player('playlist-player', {
      playerVars: { 'autoplay': 1, 'fs': 0 },
      videoId: "gJ6APKIjFQY",
      events: {
      }
    })

then there would be a variable player.L which held the string "player". So to check if the current player was a YouTube player and remove it I did this:

if (player.L == "player") {
  player.destroy();
} else {
//handle the removal of the Soundcloud or Vimeo player.
}

Sometime recently Youtube changed the location of the string "player" to now reside at player.M. I could change the above code to check player.M instead of player.L and that would work but to try to avoid this issue in the future I instead have implemented:

if (player.destroy) {
  player.destroy();
} else {
//handle the removal of the Soundcloud or Vimeo player.
}

As long as Youtube does not remove the .destroy() method unannounced this will not cause any issues.

So in summary, the issue was as @sodawillow guessed, I was not using the .destroy() method to remove the Youtube player. The reason was because Youtube made some unannounced changes to their api, changing the location of some of the static variables.

Hydro answered 14/1, 2015 at 1:17 Comment(1)
I have searched and tried many solutions. this one is simple but worked for me. tks very much.Yahrzeit
M
2

This error belongs to the Google Youtube API.

Inside "https://www.youtube.com/iframe_api":

if (!window['YT']) {
    var YT = {loading: 0, loaded: 0};
}
if (!window['YTConfig']) {
    var YTConfig = {'host': 'http://www.youtube.com'};
}

They use http instead of https.

We need to override the 'host' option and 'widget_referrer' same as 'origin'.

player = new YT.Player('player', {
          host: 'https://www.youtube.com',
          height: '390',
          width: '640',
          videoId: 'M7lc1UVf-VE'
...
          origin: "https://www.enziin.com",
          widget_referrer: "https://www.enziin.com"
}

Goodluck.

Mertens answered 5/10, 2017 at 10:3 Comment(0)
A
0

My solution is to write all the Youtube player logic in a separate page (as blank as posible) , and that page be referenced in an IFRAME tag.

<iframe src="/youtube_frame/?data=SOME_DATA -%>" height="400px" width="100%" frameborder="0" border="0" scrolling="no"></iframe>

Then, your youtube_frame.html will be something like this:

<!DOCTYPE html>
<html>
  <body>
    <!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
    <div id="player"></div>

    <script>
      // 2. This code loads the IFrame Player API code asynchronously.
      var tag = document.createElement('script');

      tag.src = "https://www.youtube.com/iframe_api";
      var firstScriptTag = document.getElementsByTagName('script')[0];
      firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

      // 3. This function creates an <iframe> (and YouTube player)
      //    after the API code downloads.
      var player;
      function onYouTubeIframeAPIReady() {
        player = new YT.Player('player', {
          height: '390',
          width: '640',
          videoId: 'M7lc1UVf-VE',
          events: {
            'onReady': onPlayerReady,
            'onStateChange': onPlayerStateChange
          }
        });
      }

      // 4. The API will call this function when the video player is ready.
      function onPlayerReady(event) {
        // event.target.playVideo();
      }

      // 5. The API calls this function when the player's state changes.
      //    The function indicates that when playing a video (state=1),
      //    the player should play for six seconds and then stop.
      var done = false;
      function onPlayerStateChange(event) {
        console.log("OnplayerStateChange");
        if (event.data == YT.PlayerState.PLAYING && !done) {
          console.log("OnplayerStateChange - If statement");
          setTimeout(stopVideo, 6000);
          done = true;
        }
      }
      function stopVideo() {
        player.stopVideo();
      }
    </script>
  </body>
</html>

(As a marginal note: my context is that Prototype.js interferes with the event 'OnStateChange', and we cannot remove this dependency. Using a jsfiddle would not be useful to reproduce the issue, as it has few dependencies. My app here is built in Rails, and using this plugin for showing a Video playlist: https://github.com/Giorgio003/Youtube-TV/)

Allstar answered 18/8, 2016 at 0:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.