<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ryo</title>
    <description>The latest articles on DEV Community by Ryo (@ryo-karasunouta).</description>
    <link>https://dev.to/ryo-karasunouta</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4014798%2F69c40c00-431b-4bb0-8258-4642d33ad8f3.png</url>
      <title>DEV Community: Ryo</title>
      <link>https://dev.to/ryo-karasunouta</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ryo-karasunouta"/>
    <language>en</language>
    <item>
      <title>How to Load the YouTube IFrame Player API Without Breaking Other Plugins</title>
      <dc:creator>Ryo</dc:creator>
      <pubDate>Fri, 10 Jul 2026 13:39:04 +0000</pubDate>
      <link>https://dev.to/ryo-karasunouta/how-to-load-the-youtube-iframe-player-api-without-breaking-other-plugins-204i</link>
      <guid>https://dev.to/ryo-karasunouta/how-to-load-the-youtube-iframe-player-api-without-breaking-other-plugins-204i</guid>
      <description>&lt;p&gt;When developing plugins for WordPress, one issue that almost everyone faces at least once is &lt;strong&gt;plugin conflicts&lt;/strong&gt;. The other day, I was developing a plugin (&lt;a href="https://karasunouta.com/en/wp-plugins/ku-sticky-video-for-youtube/" rel="noopener noreferrer"&gt;KU Sticky Video for YouTube&lt;/a&gt;) that makes YouTube videos in posts follow the scroll to stay in the corner of the screen. It worked perfectly in a clean local testing environment, and I was proud, thinking, “All right, it’s complete!”&lt;/p&gt;

&lt;p&gt;However, as soon as I moved the testing ground to a multi-plugin environment where another of my own YouTube-related plugins (unreleased) and other video-related plugins were active, things changed completely. The sticky feature, which had been working smoothly until just moments before, fell completely silent without moving an inch, and when I opened the browser console, there was that annoying red error text. &lt;strong&gt;Oh no.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But this is simply a common occurrence in plugin development. In reality, the solution varies depending on the cause of the conflict. In this article, I will explain the mechanism behind the “struggle for leadership” caused by the YouTube Iframe API, which many YouTube-related plugins depend on, in a multi-plugin environment, and introduce a JavaScript design to avoid this problem, share the ride with other scripts, and achieve coexistence.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why the Conflict? The YouTube API Struggle for Leadership
&lt;/h2&gt;

&lt;p&gt;To highly control YouTube videos from JavaScript, you need to load the official &lt;a href="https://developers.google.com/youtube/iframe_api_reference" rel="noopener noreferrer"&gt;YouTube Iframe Player API&lt;/a&gt;. In typical tutorial articles, implementation code like the following is usually introduced:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Load the API script&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://www.youtube.com/iframe_api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstScriptTag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByTagName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nx"&gt;firstScriptTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parentNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertBefore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;firstScriptTag&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Define the global function called when loading is complete&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onYouTubeIframeAPIReady&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;player&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;YT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;player-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;onStateChange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;onPlayerStateChange&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this code seems perfectly fine at first glance, it causes issues in &lt;strong&gt;environments where multiple plugins and themes run asynchronously&lt;/strong&gt;, such as in WordPress. Put simply, what happens if another plugin defines &lt;code&gt;window.onYouTubeIframeAPIReady&lt;/code&gt; in exactly the same way? Due to the nature of JavaScript, the initialization function defined first will be completely overwritten and lost by the plugin execution that runs later.&lt;/p&gt;

&lt;p&gt;As a result, the plugin that loaded first cannot detect when the API has finished loading, and it will never start. This is exactly why the initial version of KU Sticky Video for YouTube stopped working.&lt;/p&gt;




&lt;h2&gt;
  
  
  Approaches to a Solution: How to Avoid “Fights” Between Plugins
&lt;/h2&gt;

&lt;p&gt;To prevent this conflict and ensure safe operation in any environment, we decided to take the following countermeasures in the KU Sticky Video for YouTube plugin.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. “Script Presence Check” to Fill the Gap in Asynchronous Loading
&lt;/h3&gt;

&lt;p&gt;When the loading of the YouTube API script is complete, a &lt;code&gt;window.YT&lt;/code&gt; object is automatically created in the browser’s global scope (&lt;code&gt;window&lt;/code&gt;). This &lt;code&gt;window.YT&lt;/code&gt; object contains all the actual functions of the API for creating and controlling the YouTube player.&lt;/p&gt;

&lt;p&gt;The tricky part is that it is not as simple as, “I see. Then I just need to check if &lt;code&gt;window.YT&lt;/code&gt; exists.” If you do only that, what happens if the script runs &lt;strong&gt;“during the network load (when &lt;code&gt;window.YT&lt;/code&gt;&amp;nbsp;is undefined) right after another plugin inserted the tag”&lt;/strong&gt;? The script tag would be inserted twice. To prevent this, in addition to &lt;code&gt;window.YT&lt;/code&gt;, we also check whether a script tag for the YouTube API already exists in the DOM tree.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Search by partial match, considering URL notation variants (iframe_api / player_api)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;alreadyLoading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script[src*="youtube.com/iframe_api"], script[src*="youtube.com/player_api"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;YT&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;alreadyLoading&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Insert the script tag for the first time here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs.w.org%2Fimages%2Fcore%2Femoji%2F17.0.2%2Fsvg%2F1f4a1.svg" alt="💡" width="36" height="36"&gt; &lt;strong&gt;Why continue to check window.YT as well?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;At first glance, checking only whether the script tag exists in the DOM (&lt;code&gt;alreadyLoading&lt;/code&gt;) seems sufficient. After all, &lt;code&gt;window.YT&lt;/code&gt; is supposed to be created after the script is loaded. However, there may be cases where a script tag for the YouTube API does not exist in the DOM—for instance, if another plugin bundles the API directly into its JS via build tools like Vite and loads it.&lt;/p&gt;

&lt;p&gt;Therefore, it is necessary to perform a double check using both &lt;code&gt;window.YT&lt;/code&gt; to 100% guarantee that the load is already complete, and &lt;code&gt;alreadyLoading&lt;/code&gt; to detect via the script tag that “the asynchronous load is in progress right now.” By using both together, the risk of conflicts can be minimized.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. “Event Sharing (Binding)” via window.YT.get()
&lt;/h3&gt;

&lt;p&gt;If another plugin has already created a &lt;code&gt;YT.Player&lt;/code&gt; instance for a YouTube iframe on the page, executing &lt;strong&gt;&lt;code&gt;new YT.Player&lt;/code&gt; again on top of it will cause an error&lt;/strong&gt;. Therefore, we use the YouTube API global method &lt;code&gt;window.YT.get()&lt;/code&gt; to retrieve the already-created player instance, if it exists, and “share the ride” by binding only our event listeners to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;existingPlayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;YT&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;YT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;iframeElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Get by the official spec if an ID exists. Otherwise, fall back to passing the DOM element.&lt;/span&gt;
    &lt;span class="nx"&gt;existingPlayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;YT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;YT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;iframeElement&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;existingPlayer&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Share the event with the existing instance if it exists&lt;/span&gt;
    &lt;span class="c1"&gt;// * Unlike standard DOM, the YouTube API's addEventListener requires the "on" prefix (onStateChange)&lt;/span&gt;
    &lt;span class="nx"&gt;existingPlayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;onStateChange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;handlePlayerStateChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Otherwise, create a new instance&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;player&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;YT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iframeElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although the official argument for &lt;code&gt;YT.get()&lt;/code&gt; is the “iframe ID string,” we set up a two-step binding process using the unofficial yet highly compatible method of passing the DOM element as a fallback in case there is no ID attribute.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. “Polling Control” to Prevent Timing Conflicts
&lt;/h3&gt;

&lt;p&gt;The core of these countermeasures is &lt;strong&gt;timing control&lt;/strong&gt; to determine when the API load is complete and when other plugins have finished initialization. For this purpose, we decided to adopt a technique called polling.&lt;/p&gt;

&lt;p&gt;However, the YouTube API comes with a global callback function &lt;code&gt;window.onYouTubeIframeAPIReady&lt;/code&gt; that is automatically executed by the API when the script loading is complete. Why was such a roundabout method like polling necessary instead of monitoring that standard event handler?&lt;/p&gt;

&lt;h4&gt;
  
  
  3-1. The Asynchronous Risk Inherent in Wrappers for the Standard “onYouTubeIframeAPIReady”
&lt;/h4&gt;

&lt;p&gt;When considering conflicts with other plugins, a common approach introduced as a standard trick on many development blogs is to “temporarily save the existing callback function into a variable, wrap it, and execute both the other plugin’s initialization and your own in succession” as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Save the existing callback if there is one&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;previousOnReady&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onYouTubeIframeAPIReady&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Overwrite the global callback and execute the other processes in succession&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onYouTubeIframeAPIReady&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;previousOnReady&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;previousOnReady&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;myPluginInit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Initialize our own plugin&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this seems like a perfect solution for coexistence at first glance, this implementation actually carries a fatal risk: &lt;strong&gt;it cannot handle cases where other plugins initialize the player with asynchronous processing in between&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, suppose the other plugin we want to coexist with is designed to initialize by running an asynchronous process, such as “detecting API Ready, fetching configuration data via Ajax, and then creating the player.” In this case, our plugin’s (Sticky’s) initialization process has no way of knowing that the other plugin is waiting for its background asynchronous process to finish. Therefore, at the exact moment of API Ready, it determines that “no conflicting player instance exists yet” and goes ahead to create a new player (&lt;code&gt;new YT.Player&lt;/code&gt;) ahead of the other.&lt;/p&gt;

&lt;p&gt;By the time the other plugin finishes its asynchronous processing and tries to create its player, our plugin’s initialization is already complete. This causes a &lt;strong&gt;double-initialization error&lt;/strong&gt; for the same iframe element, causing the other plugin to fail. Therefore, if you want to write a robust implementation that accounts for conflicts, you cannot use this &lt;code&gt;onYouTubeIframeAPIReady&lt;/code&gt; callback directly as your own initialization trigger.&lt;/p&gt;

&lt;p&gt;Our plugin must not interfere at all, such as by overwriting or assigning to the global callback; it should simply load the API, monitor in the background to see “when the other plugin’s initialization is complete,” and then safely share the ride (bind) to it. This is precisely why we need time control using “polling,” which will be explained next.&lt;/p&gt;

&lt;h4&gt;
  
  
  3-2. The Solution: Controlling Initialization Timing with Polling
&lt;/h4&gt;

&lt;p&gt;To cleanly link the three approaches explained so far—wrapping, double-loading prevention, and event sharing—&lt;strong&gt;controlling the timing of the initialization process&lt;/strong&gt; is extremely important. This is where a design pattern called &lt;strong&gt;“polling”&lt;/strong&gt; comes in handy, which periodically checks the API load status and player initialization status from the program.&lt;/p&gt;

&lt;p&gt;In JavaScript, polling is mainly implemented using &lt;code&gt;setInterval&lt;/code&gt;. The actual initialization code is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;initPlayingMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;iframes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1. Load the API after checking if another script has already been inserted&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;YT&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script[src*="youtube.com/iframe_api"], script[src*="youtube.com/player_api"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://www.youtube.com/iframe_api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstScriptTag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByTagName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;)[&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="nx"&gt;firstScriptTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parentNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertBefore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;firstScriptTag&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. Poll and monitor the API load and the completion of other plugins' initialization&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;attempts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;apiReadyAttempts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;setupCompleted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checkInterval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;attempts&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isApiReady&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;YT&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;YT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Player&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;isApiReady&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;apiReadyAttempts&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Check if other plugins have finished creating instances for all iframes&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;allFound&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;isApiReady&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;YT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;allFound&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;iframes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;iframes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;player&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;YT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;YT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;iframes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;player&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;allFound&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Determine the termination conditions&lt;/span&gt;
        &lt;span class="c1"&gt;// - Binding by other plugins is complete (allFound), or&lt;/span&gt;
        &lt;span class="c1"&gt;// - The grace period (300ms) to wait for other plugins' initialization after the API loads has passed (apiReadyAttempts &amp;gt;= 3), or&lt;/span&gt;
        &lt;span class="c1"&gt;// - The maximum timeout (3 seconds) has been reached (attempts &amp;gt;= 30)&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shouldStop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;allFound&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;apiReadyAttempts&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;attempts&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;shouldStop&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;checkInterval&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;setupCompleted&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;setupCompleted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

                &lt;span class="c1"&gt;// Perform either "ride-sharing" or "new creation" for each iframe&lt;/span&gt;
                &lt;span class="nf"&gt;setupPlayers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;iframes&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the API is ready, instead of initializing the player immediately on our own, this code sets up a maximum wait time of 300ms (checking the status up to 3 times every 100ms = polling). If another plugin is attempting to asynchronously create a player at the moment of API Ready, the purpose is to wait a short while for its completion before sharing the ride, thereby preventing double-creation errors as much as possible.&lt;/p&gt;

&lt;p&gt;However, if you wait too long and our plugin’s initialization is delayed unnecessarily, there is a risk that the event listeners will not be registered yet by the time the video starts playing. As a result of trial and error balancing this trade-off, this 300ms wait time emerged as the empirical magic number (the best practical threshold) in this development process.&lt;/p&gt;

&lt;p&gt;This value might vary depending on the purpose of your plugin.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Ultimate Question: When Seemingly Perfect Codes Meet
&lt;/h2&gt;

&lt;p&gt;With the implementation so far, we seem to have completed a mostly perfect conflict avoidance code that “does not interfere with the loading of other plugins,” “shares the ride on players created by other plugins,” and “waits 300ms to prevent double creation.” Some readers might also have agreed, thinking, “I see, this implementation looks like it should work fine.”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here is a question. If Plugin A and Plugin B—two separate plugins, both incorporating the “perfect implementation” explained in this article—are loaded on the same page at the same time, can they coexist?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The answer, unfortunately, is &lt;strong&gt;“yes, there are cases, albeit rare, where they will cause conflict errors and go silent (break down).”&lt;/strong&gt; The cause lies in the “asynchronous registration lag” of the YouTube API. In fact, there is a tiny lag of a few milliseconds between when you execute &lt;code&gt;new YT.Player()&lt;/code&gt; and when that player instance is registered inside the API and becomes retrievable via &lt;code&gt;window.YT.get()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If Plugins A and B, which share the same “300ms wait” logic, start their timers at the exact same API Ready timing, both will execute &lt;code&gt;YT.get()&lt;/code&gt; almost simultaneously after 300ms. At this moment, since neither has created a player yet, the return value for both will be &lt;code&gt;null&lt;/code&gt;. Consequently, both assume that no existing player exists, and both execute &lt;code&gt;new YT.Player()&lt;/code&gt; almost at the same time. As a result, a double-creation error occurs on the same iframe, causing both to fail.&lt;/p&gt;

&lt;p&gt;You might think, “Then why not detect double creation inside the &lt;code&gt;onReady&lt;/code&gt; callback and clean it up with &lt;code&gt;destroy()&lt;/code&gt;?” However, the YouTube API’s &lt;code&gt;destroy()&lt;/code&gt; forcibly rewrites the DOM elements and clears event handlers, carrying the fatal side effect of taking down and destroying the player that was already running normally. In other words, &lt;strong&gt;once a double creation has occurred, it cannot be safely removed afterward&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introducing “Random Jitter” as the Solution
&lt;/h3&gt;

&lt;p&gt;Since the YouTube API does not provide events for perfect synchronization across multiple plugins, there is no perfect code that can reduce the probability of this timing collision to 0%. However, the solution to suppress this collision probability to practically zero (an ignorable level) is the introduction of &lt;strong&gt;“random jitter”&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;What we do is very simple. After the 300ms grace period expires, instead of creating the new player immediately, we insert a &lt;strong&gt;“random delay of 0 to 100ms” right before execution&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Executed after the 300ms monitoring termination condition is met&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;shouldStop&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;checkInterval&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;setupCompleted&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;setupCompleted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Disperse execution timing by inserting a random jitter (delay) of 0 to 100ms&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jitterDelay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Check window.YT.get() once more after the random delay expires&lt;/span&gt;
            &lt;span class="nf"&gt;setupPlayers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;iframes&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;jitterDelay&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By adding a random delay, there is a high probability of a discrepancy in the execution timing of Plugin A and Plugin B, which started moving at the same time.&lt;/p&gt;

&lt;p&gt;For example, suppose the random delay is 15ms for Plugin A and 78ms for Plugin B. After 15ms, Plugin A, whose delay expired first, creates a &lt;code&gt;new YT.Player&lt;/code&gt;. Subsequently, when Plugin B performs its &lt;code&gt;YT.get()&lt;/code&gt; check after 78ms, the instance from Plugin A will already be detected. As a result, Plugin B cancels the creation of a new instance and safely shares the ride on Plugin A.&lt;/p&gt;

&lt;p&gt;The beauty of this design is that &lt;strong&gt;“if all plugins depending on the YouTube API adopt this ‘concession via random jitter’ design, conflict-free coexistence (ride-sharing) can be achieved autonomously in almost all cases.”&lt;/strong&gt; This is, so to speak, a piece of wisdom to achieve coexistence by writing the spirit of mutual concession into code without waiting for improvements on the API side.&lt;/p&gt;

&lt;p&gt;We have also built this collision avoidance and coexistence design using random jitter into the sticky plugin we developed, &lt;strong&gt;“KU Sticky Video for YouTube”&lt;/strong&gt; (and its paid Pro version).&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Using the API of a major external service like YouTube in a plugin inevitably means harboring the potential for conflicts.&lt;/p&gt;

&lt;p&gt;Users embed YouTube videos in their posts and apply various customizations to them. For this, it is naturally expected that they will use multiple YouTube-related plugins together. In anticipation of this, designing an implementation that allows the dependent API to be used without conflicts is indispensable.&lt;/p&gt;

&lt;p&gt;The recently developed &lt;strong&gt;KU Sticky Video for YouTube&lt;/strong&gt; and its paid version, &lt;strong&gt;KU Sticky Video for YouTube Pro&lt;/strong&gt;, were also successfully released after identifying and resolving these issues one by one during development. If you want to showcase YouTube videos effectively alongside text, we highly recommend giving them a try.&lt;/p&gt;

&lt;p&gt;Please also try using them alongside other YouTube plugins! They should work without any problems (but if you do run into issues, please let me know quietly via the &lt;a href="https://karasunouta.com/en/contact/" rel="noopener noreferrer"&gt;contact form&lt;/a&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://karasunouta.com/en/wp-plugins/ku-sticky-video-for-youtube/" rel="noopener noreferrer"&gt;A WordPress plugin where the video player follows you (Demo &amp;amp; Info page)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://wordpress.org/plugins/ku-sticky-video-for-youtube/" rel="noopener noreferrer"&gt;KU Sticky Video for YouTube (WordPress.org official)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://karasunouta.com/en/store/ku-sticky-video-for-youtube-pro/" rel="noopener noreferrer"&gt;KU Sticky Video for YouTube Pro (Paid version store)&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>wordpress</category>
      <category>javascript</category>
      <category>api</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
