AJAX For Evil: Spyjax with jQuery

By  on  

Last year I wrote a popular post titled AJAX For Evil: Spyjax when I described a technique called "Spyjax":

Spyjax, as I know it, is taking information from the user's computer for your own use — specifically their browsing habits. By using CSS and JavaScript, I can inject anchor links into the page and tell whether you've been to the link's URL. How? Quite easy actually.

I've taken the time to demonstrate this technique using jQuery.

The CSS

a.checkme			{ color:#00ff00; }
a.checkme:visited	{ color:#ff0000; }

The most important part of the CSS is the difference in ":link" and ":visited" color; the method by which we can tell if a site has been visited is by its link color being the ":visited" color.

The jQuery JavaScript

//when the page is ready
$(document).ready(function() {
	//the list of domains to check and an array which will store hits
	var domains = ['davidwalsh.name','css-tricks.com','scriptandstyle.com','cnn.com','digg.com'];
	var visited = [];
	//for every domain...
	$.each(domains,function() {
		//inject a link into page
		var a = $('').attr({
			href: 'http://' + this,
			'class': 'checkme'
		}).appendTo(document.body);
		//check the color of the link
		if($(a).css('color') == '#ff0000' || $(a).css('color') == 'rgb(255, 0, 0)') { //either format of color
			$(a).addClass('highlight');
			visited.push(this);
		}
		//remove from the page -- no longer need the links
		a.remove();
	});
	if(visited.length) {
		//save via ajax!  shady!
		//display items on the page based on "hits"
	}
});

We start by injecting a bunch of hidden links into the page (unbeknownst to the user). For each link we've injected into the page, our jQuery JavaScript grabs the link color -- if the link's color matches the designated ":visited" link color we set via CSS, we've found a site the user's been to. Of course we can do anything we want with that information, including saving it via AJAX. Why? Well, if we know a user has been to Digg.com, maybe we show the Digg "share" icon instead of the Reddit icon.

The MooTools JavaScript

var domains = ['davidwalsh.name','css-tricks.com','scriptandstyle.com','cnn.com','digg.com'];
var visited = [];
domains.each(function(url) {
	var anchor = new Element('a', {
		href: 'http://' + url,
		'class': 'checkme',
		html: url
	}).inject(document.body);
	if(anchor.getStyle('color') == '#ff0000') {
		visited.push(url);
	}
	anchor.dispose();
});

The above code accomplishes the same task using MooTools as outlined in my previous Spyjax post.

What are your thoughts on Spyjax? Harmless? Major privacy violation? You tell me!

Recent Features

  • By
    9 Mind-Blowing Canvas Demos

    The <canvas> element has been a revelation for the visual experts among our ranks.  Canvas provides the means for incredible and efficient animations with the added bonus of no Flash; these developers can flash their awesome JavaScript skills instead.  Here are nine unbelievable canvas demos that...

  • By
    How to Create a RetroPie on Raspberry Pi &#8211; Graphical Guide

    Today we get to play amazing games on our super powered game consoles, PCs, VR headsets, and even mobile devices.  While I enjoy playing new games these days, I do long for the retro gaming systems I had when I was a kid: the original Nintendo...

Incredible Demos

  • By
    Background Animations Using MooTools

    One of the sweet effects made easy by JavaScript frameworks like MooTools and jQuery is animation. I ran across this great jQuery tutorial that walks you through animating a background image of a page. Here's a quick MooTools code snippet that...

  • By
    JavaScript Copy to Clipboard

    "Copy to clipboard" functionality is something we all use dozens of times daily but the client side API around it has always been lacking; some older APIs and browser implementations required a scary "are you sure?"-style dialog before the content would be copied to clipboard -- not great for...

Discussion

  1. Michael Warkentin

    It seems like it should be possible to do something like this, shouldn’t it?

    Var visited_links = $$('a:visited')
  2. Anton

    This will only work if a user explicitly allows for his or her browser history to be recorded. I, for one, only store it for as long as the browser is opened. And since it can be controlled, it is not a security risk. But I like the idea, since not everyone erases browsing history, I can finally deny a user access to my site if he visits nasty social networks, mwahahaha :)

  3. Anton

    @Michael Warkentin: That will only tell if user visited sites that you have links to on your page. If you want to check a specific site without linking to it, spyjax to the rescue!

  4. There are already sites out there using this technique. E.g. http://www.didyouwatchporn.com

    I’m amazed how easy this is…I think I’ll try to set up something similiar using Prototype.

  5. Anton

    @David: as expected, it fails to detect the fact that I watch porn regularly: http://www.didyouwatchporn.com/imgs/splash_no.jpg

  6. @David: Hahahaaha. That’s awesome!

  7. yeah, i wrote a mini API for this a while back – http://fragged.org/dev/vanillaspy.php (vanilla js), i have a mootools one also.

    anyway, this has a test case for some targeted advertising under test advisement ‘isPokerPlayer’.

  8. Thomas

    There’s a website dedicated to this privacy issue, and they also offer some solutions worth checking through: http://whattheinternetknowsaboutyou.com/docs/solutions.html

    I make great use of the history in my web browser, some sites aren’t “worthy” a bookmark, so I decided to use and install LinkStatus extension (https://addons.mozilla.org/en-US/firefox/addon/12312) for Firefox 3.5 – works like a charm imho.

  9. I’ve always thought this use of css and javascript was pretty interesting. I figure that advertisers can’t use the information directly but a single-site, like a person hosting a wordpress blog, could have a plugin to show related posts based on the history of the visitor.

  10. Did you get the idea here: http://whattheinternetknowsaboutyou.com ?
    With your examlpe, i see it can be used for useful things, so thx for sharing!

  11. Very nice and pretty easy.
    Thx for the jQuery code!

  12. I can’t get over how funny that porn thing is. Hilarious.

  13. Hilarious it is…you can even create links to send to your friends and if they visit the site using your link, you get an email detailing what sites they visited :D

  14. I must say that spyjax which is used with j query is a wonderful combination for development. I like that.

  15. Wonderful idea. When used for good it has lots of potential!

  16. Haha, the list of websites I have been before clicking on the Advanced Test is outdated :))

    ” davidwalsh.name, php.net, yahoo.com, google.com, gmail.com, imdb.com, jquery.com, youtube.com, facebook.com”

    First, I think anyone of us are using these websites in a daily manner and second, is inaccurate, I didn’t visit at least 50% of these websites before coming on davidwalsh.

  17. Marek Stasikowski

    I was once writing something similar, but taking ranges of url’s in the same domain into account. This could be useful to eg. see what profiles has somebody been looking at at social websites. In the script, I declared the url as follows: “http://somesocialsite/users/%id”, and replaced the %id within a loop, to cover a full range of users. In the time being, I displayed a funny Youtube video on my site, so the victim wouldn’t leave before I’m finished scanning.

  18. Would this be intrusion? I mean, anyone could use this technique and know what banks’ website you visit, who provides you your email account and so on…

    I’m actually surprised that this seems to be working and that there isn’t much “told” about it.

    In the other hand… I find it pretty cool! *evil grin* That can help in customizing the display of links and such nice little tweaks FOR the user (and not in order to profit FROM the user)…

  19. Ben

    Wow!! This is very cool, but massive potential for misuse! Guess I’ll clear my history before I visit this site any more ;)

  20. @Ben: Actually, the plugins in Firefox LinkStatus (https://addons.mozilla.org/en-US/firefox/addon/12312) works fine, if you disable visited links’ CSS.

    Thanks for that plugin Thomas.

  21. Ben

    @Nickolas Simard: Ah cool!

    Still, that doesn’t distinguish between good and evil sites.

    Do you think this could mean the end of the visited link style?!

    Once this gets into the wrong hands, the cons of keeping the visited link functionality will definitely outweight the pros.

  22. Yeah… I feel that…major privacy violation must be an issue for Spyjax

  23. We made a service that is available for free to track your visitors’ histories. Check it out over at http://360voltage.com/historian/

  24. As promised I did the same using Prototype:
    http://davidbehler.de/projects/proto.spy

  25. Daniel Oliveira

    That porn stuff is great!!! ROFL

  26. I like your idea about Digg. I don’t want to distract people and/or send them off to Digg if they are not already Digg users. OK, maybe I’m selfish but I have bills to pay.

  27. ELQ

    What I find interesting is how inaccurate it is. Anybody know why? like I went to Facebook FROM the spyjax page, then came back to the spyjax page (FORward) from Facebook..still showing I’ve not been to Facebook. Even David’s prototype solution..it’ shows I’ve been to facebook but not that I was HERE! Any way to increase the accuracy a little?

  28. Could be that you are not saving your browsing history? Because this “trick” relies upon you saving your history.

  29. sneaky

    So, I get how to display this content on a web page, but what I’m really trying to figure out is how to take the *visited* urls and place them in a variable, or array or something so that they can be sent via email or thrown into a database…

    Is there a way to essentially disregard the unvisited list and only display/store the “visited” list?

    I’m a total newbie – sorry! Thanks!

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!