Docs

Turn on Brotli or gzip

Turn on Brotli or gzip

HTML, CSS and JavaScript are plain text, and text compresses very well: a 300 KB script usually travels as 70–90 KB with gzip and a little less with Brotli. The browser unpacks it in a fraction of a millisecond. Without compression every visitor downloads three to five times more than needed, which is felt most on a phone with a weak signal, and it counts against the page in Google's speed measurements.

Compression is a server setting, not something the site's code does. The site checklist checks it in two places: the page itself and the CSS and JavaScript files the page loads from your own domain.

What should be compressed

Compress Do not compress
HTML (text/html) JPEG, PNG, WebP, AVIF, GIF
CSS (text/css) WOFF2 fonts
JavaScript (application/javascript, text/javascript) video, audio, ZIP, PDF
JSON, XML, SVG, plain text

The right column is already compressed; compressing it again only costs CPU. Brotli (br) is a bit smaller than gzip and every current browser supports it, but gzip alone is enough for the checklist.

The most common cause of a yellow "CSS and JavaScript compressed" item is nginx: Debian and Ubuntu ship it with gzip on, but the line that lists the other file types is commented out, so only the HTML gets compressed.

Check it yourself

Replace example.com with your site and the second address with one of your CSS or JS files (the checklist lists the ones it found uncompressed):

curl -s -o /dev/null -D - -H 'Accept-Encoding: br, gzip' https://example.com/ | grep -i '^content-encoding'
curl -s -o /dev/null -D - -H 'Accept-Encoding: br, gzip' https://example.com/assets/app.css | grep -i '^content-encoding'

content-encoding: br or content-encoding: gzip means compressed. No output means the file was sent as is.

How to fix

Pick the place that actually sends the files. If Cloudflare sits in front of the site, it compresses for you; otherwise it is the web server or the hosting panel.

nginx

Open /etc/nginx/nginx.conf (the same path on Debian, Ubuntu, Rocky, Alma and CentOS) and, inside the http { … } block, make sure the gzip lines are active and not commented out:

http {
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 5;
    gzip_min_length 256;
    gzip_types text/css text/plain text/xml application/javascript text/javascript
               application/json application/xml application/rss+xml image/svg+xml;
}

text/html is always compressed once gzip on is set, so it is not in the list. gzip_vary tells caches that the answer depends on what the browser accepts, and gzip_proxied any keeps compression on when the request comes through a CDN or another proxy.

Brotli needs the separate ngx_brotli module. Where your distribution packages it (on recent Debian and Ubuntu as libnginx-mod-http-brotli-filter), install it and add next to the gzip lines:

brotli on;
brotli_comp_level 5;
brotli_types text/css text/plain text/xml application/javascript text/javascript
             application/json application/xml application/rss+xml image/svg+xml;

Test and apply:

sudo nginx -t && sudo systemctl reload nginx

Apache and LiteSpeed

With server access (Apache). Compression is mod_deflate. On Debian and Ubuntu enable it with sudo a2enmod deflate; on Rocky, Alma and CentOS it is loaded by default. Then add to the site's <VirtualHost> or to .htaccess:

<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css
    AddOutputFilterByType DEFLATE application/javascript text/javascript
    AddOutputFilterByType DEFLATE application/json application/xml application/rss+xml image/svg+xml
</IfModule>
sudo apachectl configtest && sudo systemctl reload apache2

(httpd instead of apache2 on Rocky, Alma and CentOS.) Apache 2.4.26 and newer also has mod_brotli (sudo a2enmod brotli), with the filter BROTLI_COMPRESS for the same types.

Without server access (shared hosting). Put the same block in the .htaccess in the site's root. LiteSpeed servers compress at the server level, usually with gzip and Brotli already on; if the check still shows no compression on a LiteSpeed host, ask support to enable it.

cPanel

  1. Open Software → Optimize Website.
  2. Choose Compress All Content (or Compress the specified MIME types and list the types from the table above).
  3. Click Update Settings.

cPanel writes mod_deflate rules into the site's .htaccess. If the screen is missing or the check still shows no compression, the server may be LiteSpeed or nginx; ask the host, it is a server setting for them.

Plesk

In Plesk, nginx usually sits in front of Apache and sends the files to the visitor, so compression belongs there. Websites & Domains → example.com → Apache & nginx Settings, in Additional nginx directives add:

gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_types text/css text/plain text/xml application/javascript text/javascript
           application/json application/xml image/svg+xml;

Click OK; Plesk checks the syntax and reloads nginx. If the site runs on Apache alone (nginx turned off), use the .htaccess block from the Apache tab instead.

Cloudflare

When the site runs behind Cloudflare (orange cloud), Cloudflare compresses HTML, CSS, JavaScript and other text types with Brotli or gzip on its way to the visitor, on every plan, whatever the server does. There is nothing to turn on.

If the check still shows no compression, look for one of these:

  • The record is DNS only (grey cloud), so traffic does not go through Cloudflare.
  • The server sends Cache-Control: no-transform, which forbids Cloudflare to change the response.
  • The file is served from a different domain that is not on Cloudflare.

WordPress

WordPress itself does not compress anything; the web server does. Caching plugins can help with the configuration: WP Rocket writes mod_deflate rules into .htaccess, and W3 Total Cache has a gzip option under Performance → Browser Cache. Both only work on Apache or LiteSpeed, where .htaccess is read. On nginx the rules do nothing.

If the site uses LiteSpeed Cache, compression is done by the LiteSpeed server, not the plugin. If the check is still yellow after a plugin setting and clearing the cache, use the tab for your hosting panel or server, or ask the host.

Node.js and Next.js

Next.js compresses responses with gzip when you run it with next start (compress: true is the default). If nginx or a CDN in front of it already compresses, turn it off in next.config.js so the work is not done twice:

module.exports = {
    compress: false,
};

Express needs the compression middleware (npm install compression), registered before your routes and static files:

const compression = require('compression');
app.use(compression());

On a busy site it is cheaper to let nginx or a CDN compress and leave Node to the application.

IIS and ASP.NET

IIS compresses static files (CSS, JS) by default, but compression of dynamic pages is a separate role feature. Install Dynamic Content Compression in Server Manager (Add Roles and Features → Web Server → Performance), then turn both on in the site's web.config:

<configuration>
  <system.webServer>
    <urlCompression doStaticCompression="true" doDynamicCompression="true" />
  </system.webServer>
</configuration>

For Brotli, Microsoft publishes the free IIS Compression extension, which adds a Brotli scheme next to gzip.

Hosted platforms

Shopify, Wix, Squarespace and Webflow compress everything themselves. If the checklist reports a file there as uncompressed, it usually comes from a third-party app or an external host that you can ask, not from the platform.

Watch out for

  • Cached copies. A CDN or a caching plugin may keep serving a copy it stored before the change. Purge the cache after you turn compression on.
  • Compressing twice. PHP's zlib.output_compression and the web server should not both compress: it wastes CPU and, with some setups, the browser receives a response it cannot read. Let the web server do it.
  • Pre-compressed files. Build tools can produce app.css.gz and app.css.br next to the original. nginx serves them with gzip_static on; (and brotli_static on; with the module), which saves CPU on every request.

Confirm the fix

Run the two curl commands from Check it yourself again, then open the target in PulseKeeper and click Check now on the Checklist tab. Both items, for the page and for CSS and JavaScript, turn OK within a few minutes instead of at the next daily run.