Text compression is a quick server-side upgrade for faster page loads, cutting the transfer size of HTML, CSS, JavaScript, JSON, and SVG without changing what the browser renders. In practice you enable HTTP compression at the origin, reverse proxy, or CDN, prefer Brotli when supported, and keep gzip as a fallback for older clients. The key checks are that only text MIME types are compressed, responses send the correct Content-Encoding, and your cache varies by Accept-Encoding so visitors receive the right version. A frequent gotcha is enabling it on the server but losing it through a proxy or CDN rule that recompresses or removes headers.
Text compression explained: Brotli and Gzip for HTML, CSS, JS
Text compression vs minification and image compression
Text compression reduces the number of bytes sent over the network by encoding the response body (for example, HTML, CSS, and JavaScript) before it is transferred. The browser then decompresses it automatically. This is negotiated per request using Accept-Encoding and confirmed in the response with Content-Encoding.
The two most common algorithms are Brotli and gzip. Brotli typically achieves smaller files for modern text assets, and most modern browsers support it over HTTPS. Gzip is the long-time default and remains a reliable fallback for older clients and some edge cases. Brotli is standardized as an IETF RFC, which is why you will often see it referenced in server and CDN docs (see the Brotli specification).
Minification is different. Minification removes characters from the source itself (whitespace, comments, sometimes renames variables) and produces smaller files even before compression. In real setups, you usually do both: minify in your build pipeline, then compress at the CDN or server.
Image compression is also separate. Images use their own formats and codecs (WebP, AVIF, JPEG, PNG). Turning on gzip or Brotli does not meaningfully “compress images” and can waste CPU.
File types that should and should not be compressed
Compress these response types (especially when they are not tiny):
- HTML, CSS, JavaScript
- JSON, XML
- SVG (it is text-based)
- Plain text, CSV
Usually avoid compressing these, because they are already compressed or do not benefit much:
- Images (JPEG, PNG, WebP, AVIF, GIF)
- Video and audio (MP4, WebM, MP3)
- Archives and binaries (ZIP, gz, rar, exe)
- Fonts like WOFF2 (already compressed)
A practical rule: compress “text-like” MIME types, and skip formats that are already optimized. This prevents double-compression and keeps your server or edge CPU focused where it actually improves page speed.
Why enabling compression improves Lighthouse and real page speed
Typical savings for CSS, JavaScript, HTML, JSON, and SVG
Text compression improves speed for a simple reason: fewer bytes travel over the network. That matters most on mobile connections, during network congestion, and for first-time visitors who do not have assets cached yet. It also directly addresses Lighthouse’s “Enable text compression” finding, which is based on whether a text response is delivered without a supported Content-Encoding such as br or gzip (and it estimates savings by compressing the response with gzip). Lighthouse’s audit details
In real-world terms, it’s common for text-based files to shrink dramatically, especially when they include lots of repeated patterns (HTML markup, CSS selectors, JSON keys):
- HTML: often 50% to 80% smaller
- CSS: often 50% to 80% smaller
- JavaScript: often 40% to 70% smaller
- JSON / XML: often 60% to 90% smaller
- SVG: often 50% to 90% smaller
Your exact savings depend on how minified the file is, how repetitive the content is, and whether it’s already compressed (most text files are not). Google’s own PageSpeed guidance notes gzip can reduce transfer size by up to 90% in some cases.
CPU tradeoffs and minimum-size thresholds
Compression is not “free.” Dynamic (on-the-fly) compression uses CPU, and very aggressive settings can increase server response time, especially on busy origins. A practical pattern is:
- Static assets (CSS/JS/SVG): precompress and serve
.brand.gzwhere possible. - Dynamic HTML: use moderate compression levels to balance size vs latency.
Also set a minimum size. Very small responses often don’t compress well, and the overhead can outweigh the benefit. Lighthouse itself won’t flag a response under 1.4 KiB, or if estimated savings are under 10%, which is a useful rule of thumb when you pick minimum-size thresholds for your server or CDN.
How the “Enable text compression” audit gets triggered
PageSpeed Insights and Lighthouse thresholds
In modern reports, PageSpeed Insights uses Lighthouse for its Lab Data diagnostics, so the “Enable text compression” finding is essentially a Lighthouse rule shown inside the PSI UI.
Lighthouse triggers the audit when it finds text-based resources that are served without a supported Content-Encoding such as br, gzip, or deflate. It then estimates potential savings by compressing those responses with gzip.
To reduce noise, Lighthouse ignores resources that are too small or don’t benefit much. Specifically, it does not flag a response if the original size is under 1.4 KiB, or if the potential savings are under 10% of the original size.
One important nuance for 2026: in Lighthouse 13, this audit is surfaced under the “Document request latency” insight rather than standing alone, which can make it feel like the rule “moved” in your reports even though the underlying checks are similar.
GTmetrix and other test tool variations
GTmetrix runs its own audit logic and may not line up perfectly with PSI. It flags uncompressed text resources when compression would save at least 10% or 1.4 KB (whichever is met), and it recognizes gzip, Brotli, and deflate as valid compression types.
Across other testing tools, differences usually come from:
- Test conditions (location, network throttling, device emulation).
- Caching state (cold vs warm cache, CDN behavior).
- Header handling (proxies stripping
Content-Encoding, missingVary: Accept-Encoding, or edge recompression).
When tools disagree, treat the warning as a prompt to verify headers on the actual response your users receive, not just what one audit reports.
Verifying compression is working using response headers
Chrome DevTools Network: Content-Encoding and Vary
In Chrome, the quickest way to confirm text compression is to check the response headers for the exact resource that Lighthouse flagged.
Open DevTools, go to Network, and tick Disable cache (it only works while DevTools is open). Reload the page, click the document or asset, then open the Headers tab.
Look for:
Content-Encoding: this should bebr(Brotli) orgzipfor compressed text responses. If it’s missing, the resource was likely served uncompressed. MDN’s Content-Encoding reference is a useful baseline for what values mean and when they should appear.Vary: Accept-Encoding: this tells caches (browser, CDN, proxy) that the response can differ based on compression support. Without it, you can end up caching an uncompressed variant and serving it to everyone, even after you “enabled gzip/Brotli.”Content-Type: verify it is a text MIME type (liketext/html,text/css,application/javascript, orapplication/json). Some setups only compress a narrow list and accidentally skip HTML or JSON.
If you want to make this repeatable, Chrome’s Network panel reference shows how to add useful columns and inspect headers consistently.
Testing HTML, CSS, JS, and JSON responses
Don’t only test CSS and JS. Many “Enable text compression” warnings come from HTML (the main document) or JSON (API responses).
A fast checklist:
- HTML document: click the top “document” request and confirm
Content-Encodingis present. - CSS/JS: check both first-party files and third-party scripts you control.
- JSON endpoints: filter by “Fetch/XHR” and confirm APIs return compressed JSON, especially when payloads are large.
- Watch for false confidence: if the Network tab shows “from disk cache” or “from memory cache,” you may be looking at a cached response, not what new visitors get. Disable cache and reload before you decide it’s fixed.
Enabling compression at the CDN or edge layer first
Cloudflare Brotli and Gzip settings
If you use a CDN, enabling compression at the edge is often the fastest win. You fix Lighthouse warnings for many pages at once, without touching Apache or NGINX configs on every origin.
With Cloudflare, edge compression is negotiated per request based on the browser’s Accept-Encoding. Cloudflare can deliver responses using Brotli (br) or gzip (and, in some plans or configurations, other methods), and you can fine-tune behavior with rules. Cloudflare’s own content compression documentation also calls out practical constraints like minimum response sizes and which status codes are eligible for compression.
After you turn it on, verify with DevTools that your HTML, CSS, JS, and JSON responses show Content-Encoding: br (or gzip) and include Vary: Accept-Encoding.
Avoiding surprises with edge recompression
Edge compression is not always “set and forget.” CDNs may need to decompress and recompress content when they modify the payload. On Cloudflare, certain features that change the response can force recompression, which may change headers like Content-Length and complicate debugging.
Two safe habits:
- Avoid relying on a fixed
Content-Lengthfor compressed responses. - Be cautious with transformations on paths where you care about strict end-to-end behavior.
When both CDN and origin compression are needed
You may still want origin compression even with a CDN in front:
- Some traffic bypasses the CDN (direct-to-origin health checks, alternate hostnames, internal tools, API subdomains not proxied).
- You want to reduce bandwidth between your origin and the CDN. Cloudflare can request compressed content from the origin and keep that encoding end-to-end when conditions allow.
- You serve highly dynamic pages that are rarely cached at the edge, where origin compression still pays off on every request.
Server configuration to compress responses on Apache, NGINX, and IIS
Apache.htaccess with mod_deflate or Brotli
On Apache, gzip-style compression is typically handled by mod_deflate. If your host allows it, you can enable it in .htaccess and target common text MIME types. Apache’s mod_deflate docs are the best reference for directives and edge cases.
A common pattern looks like this:
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/plain text/css
AddOutputFilterByType DEFLATE application/javascript application/json image/svg+xml
</IfModule>
If you want Brotli (Content-Encoding: br), Apache can also use mod_brotli on supported builds. The approach is similar: enable the module, apply the Brotli output filter to text MIME types, and keep gzip as a fallback for clients that do not advertise Brotli support.
NGINX gzip and brotli module basics
In NGINX, gzip is built-in and straightforward:
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript image/svg+xml;
Brotli is not part of the open source NGINX core by default. It’s usually added via a module (for example, ngx_brotli or a packaged module in a managed NGINX distribution). Once installed, configuration typically mirrors gzip: turn it on, set a compression level, and define brotli_types. If you precompress assets during your build, enabling “static Brotli” support can let NGINX serve .br files directly for CSS/JS.
IIS Dynamic and Static Compression settings
On IIS, compression is split into Static (files on disk like CSS/JS) and Dynamic (responses generated by apps). In IIS Manager, you typically enable both so HTML and API responses don’t get missed.
IIS supports built-in compression, and Microsoft also provides an extension that can add Brotli and improve compression behavior. Microsoft’s IIS Compression Overview is the most reliable starting point for what’s available and how it’s deployed.
After any IIS change, re-check a few real URLs in DevTools to confirm Content-Encoding is present for HTML, CSS, JS, and JSON, and that Vary: Accept-Encoding is being sent.
Common reasons the warning persists after enabling compression
Missing MIME types or HTML not compressed
The most common cause is simple: compression is enabled, but your server only compresses a narrow set of MIME types. CSS and JS might be compressed, while the main HTML document is not.
Check for these patterns:
- HTML excluded by config: some setups only target
text/cssandapplication/javascript, and forgettext/html. - JSON and SVG missed: APIs often return
application/json, and SVG should beimage/svg+xml. If those types are not in your allowlist, they stay uncompressed. - Wrong
Content-Type: if your server labels a file asapplication/octet-stream, it may not match the compression rules even though it is text. - Already-compressed assets: if you serve
.gzor.brfiles directly but don’t set the matchingContent-Encoding, tools can still flag the resource.
For SEO, the practical impact is bigger than a score. Uncompressed HTML can delay first render, which affects real user experience and the content that both users and AI-driven systems can access quickly.
Proxies and caches stripping Content-Encoding
Even when origin compression is correct, intermediaries can break it:
- A reverse proxy or load balancer may remove
Content-Encodingor fail to forwardAccept-Encoding. - A CDN may cache an uncompressed variant and keep serving it if
Vary: Accept-Encodingis missing. - Some security or optimization layers modify responses. That can trigger decompression and recompression, or disable compression for specific routes.
If you’re optimizing for the AI search world, this consistency matters. AI agents and browser-based crawlers do not always hit your site the same way as your own tests. You want predictable, standards-based headers for every public endpoint.
Rerunning audits and confirming improvements
After changes, validate in this order:
- DevTools first: confirm
Content-Encodingon the exact URL Lighthouse flagged, with cache disabled. - Bypass stale caches: purge your CDN cache, or test with a new URL version (for example, a cache-busting query string) to avoid old variants.
- Retest with multiple tools: PSI/Lighthouse, GTmetrix, and your own header checks should agree on the core issue.
If the warning persists, focus on the specific uncompressed resources listed in the report. Fixing one global switch rarely covers every HTML page, API route, and edge rule on the first pass.