How to detect a click inside of an iframe (cross-domain)? Aka prevent click fraud
Asked Answered
A

7

11

I got a warning by my ad system provider about click fraud. No further info, all they are recommending is "hide the ads for users who click on ads too quickly'". I wrote a piece of JS script that hides all DIVs with ads for N seconds (using cookie) when clicked on, but this solution does not work as the "inner" content (with ads) is generated by an JS script that calls and renders the content from external server (as you would expect from an ad system). So, when one takes the cross-domain security into account it is kinda Catch 22. How can I detect a click inside a DIV (locally defined) of which content is rendered by an external JS and in iframe?

Example:

<div class="ad-class"> <!-- locally defined div -->
   <div id="my-id"> </div> <!-- identifies my ad in the provider's system -->
   <script>
      var foo = blah // declares the ad dimensions and stuff
      //  and renders the contextual ad in #my-id DIV
   </script>
</div>

Were it all local, solution would be easy as the internal div would inherit the parent class ("ad-class"). In case of cross-domain, this is not valid. Any tips, dudes?

Ailina answered 30/3, 2015 at 2:1 Comment(3)
you can always detect the click on a div using the onclick event without caring what is inside the div. but you can check if the div innerHTML to see if the ad is loaded or it's empty and if the ad was loaded then run your script.Rondo
Hi EhsanT, I wish you were right but unfortunately the onclick does not work here.Ailina
Possible duplicate of Detect Click into Iframe using JavaScriptAnesthetist
G
14

You cannot detect click events in cross-domain iframe.

That put, you might have one bad option:

One of the nearest things you can do is detect that the focus moved from your window to the iframe:

window.focus(); //force focus on the currenct window;
window.addEventListener('blur', function(e){
    if(document.activeElement == document.querySelector('iframe'))
    {
        alert('Focus Left Current Window and Moved to Iframe / Possible click!');
    }
});

http://jsfiddle.net/wk1yv6q3/

However it's not reliable, loose focus does not mean a click, it could be user moving across the website using TAB.

Another problem is that, you only detect the first time focus is moved to the iframe, you do not know what user does in there, he can click a million times and you will never know.

Greylag answered 30/3, 2015 at 13:19 Comment(4)
Thank you very much, Luizgrs. That is the best solution so far. The probability of ppl surfing the web site using TAB is very low. So is the probability of clicking on the ad text instead of the links. Like I said, after a click (or any interaction in this case) the ad divs get hidden, the time of such interaction in iframe is stored in a cookie. If a visitor keeps browsing the web site, the cookie is read again and ad divs will get displayed again after N seconds.Ailina
But yes, I find the ad provider's requirements kinda stupid. BTW, I wonder how one can protect Adsense divs from click fraud (I am not using Adsense now but been thinking of switching to it.)Ailina
This solution is not working in firefox's latest version. Any way to fix it?Helium
Thanks for the inspiration, you might be interested to see my answer which is an upgrade of your.Himyaritic
H
10

Luizgrs inspired me this solution :

var clickIframe = window.setInterval(checkFocus, 100);
var i = 0;

function checkFocus() {
  if(document.activeElement == document.getElementById("ifr")) {
  	console.log("clicked "+(i++));
  	window.focus();
   }
}
<!DOCTYPE html>
<h2>Onclick event on iframe</h2>
<iframe src="https://www.brokenbrowser.com/" id="ifr"></iframe>

The function detect if the iframe has the focus, if yes, the user clicked into the iframe. We then give back the focus to our main windows, which allow us to find if the user click another time.

This trick has been usefull to me for a POC on a 2 step iframe click-jacking. Getting to know when the user clicked for the first time on the iframe allowed me to reorganize my different layers to keep the illusion perfect.

Himyaritic answered 21/2, 2017 at 17:5 Comment(1)
I was using a similar script for dynamic iframes and your window.focus was the missing piece I needed! Thanks for this.Triable
S
1

The approach @Luizgrs pointed out is very accurate, however I managed to indeed detect the click event using a variation of the method:

var iframeMouseOver = false;
    $("YOUR_CONTAINER_ID")
        .off("mouseover.iframe").on("mouseover.iframe", function() {
            iframeMouseOver = true;
        })
        .off("mouseout.iframe").on("mouseout.iframe", function() {
            iframeMouseOver = false;
        });

    $(window).off("blur.iframe").on("blur.iframe", function() {
        if(iframeMouseOver){
            $j("#os_top").click();
        }
    });

The above code works like a charm on desktop if you want to add mobile support you just need to use touch events touchstartand touchendevents to simulate the mouseover on mobile.

Source

Sheliasheline answered 9/11, 2019 at 0:19 Comment(1)
Or use pointer events instead of mouse/touch for browsers that support it.Loaiasis
A
0

Well, a while ago I found this plugin for WordPress. Obviously it does what I need -- just wondering how this guy made it to work, it does count clicks on Adsense iframe. I must have a closer look though I am not a PHP programmer. I program mainly in Python and need some solution of this kind for Django. If anyone can read the code easily, I would appreciate any help.

Ailina answered 30/3, 2015 at 19:8 Comment(0)
I
0

The plugin is searching first for any iframe wrapped by a previous specified class name.

The iframe id´s will be collected in a array and for everyone of these id´s an mouseover event will be created which fires the script which hides the class 'cfmonitor'. As a result the iframe containing ad is not visible anymore.

// IFRAME ACTION
    function iframeAction () {
        jq.each(jq.cfmonitor.iframes, function(index,element) {
            frameID = jq(element).attr('id') || false;
            if (frameID) initiateIframe(frameID);
            //alert (frameID);
        });
    }

    // INIT IFRAME
    function initiateIframe(elementID) {
        var element = document.getElementById(elementID);
        // MOUSE IN && OUT
        if (element) {
            element.onmouseover = processMouseOver;
            element.onmouseout = processMouseOut;
            //console.log("mouse on out");
        }
        // CLICKS
        if (typeof window.attachEvent !== 'undefined') {
            top.attachEvent('onblur', processIFrameClick);
        }
        else if (typeof window.addEventListener !== 'undefined') {
            top.addEventListener('blur', processIFrameClick, false);
        }
}

// IFRAME CLICKS
    function processIFrameClick() {
        // ADD A CLICK
        if(isOverIFrame) {
            //addClick();
            // Some logic here to hide the class 'cfmonitor'
            //console.log("Go");
            top.focus();
        }
}
Imprudent answered 31/3, 2015 at 9:26 Comment(0)
S
0

Check this it might help. You can not detect the click event when its cross browser.

window.focus();
window.addEventListener('blur', function(e){
  if(document.activeElement == document.getElementById('Your iframe id'))
   {
    console.log('iframe click!');
   }
});
Superfine answered 19/12, 2018 at 9:57 Comment(0)
N
0

If iframe content is from the same origin there is much simpler way than using focus()..blur techniques. Simply use 'click' event on any internal iframe document element or the internal iframe window object.

  1. On internal element:

document.querySelector('iframe').contentDocument.querySelector('div.class').addEventListener('click',e=>{/*Your code here ...*/})
  1. On the internal window object:

document.querySelector('iframe').contentWindow.addEventListener('click',e=>{/*Your code here ...*/})
`
Nairn answered 19/2 at 9:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.