Adding Voice to Captcha to Secure Web Forms

Hi Guys!

In my last post here, I discussed the creation of a captcha code to secure web forms using the HTML 5 Canvas tag along with JavaScript and PHP as the server side language. I loaded a custom web font using the JavaScript Font Face API to draw a random text string on the canvas with it. The random Captcha text was also refreshable in case the site visitor did not find it legible enough.

I assume that the reader knows PHP Web Forms and Sessions, CSS, HTML5 Canvas JavaScript API, JavaScript for browsers including FontFace API, Audio API and AJAX. You may read the appropriate tutorials from the web if you don’t.

So, what’s new in this post? I have used a text to speech API to let users hear audio captcha, in case the captcha is not very legible or the user has a vision problem.

How to create a random string

The following code creates a random text and initializes it into the PHP session.

<?php @session_start(); $_SESSION["captcha_hash_voice"] = substr(hash('joaat', microtime()), 0, 6); ?>

As you can see, a timestamp is created with a call to the microtime() function. It is then hashed with the JOAAT algorithm. We then extract the first six characters of this hash as our captcha string.

Creating The Web Form

We will create the HTML form or web form using HTML and CSS for coding and styling. Here it is:

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style type="text/css">
  #captcha_img{ display:none; }
  #captcha_code{ width: 180px; }
  #captcha{ border: solid 1px black; float:left; }
  #refresh_img{ cursor:pointer; }
  #play_audio{ cursor:pointer; }
  </style>
  <script src="https://code.jquery.com/jquery-3.6.4.min.js" integrity="sha256-oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl+cbzUq8=" crossorigin="anonymous"></script>
</head>
<body>
  <h1>Canvas Captcha with Voice</h1>
  <?php if(isset($_SESSION["form_msg"])){ echo $_SESSION["form_msg"]; unset($_SESSION["form_msg"]); } ?>
  <img src="images/captcha.jpg" alt="captcha image" id="captcha_img" />
  <form action="" method="POST">
  <canvas id="captcha" width="218" height="60" ></canvas>
  <span >&nbsp;<img src="images/refresh.png" alt="refresh image" id="refresh_img" title="Refresh" /><br/>
  &nbsp;<img src="images/audio.png" alt="play_audio" id="play_audio" title="Play audio" /></span>
  <br /><br />
  <input type="text" name="captcha_code" value="" id="captcha_code" maxlength="6" />
  <input type="submit" name="submit" value="Submit" />
  </form>
  <script src="script/js/script.js"></script>
</body>
</html>

As you can see, we declare an HTML 5 document with the DOCTYPE declaration. We fetch the latest jQuery file from https://code.jquery.com/ in the script tag in the head of the HTML 5 document we just created.

We have created an invisible image fetching the image from the path “images/captcha.jpg” relative to our document or web page. We have also used some CSS to style the text input of our web form.

Notice the call to fetch “script/js/script.js”. We will discuss this later.

The Script to which Our Form is Submitted

You will notice the script above the <form> tag. In this script, we will simply compare the value of the “captcha_code” form field (i.e. $_POST[“captcha_code”]) and the random string stored in the PHP session (i.e. $_SESSION[“captcha_hash_voice”]) when the form is submitted by the user.

The code is given below:

<?php 
@session_start();

if(isset($_POST["submit"]) && $_POST["submit"] == "Submit")
{
  
  if($_POST["captcha_code"] != $_SESSION["captcha_hash_voice"])
  {
    //failed
    $_SESSION["form_msg"] = "<span style='color:red;'>Security challenge failed!</span>";
    
    header("Location: index.php");
    exit;
  }
  else{
    //passed
    $_SESSION["form_msg"] = "<span style='color:green;'>Security challenge passed!</span>";
    
    header("Location: index.php");
    exit;
  }
}
else{
  $_SESSION["captcha_hash_voice"] = substr(hash('joaat', microtime()), 0, 6);
}

?>

 

The Script That Renders the Captcha String on the Canvas

Perhaps you noticed the call to fetch “script/js/script.js”. Why do we need to do this?

This is needed because we have to reference the PHP session variable $_SESSION[“captcha_hash_voice”], so that we can render it on the HTML 5 canvas using JavaScript.

When the web page loads for the first time, the following code renders the captcha:

var canvasObj = document.getElementById('captcha');
// we need this to load the font
var myFont = new FontFace('myFont', 'url(font/Moms_typewriter.ttf)');

myFont.load().then(function(font){

  // with canvas, if this is ommited won't work
    document.fonts.add(font);

    console.log('Font loaded');

  console.log(canvasObj);
  
  var captchaImage = document.getElementById("captcha_img");

  var context = canvasObj.getContext("2d");
  
  context.drawImage(captchaImage,0,0);
    
  context.font='28px myFont';
  
  var capText = '';
  
  jQuery.get("script/getcaptchastring.php", {'action':'fetch'}, function(response){
    
    capText = response;
    
    var capArray = capText.split('');
  
    drawLines(context);
    
    rotateText(context, capArray);
    
    
  });
  
});

As you can see, there are two JavaScript functions named “drawLines” and “rotateText”, which need elaboration.

The “drawLines” function draws zigzag lines in the captcha image background by obtaining a 2D graphics context of the canvas object using the line of JavaScript as follows:

var context = canvasObj.getContext("2d");

This complete JavaScript function is as follows:

function drawLines(context)
{
  //random lines
  context.moveTo(0,0);
  context.lineTo(80, 60);
  context.stroke();
    
  context.moveTo(50,0);
  context.lineTo(20, 60);
  context.stroke();
    
  context.moveTo(58, 60);
  context.lineTo(100, 0);
  context.stroke();
    
  context.moveTo(110, 0);
  context.lineTo(140, 60);
  context.stroke();
    
  context.moveTo(120, 60);
  context.lineTo(190, 0);
  context.stroke();
}

The “rotateText” function renders the six characters of the split string, which was previously set in PHP session. It rotates the canvas 2D graphical context this way and that, sumultaneously rendering the individual characters of the captcha in the custom font. After finishing its job, the context is restored to its initial orientation.

function rotateText(context, capArray)
{
  //rotated captcha
  
  context.rotate(10 * Math.PI / 180);
  context.fillText(capArray[0], 35, 40);
  
  context.rotate(5 * Math.PI / 180);
  context.fillText(capArray[1], 59, 35);
  
  context.rotate(-5 * Math.PI / 180);
  context.fillText(capArray[2], 79, 30);
  
  context.rotate(-10 * Math.PI / 180);
  context.fillText(capArray[3], 99, 30);
  
  context.rotate(10 * Math.PI / 180);
  context.fillText(capArray[4], 119, 30);
  
  context.rotate(-5 * Math.PI / 180);
  context.fillText(capArray[5], 134, 25);
  
  context.rotate(-5 * Math.PI / 180);
  context.restore();
}

Creating a Refreshable Captcha

In the code listing that creates our web form, notice the following line:

<img src="images/refresh.png" alt="refresh image" id="refresh_img" />

We will add a click handler to it so that captcha can be refreshed on click. We will use AJAX so as to get the PHP session variable from the server side, modify it and render it without reloading the entire page. Refreshing will change the session variable and hence the captcha string, but the logic to render the changed string remains the same.

Note that on each refresh, we need to clear the Canvas of the zigzag lines and the wavy text, so that there is no overwriting and spoiling the appearance of the captcha.

Here is the code:

//Client side code

jQuery(document).ready(function()
{	
  var canvasObj = document.getElementById('captcha');
  
  var captchaImage = document.getElementById("captcha_img");
  
  var context = canvasObj.getContext("2d");
  
  jQuery("#refresh_img").click(function(){
    jQuery.get("script/getcaptchastring.php", {'action':'refresh'}, function(response){
      
      var capArray = response.split('');
      
      context.clearRect(0, 0, canvasObj.width, canvasObj.height);
      
      context.drawImage(captchaImage,0,0);
      
      context.font='28px myFont';
      
      drawLines(context);
      
      rotateText(context, capArray);	
      
    });
  });
});

There is an AJAX call to “script/getcaptchastring.php” which modifies the captcha string. The following is the code listing for getcaptchastring.php:

<?php 
  //server side code

  @session_start();

  if(isset($_GET['action']))
  {
    if($_GET['action'] == 'fetch') //render captcha first time
    {
      echo $_SESSION["captcha_hash_voice"];

      exit();
    }
    elseif($_GET['action'] == 'refresh') //refresh captcha on clicking refresh icon
    {
      $captcha_hash_new = substr(hash('joaat', microtime()), 0, 6);

      $_SESSION["captcha_hash_voice"] = $captcha_hash_new;

      echo $_SESSION["captcha_hash_voice"];

      exit();
    }
  }

?>

Add Audio Functionality

Now let us add voice functionality.

We will use Google’s Text To Speech API, to feed the captcha string to it and get the speech version as result.

Let us see the client-side code, which is an addition to script/js/script.js:

//audio
jQuery("#play_audio").click(function(){
  
  var audioClip = new Audio("script/playback.php?d="+(new Date()).getMilliseconds());
  
  audioClip.load(); //load the audio clip
  audioClip.play(); //play the audio clip
  
}); 

As you can see, we are creating an object of Audio in JavaScript. We are passing the script at the path “playback.php” to it. We are using a query string while loading playback.php so as to prevent caching while playing the sound clip with it. So that the audio clip changes as the captcha string or, in other words the $_SESSION token changes, on refreshing or reloading, for instance.

The code of playback.php is below:

<?php 
  @session_start();
  header("Content-Type: audio/mpeg");

  $audio_split = str_split($_SESSION["captcha_hash_voice"]); //read letter by letter

  foreach($audio_split as $k=>$voice)
  {

    $voice = rawurlencode(htmlspecialchars($voice));

    $audio = file_get_contents('https://translate.google.com/translate_tts?ie=UTF-8&client=gtx&q='.$voice.'&tl=en-IN');
    echo $audio;
  }

  exit;
?>

The following line:

header("Content-Type: audio/mpeg");

is used to tell the browser to treat the output of playback.php as a sound or audio clip.

We feed the captcha string character by character to the text to speech API at:

‘https://translate.google.com/translate_tts?ie=UTF8&client=gtx&q=’.$voice.’&tl=en-IN’

When the speaker icon in the web form, given above, is clicked, the characters are read by the API ,one by one, so that the user can hear them distinctly. The user can then type in his answer to the captcha challenge. If the captcha is refreshed and the speaker icon is clicked, the new captcha will be read aloud for the user, letter by letter.

Conclusion

So all in all, we did the following:

  • Initialized the first six characters of the hash of microtime() as a session variable in PHP
  • Created a HTML 5 page with a web form and Canvas tag.
  • Created a PHP script to which the form will be submitted, to check the captcha challenge.
  • Created a script to render the Captcha string on the background image, with zigzag lines, with wavy characters using a custom font.
  • Created Server side and client side logic to modify the session variable, return it to the client side and render it to the captcha background each time refresh image is clicked and the canvas is cleared.
  • Created functionality to read aloud the captcha rendered on the screen, on clicking the speaker icon on the web form, before or after clicking the refresh icon.

The code can be downloaded here, and the demo can be found here.

I hope you find it useful, with the addition of voice functionality, since we often need to secure web forms with some kind of captcha and some users may have trouble reading the captcha.

Captcha using HTML 5 Canvas and JavaScript

Hi Guys!

It’s been a while since my last post.

In this post, I shall discuss the creation of a captcha code to secure web forms using the HTML 5 Canvas tag along with JavaScript and PHP as the server side language. I will load a custom web font using the JavaScript Font Face API and draw a random text string on the canvas with it. The random Captcha text will also be refreshable in case the site visitor does not find it legible enough.

I assume that the reader knows PHP Web Forms and Sessions, CSS, HTML5 Canvas JavaScript API, JavaScript for browsers including FontFace API and AJAX. You may read the appropriate tutorials from the web if you don’t.

How to create a random string

The following code creates a random text and initializes it into the PHP session.

<?php 
@session_start();

$_SESSION["captcha_hash"] = substr(hash('joaat', microtime()), 0, 6);

?>

As you can see, a timestamp is created with a call to the microtime() function. It is then hashed with the JOAAT algorithm. We then extract the first six characters of this hash as our captcha string.

Creating The Web Form

We will create the HTML form or web form using HTML and CSS for coding and styling. Here it is:

<!DOCTYPE html>
<html>
<head>
  <style type="text/css">
  #captcha_code{ width: 180px; }
  </style>
  <script src="https://code.jquery.com/jquery-3.6.4.min.js" integrity="sha256-oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl+cbzUq8=" crossorigin="anonymous"></script>
</head>
<body>
  <h1>Canvas Captcha</h1>
  <?php if(isset($_SESSION["form_msg"])){ echo $_SESSION["form_msg"]; unset($_SESSION["form_msg"]); } ?>
  <img src="images/captcha.jpg" alt="captcha image" id="captcha_img" style="display:none;" />
  <form action="" method="POST">
  <canvas id="captcha" style="border: solid 1px black;" width="218" height="60" ></canvas>
  <img src="images/refresh.png" alt="refresh image" id="refresh_img" /><br />
  <input type="text" name="captcha_code" value="" id="captcha_code" maxlength="6" />
  <input type="submit" name="submit" value="Submit" />
  </form>
  <script src="script/js/script.js"></script>
</body>
</html>

As you can see, we declare an HTML 5 document with the DOCTYPE declaration. We fetch the latest jQuery file from
https://code.jquery.com/ in the script tag in the head of the HTML 5 document we just created.

We have created an invisible image fetching the image from the path “images/captcha.jpg” relative to our document
or web page. We have also used some CSS to style the text input of our web form.

Notice the call to fetch “script/js/script.js”. We will discuss this later.

The Script to which Our Form is Submitted

You will notice the script above the <form> web form tag above.
In this script, we will simply compare the value of the “captcha_code” form field (i.e. $_POST[“captcha_code”]) and the
random string stored in the PHP session (i.e. $_SESSION[“captcha_hash”]) when the form is submitted by the user.

The code is given below:

<?php 
  @session_start();

  if(isset($_POST["submit"]) && $_POST["submit"] == "Submit")
  {
    
    if($_POST["captcha_code"] != $_SESSION["captcha_hash"])
    {
      //failed
      $_SESSION["form_msg"] = "<span style='color:red;'>Security challenge failed!</span>";
      
      header("Location: index.php");
      exit;
    }
    else{
      //passed
      $_SESSION["form_msg"] = "<span style='color:green;'>Security challenge passed!</span>";
      
      header("Location: index.php");
      exit;
    }
  }
  else{
    $_SESSION["captcha_hash"] = substr(hash('joaat', microtime()), 0, 6);
  }

?>

The Script Which Renders the Captcha String

Perhaps you noticed the call to fetch “script/js/script.js”.

Why do we need to do this?

This is needed because we have to reference the PHP session variable $_SESSION[“captcha_hash”], so that we can render it on the HTML 5 canvas using JavaScript.

When the web page loads for the first time, the following code renders the captcha:

var canvasObj = document.getElementById('captcha');
// we need this to load the font
var myFont = new FontFace('myFont', 'url(font/Moms_typewriter.ttf)');

myFont.load().then(function(font){

  // with canvas, if this is ommited won't work
  document.fonts.add(font);

  console.log('Font loaded');

  console.log(canvasObj);
      
  var captchaImage = document.getElementById("captcha_img");
  
  var context = canvasObj.getContext("2d");
      
  context.drawImage(captchaImage,0,0);
        
  context.font='28px myFont';
      
  var capText = '';
      
  jQuery.get("script/getcaptchastring.php", {'action':'fetch'}, function(response){
        
    capText = response;
        
    var capArray = capText.split('');
      
    drawLines(context);
        
    rotateText(context, capArray);
        
        
  });
      
});

 

As you can see, there are two JavaScript functions named “drawLines” and “rotateText”, which need elaboration.

The “drawLines” function draws zigzag lines in the captcha image background by obtaining a 2D graphics context of the canvas object using the line of JavaScript as follows:

var context = canvasObj.getContext("2d");

This complete JavaScript function is as follows:

function drawLines(context)
{
  //random lines
  context.moveTo(0,0);
  context.lineTo(80, 60);
  context.stroke();
  
  context.moveTo(50,0);
  context.lineTo(20, 60);
  context.stroke();
  
  context.moveTo(58, 60);
  context.lineTo(100, 0);
  context.stroke();
  
  context.moveTo(110, 0);
  context.lineTo(140, 60);
  context.stroke();
  
  context.moveTo(120, 60);
  context.lineTo(190, 0);
  context.stroke();
}

The “rotateText” function renders the six characters of the split string, which was previously set in PHP session. It rotates the canvas 2D graphical context this way and that, sumultaneously rendering the individual characters of the captcha in the custom font. After finishing its job, the context is restored to its initial orientation.

function rotateText(context, capArray)
  {
    //rotated captcha
    
    context.rotate(10 * Math.PI / 180);
    context.fillText(capArray[0], 35, 40);
    
    context.rotate(5 * Math.PI / 180);
    context.fillText(capArray[1], 59, 35);
    
    context.rotate(-5 * Math.PI / 180);
    context.fillText(capArray[2], 79, 30);
    
    context.rotate(-10 * Math.PI / 180);
    context.fillText(capArray[3], 99, 30);
    
    context.rotate(10 * Math.PI / 180);
    context.fillText(capArray[4], 119, 30);
    
    context.rotate(-5 * Math.PI / 180);
    context.fillText(capArray[5], 134, 25);
    
    context.rotate(-5 * Math.PI / 180);
    context.restore();
  } 

Creating a Refreshable Captcha

In the code listing that creates our web form, notice the following line:

<img src="images/refresh.png" alt="refresh image" id="refresh_img" />

We will add a click handler to it so that captcha can be refreshed on click. We will use AJAX so as to get the PHP session variable from the server side, modify it and render it without reloading the entire page. Refreshing will change the session variable and hence the captcha string, but the logic to render the changed string remains the same.

Note that on each refresh, we need to clear the Canvas of the zigzag lines and the wavy text, so that there is no overwriting and spoiling the appearance of the captcha.

Here is the code:

//Client side code

  jQuery(document).ready(function()
  {	
    var canvasObj = document.getElementById('captcha'); //canvas object
    
    var captchaImage = document.getElementById("captcha_img"); //background image
    
    var context = canvasObj.getContext("2d");
    
    //click event handler
    jQuery("#refresh_img").click(function(){
    
      //AJAX GET call
      jQuery.get("script/getcaptchastring.php", {'action':'refresh'}, function(response){
        
        var capArray = response.split('');
        
        context.clearRect(0, 0, canvasObj.width, canvasObj.height); //wipe the canvas clean on each refresh 
        
        context.drawImage(captchaImage,0,0);
        
        context.font='28px myFont';
        
        drawLines(context);
        
        rotateText(context, capArray);	
        
      });
    });
  });

There is an AJAX call to “script/getcaptchastring.php” which modifies the captcha string. The following is the code listing for getcaptchastring.php:

<?php 
@session_start();

if(isset($_GET['action']))
{
  if($_GET['action'] == 'fetch')
  {
    echo $_SESSION["captcha_hash"];

    exit();
  }
  elseif($_GET['action'] == 'refresh')
  {
    $captcha_hash_new = substr(hash('joaat', microtime()), 0, 6);

    $_SESSION["captcha_hash"] = $captcha_hash_new;

    echo $_SESSION["captcha_hash"];

    exit();
  }
}

?>

Conclusion

So all in all, we did the following:

  • Initialized the first six characters of the hash of microtime() as a session variable in PHP
  • Created a HTML 5 page with a web form and Canvas tag.
  • Created a PHP script to which the form will be submitted, to check the captcha challenge.
  • Created a script to render the Captcha string on the background image, with zigzag lines, with wavy characters using a custom font.
  • Created Server side and client side logic to modify the session variable, return it to the client side and render it to the captcha background each time refresh image is clicked and the canvas is cleared.

I hope you found it useful, since we often need to secure web forms with some kind of captcha. The code is found here. The demo is here.

 

Four Ways To Detect Browser Adblockers Using Javascript

Image credit: getadblock.com

Hi guys!

In this post, I will discuss four ways to detect adblockers in browsers using Javascript with jQuery framework. I shall stick to adblocking browser extensions only. This application of code enables you to notify the user of your site whether an adblocking extension is active in the user’s browser or not. The use cases are based on Google Chrome browser and AdBlock browser extension.

1. Offering a DIV as bait to the adblocker

First we create a wrapper DIV. Inside this div we create another DIV having no content and add some CSS classes to the inner DIV such as “adBanner”, “adsBanner”, etc.

We then browse to our webpage with the DIVS in it and with “AdBlock” adblocker extension installed and active in the browser. On opening the Developer tools in the browser, we will see that the inner DIV with the aforementioned CSS classes does not show at all. What happened? The adblocker blocked the element! Now, how do we detect this programmatically?

Simple. We detect the height of the inner DIV with the CSS classes on it. It will be returned as ‘0’ (zero). This can be done with only Javascript or even with jQuery. What action do we take on getting the inner DIV height as 0? We can notify the site visitor that their adblocker is on with say, a popup. We can also ask them politely to switch it off if we have painstakingly monetized our site with adverts, since all those adverts are blocked now.

When the visitor to our site switches off their adblocker and refreshes the page, the inner DIV will not be blocked. (Hopefully!) So then we can choose not to show the popup again.

First, include jQuery file in your test webpage. Now, let’s have a look at code:

The following code goes into the <body> tag of your webpage:

<style>
.adsBanner{
  background-color: transparent;
  height: 1px;
  width: 1px;
  }
</style>
<script>
jQuery(function(){
  if(jQuery('.wrapper').height() == 0)
  {
    alert("Ad Blocker is active");
  }
  else
  {
    alert("Ad Blocker is NOT active");
  }
});
</script>
<h2>Detect addons AdBlock Div Demo</h2>
<div class="wrapper">
  <div class="adBanner adsBanner"></div>
</div>

You will see an alert with a message saying “Ad Blocker is active” in your Chrome browser on browsing to your web page with AdBlock extension active.

Reference: https://html-online.com/articles/detect-adblock-javascript/

2. Offering a dummy ad script to the ad blocker

We create a javascript file called ads.js and keep in the same folder as our test web page. We then create a boolean variable that will be true. Immmediately after this line of code, we make a call to our dummy ad script ads.js. In the dummy script, we set this variable to false. So, when the ad blocker is active, the variable is true. If not, the variable is false.

This simple technique works for many ad blockers but not for some of them such as Privacy Badger. So, when the boolean variable is true, we can choose to show the notification and not show it when the variable is false.

Let’s have a look at the code:

First, the dummy ad script, ads.js:

//simple ad script
usingAdBlocker = false;

Then, the test web page.  The following code goes in your <body> tag of your page. Be sure to include the jQuery file in your <head> tag of the page.

<script>var usingAdBlocker = true;</script>
<script src="ads.js"></script><!-- dummy ad script-->
<script>
if(usingAdBlocker == true)
{
  alert("Ad Blocker active");
}
else
{
  alert("Ad Blocker NOT active");
}
</script>
<h2>Detect addons AdBlock JS Demo</h2>

If your AdBlock extension is active, you will see an alert with the message “Ad Blocker active”

Reference: https://www.labnol.org/code/19818-detect-adblock-javascript

3. Sideloading a web accessible resource of an adblocking browser extension

The more advanced and more popular adblocker extensions do not follow the element blocking technique. They follow a more advanced method of blocking adverts. To deal with this, we side load a web asccessible resource that is part and parcel of the extension itself. How do we find such a resource?

For this example, I will use the Google Chrome browser and the “AdBlock” extension.

You can find the id of the extension by going to your extension manager in Chrome and clicking on the “Details” link corresponding to your adblocker. Here “gighmmpiobklfepjocnamgkkbiglidom” refers to the extension “id” that is assigned to it.

Browse to the following URL in Chrome:

chrome-extension://gighmmpiobklfepjocnamgkkbiglidom/manifest.json

You will see a large JSON object with one key in the array that is “web_accessible_resources”. Choose any one of the URIs under this key. We will use the “adblock-onpage-icon.svg” URI for our example.

Browse the following URL:

chrome-extension://gighmmpiobklfepjocnamgkkbiglidom/adblock-onpage-icon.svg

Verify that this URL loads properly.

What will we have to do to use this URL? We will simply load it in a browser request, ajax or fetch, via Javascript/ jQuery and wait to receive the HTTP response. If we get a HTTP response code of 200, we can be sure that the plugin or extension is active, since it is possible to load it. We can then perform functions identical to point number 1 and 2 as above.

The following code goes in your <body> tag of your page. Be sure to include the jQuery file in your <head> tag of the page.

<h2>Detect addons AdBlock Side Load Demo</h2>
<script>
console.log(navigator);
//JSON Object for extension details 
var ExtensionObj = 
    {
      "extensionName": "AdBlock",
      "extensionID": "gighmmpiobklfepjocnamgkkbiglidom",
      "resourceURL": "/adblock-onpage-icon.svg", //icon128.png
      "fileType": "image",
      "protocolPrefix": "chrome-extension://",
      "browser": "Chrome"
    };
    
//fetch extension resource	
function UrlExistsExt(protocolPrefix, extId, resourceURL, fileType, cb)
{
  
  var url = protocolPrefix+extId+resourceURL;
  
  $.ajax({
    url: url,
    dataType: fileType,
    type: 'GET',
    complete: function(xhr){
      
      console.log(xhr.status);
      
      if (typeof cb == 'function')
        cb.apply(this, [xhr.status]);
    }
  })
        
}
    
//Ghostery
var ShowPopupExt = false;

//mai function
function UnblockerExtFunc(ExtensionObj)
{
  var currExt = ExtensionObj;
  
  if(navigator.userAgent.indexOf(currExt.browser) != -1)
  {
  
    console.log("Browser matched.");
  
    UrlExistsExt(currExt.protocolPrefix, currExt.extensionID, currExt.resourceURL, currExt.fileType, function(status){
        
      if(status == 200)
      {
        ShowPopupExt = true;
        alert('Extension Detected'); //show dialog here
        
      }
      else{
         alert('Extension Not Found');
      }                                
    });
  }
}

UnblockerExtFunc(ExtensionObj);

$(document).ajaxStop(function(){
        
  if(ShowPopupExt)
  {
    alert("Show Popup"); //if dialog is to be displayed
  }

});
</script>

If your AdBlock extension is active, you will see an alert with the message “Extension Detected” and another with the message “Show Popup”.

Reference: https://developer.chrome.com/docs/extensions/mv3/manifest/web_accessible_resources/

4. Using the default adblocker behavior towards standard ad script URLs

There is a third class of adblockers that use even more advanced techniques of blocking ads. And, they provide no web accessible resources to latch on to. So what do we do? We utilize the default adblocking behavior of these extensions towards standard URLs of adblocking scripts.

The logic is as follows: We try to load a standard adblocker script URL using javascript or jQuery. If an adblocker is active, a request to such a script URL will be blocked. If it is not active, it will yield an HTTP response code of 200 or “OK”.

So if we get a HTTP status code of 200 from a request to any standard javacript ad script URL, we can be certain that an adblocker is not active and is not blocking the request.

We can then perform functions identical to point number 1, 2 and 3 as above.

The following code goes in your <body> tag of your page. Be sure to include the jQuery file in your <head> tag of the page.

<h2>Detect addons New URLs</h2>
<script> 

var FlaggedURL = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js'; //standard ad script

jQuery(function($){
  function callMe(FlaggedURL)
  {
    $.ajax({
    url: FlaggedURL,
    type: 'GET',
    complete: function(xhr){
      
        console.log(xhr.status); //200 for OK
        
        if(xhr.status === 200)
        {
          alert("NO adblocker active");
          
        }
        else if(xhr.status === 0)
        {
          alert("Adblocker active");
        }
      }
    });
  }
  
  console.log('ready');
  
  callMe(FlaggedURL);
});
</script>

You will see an alert with a message saying “Adblocker active” in your Chrome browser on browsing to your web page with AdBlock extension active.

Reference: https://stackoverflow.com/questions/33812704/run-an-ajax-request-on-a-url-blocked-for-detecting-adblocker-ghostery

Conclusion

So, in this article, I have given four ways of detecting adblockers in browsers using javascript/jQuery. You can easily apply these code snippets to make plugins, scripts, etc.

Did you like the article? Let me know in the comments below!