When we set out to redesign insideline.com back in late 2008, we set big goals for ourselves. Some of those goals included creating our very own Content Management System (CMS), Publishing System and Digital Assets Management (DAM) System and in-memory Distributed Data Grid. On the user-facing front, we had the following goals:
- Better Performance: Our pages need to be and feel fast to our users (onLoad fires in < 1.5 sec)
- Richer Content: We need to serve larger photos, more videos and interactive components
- Better Revenue: Needless to say, we need to increase our revenue
The Challenge
The challenge we had with our front-end goals was that insideline.com generated revenue through ad impressions. Almost all web developers know that including a 3rd-party component, including ads, on a page could potentially degrade the user experience. See Figure 1.0.

Figure 1.0 Eternal struggle between delivering high performing pages and including 3rd-party components with the user experience hanging in the balance
We had to find a way to reconcile our metric for performance and our need to sustain and grow our ad impressions. We knew ahead of time that it wasn't going to be easy considering that the struggle between achieving optimal page performance while including 3rd-party components onto a page has been talked about frequently in the development community without any proposed solution.
The Process
Before we jumped to solutions, we started the process by taking inventory of all the 3rd-party components that we serve on our pages and by noting the specific formats in which we include them. This is what we found:
- All 3rd-Party Components existed in either an iFrame or a JavaScript format
- All 3rd-Party Components could be lazy-loaded, except for:
- Components that use document.write (e.g. Double Click ads)
- Components that depend on DOM events like onDOMReady or onLoad (e.g. Omniture, Brightcove)
Our immediate response to that was, "We're going to hack all 3rd-party components to make them all lazy-loadable." So we tried the following:
- Overriding document.write: Cache the output of document.write and then place it on the page when you're ready.
- iFrame'N'Copy: (A term we coined) Load the 3rd-party component in an empty page that lives on our domain within an iFrame and then copying the content of that page when it's done loading.
Both techniques were successful in certain situations and in certain browsers. However, they were not viable solutions that we would implement on any of our sites in Production.
Then, we had an epiphany that later helped us form an approach toward 3rd-party components and page performance. The revelation was:
Anything You Cannot Lazy-Load Should Be Treated as a Black Box.
This concept might seem trivial to some but it was crucial for us to move forward.
Our Approach
We decided that in order to deliver fast pages that serve 3rd-party components, we need to follow the following three principles:
- You Can't Control It All: Our attempt to force some of our 3rd-party components into the "lazy-load box" was a humbling experience
- Speed Up What You Can: If we were going to treat things that are out of our control as black boxes, we needed to ensure that things we have control over are lightening fast
- Defer Everything You Can't Control: If it's a block box, we'll make sure it is the last thing that is called on the page before it's done loading.
These principles saved us a lot of time and effort. They also helped us develop a JavaScript Loader, which works as follows:
- A PAGESETUP object (lightweight static object) is created at the top of the page to act as a placeholder for everything that needs to be loaded on the page.
- As the page gets parsed, each component gets to register the following with PAGESETUP:
- File dependencies
- Code snippet to be executed
- Order of execution
- The Loader Core logic is included at the bottom of the page and as soon as it's parsed and rendered, it does the following:
- Go through PAGESETUP list of file dependencies and add them onto the page asynchronously
- When dependecies are loaded, loop through the code snippets and execute them in order
One of the things that the loader was designed to do is to be independent from DOM events, especially onLoad and onDOMReady. This allows us to render the page to our user as soon as the browser parses and executed the Loader Code logic that is included at the bottom of the page. We will have a follow-up post on the JavaScript Loader with code snippets and such.
Figure 2.0 demonstrates the flow in which our JavaScript Loader handles 3rd-party components.

Figure 2.0 3rd-Party Component Handling in JavaScript Loader
The Results
We were able to successfully achieve our goals for insideline.com. The homepage loadtime went from 9 seconds on the old site to 1.4 seconds on the new site. With JavaScript ads on the page, the load time goes up to 1.6 seconds on average. Ads load faster on the site and the we have noticed a considerable reduction in impression discrepancies, which in turn raised our ad revenue on the site by 3%.
Throughout the process, we were able to confirm and validate the results using Firebug and its extensions YSlow, Page Speed, in addition to WebPageTest. These tools have played an invaluable role in ensuring that we deliver the best user experience without compromising our revenue.
When we applied the same principles to our main site redesign (beta.edmunds.com,) we were able to cut the loading time in half. We have also received initial results that indicate that our total page views per session have increased 17%. Obviously that cannot be totally attributed to page performance since we did a major redesign of the site as well, but we are confident that page performance helped bring that number up. Please note that right now, only 25% of our total traffic is redirected to the new beta site. A full launch will be taking place in a few months.
Also, our Page Speed score has jumped 20+points, see Figure 3.0

Figure 3.0 Page Speed Scores for both edmunds.com legacy and new beta site
In The Works
We are currently working on the second generation JavaScript Loader, which will streamline the process even further and ensures even more optimized performance. We are also going to open source the component for the community to use and build upon.
Together, we'll make the web faster one site at a time :-)
P.S. We're hiring :-)


