Prevent Youtube iframes to improve Page Speed
Tags: html, javascript, pagespeed, youtube
Published: 2021-04-11 13:26:18

<i>Improving your Core Web Vitals page speed with a simple JavaScript! No HTML changes required.</i>

After Google introduced the Core Web Vitals to measure your web sites speed you have to make some changes to get a good score.

A big problem are YouTube iframes! They will make an external request as soon as you load your page. On the one hand it will load some kb/mb depending on your player settings but on the other hand it is an external request you might have to prevent because of the GDPR/DSGVO!

## The problem

So a simple page like this:

```html
<!DOCTYPE html>
<html lang="de">

<head>
    <meta charset="utf-8">
    <script src="main.js"></script>
</head>

<body>
    <main>
        <iframe id="ytplayer" type="text/html" width="640" height="360" src="http://www.youtube.com/embed/RNuUgbUzM8U?autoplay=1&origin=http://example.com" frameborder="0" />
    </main>
</body>

</html>
```

will look like this in the DevTools network tab:
![youtube1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gn53xmbl1heddfy2ran1.jpg) <i>32 requests / 2.92MB (3.47MB)</i>

Lot's of external requests and it is preloading the video already.

## How to fix it

Without changing the HTML code you can use this simple JavaScript file to prevent them from auto-loading:

```javascript
function updateElements(elements) {
	// loop through all elements
	for (var i = 0; i < elements.length; i++) {
		const currentNode = elements[i].addedNodes;

		for (var j = 0; j < currentNode.length; j++) {
			if (currentNode[j].nodeName.toLowerCase() == "iframe") {
				const myLink = currentNode[j].src;

                // create local HTML code with Youtube link - replace ___data___ with data - dev.to's markdown parser won't let me use it :)
				const localHtml = '<html><body style="background:rgb(200,200,200)"><a href="' + myLink + '" style="font-size:14px;text-align:center;position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);"><img src="___data___:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzMuOTJtbSIgaGVpZ2h0PSIyMy42Mm1tIiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAzMy45MiAyMy42MiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KIDxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKC04OC4wNCAtMTM2LjcpIj4KICA8cGF0aCB0cmFuc2Zvcm09InNjYWxlKC4yNjQ2KSIgZD0ibTM0MS43IDUxNi42Yy00Ljk0NiAwLTguOTI4IDMuOTgxLTguOTI4IDguOTI4djcxLjQzYzAgNC45NDYgMy45ODEgOC45MjggOC45MjggOC45MjhoMTEwLjRjNC45NDYgMCA4LjkyOC0zLjk4MSA4LjkyOC04LjkyOHYtNzEuNDNjMC00Ljk0Ni0zLjk4MS04LjkyOC04LjkyOC04LjkyOHptNDcuMzIgMjkuNTYgMjYuNTIgMTUuMDktMjYuNTIgMTUuMDl6IiBmaWxsPSIjZjAwIiBzdG9wLWNvbG9yPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjMuMDM0cHgiIHN0eWxlPSJwYWludC1vcmRlcjpzdHJva2UgZmlsbCBtYXJrZXJzIi8+CiA8L2c+Cjwvc3ZnPgo=" width="80" height="55"/><br/>play video</a></body></html>';

				currentNode[j].setAttribute("data-src", myLink);

				// set local HTML
				// replace ___data___ with data - dev.to's markdown parser won't let me use it :)
				currentNode[j].src = "___data___:text/html;charset=utf-8," + localHtml;
			}
		}
	}
    // remove listeners at the end
	removeEventListener(document, updateElements);
}

function removeEvents(obj, callback) {
	if (window.__obs) {
		window.__obs.disconnect();
	}
}

function registerEvents(obj, callback) {
	const MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
	if (MutationObserver) {
		const obs = new MutationObserver(function(mutations, observer) {
			callback(mutations)
		});
		obs.observe(obj, {
			childList: true,
			subtree: true
		});
		window.__obs = obs;
	}
}

// register events
registerEvents(document, updateElements);
```
> <i>Attention: please replace all `___data___` with `data`. The markdown parser will throw an error when I just use `data`</i>

This will register a MutationObserver and remove the iframe source when it is added to the DOM.

This will stop loading the original iframe source and show a local HTML file instead:
![youtube2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3gb7khzij53a2iavnm5h.jpg) <i>no external request!</i>
<br/>
As soon as you click the link it will go to the original source and - since it is a user interaction - it will play the video
![youtube3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rwbp5s4a2e6luvari0bq.jpg)

## Improvements
Of course you can change the `localHtml` page to look better or display an image and so on. For a proof of concept I've decided to keep it simple 😉