Nov 9, 2018 7:07 AM
We've recently integrated HubSpot on a client site & i have been spending some time trying to mitigate the performance hit from doing so. There are a couple of practices used by the HubSpot team that are causing me some issues.
Extremely short cache lifetimes:
There are several of your assets with extremely short cache lifetimes, likely causing a new download on every page view.
js.hs-scripts.com/2517056.js Having a 60 second cache window feels extreme to say the least. especially when viewed in the light of services like Google Analytics having a 1.4 hour window for their bootstrap script.
Similar could be said for
js.hs-analytics.net/analytics/1541674800000/2517056.js which has a 5 minute cache window, again something that could end up being requested by a user multiple times during a session.
js.hsadspixel.net/fb.js has a 10 minute cache window.
Extending the cache lifetime of the assets, even potentially using hashed URLs &
cache-control: immutable for the no bootstrap assets would have a positive impact on the site performance of your customers.
Splitting your assets up among multiple domains introduces even more overhead as each asset requires the full DNS lookup, initial server connection, SSL handshake before it can request & download the required asset. You are serving your assets from HTTP2 so your current practice of sharding isn't necessarily providing any benefit for download time.
Hosting all of your assets on a single domain would immediately remove this concern and allow site owners to preconnect to the domain without needing the concern of needing multiple preconnect tags causing priority issues with the rest of their assets.
Nov 9, 2018 3:01 PM
There are more max-age issues in the cache-control settings than the files you mentioned in your post. I am guessing the ones you mentioned are being picked up by a page speed tool you are using, here is a more comprehensive list of what is going on typical HS sites.
max-age=60 or 1 minute
max-age=300 or 5 minutes
max-age=600 or 10 minutes
max-age=1209600 or 14 days
max-age= 31536000 or 1 year
List To Fix
There may be some reasons cache life is set low on some of the above resources but certainly not things like images, css, and js used to render the site. They need to be changed.
Combing the JS assets onto a single domain is one step (likely not happening I imagine) but at least the JS or CSS from each domain should be combined into a single file to help reduce the http requests. This may take some time to implement but server tools like webpack and gulp are built to do this.
There is a quick fix boost by loading JS asynchronously (most notably the CTAs) which will have improvements, especially if there are pages with a lot of CTAs (i.e. for an event page unique CTAs for each event).
Add Expire headers with future expiration dates for the following:
[portal-id].js (from http://js.hs-scripts.com)
[portal-id].js (from http://js.hs-analytics.net/analytics/1541784900000)
All GIG & PNG files created for the CTAs
Removing the query strings from static resources
I have numerous tickets open with HS Support and while the effort is valiant, there seems to be a disconnect between the support side and dev side. If there is anyone out there in HubSpot world that can address these issues it would be welcome.
Nov 21, 2018 10:27 AM
Hi. Do you have a particular tool you're using that's generating these recommendations and the site you're running the tool on?
All the assets that have a 1 year expiration have versioned URLs so there's no concern with cache busting on them. For the 14-day ones, they could be replaced and we don't have control over browser caches or proxies that may keep them longer than they should. 14 days is a pretty long time and most likely after two weeks the user's browser will purge the assets for newer assets anyway. It does provide some assurance that if a customer updates their files, their users will eventually see it.
We also intend to move more assets to the current domain (www.yoursite.com/[portal-id].js vs http://js.hs-scripts.com/[portal-id].js) to take advantage of HTTP/2. Both the hs-scripts.com and js.hs-analytics.net are loaded ansychronously, so extending their cache time will have no effect on page load time.
Nov 26, 2018 5:23 PM
Nov 13, 2018 8:05 AM
Thank you for the feedback! We're always looking to improve our hosting performance.
While I can't guarantee changes on any of these fronts, I will share your recommendations with the relevant product team members.
At the very least, I hope to be able to give you a detailed breakdown of why each of these assets perform the way they do.
Again, I appreciate your engagement and understanding!
Isaac TakushiAssociate Certification Manager
Nov 17, 2018 12:59 PM
Nov 19, 2018 6:28 AM
I appreciate you looking in to this @Isaac_Takushi there's only so much we can do perf wise before the main blockers become third party scripts.
From my POV if we could get all of your assets loaded from a single domain (e.g.
assets.hs-scripts.com) to allow multiplexing it would help with getting all of your assets running in our page quicker for cold cache visitors. Second if we could get immutable assets with long cache durations (I understand that your bootstrap script would need a short duration cache) that would help with performance for warm cache visitors.
Of note is that your current approach means that all visitors are cold cache users for a large number of their page views.
@GeeJay those were the worst performers on our site, i'm not as bothered by a 1 year + cache lifetime, we also don't use the HubSpot styling for our forms. A second look did turn up
https://js.hsforms.net/forms/v2.js which as you've stated has a low cache duration.
Nov 22, 2018 9:27 AM
Thanks for getting back to me. We use a range of tools for looking at our site performance (Speedcurve, WebPageTest, in browser dev tools network tab, Yellowlabs, Lighthouse).
My hope would have been to get everything apart from the initial bootstrap script on a long cache duration versioned URL, that way users wouldn't be downloading the same assets multiple times per session.
Unfortunately the assets do push out the page load time, on the up side being loaded async means that they don't block the DOM construction.
Your plan to move the assets to a single domain is promising as the connection overhead tends to make up a significant proportion of the total response time (usually the majority).
There doesn't appear to be a DM facility on these forums that i can find. If you or @Isaac_Takushi can provide an email address i'd be happy to send over a WebPageTest run for you to review.
Nov 22, 2018 10:50 AM
Nov 28, 2018 3:18 PM
Apologies for the delayed response. If you celebrated Thanksgiving, I hope you had a nice holiday!
I appreciate you clarifying which tools you use. This information and the concerns you expressed above empower us to make better, more educated decisions going forward.
That said, we won't be implementing all of the changes you request in the immediate future. While we always seek to improve our hosting performance, we also have to weigh adjustments against potential impacts on app performance and the HubSpot user experience — factors those tools don't consider.
Below, I outline various teammates' responses to your main queries:
Why are many scripts hosted on different domains?
We use different domains mainly because in the past when one domain was blocked by a popular ad blocker, it affected all tools. Using different domains reduces the risk of multiple apps being blocked at the same time.
That said, as Jeff Boulter mentioned, we now proxy many scripts through the customer's CMS domain. Assets that have this enabled will appear to come through the same domain. "We do need to move more scripts [onto this model] still, but it's a start."
The script loader's short cache life ensures that if a user adds or removes a tool such as live chat or pop-up forms, the change will propagate immediately.
ETag headers make a lot of sense if the content is large, HubSpot's script loader comes in around 1.1 KB compressed. Adding
If-Modified-Since headers to this asset would prevent this small file from being re-downloaded, but it wouldn't prevent the HTTP request to the server. "Since the bulk of the cost here is the latency of that HTTP request, we didn't think it was worthwhile to apply any other caching tricks."
max-age of the script loader has been raised from
15 seconds in the past because it didn't seem to cause problems for users. We're receptive to experimenting with it again, but it's not high on our priority list at this time.
300second (5 minute)
Similar to the script loader, "we chose
5 minutes because it was a reasonable balance between having good cache hit rates and refreshing frequently enough to take into account settings updates. The tracking code is also reasonably small (~25 KB compressed), so we weren't worried about the added latency of re-fetching it."
v2.js, and the other forms scripts have
600second (10 minute)
"The 10-minute values are a good compromise between cache and speed of deployed updates. If we were to increase that to say, 1 day, a deploy with a bug would take a very long time to be reverted."
600second (10 minute)
"The reason is similar to the forms-related scripts. We try to keep our backend functionality similar to the functionality of other tools, when possible."
Why do all CDN assets (
main.js, and all image files) have a
1209600second (14 day)
See Jeff Boulter's post above.
Why aren’t CTA JS files loaded asynchronously?
"We have discussed updating all of our embed codes (forms and CTAs) to be able to load asynchronously recently. The reason we do not do this at the moment is because we can't:
The CTA embed code loads
current.js and then loads the creation script, if
current.js is not loaded when the creation script has fired, we'll get errors for undefined functions.
We have to make some considerable changes to how this loads to allow asynchronous loads, and updating the embed code can always be tricky. However this is something we're currently [discussing]. For the moment, it's roughly roadmapped for [sometime in 2019] as we have some structural changes to the team we're working on first, but this is something we do plan on addressing within the not-to-distant future."
Why don’t CTA image files have any
The GIF files are for tracking, so caching those would affect CTA analytics.
Similar to script loader explanation above, we've opted to prevent the CTA PNG previews from caching to minimize the time it takes for user updates to propagate (despite the slight performance cost).
"We are also investigating changing the way we render CTAs so this may become a non-issue in the future."
All file manager assets have
max-agevalues, so what different role do the timestamp parameters play in cache-busting?
"We actually are just finishing up a project to better handle purging our server cache of old files (e.g. when you replace them), so the timestamp parameter is no longer going to be needed to ensure the most up-to-date version of a file gets served."
Isaac TakushiAssociate Certification Manager