Cookieless domains in an HTTP/2 world
September 06, 2019Kevin Raynel7 min read
One of our client at Theodo runs a large marketplace. They sell around 3 millions items (Q1 2019), and serve more than 2 billion HTTP requests every month. We will call them "MyMarketplace" below.
MyMarketplace moved all of its assets to a cookieless domain, only to find out that the saved bandwidth was negligible compared to the overhead induced by the new SSL handshake. By using HTTP/2, the cookies are compressed and you can reuse the connection already opened to load the HTML. In summary, stop using cookieless domains, start migrating to HTTP/2!
MyMarketplace uses multiple main domains and subdomains:
Domain mymarketplace.fr has subdomains :
- www.mymarketplace.fr for the e-commerce website
- conseil.mymarketplace.fr for the advice section
- blog.mymarketplace.fr for tips and news
- cdn.mymarketplace.fr for assets
Each domain uses a cookie to store the session identifier, and several other cookies for content personnalisation and tracking purposes. The total cookie size is around 2Kb, sent for every request. We share the session cookie between the subdomains to keep the user connected during a navigation session. We want users visiting the advice subdomain to be able to add products to their cart without having to navigate back to the main site.
The problem: the
cdn. subdomains are using the same main domain
mymarketplace.fr. Every request to the CDN include all the cookies in its HTTP headers.
On mobile connections, we expected this to have a negative impact on the Speed Index. Because of TCP Slow Start, sending 2Kb of cookies for every asset (around 50 of them per page) takes at least 7-8 round trips to get the headers out “on the wire.”
With that in mind, we though getting rid of those cookies would improve the time need to load all assets, and thus improve our Speed Index, particularly for mobile devices using slower, high latency connections.
Migrate to a cookieless doamin: naive solution
One typical practice in web development has been to use a "cookieless domain" to store assets.
The idea behind a cookieless domain is to serve your static content from a different domain than your main one, in order to reduce the extra-bandwidth used to send the cookies.
We thus decided to change the domain of the CDN to another, unique domain, which would not collide with our domains serving dynamic, user-facing HTML pages, and thus we migrated cdn.mymarketplace.fr to cdn.mymarketplace.com.
Some things to consider when doing something like that:
- Remember that you are working on improving your SEO: a good practice when switching domains is to add
301redirections between your old assets and your new one. This is true for pages, but also for images.
- You may have to add CORS headers if you dynamically load JS content from the main domain.
We migrated all of our servers to use the new CDN domain, redirected from our old CDN to our new using
301 redirections, and started monitoring.
The new CDN URL for everyone is now cdn.mymarketplace.com.
We love (and highly recommand) WebPageTest and run several of those tests per day to keep track of our Speed Index .
We compared the load time before and after the CDN migration, hoping for a nice reduction in the asset load time.
The migration worsened the Speed Index by 300ms. The First Contentful Paint and Start Render are even worse, AS the rendering starts 600ms.
Impact of moving all assets to a cookieless domain for 3 pages and average for those pages
Before the switch, we used the same main domain mymarketplace.fr with two subdomains www.mymarketplace.fr and cdn.mymarketplace.fr: only one SSL handshake was required.
Now that the main domain is different, there is a second SSL handshake required. All assets are now on the cdn.mymarketplace.com domain: the time to first paint is slower, particularly on a mobile connection. We can see on the second waterfall below that the asset are waiting for the SSL negociation to finish before loading.
Cookieless domain, with resource hints?
When optimizing resource loading, you can use resource hints to notify your browser it will need to connect or fetch data to a particular domain.
There are several ways to instruct your browser to initiate a connection earlier than when it actually has to load the resource.
One way of doing that is to add preconnect or even prefetch instructions in your HTML document. The browser will start connecting to the remote server as soon as it reads that instruction. It can be useful to preconnect to the Google Font server for instance, even before having to download your CSS file with the font import instructions.
In our case however, we would instruct the browser to preconnect to the CDN server just a line before loading the CSS resource: that was nearly useless as the browser did not have time to preconnect before the actual connection.
We decided to take another approach and to give the browser the instruction to preconnect earlier by using HTTP preconnect headers: as soon as the headers for the main document are received, even before the browser started to parse the HTML.
The scales are not really relevant here (because these are different environments, and this is only a single test). What is interesting to notice is that the SSL handshake starts even before the full download of the main document: the browser received the preconnect header and decided to initiate a connection to the CDN domain.
However, as the name states, those headers are "Hints". Every browser can choose to preconnect and load the asset, or decide that it has more important things to do. We sometimes could measure the improvement, but most of the times the download graph would look the same with or without preconnect instruction.
Adopted solution: split critical vs regular assets
With that new information in mind, we knew we had to load critical assets from a server close to our document server. We left the "regular assets" (images, ...) on the CDN server, but moved all "critical assets" (blocking resources like CSS and JS) on the main domains.
What we measured:
- Only one SSL handshake for HTML, CSS, JS
- HTTP/2 connection reuse meant that we have only one connection for the main document and the assets
- Same domain connection means we could drop the additional CORS headers we had to add when switching between domains.
- The larger images were still loaded from the CDN domain, without any cookies being sent
In the future, using the same domain and HTTP/2 also means that we will be able to push assets directly to the browser using HTTP/2 Push capabilities.
Finally, and we ought to have started with that, HTTP/2 comes with HPACK, which compresses headers. According to Cloudflare, HPACK is the silent killer feature of HTTP/2: so your cookies should be fine.
Some key takeways:
- HTTP/2 has deeply changed the way browsers download our assets
- Cookieless domains are not so useful anymore
- SSL Handshake is slow, so load your assets from as few domains as you can. TLS 1.3 with 0-RTT may help with this:
- Limit the number of domains hosting your assets, and add
preconnectinstructions for those domains. It should start the SSL handshake earlier and get you some Page Speed improvements.
And finally, everything is simpler if you use a library to manage your assets. We used the Symfony Asset component for instance, which allowed us to quickly iterate over the way our assets are loaded.
Symfony also allows the developer to add resource hints in one line of template code with the web link component, which is also a nice touch.
Enjoyed this article? Our experts can help you improve your website performance!
Web Developer at Theodo