views:

76

answers:

4

We're using a third-party analytics reporting script provided by this analytics company. It adds a 1x1 pixel image into the DOM with reporting data in the URL of the image.

Is there any way for me to monitor the DOM and intercept this <img> element and change its "src" attribute before the browser requests the image?

Sounds like a really odd thing to do, I know, but there's a feature we'd like to hack onto this reporting script (the script is obsfucated).

+2  A: 

In non-IE browsers, you can detect the insertion of a DOM node by using the DOMNodeInserted event. I don't know if the browser will have made the HTTP request by the time the event is fired; it appears not to in Firefox from a quick test. Since this doesn't work in IE, this may not be an acceptable solution anyway.

document.body.addEventListener("DOMNodeInserted", function(evt) {
    var node = evt.target;
    if (node.nodeType == 1 && node.tagName == "IMG") {
        node.src = "http://www.gravatar.com/avatar/be21766f09e0e5fd3a2f8cc721ceba2e?s=32&amp;d=identicon&amp;r=PG"; // Your gravatar
    }
}, false);
Tim Down
A: 

Building on what Adam suggested:

$(document).ready(function() {
  $("img[src='http://example.com/example.gif']").attr('src','http://example.com/new_src.gif');
});
calvinf
This won't work. Adam suggested the use of `live`, which applies to elements created in the future. This script only analyzes elements currently in the DOM.
mattbasta
If the <img> is added via javascript after the DOM has loaded, I agree, he'd want to use live. However, the selector he'd want to use would be quite similar to this.
calvinf
+1  A: 

Give this a go. I don't know how useful it will be, but I felt like tinkering and it somewhat accounts for the scenario whereby the third party purposefully incorporates a delay:

$(document).ready(function() {
// match an image with specific dimension, return it
function imgNinja() {
    var $img =  $("img").filter(function() {
        return ($(this).height() == 1 && $(this).width() == 1);
    });
    return $img;
}

// periodically execute this to check for matches
function keepSeeking() {
    $img = imgNinja();
    if($img.length) {
        alert('found it');
        clearInterval(i);
        // do something with image
    }
}

// insert a fake into the DOM at a bit of an interval
function addNastyImage() {
   var $invader = $('<img src="foo.jpg" height="1px" width="1px"/>'); 
    $('html').append($invader);
}


setTimeout(addNastyImage, 5000);
var i = setInterval(keepSeeking, 1000);
});

Demo: http://jsfiddle.net/NyEdE/3/

karim79
If the pixel is added as part of a metrics suite, it likely loads before the DOM's ready event is fired.
mattbasta
A: 

If the third-party script uses a method (like .appendChild) to add the element to the document, you can probably do this by replacing that method of the relevant object with your own function.

That would have the advantage of working in all browsers, and I think you would only generate one HTTP request (for the changed URL, not for the original one).

Jason Orendorff