<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;AkUNQno4eCp7ImA9WhBaEk0.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785</id><updated>2013-05-22T13:08:13.430+05:30</updated><title>{errorception} blog</title><subtitle type="html" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://blog.errorception.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://blog.errorception.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>33</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/errorceptionBlog" /><feedburner:info uri="errorceptionblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;A0cHRX4ycCp7ImA9WhBaEE8.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-2913288838710456823</id><published>2013-05-20T11:20:00.000+05:30</published><updated>2013-05-20T11:20:34.098+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-05-20T11:20:34.098+05:30</app:edited><title>Better Script Delivery</title><content type="html">&lt;p&gt;I'm in the process of switching CDNs from Amazon's CloudFront to CloudFlare. While CloudFront has been generally good, it fell short in a couple of ways. So far, CloudFlare solves all of these problems and then gives the opportunity to have even more interesting possibilities.&lt;p&gt;
&lt;p&gt;There were two major problems with CloudFront:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;strong&gt;No CNAME support&lt;/strong&gt;. Not for HTTPS, at least. As a result, I've had to give you a script with a &lt;code&gt;someuglytoken.cloudfront.net&lt;/code&gt; URL in it. But the problem is beyond just ugliness. It gives me no control to change CDNs in the future. I've been living with this so far, but it's far from ideal. CloudFlare solves this problem elegantly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It's a dumb CDN&lt;/strong&gt;. Like, really dumb. It doesn't do any content-negotiation for what I'd consider even the most basic things. For example, if you want your scripts to be gzipped, you'd have to upload pre-gizpped scripts to the CloudFront. If a browser comes along that doesn't understand gzip, it's out of luck.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The second issue might seem obvious and trivial, but has its consequences. For example, PageSpeed recommends that every asset on the page should have a &lt;code&gt;Vary: Accept-Encoding&lt;/code&gt; header. However, on CloudFront if I provide a &lt;code&gt;Vary&lt;/code&gt; header, I'd be lying to the network, because I'm not able to vary the content at all. As a result, all sites that had embedded Errorception's snippet would have seen a slight reduction in their PageSpeed score. Indeed, &lt;a href="https://errorception.uservoice.com/forums/132896-suggestions-and-feedback/suggestions/3863028-specify-a-vary-accept-encoding-header-for-pagespe"&gt;there have been requests to fix this&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Not only do the two problems above get fixed by the move to CloudFlare, it allows for very interesting possibilites in the future. Since CloudFlare is much more smart as compared to CloudFront, and since it effectively works as a caching-proxy, the possibilities are limitless! There are features I simply couldn't roll out on CloudFront which become trivial to do on CloudFlare.&lt;/p&gt;
&lt;h3&gt;Action needed&lt;/h3&gt;
&lt;p&gt;Unfortunately, this change requires you to change the script snippet that you've embedded on your site. I know it's a pain to have to do this. I apologize. The &lt;a href="http://blog.errorception.com/2012/01/now-using-cdn-power.html"&gt;last time&lt;/a&gt; I asked you to do this was over a year and a half ago, so I assure you that these kinds of changes don't happen frequently. Please go to your Settings &gt; Tracking snippet to get the new snippet.&lt;p&gt;
&lt;h2&gt;Upgrade plan&lt;/h2&gt;
&lt;p&gt;The current script on Amazon's CloudFront will be supported for a couple of months more. Over this period, if there are any critical bugs, I'll be making releases to both the CloudFront and CloudFlare CDNs. Feature releases will &lt;strong&gt;not&lt;/strong&gt; be rolled out to CloudFront, so you will not get any new features if you are using the old snippet. It's highly recommended that you upgrade as soon as possible to ensure that you have the very latest features.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/Xw5WnlbKBdQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/2913288838710456823/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2013/05/better-script-delivery.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/2913288838710456823?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/2913288838710456823?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/Xw5WnlbKBdQ/better-script-delivery.html" title="Better Script Delivery" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.errorception.com/2013/05/better-script-delivery.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0cCSXw7cCp7ImA9WhBUEkk.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-3935757684654754850</id><published>2013-04-29T19:33:00.000+05:30</published><updated>2013-04-29T19:47:48.208+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-04-29T19:47:48.208+05:30</app:edited><title>Get your JS error notifications wherever you like!</title><content type="html">&lt;p&gt;Just three days ago, I had launched &lt;a href="http://blog.errorception.com/2013/04/announcing-webhooks.html"&gt;WebHooks support&lt;/a&gt; so that you can view your site's client-side JS errors anywhere you prefer. The trouble with vanilla WebHooks is that everyone has to implement the same sets of hooks for integration with the same services. For example, if two companies need the error to be posted to HipChat, they'd both have to independently develop HipChat integrations on top of Errorception's WebHooks, and then manage and maintain their implementations themselves. Such a pain! So, today, there are two announcements to help ease the pain.&lt;/p&gt;

&lt;p&gt;Firstly, using the same underlying stack I'm using for WebHooks, I'll host integrations for most popular services myself so that you don't have do a thing. I'm calling this &lt;q&gt;service hooks&lt;/q&gt;, blatantly copying the name from GitHub. Simply go over to your settings, and click on &lt;q&gt;Service Hooks&lt;/q&gt; to find the list of services you can already integrate with today. You don't have to write any code to implement the hook. Just fill a form, and you are ready to go.&lt;/p&gt;

&lt;p&gt;Currently, I'm launching &lt;a href="http://campfirenow.com/"&gt;Campfire&lt;/a&gt;, &lt;a href="https://www.hipchat.com/"&gt;HipChat&lt;/a&gt; and &lt;a href="http://www.pagerduty.com/"&gt;PagerDuty&lt;/a&gt; integration. Integrations with these services have been asked for before, so I decided to start with these. I expect this list to expand further.&lt;/p&gt;

&lt;div style="text-align: center"&gt;
&lt;a href="http://4.bp.blogspot.com/-wBcI9YVFeyg/UX58bxLnPKI/AAAAAAAAADM/QmaLqlzfFq4/s1600/Screen+Shot+2013-04-29+at+6.02.44+PM.png" imageanchor="1" &gt;&lt;img border="0" src="http://4.bp.blogspot.com/-wBcI9YVFeyg/UX58bxLnPKI/AAAAAAAAADM/QmaLqlzfFq4/s320/Screen+Shot+2013-04-29+at+6.02.44+PM.png" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href="http://1.bp.blogspot.com/-L22Z5hx_k-E/UX58baQppaI/AAAAAAAAADI/kvi-Oqeds-c/s1600/Screen+Shot+2013-04-29+at+6.17.15+PM.png" imageanchor="1" &gt;&lt;img border="0" src="http://1.bp.blogspot.com/-L22Z5hx_k-E/UX58baQppaI/AAAAAAAAADI/kvi-Oqeds-c/s320/Screen+Shot+2013-04-29+at+6.17.15+PM.png" /&gt;&lt;/a&gt;
&lt;p style="color: #999; font-size: 11px"&gt;What an error looks like on Campfire (left) and HipChat&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;As interesting as that is, what's even more exciting is how it's implemented, and how it matters to you.&lt;/p&gt;

&lt;h2&gt;&amp;lt;3 GitHub, &amp;lt;3 open-source&lt;/h2&gt;

&lt;p&gt;All the code that makes these service hooks possible is all open-source. &lt;a href="https://github.com/errorception/errorception-hooks"&gt;Check it out on GitHub&lt;/a&gt;. Even the documentation on Errorception for these services is driven off README.md files from GitHub! That's just awesome!&lt;/p&gt;

&lt;p&gt;There are two reasons I wanted this to be open-source. One of the reasons of course is that I like the transparency with open source. When I'm asking you to enter API tokens for, say, your HipChat account, I want to make it clear to you that I'm not going to misuse it. What better way to convince you than to show you the code itself!&lt;/p&gt;

&lt;p&gt;Secondly, and probably more importantly, if you want to see a new service integrated with Errorception, you will be able to do that yourself! Just fork the repo on GitHub, write a small little JS function to implement the integration, and send me a pull request. I'll have it merged in no time, and will immediately be available to everyone. It's really simple! And when I say it's a &lt;q&gt;small little function&lt;/q&gt;, I mean it - Have a look at &lt;a href="https://github.com/errorception/errorception-hooks/blob/master/hooks/webhook/index.js#L13-L25"&gt;the WebHooks implementation&lt;/a&gt; as an example.&lt;/p&gt;

&lt;p&gt;I've had a lot of fun planning and coding this release. I hope you make the most of it. And if you want to see your favorite services integrated with Errorception, feel free to give it a shot on GitHub. I'll only be glad to help you along.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/PMAN5FOKJfM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/3935757684654754850/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2013/04/get-your-js-error-notifications.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/3935757684654754850?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/3935757684654754850?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/PMAN5FOKJfM/get-your-js-error-notifications.html" title="Get your JS error notifications wherever you like!" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-wBcI9YVFeyg/UX58bxLnPKI/AAAAAAAAADM/QmaLqlzfFq4/s72-c/Screen+Shot+2013-04-29+at+6.02.44+PM.png" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://blog.errorception.com/2013/04/get-your-js-error-notifications.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkEARH8-cCp7ImA9WhBVGUQ.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-2135827212474258214</id><published>2013-04-26T22:14:00.000+05:30</published><updated>2013-04-26T22:14:05.158+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-04-26T22:14:05.158+05:30</app:edited><title>Announcing WebHooks</title><content type="html">&lt;p&gt;Though the Errorception &lt;a href="http://errorception.com/api/http"&gt;HTTP API&lt;/a&gt; is awesome for browsing your errors, it has so far been very hard to get real-time error notifications. There was the hacky solution of polling the API of course, but that's terribly inefficient, and just feels dirty. Today, this gets fixed.&lt;/p&gt;

&lt;p&gt;You can now configure WebHooks in your settings, which Errorception will POST to whenever it encounters an error on your site. You can choose if you want to receive POSTs for every occurrence of every error, of the very first time an error occurs.&lt;p&gt;

&lt;div style="text-align: center"&gt;
&lt;a href="http://2.bp.blogspot.com/-oTaxUot_myw/UXqtU81VWDI/AAAAAAAAAC4/E1YhCPuGv6M/s1600/Screen+Shot+2013-04-26+at+10.01.18+PM.png" imageanchor="1" &gt;&lt;img border="0" src="http://2.bp.blogspot.com/-oTaxUot_myw/UXqtU81VWDI/AAAAAAAAAC4/E1YhCPuGv6M/s700/Screen+Shot+2013-04-26+at+10.01.18+PM.png" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;This has been made available to all projects in Errorception, just like every other feature. Head over to the &lt;a href="http://errorception.com/api/webhook"&gt;WebHook docs&lt;/a&gt; to learn how to make the most of this feature.&lt;p&gt;

&lt;p&gt;As usual, feedback always welcome! I can't wait to see what you'll be pulling off with this. :)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/FSBy8n4xa18" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/2135827212474258214/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2013/04/announcing-webhooks.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/2135827212474258214?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/2135827212474258214?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/FSBy8n4xa18/announcing-webhooks.html" title="Announcing WebHooks" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-oTaxUot_myw/UXqtU81VWDI/AAAAAAAAAC4/E1YhCPuGv6M/s72-c/Screen+Shot+2013-04-26+at+10.01.18+PM.png" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://blog.errorception.com/2013/04/announcing-webhooks.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU4NQ309cSp7ImA9WhBSEko.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-3137184709582920689</id><published>2013-02-19T17:22:00.000+05:30</published><updated>2013-02-19T18:16:32.369+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-02-19T18:16:32.369+05:30</app:edited><title>Error Object Compatibility Table</title><content type="html">&lt;p&gt;I've been spending some time lately studying JavaScript's Error object. These are some of my notes on Error object compatibility across browsers, in case anyone else finds this useful.&lt;/p&gt;

&lt;style&gt;
.compatTable td { text-align: center; }
.compatTable .separate th, .compatTable .separate td { border-top: 1px solid #eee; }
&lt;/style&gt;

&lt;table width="100%" class="compatTable"&gt;
 &lt;thead&gt;
  &lt;tr&gt;
   &lt;th&gt;Property&lt;/th&gt;
   &lt;th&gt;Google Chrome&lt;/th&gt;
   &lt;th&gt;Safari&lt;/th&gt;
   &lt;th&gt;Opera&lt;/th&gt;
   &lt;th&gt;Firefox&lt;/th&gt;
   &lt;th&gt;MSIE&lt;/th&gt;
  &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
  &lt;tr&gt;
   &lt;th scope="row" align="left"&gt;name&lt;/th&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;Yes&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
   &lt;th scope="row" align="left"&gt;message&lt;/th&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;Yes&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
   &lt;th scope="row" align="left"&gt;stack&lt;/th&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;Yes (IE10+)&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
   &lt;th scope="row" align="left"&gt;toString()&lt;/th&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;Yes&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr class="separate"&gt;
   &lt;th scope="row" align="left"&gt;type&lt;/th&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
   &lt;th scope="row" align="left"&gt;columnNumber&lt;/th&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr class="separate"&gt;
   &lt;th scope="row" align="left"&gt;fileName&lt;/th&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
   &lt;th scope="row" align="left"&gt;sourceURL&lt;/th&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr class="separate"&gt;
   &lt;th scope="row" align="left"&gt;line&lt;/th&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
   &lt;th scope="row" align="left"&gt;lineNumber&lt;/th&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;Yes&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr class="separate"&gt;
   &lt;th scope="row" align="left"&gt;number&lt;/th&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;No&lt;/td&gt;
   &lt;td&gt;Yes&lt;/td&gt;
  &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;br /&gt;
&lt;h2&gt;Notes:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Though file name is available in the &lt;code&gt;.stack&lt;/code&gt; property, only Firefox and Safari provide this as an explicit property, and that too with different property names (FF: &lt;code&gt;.fileName&lt;/code&gt;, Safari: &lt;code&gt;.sourceURL&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;All browsers string-format the stack subtly differently. There's no standard regarding stack formatting. Firefox has the least informative stack property. I'm going to cut Firefox some slack though, since they were the first to expose this property. That said, this might change in the future. Worth keeping an eye on &lt;a href="http://wiki.ecmascript.org/doku.php?id=strawman:error_stack"&gt;this discussion&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Firefox doesn't provide column numbers in the stack at all. However, it does provide a &lt;code&gt;.columnNumber&lt;/code&gt; property which is only useful for the first stack frame.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;.number&lt;/code&gt; property (IE) is practically useless. It points to IE's internal representation of errors.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.line&lt;/code&gt; (Safari) and &lt;code&gt;.lineNumber&lt;/code&gt; (Firefox) properties give the line number of the first stack frame of the error. No one else provides a similar property, though this data is available in the &lt;code&gt;.stack&lt;/code&gt; everywhere except Firefox.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;.toString()&lt;/code&gt; formatting seems consistent, and similar to the formatting of the error message in &lt;code&gt;window.onerror&lt;/code&gt;. That is, it uses the format &lt;code&gt;name + ": " + message&lt;/code&gt;. The only exception to this, of course, is that &lt;code&gt;window.onerror&lt;/code&gt; formats errors differently &lt;a href="http://blog.errorception.com/2012/04/script-error-on-line-0.html"&gt;when the source file has x-domain restrictions&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Column numbers in the &lt;code&gt;.stack&lt;/code&gt; property are only available in IE10+ and Chrome. Opera provides a &lt;code&gt;.stacktrace&lt;/code&gt; property in addition to &lt;code&gt;.stack&lt;/code&gt; that has column numbers (go figure!). No other browser provides column numbers in the stack trace. As mentioned above, Firefox does provide an explicit &lt;code&gt;.columnNumber&lt;/code&gt; property that's only useful for the first stack frame.&lt;/li&gt;
&lt;li&gt;No stack support for IE&amp;lt;10. Nothing. Zilch.&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/f7Zizr3ndx0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/3137184709582920689/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2013/02/error-object-compatibility-table.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/3137184709582920689?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/3137184709582920689?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/f7Zizr3ndx0/error-object-compatibility-table.html" title="Error Object Compatibility Table" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.errorception.com/2013/02/error-object-compatibility-table.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUUARn48fip7ImA9WhNaFUo.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-7551769885982509489</id><published>2013-01-31T00:44:00.000+05:30</published><updated>2013-01-31T00:44:07.076+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-01-31T00:44:07.076+05:30</app:edited><title>Stack Traces and Error Objects</title><content type="html">&lt;p&gt;A frequently requested feature has been that of stack traces with errors. However, because &lt;code&gt;window.onerror&lt;/code&gt;, doesn't give access to an error object, it has not been possible for Errorception to capture stack traces. That's set to change today.&lt;/p&gt;
&lt;p&gt;Starting today, you will be able to pass error objects to Errorception. An example is probably the best way to explain this.&lt;/p&gt;
&lt;pre style="background: #f9f9f9; padding: 10px;"&gt;&lt;code&gt;try {
    var myObject = JSON.parse(jsonString); // will break if jsonString is invalid
} catch(e) {
    &lt;strong&gt;_errs.push(e);&lt;/strong&gt;
    &lt;strong&gt;throw e;&lt;/strong&gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you pass such errors manually to Errorception, Errorception will now be able to record the stack trace for this error. Undoubtedly, this can be very useful for debugging.&lt;/p&gt;
&lt;h2&gt;Important&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;What you &lt;code&gt;push&lt;/code&gt; to &lt;code&gt;_errs&lt;/code&gt; should be a valid Error object, that is, it should be an &lt;code&gt;instanceof Error&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It is important that you &lt;code&gt;throw&lt;/code&gt; the error right after passing it to &lt;code&gt;_errs&lt;/code&gt;. This is for two reasons. Firstly, you really want your program's execution to stop when you encounter an error, and &lt;code&gt;throw&lt;/code&gt; is a great way to do so. Secondly, Errorception internally uses both the &lt;code&gt;Error&lt;/code&gt; object and the data from &lt;code&gt;window.onerror&lt;/code&gt; to capture error data. If you don't &lt;code&gt;throw&lt;/code&gt; the error, Errorception will ignore the error object.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-CtHwG9b-JpU/UQltUPCaosI/AAAAAAAAACo/eYFhBfYgBn4/s1600/Call%2Bstack.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" width="700" src="http://2.bp.blogspot.com/-CtHwG9b-JpU/UQltUPCaosI/AAAAAAAAACo/eYFhBfYgBn4/s700/Call%2Bstack.png" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;As an additional bonus, with the exception of Firefox and Safari, you will also get the column number of your error. This is especially important since your JS is likely minified without line-breaks. This column number information is especially exciting &amp;mdash; it's likely to guide the future features of Errorception.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bonus&lt;/strong&gt;: This works perfectly well with the recently launched ability to &lt;a href="http://blog.errorception.com/2012/11/capture-custom-data-with-your-errors.html"&gt;record custom information with errors&lt;/a&gt;. For example, in Errorception I was recently doing this (yes, Errorception uses Errorception):&lt;/p&gt;
&lt;pre style="background: #f9f9f9; padding: 10px;"&gt;&lt;code&gt;try {
    var myObject = JSON.parse(jsonString);
} catch(e) {
    &lt;strong&gt;_errs.meta = {json: jsonString};&lt;/strong&gt;
    _errs.push(e);
    throw e;
}
&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/MVLHhh5JRuo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/7551769885982509489/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2013/01/stack-traces-and-error-objects.html#comment-form" title="8 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/7551769885982509489?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/7551769885982509489?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/MVLHhh5JRuo/stack-traces-and-error-objects.html" title="Stack Traces and Error Objects" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-CtHwG9b-JpU/UQltUPCaosI/AAAAAAAAACo/eYFhBfYgBn4/s72-c/Call%2Bstack.png" height="72" width="72" /><thr:total>8</thr:total><feedburner:origLink>http://blog.errorception.com/2013/01/stack-traces-and-error-objects.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEcMQnc7eip7ImA9WhNUGEs.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-8901428199853359276</id><published>2013-01-11T06:31:00.000+05:30</published><updated>2013-01-11T06:31:23.902+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-01-11T06:31:23.902+05:30</app:edited><title>Your JS Errors Are Now An API Call Away</title><content type="html">&lt;p&gt;It always annoys me when data gets caught in inaccessible silos, yet that's exactly what I had ended up building with Errorception. Today, that gets rectified.&lt;/p&gt;
&lt;p&gt;Today I'm announcing the first cut of the Errorception API. As far as I know at least, it is the first API in the wild tailored specifically for JS errors in your site.&lt;/p&gt;
&lt;p&gt;Being a huge fan of simplicity, the API is really simple to use too. In fact, I've embedded a &lt;code&gt;curl&lt;/code&gt; example right here in this blog post:&lt;/p&gt;
&lt;pre style="background: #444; font: 13px Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; color: #eee; padding: 10px;"&gt;&lt;code&gt;$ curl -i https://api.errorception.com/
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 77
Connection: keep-alive

{"links":[{"rel":"projects","href":"https://api.errorception.com/projects"}]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can view detailed API documentation on &lt;a href="http://errorception.com/api/http"&gt;the API docs page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I'm excited to see what you will do with this data. I'm hoping to evolve this API based on what your experience is like. As usual, feel free to mail me at rakeshpai at errorception dot com with any suggestions or feedback.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/LTNPsp_zaGw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/8901428199853359276/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2013/01/your-js-errors-are-now-api-call-away.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/8901428199853359276?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/8901428199853359276?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/LTNPsp_zaGw/your-js-errors-are-now-api-call-away.html" title="Your JS Errors Are Now An API Call Away" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://blog.errorception.com/2013/01/your-js-errors-are-now-api-call-away.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck4HSXYyfCp7ImA9WhNUFEg.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-2731685725439578895</id><published>2013-01-06T11:10:00.001+05:30</published><updated>2013-01-06T11:12:18.894+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-01-06T11:12:18.894+05:30</app:edited><title>Improving Daily Emails</title><content type="html">&lt;p&gt;The daily notification email, which had been turned off for some time now due to a snag, has now been turned back on.&lt;/p&gt;
&lt;p&gt;Previously, all the emails used to be sent at the turn of the day on the server. This was problematic in at least two ways.&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;The load on the DB to sift through the large volume of errors to generate emails was turning out to be a bit much. The server had begun to protest about the load.&lt;/li&gt;&lt;li&gt;All users got emails at the same time, irrespective of which timezone they belonged to. I would personally prefer to get my error notification in the morning when I'm starting my day, so that I can schedule time for fixing it. A mail that lands up in my mailbox when I'm about to go to bed is useless at best, and worrisome at worst.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Turns out, solving the latter problem solved the former problem as well, because the server load of sending out the email would get more-or-less evenly distributed across the entire day. So, taking inspiration from &lt;a href="https://strideapp.com/blog/2012/11/sending-morning-emails/"&gt;what Stride did recently&lt;/a&gt;, I've rolled out something similar for Errorception.&lt;/p&gt;
&lt;p&gt;A &lt;a href="https://bitbucket.org/pellepim/jstimezonedetect"&gt;small JS snippet&lt;/a&gt; notes your timezone every time you use Errorception. This timezone information is passed along to the server and recorded against your records. A cron kicks in every half hour on the server to determine if you should be sent an email to right now, based on whether it is 9:30 AM in your timezone, using the excellent &lt;a href="https://github.com/TooTallNate/node-time"&gt;'time' module by Nathan Rajlich (TooTallNate)&lt;/a&gt;. It just works!&lt;/p&gt;
&lt;p&gt;So, starting about 15 mins ago, you should now receive emails at 9:30 in the morning, irrespective of which timezone you are in, or whether it's daylight savings or not. If you still aren't receiving emails, get in touch at rakeshpai at errorception dot com.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Almost forgot:&lt;/strong&gt; Wish you a great 2013! Happy debugging!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/ZUz98lWxE48" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/2731685725439578895/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2013/01/improving-daily-emails.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/2731685725439578895?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/2731685725439578895?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/ZUz98lWxE48/improving-daily-emails.html" title="Improving Daily Emails" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.errorception.com/2013/01/improving-daily-emails.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0UMR3o6eSp7ImA9WhNbFUo.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-6885265230493654267</id><published>2012-12-14T22:18:00.000+05:30</published><updated>2013-01-19T12:38:06.411+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-01-19T12:38:06.411+05:30</app:edited><title>Catching Cross-Domain JS Errors</title><content type="html">&lt;p&gt;
As I've &lt;a href="http://blog.errorception.com/2012/04/script-error-on-line-0.html"&gt;mentioned before&lt;/a&gt;, most modern browsers do not provide access to error information in &lt;code&gt;window.onerror&lt;/code&gt; for scripts loaded from across domains. This is a very severe restriction, and has limited the usefulness of &lt;a href="http://errorception.com/"&gt;Errorception&lt;/a&gt; to some extent.
&lt;/p&gt;
&lt;p&gt;
Fortunately, a couple of months ago, &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=696301"&gt;Firefox landed a patch&lt;/a&gt; to add this feature, and this has already been shipped with the latest versions of Firefox. Chrome is expected to follow suit very soon, since this has already &lt;a href="https://bugs.webkit.org/show_bug.cgi?id=81438"&gt;landed in Webkit&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
Unfortunately, this doesn't work out of the box, and will require some tweaking of your server and markup. Fortunately, the changes you need to make are minimal.
&lt;/p&gt;
&lt;h2&gt;On the server&lt;/h2&gt;
&lt;p&gt;You will need to &lt;a href="http://enable-cors.org/"&gt;enable CORS&lt;/a&gt; for the external JS file you load. The most minimal way to do this is to set the following HTTP header in the response for your JS file.
&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Access-Control-Allow-Origin: *&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;That's the only server-side change you need to make!&lt;/p&gt;
&lt;h2&gt;In the markup&lt;/h2&gt;
&lt;p&gt;Script tags have now got a new non-standard attribute called &lt;code&gt;crossorigin&lt;/code&gt;. The most secure value for this would be &lt;code&gt;anonymous&lt;/code&gt;. So, you'll have to modify your script tags to look like the following.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;script src="http://sub.domain.com/script.js" &lt;b&gt;crossorigin="anonymous"&lt;/b&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Browser support&lt;/h2&gt;
&lt;p&gt;As of this writing, only Firefox &lt;a href="https://developer.mozilla.org/en-US/docs/HTML/Element/script#attr-crossorigin"&gt;supports&lt;/a&gt; reporting errors for cross-domain scripts. All WebKit browsers including Chrome is expected to support this very soon. This isn't a problem with IE at all, since IE already reports errors to &lt;code&gt;window.onerror&lt;/code&gt; irrespective of the domain (yay, security!). Standardisation for the new attribute &lt;a href="http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2012-February/034969.html"&gt;has been proposed&lt;/a&gt; though it hasn't gotten anywhere.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: Thanks to Matthew Schulkind for pointing out &lt;a href="http://blog.errorception.com/2012/12/catching-cross-domain-js-errors.html?showComment=1358574712626#c9011348141614317852"&gt;in the comments below&lt;/a&gt;: It appears that Firefox insists that if you are using the cross-origin attribute, the script file must be served with the access control HTTP header. If the access control header isn't present, the script simply doesn't get evaluated. This is a minor annoyance at development time, so I've &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=832587"&gt;filed a bug with Mozilla&lt;/a&gt; about this.&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/hEjkM9JP2M8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/6885265230493654267/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2012/12/catching-cross-domain-js-errors.html#comment-form" title="13 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/6885265230493654267?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/6885265230493654267?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/hEjkM9JP2M8/catching-cross-domain-js-errors.html" title="Catching Cross-Domain JS Errors" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>13</thr:total><feedburner:origLink>http://blog.errorception.com/2012/12/catching-cross-domain-js-errors.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEcHSXgzeCp7ImA9WhBSE0w.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-8626272923830942976</id><published>2012-11-23T18:08:00.000+05:30</published><updated>2013-02-20T03:43:58.680+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-02-20T03:43:58.680+05:30</app:edited><title>Capture Custom Data With Your Errors</title><content type="html">&lt;p&gt;The more context you have around an error, the better it'll help you when debugging. And who understands your application's context better than you!&lt;/p&gt;

&lt;p&gt;Starting today, you will be able to record custom information with your errors. It's super simple too! Just create an &lt;code&gt;_errs.meta&lt;/code&gt; object, and add anything you want to it!&lt;/p&gt;

&lt;script src="https://gist.github.com/rakeshpai/4135253.js"&gt;&lt;/script&gt;

&lt;p&gt;You can pass the &lt;code&gt;_errs.meta&lt;/code&gt; object any number of properties, and the values can either be strings, numbers or booleans. Values with other types will be ignored.&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-Xbwlp3Q2-5k/UK9rluYYICI/AAAAAAAAACQ/PDaBvSTjotE/s1600/custom-data.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" width="681" src="http://4.bp.blogspot.com/-Xbwlp3Q2-5k/UK9rluYYICI/AAAAAAAAACQ/PDaBvSTjotE/s681/custom-data.png" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;You can even add and remove properties from the &lt;code&gt;_errs.meta&lt;/code&gt; object at runtime. So, if your user changes his or her preferences about cats while using your application, you can set &lt;code&gt;_errs.meta.lovesCats = false;&lt;/code&gt; when that happens. The tracking script will record the new value &lt;code&gt;lovesCats&lt;/code&gt; from that point on whenever an error occurs.&lt;/p&gt;

&lt;p&gt;This can be a huge help when debugging your code. Imagine if you could record which user got the error, which action the user was performing at the time, and on which area of your page!&lt;/p&gt;

&lt;h2&gt;Other improvements&lt;/h2&gt;
&lt;p&gt;There have also been several improvements to the tracking code. Two hard-to-find bugs have been squashed, overall performance has been improved, browser support has been expanded, resilience has been improved in case our servers are in the middle of a hurricane, and the code is much better tested now. All of this while reducing the code size! (Ok, it only reduced by 4 bytes, but it's something, right?) Just to remind you, the code size doesn't really effect you, because the tracking script doesn't come in the way of your page load time at all, giving you maximum performance at all times.&lt;/p&gt;

&lt;p&gt;As always, feedback welcome. I can't wait to see what you will do with this ability to record custom data.&lt;/p&gt;

&lt;h2&gt;Limits&lt;/h2&gt;
&lt;p&gt;The custom data recorded is put into the same store as the one used for &lt;a href="http://blog.errorception.com/2012/11/raw-error-data.html"&gt;raw error data&lt;/a&gt; and shares the same limits. That is, you can currently put in upto 25 MB of data. Beyond that, older data is purged to make room for the new data.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/Q1ZtRvvFl0E" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/8626272923830942976/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2012/11/capture-custom-data-with-your-errors.html#comment-form" title="9 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/8626272923830942976?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/8626272923830942976?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/Q1ZtRvvFl0E/capture-custom-data-with-your-errors.html" title="Capture Custom Data With Your Errors" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-Xbwlp3Q2-5k/UK9rluYYICI/AAAAAAAAACQ/PDaBvSTjotE/s72-c/custom-data.png" height="72" width="72" /><thr:total>9</thr:total><feedburner:origLink>http://blog.errorception.com/2012/11/capture-custom-data-with-your-errors.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkYMRX4_fSp7ImA9WhNQFUU.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-2855185872854706588</id><published>2012-11-22T15:59:00.000+05:30</published><updated>2012-11-22T15:59:44.045+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-11-22T15:59:44.045+05:30</app:edited><title>Raw Error Data</title><content type="html">&lt;p&gt;Since about 2 weeks now, I've been recording information about each individual error occurrence. This data was previously being discarded. I thought, why throw away perfectly fine data, if it can be useful in any way to help in debugging?&lt;/p&gt;

&lt;p&gt;A couple of minutes ago, I rolled out a UI to start looking at this data. Now, every error details page will show you all the information that we've captured for every occurrence of the error.&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-sv7wgyn-rQ4/UK35poGlgfI/AAAAAAAAAB8/lC8K4AO22XA/s1600/occurrences.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" width="600" src="http://3.bp.blogspot.com/-sv7wgyn-rQ4/UK35poGlgfI/AAAAAAAAAB8/lC8K4AO22XA/s600/occurrences.png" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;Give it a spin, and let me know what you think.&lt;/p&gt;
&lt;br /&gt;
&lt;h2&gt;Limits&lt;/h2&gt;
&lt;p&gt;The reason I used to discard this data previously is because it grows really big really quickly. So, for now, I've decided to cap the amount of logs stored. &lt;strong&gt;Each project gets 25 MB of storage for these raw logs&lt;/strong&gt;. If you end up generating more logs than the limit, older log entries are discarded to make room for the new ones.&lt;/p&gt;
&lt;p&gt;Though 25 MB might seem small, it's actually quite a bit. Considering that each log line will realistically be much lesser than 0.5kb of data, you can store more than 50,000 individual log entires before older records get purged.&lt;/p&gt;
&lt;p&gt;That said, I've not wholly decided on the 25 MB limit, and am open to change my mind. Feedback welcome.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/GRauM497HG4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/2855185872854706588/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2012/11/raw-error-data.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/2855185872854706588?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/2855185872854706588?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/GRauM497HG4/raw-error-data.html" title="Raw Error Data" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-sv7wgyn-rQ4/UK35poGlgfI/AAAAAAAAAB8/lC8K4AO22XA/s72-c/occurrences.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.errorception.com/2012/11/raw-error-data.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkQHQ3w8eSp7ImA9WhNQFE8.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-5075244262983120928</id><published>2012-11-20T19:32:00.000+05:30</published><updated>2012-11-20T19:35:32.271+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-11-20T19:35:32.271+05:30</app:edited><title>Problems with MasterCard Payments</title><content type="html">&lt;p&gt;At the outset, I want to apologize for the email notifications you've been getting about "billing attempt failures", or "rebill attempts exceeded". This affects all MasterCard payments. This is not the experience I want to provide, and this ordeal has been hugely embarrassing for me.&lt;/p&gt;&lt;p&gt;I've been using payment services from 2checkout, who seem to have run into an issue with MasterCard payments. They have not been very transparent about the issue, and kept dragging their feet about the problem despite repeated requests to fix it soon. Today they sent an email saying that the issue won't be resolved for another month!&lt;/p&gt;
&lt;h2&gt;What you can do&lt;/h2&gt;&lt;p&gt;If you are one of those who's affected, 2checkout would have already sent you a mail with a link to update your payment information. Please use the link to pick a different payment method (they still support Visa, Amex and Paypal among others). If you only have a MasterCard card, you could update your payment method to use Paypal and make a MasterCard payment through them. You don't need a Paypal account for this.&lt;/p&gt;&lt;p&gt;If you have already updated your payment information, huge thanks to you! You rock!&lt;/p&gt;&lt;p&gt;If you are paying for a new account, you won't have the MasterCard option when you checkout, but you will be able to use any other card, or use Paypal to route your MasterCard transaction.&lt;/p&gt;&lt;p&gt;If either of these is not possible, please get in touch with me at rakeshpai at errorception dot com, and we'll take it from there.&lt;/p&gt;&lt;p&gt;I know that this is annoying for you, and it's annoying for me to have to put you through this. This has been an embarrassing ordeal for me over the last few weeks, and I will continue to chase 2checkout until they resolve this issue. I wholeheartedly apologize again.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/eepb9DESX7I" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/5075244262983120928/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2012/11/problems-with-mastercard-payments.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/5075244262983120928?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/5075244262983120928?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/eepb9DESX7I/problems-with-mastercard-payments.html" title="Problems with MasterCard Payments" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.errorception.com/2012/11/problems-with-mastercard-payments.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0ENQXY5eCp7ImA9WhJWFEw.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-5176557102045629266</id><published>2012-08-20T02:58:00.000+05:30</published><updated>2012-08-20T02:58:10.820+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-08-20T02:58:10.820+05:30</app:edited><title>Improved Error Management</title><content type="html">&lt;p&gt;
Errorception turned 1 on the 15th of this month, and I thought I would do a major release for the birthday. However, you know how all software projects go. Fortunately, I'm only 4 days late. That's not too bad, right?
&lt;/p&gt;
&lt;h3&gt;Automatic closing of errors&lt;/h3&gt;
&lt;p&gt;
Starting today, all errors that haven't recurred over the last month are automatically marked as &lt;q&gt;closed&lt;/q&gt;. This has caused the average list of open errors to reduce by over 70%!
&lt;/p&gt;
&lt;p&gt;
The huge never-reducing list of errors was turning out to be quite the de-motivator, so I wanted to have a no-hassles way of keeping the list trim. The one month period is quite arbitrary, but most likely sufficient to ensure that the error has indeed disappeared.
&lt;/p&gt;
&lt;h3&gt;And you can close them manually too&lt;/h3&gt;
&lt;p&gt;
Errorception will keep working for you in the background, closing errors that haven't occurred in a long time. However, nothing beats the pleasure of manually marking an error as &lt;q&gt;closed&lt;/q&gt;. Errorception hasn't provided that pleasure so far, but now you can clear your list as you please.
&lt;/p&gt;
&lt;h3&gt;Re-opening errors&lt;/h3&gt;
&lt;p&gt;
If an error was closed, and then for some reason occurs again, Errorception will re-open the bug for you. This way, you can keep your errors list trim, while we work in the background ensuring that you aren't missing recurrences.
&lt;/p&gt;
&lt;h3&gt;Ignoring errors&lt;/h3&gt;
&lt;p&gt;
This has been a highly requested feature. If an error isn't something that you can fix, usually the case with third-party embedded scripts, you can now &lt;q&gt;ignore&lt;/q&gt; the error. Occurrences of such ignored errors will still be recorded, but will be tucked away from the main error listing to help keep your list clean. Just a quick reminder: we have always been ignoring errors automatically for you, based on several criteria. This ability has now been exposed to you as well.
&lt;/p&gt;
&lt;h3&gt;And much more&lt;/h3&gt;
&lt;p&gt;The stuff listed above is just the biggest of the features in today's release. There are several small enhancements too. After all, this release has been in the making for almost two months! Poke around see if you can spot them.&lt;/p&gt;
&lt;p&gt;Feedback welcome as always!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/FnOawVe36dY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/5176557102045629266/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2012/08/improved-error-management.html#comment-form" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/5176557102045629266?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/5176557102045629266?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/FnOawVe36dY/improved-error-management.html" title="Improved Error Management" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>6</thr:total><feedburner:origLink>http://blog.errorception.com/2012/08/improved-error-management.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU8BRnY7cCp7ImA9WhJSE0k.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-4059541538367095050</id><published>2012-07-02T19:44:00.000+05:30</published><updated>2012-07-04T01:00:57.808+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-07-04T01:00:57.808+05:30</app:edited><title>Announcing Multi-User Support</title><content type="html">&lt;p&gt;This post is from the &lt;q&gt;OMG, I can't believe you didn't already have this!&lt;/q&gt; department.&lt;/p&gt;&lt;p&gt;One of the most requested features on &lt;a href="http://errorception.com/"&gt;Errorception&lt;/a&gt; has been support for multiple users. Today I rolled out a build to add just this.&lt;/p&gt;&lt;p&gt;The reason it took so long, among others, was that I was finding it hard to distill the feature down to the least required, but no lesser. I think the current implementation does a good job of this.&lt;/p&gt;&lt;p&gt;Once logged in, simply navigate to Settings &gt; User Accounts to manage who has access to your project. You simply have to provide the email address of the person you want to invite, and you are done. It's really that simple!&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-umTooyqtSdg/T_Grpph6d5I/AAAAAAAAABs/qrcwo_Hu3_U/s1600/Screen%2Bshot%2B2012-07-02%2Bat%2B7.38.15%2BPM.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" width="550" src="http://4.bp.blogspot.com/-umTooyqtSdg/T_Grpph6d5I/AAAAAAAAABs/qrcwo_Hu3_U/s550/Screen%2Bshot%2B2012-07-02%2Bat%2B7.38.15%2BPM.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;Invited people will get an email telling them about the invitation. If they were already users of Errorception, they don't need to do a thing. The mail is just a notification. It can't get simpler. If they didn't already have an account, they have to go through the simplest signup process possible &amp;mdash; they have to pick a password. That's it! That's the signup process!&lt;/p&gt;&lt;p&gt;&lt;code&gt;&amp;lt;aside&amp;gt;&lt;/code&gt;The real reason for not pushing out a user-facing build in the last month or so was that I've been hard at work dealing with the scale that Errorception is growing at. It's amazing. I wouldn't in my wildest dreams have guessed that Errorception would be this successful, and hadn't engineered for those kind of scales. Over the last month or so, I've been rewriting the very guts of Errorception to cope with the surge of traffic. It's like changing the parts of a car while it's running. At 200 mph. But that's done now, and the code-base is managagable once again. Today's release is the first in a series of pending feature releases.&lt;code&gt;&amp;lt;/aside&amp;gt;&lt;/code&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/8PkXXJTnjDc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/4059541538367095050/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2012/07/announcing-multi-user-support.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/4059541538367095050?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/4059541538367095050?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/8PkXXJTnjDc/announcing-multi-user-support.html" title="Announcing Multi-User Support" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-umTooyqtSdg/T_Grpph6d5I/AAAAAAAAABs/qrcwo_Hu3_U/s72-c/Screen%2Bshot%2B2012-07-02%2Bat%2B7.38.15%2BPM.png" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://blog.errorception.com/2012/07/announcing-multi-user-support.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkUBQH89eip7ImA9WhNWFU0.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-3049088911145552025</id><published>2012-04-15T17:11:00.000+05:30</published><updated>2012-12-14T22:27:31.162+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-12-14T22:27:31.162+05:30</app:edited><title>"Script Error" on line 0</title><content type="html">&lt;p&gt;&lt;b&gt;Update&lt;/b&gt;: Cross-domain error reporting is improving. &lt;a href="http://blog.errorception.com/2012/12/catching-cross-domain-js-errors.html"&gt;See this post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This blog post is to address some confusion about "Script error on line 0" errors as recorded by &lt;code&gt;window.onerror&lt;/code&gt; &amp;mdash; A confusion I've certainly had, and one that I've seen many others have too.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://stackoverflow.com/questions/5913978/cryptic-script-error-reported-in-javascript-in-chrome-and-firefox/7778424#7778424"&gt;This Stack Overflow answer&lt;/a&gt; does a great job of explaining the details:&lt;/p&gt;
&lt;blockquote&gt;The "Script error." happens in Firefox, Safari, and Chrome when an exception violates the browser's &lt;a href="http://en.wikipedia.org/wiki/Same_origin_policy"&gt;same-origin policy&lt;/a&gt; - i.e. when the error occurs in a script that's hosted on a domain other than the domain of the current page.&lt;/blockquote&gt;
&lt;h3&gt;Who's affected?&lt;/h3&gt;
&lt;p&gt;If you are recording errors from &lt;code&gt;window.onerror&lt;/code&gt;, and your scripts are loading from a different subdomain or domain, and if such an external file throws an error, the error will be recorded as &lt;q&gt;Script error&lt;/q&gt; with no more details, in all browsers except IE. Errors in IE get recorded as expected, irrespective of the hosting domain of the script.&lt;/p&gt;
&lt;p&gt;You are not affected if your scripts load from the same domain as your page, or if your errors occur in IE.&lt;/p&gt;
&lt;p&gt;Unfortunately, loading scripts from a different domain is a &lt;a href="http://developer.yahoo.com/performance/rules.html#cdn"&gt;very&lt;/a&gt; &lt;a href="http://developer.yahoo.com/performance/rules.html#split"&gt;good&lt;/a&gt; &lt;a href="http://developer.yahoo.com/performance/rules.html#cookie_free"&gt;idea&lt;/a&gt;, and is something you should strongly consider. However, this severely limits the usefulness of &lt;code&gt;window.onerror&lt;/code&gt; in non-IE browsers.&lt;/p&gt;
&lt;h3&gt;Why is this?&lt;/h3&gt;
&lt;p&gt;It's because of a &lt;a href="http://jeremiahgrossman.blogspot.in/2006/12/i-know-if-youre-logged-in-anywhere.html"&gt;possible exploit&lt;/a&gt; in browsers that support &lt;code&gt;window.onerror&lt;/code&gt;. &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=363897"&gt;Firefox fixed this issue&lt;/a&gt; by restricting the information available in &lt;code&gt;window.onerror&lt;/code&gt; for x-domain scripts. As far as I can tell, WebKit and Opera (which were late entrants in the &lt;code&gt;window.onerror&lt;/code&gt; game) have had this behavior from the outset. In IE, even as recently as IE9, this security vulnerability still exists.&lt;/p&gt;
&lt;h3&gt;What about Errorception?&lt;/h3&gt;
&lt;p&gt;From the very beginning, &lt;a href="http://errorception.com/"&gt;Errorception&lt;/a&gt; has not recorded any &lt;q&gt;Script error&lt;/q&gt; errors, because the information is insufficient to debug in any sensible way. However, I never knew the cause of this error, and admittedly have been confused about how it originated. Now that it's clear why this error occurs, it's also clear that there's a class of errors that Errorception cannot catch &lt;em&gt;(hat-tip: &lt;a href="http://twitter.com/vitaly_babiy"&gt;@vitaly_babiy&lt;/a&gt;)&lt;/em&gt;, and that it's necessary to come up with an alternative mechanism to catch such errors. All isn't lost yet &amp;mdash; IE still gives enough information to debug the error in all cases, and all this only happens if you loading from across domains. However we clearly need to do better than &lt;code&gt;window.onerror&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Lest you think otherwise, problems like this are in fact the very reason you should use services like Errorception. Catching and processing errors is evidently a complex task, and is something you don't want to bother with too much &amp;mdash; you just care about the results. Errorception takes on the responsibility to catch errors for you, and to process them to make them easy to digest. Setbacks like this are common, and we've always found a way around such problems.&lt;/p&gt;
&lt;p&gt;Why I'm telling you all this is because I think it's far better to educate people and be open about Errorception's limitations, than to hide such information. Hiding information is tantamount to lying, and I don't want to do that.&lt;/p&gt;
&lt;p&gt;I'll be actively looking for alternative ways to record errors, since &lt;code&gt;window.onerror&lt;/code&gt; has these (&lt;a href="http://blog.errorception.com/2011/12/call-stacks-in-ie.html"&gt;and other&lt;/a&gt;) restrictions. I already have a couple of ideas to improve error information, and will be testing them out soon. Meanwhile, I'm open to suggestions, if any.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/K-3pdD5gEYI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/3049088911145552025/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2012/04/script-error-on-line-0.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/3049088911145552025?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/3049088911145552025?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/K-3pdD5gEYI/script-error-on-line-0.html" title="&quot;Script Error&quot; on line 0" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>3</thr:total><feedburner:origLink>http://blog.errorception.com/2012/04/script-error-on-line-0.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkIHQXw4fyp7ImA9WhVXE00.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-4109358459640413925</id><published>2012-04-13T12:32:00.000+05:30</published><updated>2012-04-13T12:32:10.237+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-04-13T12:32:10.237+05:30</app:edited><title>New Pricing Slab: $5/month!</title><content type="html">&lt;h3&gt;$5/month, 500 errors/day&lt;/h3&gt;
&lt;p&gt;You wanted a cheaper plan, so we created one! For only $5/month you find out about upto 500 JS errors everyday that your users encounter on your site! It doesn't get much cheaper than this.&lt;/p&gt;
&lt;p&gt;Just because it's cheaper, don't think that it's worse. &lt;i&gt;You get all the features&lt;/i&gt; of the more expensive plans &amp;mdash; high performance fail-safe error tracking, powerful grouping and aggregation to keep the noise low, flexible filters to let you slice and dice your errors, and above all, peace of mind knowing that you aren't in the dark about errors your users encounter.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/5W0PqNz6c-Q" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/4109358459640413925/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2012/04/new-pricing-slab-5month.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/4109358459640413925?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/4109358459640413925?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/5W0PqNz6c-Q/new-pricing-slab-5month.html" title="New Pricing Slab: $5/month!" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://blog.errorception.com/2012/04/new-pricing-slab-5month.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEAFQ30-eCp7ImA9WhVQEUw.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-2539156257040156955</id><published>2012-03-30T19:41:00.000+05:30</published><updated>2012-03-30T19:41:52.350+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-03-30T19:41:52.350+05:30</app:edited><title>The Tale of an Unfindable JS Error</title><content type="html">&lt;p&gt;At &lt;a href="http://errorception.com/"&gt;Errorception&lt;/a&gt;, I genuinely care about making people's front-end code bug-free. Often this means that when people email me asking for help with bugs they are seeing, I wholeheartedly help them track down and fix the bug.&lt;/p&gt;
&lt;p&gt;Today morning I woke up to an email from a user, asking about a bug that had occurred nearly 4,000 times in the last two days!&lt;/p&gt;
&lt;blockquote&gt;Hey Rakesh,&lt;br/&gt;&lt;br /&gt;
This just showed up yesterday, and I'm really stumped by it. It's only on Chrome 18/19, and it's put us way over the daily limit.&lt;br /&gt;&lt;br /&gt;
&amp;lt;link to the bug&amp;gt;&lt;br /&gt;&lt;br /&gt;
Just wondering if you seen it before, as I found one reference to it being caused by the Twitter widget (&lt;a href="https://gist.github.com/1878283"&gt;https://gist.github.com/1878283&lt;/a&gt;). I've grep'd every piece of JS looking for it, but haven't found one mention. Any ideas?&lt;br /&gt;&lt;br /&gt;
&amp;lt;snip&amp;gt;&lt;/blockquote&gt;
&lt;p&gt;I rubbed my eyes and got ready to start looking at the user's site, almost certain that he must've missed something. I mean, how could he have an error in his site and not have a source for the error? That just doesn't make sense.&lt;/p&gt;
&lt;p&gt;Looking at the error report, this is what it said:&lt;/p&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-wunKHyzfq0k/T3WLTa_QTlI/AAAAAAAAABg/iUtsYcEyuxo/s1600/Error%2Bcaught%2B%2B%2BUncaught%2BTypeError%2B%2BCannot%2Bread%2Bproperty%2B%2BoriginalCreateNotification%2B%2Bof%2Bundefined%2B%2B%2B%2Berrorception%2B.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="240" width="400" src="http://1.bp.blogspot.com/-wunKHyzfq0k/T3WLTa_QTlI/AAAAAAAAABg/iUtsYcEyuxo/s400/Error%2Bcaught%2B%2B%2BUncaught%2BTypeError%2B%2BCannot%2Bread%2Bproperty%2B%2BoriginalCreateNotification%2B%2Bof%2Bundefined%2B%2B%2B%2Berrorception%2B.png" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;&lt;h3&gt;Uncaught TypeError: Cannot read property "originalCreateNotification" of undefined&lt;/h3&gt;
&lt;p&gt;It's an inline error on the page, not an external JS file. &lt;q&gt;This just has to be something on the site&lt;/q&gt;, I thought to myself. Hit the page, viewed the source, and there was nothing there. &lt;q&gt;That's weird&lt;/q&gt; I thought, because Chrome usually does a good job of reporting line numbers correctly.&lt;/p&gt;
&lt;p&gt;As I was brushing my teeth, I got the feeling that I had heard about this error before. &lt;q&gt;&lt;code&gt;originalCreateNotification&lt;/code&gt;. Where had I heard about this before?&lt;/q&gt; Toothbrush still in my mouth, I did a quick Google search. The only sensible hits were the gist the user mentioned above, and a StackOverflow question where the poster was asking for help with his code. His code used a variable called &lt;code&gt;originalCreateNotification&lt;/code&gt;. &lt;q&gt;That's an interesting coincidence&lt;/q&gt; I thought to myself, but I was sure that that's not where I had heard about this bug. Then, I decided to search my mailbox for this bug, wondering if someone had emailed me about it before.&lt;/p&gt;
&lt;p&gt;There I found it. Another user had once mailed me about this error, and that it had occurred 17,000 times within a few minutes, all from the same client! I recollected that we had tried to track down the bug for quite some time, but we couldn't. The error interestingly never happened again. We just let the matter be, hoping to never see the bug again.&lt;/p&gt;
&lt;p&gt;Two different users facing the same bug! Both the cases were in Chrome, and on line 4! &lt;q&gt;That's just too much of a coincidence&lt;/q&gt;, I thought. &lt;q&gt;Something's going on here.&lt;/q&gt;&lt;/p&gt;
&lt;h3&gt;Twitter?&lt;/h3&gt;
&lt;p&gt;I jumped to &lt;a href="https://gist.github.com/1878283"&gt;the gist&lt;/a&gt; that we had found. It was authored by &lt;a href="http://www.pamelafox.org/"&gt;Pamela Fox&lt;/a&gt;. I have tremendous respect for Pamela, and I know that &lt;a href="http://blog.pamelafox.org/2011/10/client-side-error-logging.html"&gt;she has her own internal error reporting system&lt;/a&gt;. The gist is the code she uses to catch and post errors to the server. She has a list of errors she ignores because its unfixable, and &lt;code&gt;originalCreateNotification&lt;/code&gt; is one of them. Clearly, I wasn't the first to find this bug. She has a comment there, simply saying &lt;code&gt;// Twitter widget&lt;/code&gt;. So Twitter seems to be responsible for this problem. That also explains why two different users got the same error. &lt;q&gt;Case closed,&lt;/q&gt; I thought.&lt;/p&gt;
&lt;p&gt;Except, it didn't explain one little thing. How did Twitter generate so many errors in such a short time? It not unusual for files to be somehow unreachable at the client, so it's entirely possible that a small fraction of Twitter's widget users will face an error. However, that would just be an error or two. It can't be tens of thousands of errors. I decided to find out which Twitter widget this is, and find the bug in their code. So, I pulled up my user's page again to find the Twitter widget that he was using, so that I could start looking at Twitter's JS code. That's when the case became far more complex.&lt;/p&gt;
&lt;p&gt;The user didn't have any Twitter widgets on the site!&lt;/p&gt;
&lt;h3&gt;Is there anybody out there?&lt;/h3&gt;
&lt;p&gt;&lt;q&gt;Back to square one,&lt;/q&gt; I thought, as I prepared my green tea. By now, I was too deep into this. I wanted to find and solve the problem once and for all. Two of my users had already noticed this error, and it wasn't cool that I wasn't helping them fix it. How is it that no one else has mentioned the error on the web anywhere? Of course, one reason is that hardly anyone even tracks JS errors in the first place. It's a shame, I thought. Maybe a lot of people face this error and are completely unaware of it.&lt;/p&gt;
&lt;p&gt;Back at my laptop, I decided to &lt;code&gt;ssh&lt;/code&gt; into my server, and find any other occurrence of this error across all my error logs. Ran the query. 57 sites had seen this error occur at some time or the other! All of them with similar characteristics. They all occurred in short bursts, tens of thousands of times! And all of them were on Chrome, at line 4! I was onto something, but I wasn't sure what it was. I needed to get more information.&lt;/p&gt;
&lt;p&gt;So, I took all the user-agent strings of the browsers where this error occurred, and started looking at them for patterns. The browser version numbers were too varied to extract any meaningful information. &lt;q&gt;It seems to occur on all versions of Chrome,&lt;/q&gt; I thought. Not too useful. Dead end.&lt;p&gt;
&lt;h3&gt;OS specific?&lt;/h3&gt;
&lt;p&gt;&lt;q&gt;It can't be OS specific, can it?&lt;/q&gt; It didn't make sense for a bug in Chrome to be OS specific. That era of browser bugs is long gone, and I've never experienced such a thing with Chrome. In any case, I started mining the UA strings again, and found that it occurred on all versions of Mac and Windows. No dice. There wasn't a single instance of Linux, but that's probably just a coincidence, I thought. It may be because Linux has a &lt;a href="http://gs.statcounter.com/#os-ww-monthly-201102-201202"&gt;lower market-share&lt;/a&gt; on desktops.&lt;/p&gt;
&lt;p&gt;With no other lead, and almost ready to give up, I was staring at the Google search results page for &lt;code&gt;originalCreateNotification&lt;/code&gt;. Just two sensible hits. Pamela's gist, and a StackOverflow question. I decided to read &lt;a href="http://stackoverflow.com/questions/4627334/access-npapi-from-pages-dom"&gt;the StackOverflow question&lt;/a&gt; as I kept pondering what the cause of the error might be. The question read:&lt;/p&gt;
&lt;blockquote&gt;I'm attempting to override the default functionality for webkitNotifications.createNotification and via a Chrome extension I'm able to inject a script in the pages DOM that does so. [&amp;hellip;]&lt;/blockquote&gt;
&lt;p&gt;A Chrome Extension! Why didn't I think of that! I decided to find out more about the author of the question, and landed up on &lt;a href="http://marcoceppi.com/"&gt;his site&lt;/a&gt;, where he was advertising a Chrome Extension. Clicked through, and I landed up on the &lt;a href="https://chrome.google.com/webstore/detail/nmgdlkljbfeeinemfljcbmnkmbeligmn"&gt;Chrome Web Store&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;This extension is meant to create more native Webkit notifications on Linux Operating Systems which use the notify-osd notification framework. Notify-OSD is installed on Ubuntu by default and used for all system notifications.&lt;/blockquote&gt;
&lt;p&gt;This has to be it! It explains why the bug only exists on Chrome, why it occurred at the same place at all times, why it was independent of the site or its contents, and more importantly why it never occurred on Linux! Time to do a couple of quick checks to test my theory.&lt;/p&gt;
&lt;p&gt;Fortunately, the extension code is open-source. With my heart racing, I pulled up the repo, and started browsing it to find a mention of &lt;code&gt;originalCreateNotification&lt;/code&gt;, and &lt;a href="http://bazaar.launchpad.net/~chromify-osd-team/chromify-osd/trunk/view/head:/page.js"&gt;there it was&lt;/a&gt;, staring me in the face! It was clearly an extension designed for Linux, so it made sense that the author might not have tested it on other platforms. I decided to give it a spin. I installed it on my Mac, and BAM! My console filled up with &lt;code&gt;Uncaught TypeError: Cannot read property "originalCreateNotification" of undefined&lt;/code&gt;, on line 4!&lt;/p&gt;
&lt;p&gt;I don't think I've been happier seeing an error.&lt;/p&gt;
&lt;p&gt;I've now filed &lt;a href="https://bugs.launchpad.net/chromify-osd/+bug/968858"&gt;a bug report&lt;/a&gt;, asking the author to do what he can to make the extension fail gracefully on Mac and Windows. Meanwhile, I've added &lt;code&gt;originalCreateNotification&lt;/code&gt; to my blacklist, so that none of my users will ever see this problem again.&lt;p&gt;
&lt;p&gt;Another day, another bug squashed. Just another perk of working with &lt;a href="http://errorception.com/"&gt;Errorception&lt;/a&gt;. You are tracking JS errors, aren't you? If you aren't, &lt;a href="http://errorception.com"&gt;start now&lt;/a&gt;!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/h-khhn--HKg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/2539156257040156955/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2012/03/tale-of-unfindable-js-error.html#comment-form" title="8 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/2539156257040156955?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/2539156257040156955?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/h-khhn--HKg/tale-of-unfindable-js-error.html" title="The Tale of an Unfindable JS Error" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-wunKHyzfq0k/T3WLTa_QTlI/AAAAAAAAABg/iUtsYcEyuxo/s72-c/Error%2Bcaught%2B%2B%2BUncaught%2BTypeError%2B%2BCannot%2Bread%2Bproperty%2B%2BoriginalCreateNotification%2B%2Bof%2Bundefined%2B%2B%2B%2Berrorception%2B.png" height="72" width="72" /><thr:total>8</thr:total><feedburner:origLink>http://blog.errorception.com/2012/03/tale-of-unfindable-js-error.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUYDQX0yfCp7ImA9WhRaEU8.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-7409522603578664596</id><published>2012-02-13T14:22:00.000+05:30</published><updated>2012-02-13T14:22:50.394+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-13T14:22:50.394+05:30</app:edited><title>Slicing and Dicing Errors</title><content type="html">&lt;p&gt;
The &lt;a href="http://errorception.uservoice.com/forums/132896-suggestions-and-feedback/suggestions/2362537-reset-button"&gt;most up-voted feature request&lt;/a&gt; on &lt;a href="http://errorception.uservoice.com/forums/132896-suggestions-and-feedback"&gt;our UserVoice Forum&lt;/a&gt; had to do with slicing the errors list to see only a sub-section of the errors. The use case was this: Let's say you deployed code yesterday that fixed a bunch of your bugs. Now, you are particularly interested in bugs that happened since yesterday, since it'll tell you if your fix did indeed work and if any new bugs have been introduced. However, Errorception didn't allow any such slicing of errors. Until now.
&lt;/p&gt;
&lt;p&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-b9h2UfSB8MQ/TzU-MzuuBsI/AAAAAAAAABI/mv6-Y3oDKT8/s1600/Screen%2Bshot%2B2012-02-10%2Bat%2B9.26.00%2BPM.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="294" width="223" src="http://1.bp.blogspot.com/-b9h2UfSB8MQ/TzU-MzuuBsI/AAAAAAAAABI/mv6-Y3oDKT8/s400/Screen%2Bshot%2B2012-02-10%2Bat%2B9.26.00%2BPM.png" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;
Now, in your error listing, you will see a little sidebar that will let you slice and dice your errors list based on time, browser, and any combination of the two.
&lt;/p&gt;
&lt;h3&gt;JavaScript App&lt;/h3&gt;
&lt;p&gt;
To make the filters possible, and to provide the best UX, Errorception's error listing page is now rather JS-heavy. What this means for you is that you get a highly responsive UI, and you can interact with the filters mentioned above without having to go through painful page reloads. But this JS-driven UI has another benefit, one that is just awesome in the long term.
&lt;/p&gt;
&lt;h3&gt;Yo dawg, I herd you like Errorception&lt;/h3&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://knowyourmeme.com/memes/xzibit-yo-dawg" imageanchor="1" style="clear:right; float:right; margin-left:1em; margin-bottom:1em"&gt;&lt;img border="0" width="200" src="http://2.bp.blogspot.com/-dNWi0CKSrPc/TzWD8JGC2PI/AAAAAAAAABU/dZPzHuyWC4g/s200/Yo%252Bdawg%252Bi%252Bheard%252Byou%252Blike.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;
The most important change, is that now Errorception uses &amp;mdash; wait for it &amp;mdash; Errorception! I was never comfortable that I wasn't a heavy user of Errorception myself, but now that's fixed. I'll be actively using Errorception to find bugs in Errorception. Of course, this helps reduce errors. However, and more importantly, it helps me identify pain-points that everyone faces in the day-to-day use of Errorception. It ensures that the feature set of Errorception grows to have the right mix of the best features and ease of use.
&lt;/p&gt;
&lt;p&gt;
It was exciting to see that since I've pushed this build out, I've already caught two errors in the new JS. I have already fixed and deployed new code to address these issues! That's exciting!
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/WVqOcnrh5FM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/7409522603578664596/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2012/02/slicing-and-dicing-errors.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/7409522603578664596?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/7409522603578664596?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/WVqOcnrh5FM/slicing-and-dicing-errors.html" title="Slicing and Dicing Errors" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-b9h2UfSB8MQ/TzU-MzuuBsI/AAAAAAAAABI/mv6-Y3oDKT8/s72-c/Screen%2Bshot%2B2012-02-10%2Bat%2B9.26.00%2BPM.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.errorception.com/2012/02/slicing-and-dicing-errors.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A04FSXo5eSp7ImA9WhRUFEU.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-4897989328399096527</id><published>2012-01-25T16:41:00.000+05:30</published><updated>2012-01-25T16:41:58.421+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-25T16:41:58.421+05:30</app:edited><title>Now, Using CDN-Power!</title><content type="html">&lt;p&gt;
Using a CDN has been on my list for some time now, and I've finally gotten around to configuring one. I just changed the tracking snippet to use Amazon's CloudFront CDN, ensuring that the tracking snippet is edge-cached at over 25 locations world-wide, in North America, South America, Europe and Asia. This means that your users will get the least possible delay in loading Errorception's tracking code. Your users get blazing high performance by default! And boy, do we at Errorception love high performance. :)
&lt;/p&gt;
&lt;p&gt;
This change is being rolled out all of Errorception's users, whether on the free trial or on any of the paid plans, at no extra cost.
&lt;/p&gt;
&lt;h3&gt;Action required&lt;/h3&gt;
&lt;p&gt;
Unfortunately, to use the CDN you will have to change your tracking snippet in your site. &lt;a href="http://errorception.com/login"&gt;Log in&lt;/a&gt;, and go over to Settings &gt; Tracking Snippet to get your new tracking snippet, and replace the old tracking snippet in your site with the new one. I know it's a chore &amp;mdash; I apologize for the inconvenience. However, the benefits far outweigh the little trouble.
&lt;/p&gt;
&lt;p&gt;
While the old tracking snippet will continue to work for some more time, I urge you to upgrade soon so that you can make the most of the CDN. At some point in the not-too-distant future, the old tracking snippet will not be supported anymore.
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/LD3CD3uSApg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/4897989328399096527/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2012/01/now-using-cdn-power.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/4897989328399096527?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/4897989328399096527?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/LD3CD3uSApg/now-using-cdn-power.html" title="Now, Using CDN-Power!" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://blog.errorception.com/2012/01/now-using-cdn-power.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0MDSXwzcSp7ImA9WhRVF0g.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-6428124269971147362</id><published>2012-01-17T03:34:00.000+05:30</published><updated>2012-01-17T03:34:38.289+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-17T03:34:38.289+05:30</app:edited><title>Writing Quality Third-Party JS - Part 3: Planning for an API</title><content type="html">&lt;p&gt;
In the &lt;a href="http://blog.errorception.com/2012/01/writing-quality-third-party-js-part-1.html"&gt;first post&lt;/a&gt; in this series, I wrote about the fact that you don't own the page, and how that affects even little things in your code. In the &lt;a href="http://blog.errorception.com/2012/01/writing-quality-third-party-js-part-2.html"&gt;second post&lt;/a&gt; in the series, I dived into a good deal of detail about how to bootstrap your code. In this third and final part of the series, I'll talk about how to make an API available to your users, and how to communicate with your server.
&lt;/p&gt;
&lt;p style="padding: 10px; border: 1px solid #ccc; background: #eee; font-size: 12px;"&gt;
This is a three-part series of articles aimed at people who want to write JavaScript widgets (or other kinds of scripts) to make their application's data/services/UI available on other websites. This is the third in the series, discussing means to making an API available to your users, and communicating with your server.
&lt;/p&gt;
&lt;h3&gt;So you want to provide an API&lt;/h3&gt;
&lt;p&gt;
Why is this such a big deal? I mean, look at jQuery, or any library for that matter, right? You add a script tag to the page, and you have the API ready to use, right? How is this any different for a third-party script?
&lt;/p&gt;
&lt;p&gt;
It's different depending on the way you choose to load your code. In &lt;a href="http://blog.errorception.com/2012/01/writing-quality-third-party-js-part-2.html"&gt;Part 2: Loading Your Code&lt;/a&gt;, we went over why your code should be loaded asynchronously. We'll get back to that in a moment. Let's first consider the really bad case when your loading strategy requires that your code is loaded synchronously &amp;mdash; Twitter's @Anywhere API, for example.
&lt;/p&gt;
&lt;p&gt;
Again, to clarify, I'm sure Twitter has got their reasons to do what they do. I'm still going to call it &lt;q&gt;bad&lt;/q&gt; because it is something you should not do.
&lt;/p&gt;
&lt;p&gt;
So, from &lt;a href="https://dev.twitter.com/docs/anywhere/welcome"&gt;Twitter's examples&lt;/a&gt;:
&lt;/p&gt;
&lt;script src="https://gist.github.com/1622976.js?file=twitter_anywhere_api.html"&gt;&lt;/script&gt;
&lt;p&gt;
This is really the simplest way to define an API. It's similar to how JS libraries, like jQuery, work. Add a script tag, and then use the library's code. Simple enough. Except, for reasons explained in Part 2, we should load our code in an asynchronous fashion.
&lt;/p&gt;
&lt;h4&gt;Asynchronous loading&lt;/h4&gt;
&lt;p&gt;
If your code is loaded in an asynchronous fashion, it means that the browser's parser will continue parsing and evaluating other script tags on the page before your own script is evaluated. This is great of course &amp;mdash; it means that you have stepped out of the way when loading the page. Unfortunately, this also means that if someone attempts to access your API namespace, they might get errors, depending on whether your code has been downloaded and evaluated already or not. You now need a way of signaling to your API consumer that your code is ready to use. &lt;a href="http://developers.facebook.com/docs/reference/javascript/"&gt;Facebook's documentation&lt;/a&gt; talks about how they do this, from the API consumer's perspective:
&lt;/p&gt;
&lt;script src="https://gist.github.com/1622985.js?file=fbAsyncInit.html"&gt;&lt;/script&gt;
&lt;p&gt;
What Facebook requires you to do is to declare a global function called &lt;code&gt;fbAsyncInit&lt;/code&gt;. When Facebook's JS SDK has loaded, it checks for the existence of this function in the global object (&lt;code&gt;window&lt;/code&gt;), and then simply calls it if it exists. In fact, here are the relevant lines from the SDK that call this function:
&lt;/p&gt;
&lt;script src="https://gist.github.com/1622992.js?file=fbJSSdkCheck.js"&gt;&lt;/script&gt;
&lt;p&gt;
The &lt;code&gt;hasRun&lt;/code&gt; is irrelevant to us &amp;mdash; it's an internal detail to Facebook. But note how they explictly check if the function exists, and if it does, they call it. I've removed an outer wrapper here for clarity &amp;mdash; The code above is called in a &lt;code&gt;setTimeout(0)&lt;/code&gt; to ensure that it's at the end of the execution stack. Chances are, you'd want to wait till the end of the execution stack too. You could either wait explicitly till the end, or fire it off as a &lt;code&gt;setTimeout&lt;/code&gt;, like Facebook does.
&lt;/p&gt;
&lt;p&gt;To drive home the point, the flow works as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Before starting to load the code, ask the user to define a global function that should be called when the third-party code has finished loading.&lt;/li&gt;
&lt;li&gt;Start loading the third-party code asynchronously.&lt;/li&gt;
&lt;li&gt;In the third-party code, when the code has finished loading, call the global function if it has been defined.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
There are minor variations one can make on the pattern above. One I'd like to make is that of removing the need for a global function. I'd agree that it's a bit nit-picky to remove just one global variable, but take it for what it's worth.
&lt;/p&gt;
&lt;script src="https://gist.github.com/1623014.js?file=fbWithoutFbAsyncInit.html"&gt;&lt;/script&gt;
&lt;p&gt;
The improvement is that &lt;code&gt;fbAsyncInit&lt;/code&gt; has been replaced by &lt;code&gt;FB.onReady&lt;/code&gt;. This removes the need for the global function definition. Also, when the FB's SDK loads, it will continue to use the FB namespace, so no more globals are created.
&lt;/p&gt;
&lt;p&gt;
For APIs that are as complex as Facebook's, I think this is the best that can be done without adding more complexity. There are many more interesting things that can be done if you are willing to embrace say &lt;a href="http://requirejs.org/docs/whyamd.html"&gt;AMD support&lt;/a&gt;, but this is the very least required.
&lt;/p&gt;
&lt;h4&gt;Other uses of having a predefined global&lt;/h4&gt;
&lt;p&gt;
There are other uses of having a predefined global. For example, it could house all your initialization parameters. In FB's case, it might need the API key before making any API calls. This could be configured as members in the &lt;code&gt;FB&lt;/code&gt; object, even before the API is actually loaded.
&lt;/p&gt;
&lt;h4&gt;But Facebook is complex&lt;/h4&gt;
&lt;p&gt;
Sometimes, APIs are not as rich as Facebook's. Facebook's API is rich, and allows for both reads and writes. Usually, widgets/snippets are much simpler than that.
&lt;/p&gt;
&lt;h4&gt;Write-only APIs&lt;/h4&gt;
&lt;p&gt;
This requires special mention, since the most frequently used third-party APIs are usually invisible, write-only APIs (ref: end of &lt;a href="http://www.webperformancetoday.com/2011/10/13/how-vulnerable-is-your-site-to-third-party-failure/"&gt;this post&lt;/a&gt;). Take Google Analytics for example. It only collects data from the page, and posts them to Google's servers. It doesn't read anything from Google's servers - it doesn't need to. The API is a classic write-only API. In such a case, initialization can be simplified drastically. In fact, this is what &lt;a href="http://errorception.com"&gt;Errorception&lt;/a&gt; itself does too &amp;mdash; admittedly blatantly copying the technique from GA.
&lt;/p&gt;
&lt;p&gt;
If you follow this technique, you don't need a global &lt;code&gt;onReady&lt;/code&gt; function to be defined, since it is immaterial to know when the code has loaded. All you need a &lt;q&gt;queue&lt;/q&gt; that needs to be flushed to the server. This &lt;q&gt;queue&lt;/q&gt; can be maintained as an array of ordered items. Since arrays already have a &lt;code&gt;.push&lt;/code&gt; method on them, that is your API method! It's that simple!
&lt;/p&gt;
&lt;p&gt;
So, both Google Analytics, and learning from it, Errorception, have a &lt;code&gt;.push&lt;/code&gt; method on their only global variable (&lt;code&gt;_gaq&lt;/code&gt; / &lt;code&gt;_errs&lt;/code&gt;), because this global variable is essentially just a regular array! See how it's set up:
&lt;/p&gt;
&lt;script src="https://gist.github.com/1623022.js?file=_gaqAsAnApi.html"&gt;&lt;/script&gt;
&lt;p&gt;
This doesn't stop you from doing what you'd expect a decent write API to do. For example, GA let's you do a bunch of configuration and record custom data, all &lt;a href="http://code.google.com/apis/analytics/docs/gaJS/gaJSApi_gaq.html#_gaq.push"&gt;using just the &lt;code&gt;.push&lt;/code&gt; method&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
In Errorception's case, we are recording JS errors, and despite the need to load our code late and asynchronously, errors must be caught as early as possible. So, we start populating this queue as early as possible. Our embed code itself does this, using the &lt;code&gt;window.onerror&lt;/code&gt; event.
&lt;/p&gt;
&lt;script src="https://gist.github.com/1623028.js?file=_errsAsAnApi.html"&gt;&lt;/script&gt;
&lt;p&gt;
This way, errors are caught very early in the page lifecycle, without compromising performance one bit. Once our code has loaded, we simply start processing this &lt;q&gt;queue&lt;/q&gt; to flush it to the server. Once the queue has been completely flushed for the first time, we simply redefine the global &lt;code&gt;_errs&lt;/code&gt; object to now be an object (instead of an array), with just one &lt;code&gt;.push&lt;/code&gt; method on it. So, all existing push calls will continue to work, and when push is called we can directly trigger internal code. This might break if someone has got a reference to the &lt;code&gt;_errs&lt;/code&gt; object, and I decide to change the global. An alternative would be to leave the array untouched, and to poll the array to check for new members. Since polling just seems inefficient, and at the moment I don't have a public API anyway, I opted for redefining &lt;code&gt;.push&lt;/code&gt;.
&lt;/p&gt;
&lt;p&gt;
It's hard to read &lt;a href="http://www.google-analytics.com/ga.js"&gt;the minified code from Google Analytics&lt;/a&gt;, but it appears that Google does the exact same thing. They too seem to be redefining the global &lt;code&gt;_gaq&lt;/code&gt; to add a &lt;code&gt;.push&lt;/code&gt; that points to an internal method.
&lt;/p&gt;
&lt;h3&gt;Communicating with your server&lt;/h3&gt;
&lt;p&gt;
There are established ways to bypass the browser same-origin policy and communicate with remote servers across domains. Though usually considered to be hacks, there's no way around them in third-party scripts. Let's quickly round-up the most common techniques.
&lt;/p&gt;
&lt;h4&gt;Make an image request with a query string&lt;/h4&gt;
&lt;p&gt;
This is the technique Google Analytics uses. When the queue is flushed, the data is encoded into query strings, and an &lt;a href="https://developer.mozilla.org/en/Canvas_tutorial/Using_images#Creating_an_image_from_scratch"&gt;Image object&lt;/a&gt; is created, to load a image with the data passed in as a query string. Though the server responds with a simple enough 1x1 gif since it has to play well with the page, the query string data is recorded as what the client had to say.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;: Simple, non-obtrusive since the DOM is not affected. (The image need not be appended to the DOM.) Works everywhere.&lt;br /&gt;&lt;strong&gt;Cons&lt;/strong&gt;: Ideal only for client-to-server communication. Not the best way to have a two-way communication. Have to consider &lt;a href="http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url"&gt;URL length limits&lt;/a&gt;. Can only use HTTP GETs.&lt;/p&gt;
&lt;h4&gt;JSON-P&lt;/h4&gt;
&lt;p&gt;
You can alternatively create a &lt;a href="http://remysharp.com/2007/10/08/what-is-jsonp/"&gt;JSON-P&lt;/a&gt; request. This is in essence similar to the image technique above, except that instead of creating a image object, we create a script tag. It comes with the down-side that we'll be creating script tags each time we want to tell the server something (and hence we'll have to aggressively clean up), but also has the upside that we have two-way communication since we can listen to what the server has to say.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;: Still simple. Two way communication, since the server can respond meaningfully. Works everywhere. Excellent when you want to read data from the server.&lt;br /&gt;
&lt;strong&gt;Cons&lt;/strong&gt;: Still have to consider URL length limits. Only HTTP GETs. Requires DOM cleanup.&lt;/p&gt;
&lt;h4&gt;Posting in hidden iframes&lt;/h4&gt;
&lt;p&gt;
This is the technique Errorception uses. In this method, we create a hidden iframe, post a form to that iframe, wait for the iframe to finish loading, then destroy the iframe. The data is sent to the server as POST parameters, but the response is not readable due to the domains not matching any more after the iframe has been POSTed.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;: Simple. HTTP semantics respected. Works everywhere. URL length limits don't apply.&lt;br /&gt;
&lt;strong&gt;Cons&lt;/strong&gt;: Only client-to-server communication. Requires DOM cleanup.&lt;/p&gt;
&lt;h4&gt;CORS&lt;/h4&gt;
&lt;p&gt;
Errorception will soon be moving to &lt;a href="http://www.html5rocks.com/en/tutorials/cors/"&gt;CORS&lt;/a&gt; while maintaining the iframes approach for backwards compatibility. The benefits over the iframe based approach for us is that there is no DOM cleanup required. Another obvious benefit is that you can read the response of the request as well, though this is not very critical for the fire-and-forget nature of write APIs like Errorception's.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;: Full control on HTTP semantics. No data size limits. No DOM alterations.
&lt;strong&gt;Cons&lt;/strong&gt;: Only works in newer browsers, hence must be supported by another method for the time being.&lt;/p&gt;
&lt;h4&gt;More elaborate hacks&lt;/h4&gt;
&lt;p&gt;Hacks can get pretty elaborate, of course. I had discussed on my personal blog a couple of years ago how we can &lt;a href="http://blog.rakeshpai.me/2007/11/how-to-build-readwrite-javascript-api.html"&gt;use nested iframes&lt;/a&gt; to devise a ugly but workable method of establishing read-write communication. This was at a time when CORS wasn't around yet. Even today, you'd need this mechanism to deal with older browsers. This should be superseded by CORS now, though. Facebook still uses this as a fallback for older browsers, as do other read-write APIs like Google Calendar.&lt;/p&gt;
&lt;h3&gt;Wrapping up&lt;/h3&gt;
&lt;p&gt;
This has been one massive article series! We've very quickly covered several topics to do with creating high quality third-party JS. This gives a decent birds-eye-view of the factors to consider, and possible solutions to problems, if you want to act like a well behaved citizen on the page. There's so much more details we can get into, but I have to draw the line somewhere. :)&lt;/p&gt;
&lt;p&gt;Do let me know what you think in the comments. Have you come across other problems in writing your own third-party JS? What fixes did you use? I'll be only glad to know more.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/-wsjO9ec63Q" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/6428124269971147362/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2012/01/writing-quality-third-party-js-part-3.html#comment-form" title="9 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/6428124269971147362?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/6428124269971147362?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/-wsjO9ec63Q/writing-quality-third-party-js-part-3.html" title="Writing Quality Third-Party JS - Part 3: Planning for an API" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>9</thr:total><feedburner:origLink>http://blog.errorception.com/2012/01/writing-quality-third-party-js-part-3.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEcDQn4zfyp7ImA9WhRVF0g.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-2320883898666441184</id><published>2012-01-11T20:44:00.000+05:30</published><updated>2012-01-17T04:51:13.087+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-17T04:51:13.087+05:30</app:edited><title>Writing Quality Third-Party JS - Part 2: Loading Your Code</title><content type="html">&lt;p&gt;
In the previous post &lt;a href="http://blog.errorception.com/2012/01/writing-quality-third-party-js-part-1.html"&gt;Writing Quality Third-Party JS - Part 1: The First Rule&lt;/a&gt;, I wrote about the fact that you don't own the page, and how that affects even little things in your code. With that background, this post focuses on how to load your code in the host page.
&lt;/p&gt;
&lt;p style="padding: 10px; border: 1px solid #ccc; background: #eee; font-size: 12px;"&gt;
This is a three-part series of articles aimed at people who want to write JavaScript widgets (or other kinds of scripts) to make their application's data/services/UI available on other websites. This is the second in the series, tackling the topic of loading your code in the host page.
&lt;/p&gt;
&lt;h3&gt;Bootstrapping&lt;/h3&gt;
&lt;p&gt;
Remember how &lt;a href="http://blog.errorception.com/2012/01/writing-quality-third-party-js-part-1.html"&gt;in my last post&lt;/a&gt; I kept harping on that you don't own the page? It applies here too. Two factors to consider are:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Can the network performance effects of downloading your code be eliminated completely?&lt;/li&gt;
&lt;li&gt;If your servers ever go down, will it affect the host page at all?&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;What's wrong with a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag?&lt;/h4&gt;
&lt;p&gt;
I won't go into too much detail here since it has been written about in enough detail elsewhere, but just to quickly summarize: a script tag will block download of resources on your page AND will block the rendering of the page. It's what Steve Souders calls the &lt;a href="http://www.stevesouders.com/blog/2010/06/01/frontend-spof/"&gt;Frontend Single Point of Failure&lt;/a&gt;. You don't want to be a point of failure.
&lt;/p&gt;
&lt;p&gt;
It surprises me then, that Twitter not only requires you to include a vanilla script tag, but also that you should put it in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; of your page. This is despite it being common knowledge at the time of the launch of their @Anywhere APIs that this is a bad practice. In fact, on the contrary, &lt;a href="https://dev.twitter.com/docs/anywhere/welcome"&gt;they say in their docs&lt;/a&gt;:
&lt;/p&gt;
&lt;blockquote&gt;
As a best practice always place the anywhere.js file as close to the top of the page as possible.
&lt;/blockquote&gt;
&lt;p&gt;
Now, I don't mean to make them look bad &amp;mdash; they are smart people and know what they are doing. What I'm saying is that I can't think of any reason to do this. &lt;a href="https://dev.twitter.com/docs/anywhere/welcome#best-practices"&gt;They claim&lt;/a&gt; that it's for a better experience with OAuth 2.0 authentication, but I'm not convinced. I'd recommend that you do not use Twitter's model as an example for how to load your script. There are much better mechanisms available.
&lt;/p&gt;
&lt;p&gt;
To be fair, even &lt;a href="http://code.google.com/apis/analytics/docs/tracking/gaTrackingOverview.html"&gt;Google Analytics was doing something very similar&lt;/a&gt; until recently, but at least they asked for the script tag to be before the closing &lt;code&gt;&amp;lt;/body&amp;gt;&lt;/code&gt; tag. They've since deprecated this technique anyway.
&lt;/p&gt;
&lt;h4&gt;Eliminating the performance hit&lt;/h4&gt;
&lt;p&gt;
Realize that my first point above isn't about &lt;b&gt;reducing&lt;/b&gt; the performance cost, but about &lt;b&gt;eliminating&lt;/b&gt; it. Techniques for reducing the performance hit are already well known &amp;mdash; caching and expiry, CDNs, etc. That said, how much ever you reduce the performance hit, there is still a performance hit anyway. How can this be eliminated?
&lt;/p&gt;
&lt;h4&gt;&lt;code&gt;async&lt;/code&gt; FTW?&lt;/h4&gt;
&lt;p&gt;
HTML(5) introduced the &lt;a href="https://developer.mozilla.org/En/HTML/Element/Script#attr-async"&gt;&lt;code&gt;async&lt;/code&gt; attribute&lt;/a&gt;, which instructs the browser's parser-renderer to load the file asynchronously, while continuing to render the page as usual. This is a life-saver, but unfortunately not good enough for use just yet.
&lt;/p&gt;
&lt;p&gt;
Why isn't it good enough? Because it &lt;a href="http://stackoverflow.com/questions/1834077/which-browsers-support-script-async-async/6766189#6766189"&gt;isn't supported in older browsers&lt;/a&gt;, including IE9 and lower. Considering that IE is a large part of the browser market, and as of right now IE10 isn't in lay-people's hands yet, you will need to do better than slap on an &lt;code&gt;async&lt;/code&gt; attribute on your script tag. The &lt;code&gt;async&lt;/code&gt; attribute is amazing, just not ready yet.
&lt;/p&gt;
&lt;h4&gt;Dynamic script tag creation&lt;/h4&gt;
&lt;p&gt;
Another way to load your code is to create a script tag dynamically. Nicholas Zakas has gone into details about this technique &lt;a href="http://www.nczonline.net/blog/2009/06/23/loading-javascript-without-blocking/"&gt;in a blog post&lt;/a&gt;, so I won't mention it all here. I'll just show his code here instead:
&lt;/p&gt;
&lt;script src="https://gist.github.com/1594911.js?file=ncz-loader.html"&gt;&lt;/script&gt;
&lt;p&gt;
Seems simple enough. He uses DOM methods to create a script tag, and then appends it to the page. As &lt;a href="http://www.stevesouders.com/blog/2009/04/27/loading-scripts-without-blocking/"&gt;Souders has explained&lt;/a&gt;, this technique causes the script to be downloaded immediately, but asynchronously. This is usually what you want. In fact, this is the approach Facebook takes &lt;a href="http://developers.facebook.com/docs/reference/javascript/"&gt;to load their JavaScript SDK&lt;/a&gt;, though they append to the head instead of the body, which also has the same effect.
&lt;/p&gt;
&lt;script src="https://gist.github.com/1594914.js?file=fb-loader.html"&gt;&lt;/script&gt;
&lt;p&gt;
There's a minor improvement that has been common knowledge since some time now. Remember in my previous post I said that you cannot make any assumptions about the page? The snippets above assume that &lt;code&gt;document.body&lt;/code&gt; or &lt;code&gt;document.getElementsByTagName("head")[0]&lt;/code&gt; reliably exists for use. Turns out, &lt;a href="http://www.stevesouders.com/blog/2010/05/11/appendchild-vs-insertbefore/"&gt;that assumption might be wrong&lt;/a&gt;. So, the minor improvement is to not depend on &lt;code&gt;document.body&lt;/code&gt; or the &lt;code&gt;head&lt;/code&gt;. Instead, only assume that at least one script tag exists on the page. This assumption is always right, since that's how your code is running in the first place. So, instead of appending to &lt;code&gt;document.body&lt;/code&gt;, do what &lt;a href="http://code.google.com/apis/analytics/docs/tracking/asyncTracking.html"&gt;Google does&lt;/a&gt;:
&lt;/p&gt;
&lt;script src="https://gist.github.com/1594920.js?file=ga-loader.html"&gt;&lt;/script&gt;
&lt;p&gt;
The code inside the &lt;del&gt;self-executing anonymous function&lt;/del&gt; &lt;ins&gt;immediately invoked function&lt;/ins&gt; (&lt;a href="http://blog.errorception.com/2012/01/writing-quality-third-party-js-part-1.html?showComment=1326165452474#c2903191727875292943"&gt;hat-tip&lt;/a&gt;) creates the script tag, and then appends it as a sibling of the first script tag on the page. It doesn't matter which the first script tag is &amp;mdash; we rely on the fact that a script tag surely exists on the page. We also rely on the fact that the script tag has a &lt;code&gt;parentNode&lt;/code&gt;. Turns out, this is a safe assumption to make.
&lt;/p&gt;
&lt;p&gt;
Both these scripts set &lt;code&gt;script.async = true;&lt;/code&gt;. I'm unsure why they do this. Firefox's documentation implies that &lt;a href="https://developer.mozilla.org/En/HTML/Element/Script#attr-async"&gt;this is not necessary in Firefox, IE, or Webkit&lt;/a&gt;:
&lt;/p&gt;
&lt;blockquote&gt;
In Firefox 4.0, the async DOM property defaults to true for script-created scripts, so the default behavior matches the behavior of IE and WebKit.
&lt;/blockquote&gt;
&lt;p&gt;&lt;strike&gt;I guess there's no harm done in setting the &lt;code&gt;async&lt;/code&gt; flag to true, so everyone just does it. Either that, or I simply don't know.&lt;/strike&gt; As pointed by Steve Souders in a comment below, &lt;code&gt;async=true&lt;/code&gt; is required for some edge-case browsers, including Firefox 3.0.&lt;/p&gt;
&lt;h4&gt;But when does the download happen?&lt;/h4&gt;
&lt;p&gt;
All browsers that implement &lt;code&gt;async&lt;/code&gt; start the download immediately and asynchronously. This means that your script will be parsed and executed at some time in the future. The question I had at this point was: At what point in the page load cycle does my script get evaluated? Does &lt;code&gt;onload&lt;/code&gt; get blocked? This addresses my second point at the top of the post. There might be situations when my script is unreachable due to either server or network problems, and I didn't want &lt;a href="http://errorception.com/"&gt;Errorception&lt;/a&gt; to affect any other scripts on the page in such a situation.
&lt;/p&gt;
&lt;p&gt;
So, I ran quick tests to find the answer, and unsurprisingly the answer is &lt;q&gt;you can't be sure&lt;/q&gt;. Just today, Steve Souders published a &lt;a href="http://stevesouders.com/tests/jsorder.php"&gt;browser-scope test page&lt;/a&gt; that tests just this behavior. It looks like older implementations of &lt;code&gt;async&lt;/code&gt; were indeed holding back page load events. This seems to be getting phased out in newer versions of browsers. If I were writing the tracking snippet today, I would probably have used the technique mentioned above.
&lt;/p&gt;
&lt;p&gt;
Instead, I decided to do slightly better than these techniques while coding the Errorception tracking script. I decided that I'll explicitly wait for the page &lt;code&gt;onload&lt;/code&gt; to fire first, and only then include the Errorception tracking script. The tracking snippet in Errorception's case looks as follows:
&lt;/p&gt;
&lt;script src="https://gist.github.com/1594924.js?file=errorception-loader.html"&gt;&lt;/script&gt;
&lt;p&gt;
The snippet above completely gets out of the way during the page load process, hence ensuring that we do not depend on browser behavior of event firing sequences when using the &lt;code&gt;async&lt;/code&gt; attribute. It has an additional minor benefit that the end user's bandwidth is completely available for loading up the site's intended resources first before loading the Errorception tracking code. Effectively, it prioritizes the site's code and content over Errorception's own code. This fits in perfectly with Errorception's philosophy of not affecting page load time at all. Depending on the type of connection the end-user has, this bandwidth-prioritization technique might have merits.
&lt;/p&gt;
&lt;p&gt;
I'll be the first to admit that what Errorception is doing might not be for everyone. Take Facebook for example. If you are including their API, chances are, you want to do something with it. Delaying the loading will only deteriorate the end-user experience. However, in Errorception's case, there's no such interaction that will ever block, so this works out fine.
&lt;/p&gt;
&lt;p&gt;
I initially thought I'll discuss about APIs as well in this post, but the post has seemed to run too long already. I'll save that bit for the next post.
&lt;/p&gt;
&lt;p style="padding: 10px; border: 1px solid #ccc; background: #eee; font-size: 12px;"&gt;
Errorception is a ridiculously easy-to-use JavaScript error tracking system, designed for high performance and high reliability. There's a free trial so you can give it a spin. &lt;a href="http://errorception.com"&gt;Find out more &amp;raquo;&lt;/a&gt;
&lt;/p&gt;
&lt;h4&gt;In Part 3&amp;hellip;&lt;/h4&gt;
&lt;p&gt;
In &lt;a href="http://blog.errorception.com/2012/01/writing-quality-third-party-js-part-3.html"&gt;the next post in the series&lt;/a&gt;, I'll discuss mechanisms to signal the availability of your APIs to your developers considering that your code is downloaded at some arbitrary time in the future, and methods of communicating with your server by bypassing the &lt;a href="http://en.wikipedia.org/wiki/Same_origin_policy"&gt;same-origin policy&lt;/a&gt;.&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/qRLHf3vDIn0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/2320883898666441184/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2012/01/writing-quality-third-party-js-part-2.html#comment-form" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/2320883898666441184?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/2320883898666441184?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/qRLHf3vDIn0/writing-quality-third-party-js-part-2.html" title="Writing Quality Third-Party JS - Part 2: Loading Your Code" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>4</thr:total><feedburner:origLink>http://blog.errorception.com/2012/01/writing-quality-third-party-js-part-2.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU8ESXwzeCp7ImA9WhRVE0w.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-6582433218431230207</id><published>2012-01-09T14:37:00.000+05:30</published><updated>2012-01-12T03:06:48.280+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-12T03:06:48.280+05:30</app:edited><title>Writing Quality Third-Party JS - Part 1: The First Rule</title><content type="html">&lt;p&gt;
It's fascinating how JavaScript has quickly become to de-facto mechanism to deliver third-party integrations that are easily pluggable into people's websites. Services like &lt;a href="http://developers.facebook.com/docs/"&gt;Facebook&lt;/a&gt;, &lt;a href="https://dev.twitter.com/docs/anywhere/welcome"&gt;Twitter&lt;/a&gt; and &lt;a href="http://docs.disqus.com/developers/universal/"&gt;Disqus&lt;/a&gt;, programmable widgets like &lt;a href="http://code.google.com/apis/maps/documentation/javascript/tutorial.html"&gt;Google Maps&lt;/a&gt;, and even invisible scripts like &lt;a href="http://code.google.com/apis/analytics/docs/tracking/asyncTracking.html"&gt;Google Analytics&lt;/a&gt;, &lt;a href="http://support.kissmetrics.com/getting-started/5-minutes"&gt;KissMetrics&lt;/a&gt; and our own &lt;a href="http://errorception.com/"&gt;Errorception&lt;/a&gt; give you ways to integrate their services with your website.
&lt;/p&gt;
&lt;p&gt;
You'd think that with these mechanisms becoming so popular, there'd be a good deal of information available about how to build great third-party integrations in JavaScript. Turns out, the information available on the Interwebs is actually rather sparse. This series of posts aims to add to that repository of knowledge, based on my experience building Errorception.
&lt;/p&gt;
&lt;p style="padding: 10px; border: 1px solid #ccc; background: #eee; font-size: 12px;"&gt;
This is a three-part series of articles aimed at people who want to write JavaScript widgets (or other kinds of scripts) to make their application's data/services/UI available on other websites. This is the first in the series, highlighting important considerations.
&lt;/p&gt;
&lt;h3&gt;The First Rule&lt;/h3&gt;
&lt;p&gt;The First Rule of Third-Party JavaScript is... man, this will never sound as epic as Tyler Durden. Anyway, here's the first rule, and the most important consideration:&lt;/p&gt;
&lt;big style="font-size: 23px; display: block; text-align: center; padding: 20px;"&gt;The Rule: You DO NOT Own The Page&lt;/big&gt;
&lt;p&gt;Understanding and assimilating this rule gives you two principle considerations when designing your script.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The impact of adding your script should be minimal. Preferably none.&lt;/li&gt;
&lt;li&gt;You cannot make any assumptions about how the page is coded.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let's start with the first point. How can you make the impact of your script minimal? A couple of considerations come to mind.&lt;p&gt;
&lt;h4&gt;No globals&lt;/h4&gt;
&lt;p&gt;You should ideally have no global variables in your code. Making sure this happens is rather simple. Firstly, ensure that you enclose your code in a self-executing anonymous function. Secondly, pass your code through &lt;a href="http://www.jshint.com/"&gt;a good lint tool&lt;/a&gt; to ensure that you've not used any undeclared variables, since &lt;a href="http://javascript.crockford.com/style2.html"&gt;undeclared variables will cause implicit global variables&lt;/a&gt;. This is also regarded as a general best-practice for JS development, and there's absolutely no reason you shouldn't adhere to it.&lt;/p&gt;
&lt;p&gt;A typical self-executing anonymous function looks as follows, in its most minimal form:&lt;/p&gt;
&lt;script src="https://gist.github.com/1582057.js?file=self-executing-anonymous-function.js"&gt;&lt;/script&gt;
&lt;p&gt;To do this slightly better, I recommend the following form instead:&lt;/p&gt;
&lt;script src="https://gist.github.com/1582067.js?file=better-self-executing-anon-function.js"&gt;&lt;/script&gt;
&lt;p&gt;In the pattern above, the &lt;code&gt;window&lt;/code&gt; and &lt;code&gt;document&lt;/code&gt; objects &amp;mdash; both rather frequently used &amp;mdash; become local-scope variables. Local variables are usually reduced to one or two letter variable names when passed through the most popular JS minifiers, so the size of your code reduces somewhat by using this pattern. I'll come back to the &lt;code&gt;undefined&lt;/code&gt; variable in just a bit. Once minified, your code will look something like the following (using closure-compiler in this case). Notice how &lt;code&gt;window&lt;/code&gt; and &lt;code&gt;document&lt;/code&gt; have been reduced to single letter variable names.&lt;/p&gt;
&lt;script src="https://gist.github.com/1582088.js?file=better-self-exec-anon-function-compressed.js"&gt;&lt;/script&gt;
&lt;h4&gt;Wait, what? No globals?&lt;/h4&gt;
&lt;p&gt;Ok, there are some cases when a global variable is absolutely necessary. Since linkage in JS happens through global variables, it might be necessary to add a global variable just to provide an API namespace to your users. Here's what the most popular third-party snippets do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Google Analytics exposes a &lt;code&gt;_gaq&lt;/code&gt; variable (&lt;a href="http://code.google.com/apis/analytics/docs/gaJS/gaJSApi_gaq.html"&gt;docs&lt;/a&gt;) with one method on it &amp;mdash; &lt;code&gt;push&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Facebook exposes a &lt;code&gt;FB&lt;/code&gt; variable (&lt;a href="http://developers.facebook.com/docs/reference/javascript/"&gt;docs&lt;/a&gt;), which is the namespace for their API. (Using FB also requires you to define a global &lt;code&gt;fbAsyncInit&lt;/code&gt; function, which could've been avoided. I guess they're doing what they do for ease of use, even though it's against best practice.)&lt;/li&gt;
&lt;li&gt;Twitter @Anywhere exposes a &lt;code&gt;twttr&lt;/code&gt; variable (&lt;a href="https://dev.twitter.com/docs/anywhere/welcome#Example_Initialization"&gt;docs&lt;/a&gt;), which like FB is their API's container namespace.&lt;/li&gt;
&lt;li&gt;For completeness, Errorception exposes a &lt;code&gt;_errs&lt;/code&gt; variable. We currently do not have an API (coming soon!), but this has been left as a placeholder.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Take a moment to think about those variable names. They are pretty unique to the service-provider, and will usually not conflict. The possibility of conflict cannot be completely avoided, but can be reduced significantly by picking one that's unique to your service. So, exporting a global of &lt;code&gt;&lt;a href="http://jquery.com/"&gt;$&lt;/a&gt;&lt;/code&gt;, &lt;a href="http://www.prototypejs.org/"&gt;&lt;code&gt;$$&lt;/code&gt;&lt;/a&gt; or &lt;code&gt;&lt;a href="http://documentcloud.github.com/underscore/"&gt;_&lt;/a&gt;&lt;/code&gt; is just a horrible idea, however easy-to-type it may seem.&lt;/p&gt;
&lt;h4&gt;No modifications to shared objects&lt;/h4&gt;
&lt;p&gt;Several objects are shared in the JS runtime &amp;mdash; even more than you might imagine at first. For example, the DOM is shared, but then so are the &lt;code&gt;String&lt;/code&gt; and &lt;code&gt;Number&lt;/code&gt; objects. Do not modify these objects either by altering their instances directly or by modifying their prototypes. That's simply not cool.&lt;/p&gt;
&lt;p&gt;The only cautious exception to this rule might be if you need to &lt;a href="http://remysharp.com/2010/10/08/what-is-a-polyfill/"&gt;polyfill&lt;/a&gt; browser methods. In all honesty, I would avoid using polyfills as much as possible in my third-party code and I don't recommend it at all, but you could do this if you are feeling adventurous. The reason I wouldn't recommend it is two-fold:
&lt;ul&gt;
&lt;li&gt;The code on the page may make assumptions about browser capabilities based on browser detection rather than feature detection. (Remember, even &lt;a href="http://docs.jquery.com/Release:jQuery_1.3#No_More_Browser_Sniffing"&gt;jQuery removed browser detection only recently&lt;/a&gt;, and many popular libraries still do a good deal of browser detection.)&lt;/li&gt;
&lt;li&gt;The code on the page might do object enumeration &lt;code&gt;for...in&lt;/code&gt; instead of array iteration &lt;code&gt;for(var i=0;i&amp;lt;len;i++)&lt;/code&gt; for iterating through arrays. Even when enumerating object properties (which is a legit case of &lt;code&gt;for...in&lt;/code&gt;), the code on the page might not use &lt;code&gt;hasOwnProperty&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Either of these will break the code on the host page. You don't want code on the host page to break just because they've added your script.&lt;/p&gt;
&lt;h4&gt;No DOM modifications&lt;/h4&gt;
&lt;p&gt;Just like you don't own the global namespace, you don't own the DOM either. Making any changes to the DOM is simply unacceptable. Do not add properties or attributes to the DOM, and do not add or remove elements in the DOM. Your widget is never important enough to add extra nodes or attributes to any element of the DOM. This is because code on the page might be too tightly dependent on the DOM being one way, and if you modify it their code is likely to break.&lt;/p&gt;
&lt;p&gt;That said, there are two permissible cases when you can modify the DOM. The first is when you are expected to present a UI, and the second is when you need to communicate with your server and circumvent the &lt;a href="http://en.wikipedia.org/wiki/Same_origin_policy"&gt;same-origin policy&lt;/a&gt; of the browser. In the first case, make the contract explicit by asking for a DOM node within which you will make the modifications, so that the developer of the page knows what to expect. I'll address the second case in detail in the third post in this series.&lt;/p&gt;
&lt;h4&gt;Make no assumptions about the page&lt;/h4&gt;
&lt;p&gt;
This is the most complex to ensure. Even Google Analytics has had issues with their tracking script because of assumptions they inadvertently made. &lt;a href="http://www.stevesouders.com/blog/2010/05/11/appendchild-vs-insertbefore/"&gt;Steve Souders has enumerated some on his blog&lt;/a&gt;. So, for example, you can't even assume that the DOM will have a &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; node even after parsing the HTML! jQuery also had &lt;a href="http://dev.jquery.com/ticket/2709"&gt;some&lt;/a&gt; &lt;a href="http://dev.jquery.com/ticket/4378"&gt;bugs&lt;/a&gt; in their dynamic loader due to assumptions they inadvertently made. It seems that the only real thing you can rely on is that your script tag is on the page (and hence in the DOM). Nothing else should be taken for granted.
&lt;/p&gt;
&lt;p&gt;
Unfortunately, I don't have a clean solution for this problem. The only solution seems to be that you should keep your dependencies on the DOM and to native object to a bare minimum, and test in every environment you can lay your hands on. In Errorception, I test on way more browsers than I'd care about, even including old browser versions and mobile phones. It's the only real way to be sure. I have to do this irrespective of whether I support the browser or not, because it might be perfectly supported by the developers of the page.
&lt;/p&gt;
&lt;h4&gt;&lt;code&gt;undefined&lt;/code&gt; redefined&lt;/h4&gt;
&lt;p&gt;
A slightly less scary but equally dangerous problem is that &lt;code&gt;undefined&lt;/code&gt; is not a keyword or literal in JavaScript. It really should have been. Since it's not a keyword, it's possible for someone to create a global variable called &lt;code&gt;undefined&lt;/code&gt;, and that can mess with your script. If you really need to use &lt;code&gt;undefined&lt;/code&gt;, you should ensure that you have a clean, unassigned &lt;code&gt;undefined&lt;/code&gt; for your use. There are several ways to &lt;a href="http://www.javascriptkata.com/2011/09/13/how-to-make-sure-undefined-is-not-defined/"&gt;make sure you are working with a clean &lt;code&gt;undefined&lt;/code&gt;&lt;/a&gt;. The anonymous function I've shown above implements one of these mechanisms, such that &lt;code&gt;undefined&lt;/code&gt; inside the function is the &lt;code&gt;undefined&lt;/code&gt; you expect.
&lt;/p&gt;
&lt;h4&gt;Trust&lt;/h4&gt;
&lt;p&gt;
Before closing this post, I want to touch upon the issue of trust. By adding your script to a page, the developer is knowingly or unknowingly placing a lot of trust in you. I completely dislike this, but unfortunately JavaScript has no built in mechanism to reduce the problems of trust. &lt;a href="http://code.google.com/p/google-caja/"&gt;Several&lt;/a&gt; &lt;a href="http://www.adsafe.org/"&gt;projects&lt;/a&gt; exist to reduce the possibilities of vulnerabilities, but they seem too heavy to use. Douglas Crockford has been &lt;a href="http://www.slideshare.net/webdirections/douglas-crockford-ajax-security-presentation"&gt;trying to educate people about the issues&lt;/a&gt;, but it seems to be mostly falling on deaf ears.
&lt;/p&gt;
&lt;p&gt;
One post in particular is relevant here: &lt;a href="http://tech.bluesmoon.info/2011/04/how-much-do-you-trust-third-party.html"&gt;an excellent post by Philip Tellis titled "How much do you trust third-party widgets?"&lt;/a&gt;. It's a must read to get a gist of the issues surrounding trust in third-party widgets, along with some high-level solutions.
&lt;/p&gt;
&lt;h4&gt;In Part 2&amp;hellip;&lt;/h4&gt;
&lt;p&gt;In &lt;a href="http://blog.errorception.com/2012/01/writing-quality-third-party-js-part-2.html"&gt;the next installment of this article series&lt;/a&gt;, I'll talk about strategies to load and bootstrap your code in the page, without causing a performance hit. I'll also be touching upon how, at &lt;a href="http://errorception.com"&gt;Errorception&lt;/a&gt;, we mitigate the risk of the service going down, if ever &amp;mdash; an approach that's definitely not unique to Errorception, but isn't as abundantly used as you think.
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/yFonu712CYk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/6582433218431230207/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2012/01/writing-quality-third-party-js-part-1.html#comment-form" title="10 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/6582433218431230207?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/6582433218431230207?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/yFonu712CYk/writing-quality-third-party-js-part-1.html" title="Writing Quality Third-Party JS - Part 1: The First Rule" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>10</thr:total><feedburner:origLink>http://blog.errorception.com/2012/01/writing-quality-third-party-js-part-1.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUQARXgzeCp7ImA9WhRVEE4.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-715001254163509504</id><published>2012-01-08T21:12:00.000+05:30</published><updated>2012-01-08T21:12:24.680+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-08T21:12:24.680+05:30</app:edited><title>A Host of New Features</title><content type="html">&lt;p&gt;
Just rolled out a new build - the first build of the new year!
&lt;/p&gt;
&lt;h3&gt;Improved duplicate detection&lt;/h3&gt;
&lt;p&gt;
Some time ago I had rolled out the &lt;a href="http://blog.errorception.com/2011/10/mark-as-duplicate.html"&gt;"Mark as Duplicate"&lt;/a&gt; feature, which inspected your errors and automatically tried to find if they are duplicates of each other. Today that algorithm underwent a significant improvement, and now does a much better job of finding duplicates. This has been applied to all the existing errors as well, bringing down error count by a &lt;i&gt;massive 93%&lt;/i&gt;!
&lt;/p&gt;
&lt;p&gt;
What this means for you is that the number of errors you need to worry about has come down significantly. Like I say, fewer bugs = happy developer. :)
&lt;/p&gt;
&lt;h3&gt;"Mark as Duplicate" no more!&lt;/h3&gt;
&lt;p&gt;
Even though the Mark as Duplicate feature was nice and was very helpful in bringing down bug count, it always felt very clunky and legacy-like. The idea of different bugs reports for the same bug, and links flying between them just felt wrong. It doesn't help productivity if you spend a lot of time just navigating the bug reporting system. It sorely needed improvement.
&lt;/p&gt;
&lt;p&gt;
But why improve it if you can drop the concept completely! Now, &lt;i&gt;all of the duplicates are merged into one bug&lt;/i&gt;, while still preserving all of the details that each individual bug had. This gives you details about which browser the error occurred in, which versions of the browser it occurred in, which pages the error was on, and how many times it has occurred in the past, all in one page. All this done while keeping the report pretty. I feel that this is a &lt;i&gt;huge productivity win&lt;/i&gt;. Do let me know what you think.
&lt;/p&gt;
&lt;h3&gt;Graphs integrated right into error reports&lt;/h3&gt;
&lt;p&gt;
The &lt;a href="http://blog.errorception.com/2011/12/moar-stats.html"&gt;graphs feature&lt;/a&gt; was an instant hit from when it was launched. It was clear that graphically visualizing information is much more pleasant as compared to loads of text. So, I've taken the idea of graphs to the next level &amp;mdash; displaying them within the error report itself. See the following screenshot for an example.
&lt;/p&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-HePrQ9Q7o4E/TwmqO6ywsHI/AAAAAAAAAA8/UajS5XCThFQ/s1600/New%2BErrors%2BPage.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" width="500" src="http://3.bp.blogspot.com/-HePrQ9Q7o4E/TwmqO6ywsHI/AAAAAAAAAA8/UajS5XCThFQ/s500/New%2BErrors%2BPage.png" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3&gt;Inline scripts&lt;/h3&gt;
&lt;p&gt;
Inline scripts' detection has been added. This tells you where the breaking script was located &amp;mdash; whether it was in an external script file, or it was in an inline script tag on the page. This &lt;i&gt;helps a great deal in debugging&lt;/i&gt; the the error, as you know exactly where to look.
&lt;/p&gt;
&lt;p&gt;
Inline scripts usually tend to exist on several pages &amp;mdash; for example if they are generated by Rails helpers. We now smartly detect if there are such pages on which the same error has occurred in the same script, and designate them as duplicates of each other. Previously this wasn't a factor that was taken into account when marking bugs as duplicates. This has been &lt;i&gt;the single largest contributor towards reducing total bug count&lt;/i&gt;.
&lt;/p&gt;
&lt;h3&gt;When did the error occur?&lt;/h3&gt;
&lt;p&gt;
One critical piece of information for a JavaScript developer is &lt;i&gt;when in the page cycle did the error occur&lt;/i&gt;. Errors that happened during bootstrapping (ie. before page load) are very different from errors that happened after page load. This information was never before available, and has now been added to your error logs. This should simplify debugging significantly.
&lt;/p&gt;
&lt;h3&gt;And much more&amp;hellip;&lt;/h3&gt;
&lt;p&gt;
That's just a small set of the new features rolled out. There have been improvements all over the place, right from the error listing to the notification emails. There has also been a massive performance boost &amp;mdash; previously the report generation slowed down as the number of errors grew. Support for Opera and iOS has been improved since they started supporting &lt;code&gt;window.onerror&lt;/code&gt;. However, probably the most important improvements have been in areas that are invisible &amp;mdash; this build gives us immense flexibility at the logging and data-model end, so that additional features can be built with amazing ease and at a high pace.
&lt;/p&gt;
&lt;p&gt;Do let me know what you think of the new features in the comments or over email. Feedback is always welcome. Wish you a great year ahead!
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/zwbMs6uQmao" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/715001254163509504/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2012/01/host-of-new-features.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/715001254163509504?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/715001254163509504?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/zwbMs6uQmao/host-of-new-features.html" title="A Host of New Features" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-HePrQ9Q7o4E/TwmqO6ywsHI/AAAAAAAAAA8/UajS5XCThFQ/s72-c/New%2BErrors%2BPage.png" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://blog.errorception.com/2012/01/host-of-new-features.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkEMQn49eCp7ImA9WhRXEUw.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-7519944418865421846</id><published>2011-12-17T15:59:00.000+05:30</published><updated>2011-12-17T16:14:43.060+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-17T16:14:43.060+05:30</app:edited><title>Control Error Posting Better</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
&lt;p&gt;One constant problem with Errorception is managing the huge influx of errors, because Errorception does such a good job of recording errors. (You see how I sneaked that last bit in?) We've always had automatic "muting" of possibly uninteresting errors. Some time ago, we started &lt;a href="http://blog.errorception.com/2011/10/mark-as-duplicate.html"&gt;automatic marking bugs as duplicates&lt;/a&gt;, which brought down the number of errors that you had to deal with drastically.&lt;/p&gt;
&lt;p&gt;Today, we've launched yet another feature to help reduce the number of errors you need to care about. You can find this under "Settings &amp;gt; Posting errors".&lt;/p&gt;
&lt;h3&gt;Allowed domains&lt;/h3&gt;
&lt;p&gt;You can now specify a white-list of domains from which you want to record errors. So, if you whitelist www.mydomain.com, errors from localhost will not be recorded. You can specify as many domains as you want - just comma-separate them. This also helps safeguard you from people who might have stolen your tracking code and are spamming you.&lt;/p&gt;
&lt;h3&gt;Ignored scripts&lt;/h3&gt;
&lt;p&gt;You can specify a black-list of paths for script files. If errors occur in script files matching this file path, such errors are not recorded. This means that you can now block your third-party scripts for example from posting errors to Errorception. So, no more do you need to get errors from the Facebook Like button, or from your Customer Support chat widget.&lt;/p&gt;
&lt;p&gt;Also, as a bonus, if the errors are ignored due to any of the reasons above, such errors will not count against your rate limit. This gives you more room every day to record the errors you really care about.&lt;/p&gt;
&lt;p&gt;Lesser errors = happier developer, right?&lt;/p&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/kKdmhC_uiMU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/7519944418865421846/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2011/12/control-error-posting-better.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/7519944418865421846?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/7519944418865421846?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/kKdmhC_uiMU/control-error-posting-better.html" title="Control Error Posting Better" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.errorception.com/2011/12/control-error-posting-better.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0QCRn85fCp7ImA9WhRQF0g.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-2370089012478788238</id><published>2011-12-13T10:06:00.000+05:30</published><updated>2011-12-13T10:12:47.124+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-13T10:12:47.124+05:30</app:edited><title>Call Stacks in IE</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
Over the weekend I rolled out a build that provided call stacks for certain errors, under certain conditions. You only get a call stack if:&lt;br /&gt;
&lt;ul style="text-align: left;"&gt;
&lt;li&gt;The error occurs in Internet Explorer,&lt;/li&gt;
&lt;li&gt;The error happens after page load&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;div&gt;
I must admit, because of these conditions I was unsure how useful the feature will be. But after having it run for some time now, it looks awesome!&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
If we were able to capture the call stack of an error, it is highlighted in the errors listing.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-DDTZtkE8I8s/TubLWbNPO7I/AAAAAAAAAAo/C1AnTEd_f7w/s1600/Stack+available.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="79" src="http://2.bp.blogspot.com/-DDTZtkE8I8s/TubLWbNPO7I/AAAAAAAAAAo/C1AnTEd_f7w/s320/Stack+available.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
The call stack is shown in the error details page for the error.&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-puK0g1UEDBA/TubMGD0JN3I/AAAAAAAAAAw/C8sQ91Fpd5g/s1600/stack.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="68" src="http://4.bp.blogspot.com/-puK0g1UEDBA/TubMGD0JN3I/AAAAAAAAAAw/C8sQ91Fpd5g/s320/stack.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
How it works&lt;/h3&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
One interesting behaviour of IE is that when &lt;code&gt;window.onerror&lt;/code&gt; is called, it doesn't actually destroy the call stack &amp;mdash; in fact, the &lt;code&gt;window.onerror&lt;/code&gt; function call is placed on the top of the currently executing stack. This is different from how all other browsers behave. We exploit this behaviour in IE.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
However, IE doesn't give you a nicely formatted stack trace. In fact, there's no explicit way to get the call stack at all. However, IE does give you a meaningful &lt;code&gt;arguments.callee.caller&lt;/code&gt;, which is used here. We then recursively walk the call stack using &lt;code&gt;arguments.callee.caller.caller&lt;/code&gt; etc. to build individual stack frames of the error. We do this for 10 stack frames and stop there, just in case the call stack is for a recursive function.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;&lt;code&gt;arguments.callee&lt;/code&gt;?&lt;/h3&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;code&gt;arguments.callee&lt;/code&gt; refers to the currently executing function. It's a way for a function to know itself, if you will. In JavaScript, since every function is also an object, the function has it's own properties as well. One such property of a function is its &lt;code&gt;.caller&lt;/code&gt;, which is a reference to the function that called it. In other words, it's a reference to the function one stack frame below itself.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
In the case of &lt;code&gt;window.onerror&lt;/code&gt;, &lt;code&gt;arguments.callee&lt;/code&gt; will refer to the &lt;code&gt;window.onerror&lt;/code&gt; handler itself, since it points to itself. Once we have a handle to our own function, we can then access properties of our function, as described above.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
There's one caveat though. Only IE retains a meaningful &lt;code&gt;arguments.callee.caller&lt;/code&gt;. In all other browsers, this value is &lt;code&gt;null&lt;/code&gt;. That's because all other browsers destroy the call stack before calling &lt;code&gt;window.onerror&lt;/code&gt;. IE retains the call stack. So, since we have a call stack in IE, we can now recursively call &lt;code&gt;.caller&lt;/code&gt; for each function in the stack to know the previous function in the stack.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;Why after page load?&lt;/h3&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
As I've mentioned several times before, Errorception will always maintain a zero performance cost. I wouldn't use a error reporting system that would cause page load delays for every single user. To ensure that the performance cost is zero, Errorception introduces it's script after page load. This doesn't mean that we don't catch errors from before page load, of course. We do. But we only process them once our script has loaded.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Because of this loading pattern, we won't have access to call stacks from before page load. &lt;code&gt;arguments.callee.caller&lt;/code&gt; will always point to null since the stack has already unrolled. This is why we cannot generate call stacks before page load, even though we have all other error details.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;But that sucks!&lt;/h3&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Not really, if you think about it. While it would be awesome if we could get call stacks from before page load as well, these errors are really easy to replicate. That's because the error happens in such a small and predictable time interval that it's easy to recreate it locally. The error happens between when the page started loading and when page load was fired - usually within a couple of seconds, maybe before any user interaction has even occurred.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;Caveats&lt;/h3&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
In a lot of cases, the call stack consists of anonymous functions, which isn't very descriptive. I would ask you to rewrite your code using &lt;a href="http://www.javascriptkata.com/2010/05/19/how-to-de-anonymize-your-anonymous-functions/"&gt;named anonymous functions&lt;/a&gt;, but we all know that no one's going to do that. I'm still on the lookout for a decent way to solve this. If you have any suggestions, I'm all ears.&lt;/div&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/x7H4-fbsMj8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/2370089012478788238/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2011/12/call-stacks-in-ie.html#comment-form" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/2370089012478788238?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/2370089012478788238?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/x7H4-fbsMj8/call-stacks-in-ie.html" title="Call Stacks in IE" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-DDTZtkE8I8s/TubLWbNPO7I/AAAAAAAAAAo/C1AnTEd_f7w/s72-c/Stack+available.png" height="72" width="72" /><thr:total>4</thr:total><feedburner:origLink>http://blog.errorception.com/2011/12/call-stacks-in-ie.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkYASHozfyp7ImA9WhRQFU4.&quot;"><id>tag:blogger.com,1999:blog-8179719408804246785.post-6756905463836166075</id><published>2011-12-10T20:40:00.001+05:30</published><updated>2011-12-10T20:45:49.487+05:30</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-10T20:45:49.487+05:30</app:edited><title>MOAR Stats!</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
Just released a build that takes all your error data and makes pretty little pie charts out of it. Who doesn't like pie charts, right?&lt;br /&gt;
&lt;br /&gt;
To access this data, hover over your projects menu at the top right when you log in, and click on the "See more stats" link in the drop-down.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-0K_urQWCpPc/TuN2_EzVzcI/AAAAAAAAAAg/A17LM_7_kx0/s1600/Graphs+-+%257Berrorception%257D+%25281%2529.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="500" src="http://3.bp.blogspot.com/-0K_urQWCpPc/TuN2_EzVzcI/AAAAAAAAAAg/A17LM_7_kx0/s500/Graphs+-+%257Berrorception%257D+%25281%2529.png" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/errorceptionBlog/~4/1HI-vtDT8_Y" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.errorception.com/feeds/6756905463836166075/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.errorception.com/2011/12/moar-stats.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/6756905463836166075?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8179719408804246785/posts/default/6756905463836166075?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/errorceptionBlog/~3/1HI-vtDT8_Y/moar-stats.html" title="MOAR Stats!" /><author><name>Rakesh Pai</name><uri>http://www.blogger.com/profile/05275465816567723588</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-0K_urQWCpPc/TuN2_EzVzcI/AAAAAAAAAAg/A17LM_7_kx0/s72-c/Graphs+-+%257Berrorception%257D+%25281%2529.png" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://blog.errorception.com/2011/12/moar-stats.html</feedburner:origLink></entry></feed>
