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
    7 Essential JavaScript Functions

    I remember the early days of JavaScript where you needed a simple function for just about everything because the browser vendors implemented features differently, and not just edge features, basic features, like addEventListener and attachEvent.  Times have changed but there are still a few functions each developer should...

  • By
    Regular Expressions for the Rest of Us

    Sooner or later you'll run across a regular expression. With their cryptic syntax, confusing documentation and massive learning curve, most developers settle for copying and pasting them from StackOverflow and hoping they work. But what if you could decode regular expressions and harness their power? In...

Incredible Demos

  • By
    Element Position Swapping Using MooTools 1.2

    We all know that MooTools 1.2 can do some pretty awesome animations. What if we want to quickly make two element swap positions without a lot of fuss? Now you can by implementing a MooTools swap() method. MooTools 1.2 Implementation MooTools 1.2 Usage To call the swap...

  • By
    MooTools, Mario, and Portal

    I'm a big fan of video games. I don't get much time to play them but I'll put down the MacBook Pro long enough to get a few games in. One of my favorites is Portal. For those who don't know, what's...

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!