Defending the Perimeter Against Web Widgets
9 Comments
Comments are ordered by helpfulness, as indicated by you. Help us pick out the gems and discourage asshattery by voting on notable comments.
Got something to add? You can leave a comment below.
TVD
Russell Heimlich
I appreciated the domain of the widget provider being widgetjonesdiary.com. It made me chuckle.
barryvan
Another option might be to override document.write. Assuming you are in control of the ad providers, and don’t make use of document.write yourself (which you shouldn’t!), you could then put the provider’s <script> tag at the bottom of your document, and use your own document.write method to deal with the content as appropriate.
The only caveat with this approach is that when setting innerHTML (as you will ultimately need to), <script> tags aren’t processed, so these would need to be manually found and added. This is the approach that Steve Souders takes in his ControlJS library, and, to my mind at least, it seems to be a pretty good idea.
There are, of course, other approaches that you could take. Iframes purely for the provider’s script, which can then be positioned or scraped, could work as well. Of course, the best possible solution would be to use a provider that supports JSONP. :)
Damien Petitjean
This is something really useful, thanks for the post. I would like to add some information :
This can be combined with asynchronous loading of javascript, where you can earn some seconds during loading. That’s what I use to display share buttons such as Facebook or Google+.
Let’s take a look at the code
// Google+ Tag
googleTag.type = ‘text/javascript’;
googleTag.async = true;
googleTag.src = ‘http://apis.google.com/js/plusone.js’;
var s = document.getElementsByTagName(‘script’)0;
s.parentNode.insertBefore(googleTag, s);
Have some fun !
Alan White
I spent a lot of time recently looking into all this stuff and I did try the approach in this article, where I found it fell over was when scripts are writing iframes which are in in turn writing more scripts… rinse & repeat, pretty messy!
In this scenario, I found it extremely difficult to know when ads had actually finished doing whatever they were doing so that you could copy them in their entirety, it gets even worse when ads refresh :(
Anyway, I just wanted to add some of my experiences to the conversation. Do you have an answer to this problem?
Thomas
Maybe we can solve one of such issues, but what if I want to integrate more 3rd party JavaScripts using document.write()?
If it is the first one hanging, all other will not be executed as well.
Andy Davies
I’d encourage everyone to go read yesterday’s post on the Performance Advent Calendar – http://calendar.perfplanet.com/2011/the-art-and-craft-of-the-async-snippet/
Stoyan covers how to write async loading javascript for third party widgets and so avoid the single point of failure they can introduce.
@andydavies
Mark Wales
Firstly, you should never use document.write() – it has the potential to delete the entire DOM if used in the wrong place. That’s not something you want to do! There are always better alternatives, like using innerHTML (supported in all browsers, and much safer).
Maybe I’m missing something, but this code seems unnecessarily complicated – and relies on jQuery, which you shouldn’t force developers to put on their site (don’t get me wrong, I’m a big fan of jQuery, but if you’re only using it for a few lines of DOM manipulation then 31KB is a big price to pay).
Could you not do something as simple as:
HTML
<div id=“pun-of-the-day”></div>
…
<!— bottom of page —>
<script src=“http://adnetworksite.ads/puns.js”></script>
AD JAVASCRIPT
// Self-executing function (to keep variables out of global scope
(function () {
var div = document.getElementById(‘pun-of-the-day’); div.innerHTML = ‘A good pun is its own reword’;}());
======
Obviously the ad javascript would be more clever than that and have multiple puns in and such. But it works. And it involves less code for both ends.
As long as the script is called at the bottom of the page (which it should be anyway) this will work. No jQuery needed, no complicated DOM manipulations.
Nicolas Chevallier
More info about that on Steve’s blog, for example :
http://www.stevesouders.com/blog/2010/12/15/controljs-part-1/
It’s even more important now to load javascript asynchronously because of performance and because Google will take care of website speed in the future.
Great article Rich! I’m a huge fan of your work on Dribble.
Quite often document.write() gets a bad rap. But, to be fair, the issue isn’t using document.write() to write content to the DOM.
The overarching issue is should we use document.write() to load cross-domain scripts (or any scripts for that matter)? I believe we can all agree the answer is no.
Using a Callback approach is novel indeed, but what I really like about it is its unobtrusive foundation and the control it places in the hands of the developer.
Today, widgets like The Deck answer the “what”, “where”, “when” and “how” of injected content. Using a predefined callback puts the “where” and “when” concerns back in the hands of the developer – where they belong!
With a 50/50 split, and the right concerns in the right hands, surely this is a win/win for both parties.
How would a Callback approach compare to loading The Deck’s script asynchronously?
Asynchronous Loading Example:
(function(id) {
var s = document.createElement(‘SCRIPT’), s1 = document.getElementsByTagName(‘SCRIPT’) [0];s.type = ‘text/javascript’;
s.async = true;
s.src = ‘http://widgetjonesdiary.com/punoftheday.js?id=’ + id;
s1.parentNode.insertBefore(s, s1);
})(“24ways”);
Love the approach! Take Care!