Youtube Ad Accelerator

Vatsalya Singhi
4 min readNov 30, 2023

Today we talk about “Youtube Ad Accelerator”, a chrome extension that warps through Youtube adverts and auto clicks the “Skip Ad” button using javascript.

Being a software developer, I was always fascinated by how well chrome extensions worked and integrated with different websites. The sheer abundance of chrome extensions makes sure that there’s always an extension available for even the most narrowed down tasks one could think. On the hindsight, this also makes it difficult to built one that stands out from the crowd.

I am an avid user of Youtube and with Youtube’s crack down on almost every popular and widely used “ad-blocker” extensions, this situation presented me with a keen problem statement, “How can I build a ‘ad-blocker’ that really isn’t one”.

Working

After doing some quick research and with prior experience with web scraping/automation, I was able to deduce how adverts are displayed on Youtube. I found a pattern where a number of classes are being added right before the adverts are played. The next challenge was to identify how can I “skip” these adverts. After few hours of brainstorming, I finally realised that these adverts are nothing but bunch of videos and video can be speeded up! This led to a moment of realisation where all I had to do was manipulate the video playback to its maximum which is 16x as well as mute the video programmatically which would technically “skip” the advert.

The next part was setting up a event listener on the specific parent tag which enclosed the video tag, which is exactly what a “MutationObserver” does. It is a nothing short of a swiss knife in programmer’s analogy. MutationObserver provides the ability to watch for changes made in the DOM tree.

const e = document.getElementById('movie_player');
if (!e) return null;
// Create an observer instance
const observer = new MutationObserver((mutation) => {
skipBtnClick();
adVideoManipulation();
})
observer.observe(e, {
subtree: false, // default
childList: false, // default
attributes: true, // monitor select element attribute only
attributeFilter: ['class'], // specific attribute to monitor
characterData: false // default
})

The above logic is triggered whenever there is a change in the class attribute of the specific element.

Now, Let's look into what the individual functions perform starting with the adVideoManipulation() function.

function adVideoManipulation() {
try {
const getElementByXpath = (path) => document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
const elementXPath = '//*[@id="movie_player" and contains(@class, "ad-showing")]/div[1]/video';
const adElement = getElementByXpath(elementXPath);
// no ads found
if (!adElement) return false;

// set params
adElement.volume = 0;
adElement.muted = true;
adElement.playbackRate = 16; // max video playback speed
// console.info("ad video manipulation successful");
return true;
} catch (err) {
console.error("ad manipulation error=>", err);
}
return false;
}

The above function searches for the video element having the class “ad-showing” using built-in Xpath. The prior research led to the conclusion that adverts were being displayed whenever this class name is added to the parent element. Therefore, the video element in such cases is manipulated in muting the video, and maxing the playback rate to 16. This resulted in running through adverts in a fraction of a second. To have this run successfully the first time was sure a delightful experience as it is with almost all new projects. The second phase of the project was to auto click the skip button with is performed in the skipBtnClick() function.

function skipBtnClick() {
try {
const skipBtnXPath = '//span[@class="ytp-ad-skip-button-container"]/button';
const getElementByXpath = (path) => document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
const skipBtn1 = getElementByXpath(skipBtnXPath);
if (skipBtn1) {
skipBtn1.click();
// console.info('skip button click by XPath successful');
return true;
}

const skipBtnList = [];
const targetClassNames = ["ytp-ad-skip-button-modern ytp-button", "ytp-ad-skip-button ytp-button", "ytp-ad-skip-button-container"];
targetClassNames.forEach((classNames) => {
skipBtnList.push(...document.getElementsByClassName(classNames));
});
if (skipBtnList.length !== 0) {
skipBtnList.forEach(btn => btn?.click());
// console.info('skip button click by ClassName successful');
return true;
}
} catch (err) {
console.error("skip btn click error=>", err);
}
return false;
}

The above code is self explanatory, where I find the specific button based on certain properties and if and when detected, I perform the click action programmatically.

The extension is the cumulation of these two powerful functions. The one bug that was later identified was where Youtube plays advert before the actual video content. This fails to be detected by the MutationObserver which is designed to detect for changes and not the initial state of the DOM. A quick and simple hack to bypass this was to call the two functions using a setTimeout() function with a small delay of 1000 milliseconds by which all the contents are initialized.

The extension is built on the Manifest Version 3, the latest iteration of the Chrome extension platform and a step in the direction of better security, privacy, and performance. The git repository has been made publicly accessible for education purposes. The documentation on how to publish extensions on Chrome Web Store and Microsoft Edge Add-ons made the process all the more easy. Special remarks to the Microsoft Edge Add-ons platform which doesn’t charge a penny and also allows importing chromium extensions with absolutely no compatibility issues.

Conclusion

This was perhaps one the most exciting personal projects I have worked on, tinkering with Chrome Extensions and writing scripts for Youtube. I am happy to share that the extension is doing phenomenally on the Chrome Web Store with almost 700 + active daily users in just a matter of 2 months since its release, a feat well beyond my expectations. I also thank everyone for their positive reviews & ratings which has been absolutely encouraging and hope this extension and its development help boost the general productivity.

--

--