Google Analytics and the Warning "Leverage Browser Caching"

When optimizing your website’s speed while following the GooglePage Speed Insights guidelines, you’ll know this alert. Activate “Leverage Browser Caching” for the Google Analytics Script. Often, this alert is to be blamed when a website doesn’t reach the infamous 100 of 100 PageSpeed points. That’s exactly where the problem is, because how can you cache a file that is not on your server? Today, we’ll show you three solutions.

Google Analytics: Leverage browser caching

Google Analytics is a good thing and still the tool of choice for every user that wants to take a close look at their website’s traffic. However, the script can also cause quite a headache when the goal is to optimize your website to achieve the famous 100 points from GooglePage Speed.

One problem is that some of the aspects desired and recommended by Google will not accelerate your blog, so they are not recommendable. For example, when you implement your entire CSS (often multiple files, including the plugin stylesheets) in the HTML inline, Google will congratulate you for making this decision.

However, when you only have a small perfectly cacheable stylesheet in the header, and the rest of the CSS in the footer, Google will try to tell you that this will slow your website down. Of course, the opposite is the case.

The same applies for the Google Analytics error. The script will be cached by Google for two hours. However, Google wants to have a longer period. This doesn’t increase your website’s speed either.

google-analytics-leverage-browser-caching

Google criticizes the short caching of the Analytics script, and thus, it only shows a maximum of 99 out of the 100 points. To solve this, there are multiple options. Three of which I’ll introduce you to today.

Before We Start: Make Sure To Use Browser Caching

If you’re still not using a code for a caching in your .htacess file, it’s about time. A simple browser caching combined with a compression of files already causes a significant speed boost. Here, you’ll find the necessary code, add it into the .htaccess in your blog’s main index.

# ----------------------------------------------------------------------
# | Komprimierung und Caching |
# ----------------------------------------------------------------------
# Serve resources with far-future expires headers.
#
# (!) If you don't control versioning with filename-based
# cache busting, you should consider lowering the cache times
# to something like one week.
#
# https://httpd.apache.org/docs/current/mod/mod_expires.html
<IfModule mod_expires.c>
ExpiresActive on
ExpiresDefault "access plus 1 month"
# CSS
ExpiresByType text/css "access plus 1 year"
# Data interchange
ExpiresByType application/atom+xml "access plus 1 hour"
ExpiresByType application/rdf+xml "access plus 1 hour"
ExpiresByType application/rss+xml "access plus 1 hour"
ExpiresByType application/json "access plus 0 seconds"
ExpiresByType application/ld+json "access plus 0 seconds"
ExpiresByType application/schema+json "access plus 0 seconds"
ExpiresByType application/vnd.geo+json "access plus 0 seconds"
ExpiresByType application/xml "access plus 0 seconds"
ExpiresByType text/xml "access plus 0 seconds"
# Favicon (cannot be renamed!) and cursor images
ExpiresByType image/vnd.microsoft.icon "access plus 1 week"
ExpiresByType image/x-icon "access plus 1 week"
# HTML
ExpiresByType text/html "access plus 0 seconds"
# JavaScript
ExpiresByType application/javascript "access plus 1 year"
ExpiresByType application/x-javascript "access plus 1 year"
ExpiresByType text/javascript "access plus 1 year"
# Manifest files
ExpiresByType application/manifest+json "access plus 1 week"
ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds"
ExpiresByType text/cache-manifest "access plus 0 seconds"
# Media files
ExpiresByType audio/ogg "access plus 1 month"
ExpiresByType image/bmp "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/svg+xml "access plus 1 month"
ExpiresByType image/webp "access plus 1 month"
ExpiresByType video/mp4 "access plus 1 month"
ExpiresByType video/ogg "access plus 1 month"
ExpiresByType video/webm "access plus 1 month"
# Web fonts
# Embedded OpenType (EOT)
ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
ExpiresByType font/eot "access plus 1 month"
# OpenType
ExpiresByType font/opentype "access plus 1 month"
# TrueType
ExpiresByType application/x-font-ttf "access plus 1 month"
# Web Open Font Format (WOFF) 1.0
ExpiresByType application/font-woff "access plus 1 month"
ExpiresByType application/x-font-woff "access plus 1 month"
ExpiresByType font/woff "access plus 1 month"
# Web Open Font Format (WOFF) 2.0
ExpiresByType application/font-woff2 "access plus 1 month"
# Other
ExpiresByType text/x-cross-domain-policy "access plus 1 week"
</IfModule>
<IfModule mod_deflate.c>
# Insert filters / compress text, html, javascript, css, xml:
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/vtt
AddOutputFilterByType DEFLATE text/x-component
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/js
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/x-httpd-php
AddOutputFilterByType DEFLATE application/x-httpd-fastphp
AddOutputFilterByType DEFLATE application/atom+xml
AddOutputFilterByType DEFLATE application/json
AddOutputFilterByType DEFLATE application/ld+json
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
AddOutputFilterByType DEFLATE application/x-font-ttf
AddOutputFilterByType DEFLATE application/x-web-app-manifest+json
AddOutputFilterByType DEFLATE font/opentype
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
# Exception: Images
SetEnvIfNoCase REQUEST_URI \.(?:gif|jpg|jpeg|png|svg)$ no-gzip dont-vary
# Drop problematic browsers
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
# Make sure proxies don't deliver the wrong content
Header append Vary User-Agent env=!dont-vary
</IfModule>
#Alternative caching using Apache's "mod_headers", if it's installed.
#Caching of common files - ENABLED
<IfModule mod_headers.c>
<FilesMatch "\.(ico|pdf|flv|swf|js|css|gif|png|jpg|jpeg|txt)$">
Header set Cache-Control "max-age=2592000, public"
</FilesMatch>
</IfModule>
<IfModule mod_headers.c>
<FilesMatch "\.(js|css|xml|gz)$">
Header append Vary Accept-Encoding
</FilesMatch>
</IfModule>
# Set Keep Alive Header
<IfModule mod_headers.c>
Header set Connection keep-alive
</IfModule>
# If your server don't support ETags deactivate with "None" (and remove header)
<IfModule mod_expires.c>
<IfModule mod_headers.c>
Header unset ETag
</IfModule>
FileETag None
</IfModule>
view raw .htaccess hosted with ❤ by GitHub

Solution 1: Host the Analytics Script Locally

Host the script on your server. This solution is ambivalent. On one hand, it immediately removes the error, and you’ll easily get the 100 points. On the contrary, it is quite troublesome, as you have to make sure that the script is getting updated.

To me, this solution seems to be good, as firstly, the script is delivered faster on my server, and secondly, with a little effort, it can also be updated automatically if you can start the proper cronjob on your hosting package.

Step 1: Downloading Analytics.js

Download the script used in the Google Analytics code. The URL is the following:

https://www.google-analytics.com/analytics.js

Load the script into the WordPress main index. The new path to the file could look like this:

https://yourwebsite.com/analytics.js

Now, search for your Google Analytics code in the theme or your plugins. If you happen to use a plugin that adds your Analytics code to the theme, deactivate the automatic addition to your theme. Otherwise, look in the header.php or the footer.php. You might also find it in your theme’s functions.php.

Replace the Original URL With Your URL. View Script:

<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://deinewebsite.de/analytics.js','ga');
ga('create', 'UA-xxxxxxx-x', 'auto');
ga('send', 'pageview');
</script>
view raw analytics.js hosted with ❤ by GitHub

Add the edited code into your theme’s footer – in the footer.php above or below of wp_footer();. Subsequently, upload the file into your theme folder.

Step 2: Create a Script That Keeps Your Local Script Up to Date

Create an empty file and name it analytics-update.php. Implement the following code into the file.

<?
// script to update local version of Google analytics script
// Remote file to download
$remoteFile = 'https://www.google-analytics.com/analytics.js';
$localfile = 'Hier kommt der absolute Pfad zum Script hinein';
//For Cpanel it will be /home/USERNAME/public_html/local-ga.js
// Connection time out
$connTimeout = 10;
$url = parse_url($remoteFile);
$host = $url['host'];
$path = isset($url['path']) ? $url['path'] : '/';
if (isset($url['query'])) {
$path .= '?' . $url['query'];
}
$port = isset($url['port']) ? $url['port'] : '80';
$fp = @fsockopen($host, '80', $errno, $errstr, $connTimeout );
if(!$fp){
// On connection failure return the cached file (if it exist)
if(file_exists($localfile)){
readfile($localfile);
}
} else {
// Send the header information
$header = "GET $path HTTP/1.0\r\n";
$header .= "Host: $host\r\n";
$header .= "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6\r\n";
$header .= "Accept: */*\r\n";
$header .= "Accept-Language: en-us,en;q=0.5\r\n";
$header .= "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n";
$header .= "Keep-Alive: 300\r\n";
$header .= "Connection: keep-alive\r\n";
$header .= "Referer: http://$host\r\n\r\n";
fputs($fp, $header);
$response = '';
// Get the response from the remote server
while($line = fread($fp, 4096)){
$response .= $line;
}
// Close the connection
fclose( $fp );
// Remove the headers
$pos = strpos($response, "\r\n\r\n");
$response = substr($response, $pos + 4);
// Return the processed response
echo $response;
// Save the response to the local file
if(!file_exists($localfile)){
// Try to create the file, if doesn't exist
fopen($localfile, 'w');
}
if(is_writable($localfile)) {
if($fp = fopen($localfile, 'w')){
fwrite($fp, $response);
fclose($fp);
}
}
}

Now, you need to extend this update file by the absolute path to your Google Analytics file. To do so, line 6 of the PHP file has to be added.

To transmit the absolute path, create an empty file called dir.php and enter the following code:

<?php echo dirname(__FILE__); ?>
<?php
$dir = dirname(__FILE__);
echo "<p>Full path to this dir: " . $dir . "/analytics.js</p>";
?>
view raw dir.php hosted with ❤ by GitHub

Copy this file into your WordPress’ main index and call up the file in the browser:

http://yourwebsite/dir.php

The lower path is correct, copy it, and replace the information in the analytics-update.php in line 6 with it.

Afterward, delete the dir.php from your server, as it poses a security risk. Now make sure that both files on your server are writable. The file rights CHMOD 755 should be okay and work.

Now, all you need to do is create a cronjob that calls up the analytics-update.php once a week. This works differently for each host and operating system so that I won’t post a code for this job.

If your server doesn’t allow for Cronjobs, use an external service like cronjob.de.

More Information:

HowTo: Add Jobs To cron Under Linux or UNIX?

The Final Result of Our Efforts

By hosting it on our server, the file can be moved into the cache, and GooglePage Speed Insights now shows the desired 100/100 points.

The Removed Error of the Google Analytics JavaScript

Solution 2: Use ga-lite.js Instead of Google-Analytics.js

Ga-Lite is a slim version of the Google Analytics script. It was developed and optimized to have the best speed and optimal browser caching. It works perfectly and records the basic functions of the original code by Google Analytics. Another advantage: the ga-lite.js script loads much faster than the original.

When you don’t just want to trick Google, but want to do something for the performance of your website, ga-lite is the right choice.

However, it does have downsides at the moment. Custom quotations can not be used. The bounce rate can not be adjusted, and links can not be tracked. By now, the IPs can be marked up anonymously, however.

The Installation of ga-lite:

Implement the following code into the footer.php of your theme, above or below of wp_footer().

<script src="https://cdn.jsdelivr.net/ga-lite/latest/ga-lite.min.js" async></script>
<script>
var galite = galite || {};
galite.UA = 'UA-XXXXXX'; // Füge deinen Tracking Code ein!
galite.anonymizeIp = true; // IP-Adresse wird anonymisiert. Wenn nicht gewünscht, true auf false setzen
</script>

ga-lite will also get you to the desired result at GooglePage Speed.

Solution 3: We Outsmart Google

You’re using an adjusted Analytics code, and both solutions are out of the question? You want to keep everything the way it is, but you still want the 100 points for your ego?

No problem, we also got an ego-solution to offer. For that, we use a small PHP function that simply makes the Google Analytics code “invisible” for PageSpeed Insights. This way, the Analytics.js works perfectly fine everywhere, except for the page of Google PageSpeed.

Extend the Analytics Code With the Following:

<?php if (!isset($_SERVER['HTTP_USER_AGENT']) || stripos($_SERVER['HTTP_USER_AGENT'], 'Speed Insights') === false): ?>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-xxxxxxx-x', 'auto'); // Deinen UA-Code hier noch einfügen
ga('send', 'pageview');
</script>
<?php endif; ?>

This code also gets you to the 100 points, but won’t speed up your website. This code is only there for your ego and lets you reach the 100 points without any significant modifications.

Conclusion:

The first solution seems to be the best to me but is not recommended by Google. It can only be used with a cronjob that always keeps the local file updated. Without this update step, the first solution is not recommendable at all. The second one is ideal when you have not made any changes to the Google Analytics code yet, and only use the analysis software’s default functions. You’ll still have access to them without any issues, and your website will be sped up at the same time.

The third solution also works, but I don’t recommend it. Personally, I would prefer living with 99 points or less. The main thing is that my websites load in much less than a second.

Source: KeyCDN

Photo by Carlos Muza on Unsplash

AUTHOR
Andreas Hecht is a journalist and specialist for WordPress and WordPress Security. He roams the web since its inception. He has published an ebook on WordPress Security, which you might want to take a look at.

Send Comment:

Jotform Avatar
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Comments: