HSTS missing: how to add the Strict-Transport-Security header to your app
"HSTS missing" means your HTTPS responses don't include a Strict-Transport-Security header, so browsers aren't told to stick to HTTPS for your domain. Add the header to every HTTPS response with a starting value such as max-age=31536000 (one year), and add includeSubDomains only once every subdomain you own serves HTTPS.
What HSTS does
MDN: the header "informs browsers that the host should only be accessed using HTTPS, and that any future attempts to access it using HTTP should automatically be upgraded to HTTPS." It adds that on later visits the browser won't let the visitor click past certificate errors, "such as an invalid certificate."
Two details matter:
- It only counts over HTTPS. MDN: "Browsers ignore the header if sent over HTTP." You still need an HTTP-to-HTTPS redirect for the first visit (see HTTP not redirecting to HTTPS).
max-ageis in seconds. It's how long the browser remembers the rule.31536000is one year.
Pick a value
| Value | When to use it |
|---|---|
max-age=31536000 |
A good start for an app on one host name. |
max-age=31536000; includeSubDomains |
When every subdomain (www, app, api, mail web pages) serves HTTPS. MDN: the policy then "applies to all subdomains of the host's domain as well." |
max-age=63072000; includeSubDomains; preload |
Only if you plan to submit the domain to the HSTS preload list. |
Be careful with preload. Netlify's HTTPS docs warn that this "is not easily reversible", and to "only use the directive preload once you're confident that the domain and all subdomains are ready to be served using only HTTPS."
Add it on your host
Netlify (_headers file in your publish folder):
/*
Strict-Transport-Security: max-age=31536000
Cloudflare Pages (_headers file in your static assets or public/ folder):
/*
Strict-Transport-Security: max-age=31536000
Cloudflare notes that _headers rules "are not applied to responses generated by Pages Functions", so set the header in the Function's code for server-rendered pages.
Vercel (vercel.json):
{
"headers": [
{
"source": "/(.*)",
"headers": [
{ "key": "Strict-Transport-Security", "value": "max-age=31536000" }
]
}
]
}
Test this on a preview deployment before relying on it. Read your live response headers first: if strict-transport-security is already there, your host sets it and you can leave it.
Confirm it
Open your site, open the browser's developer tools, go to Network, select the first document request, and look under Response Headers for strict-transport-security. Or run curl -sI https://yourdomain.com and look for the same line.
What Pewterkit Check looks at
The check reads the response headers of your home page over HTTPS and reports when Strict-Transport-Security is missing, together with the other basic browser protections (clickjacking protection, nosniff, a referrer policy) in one finding. It skips this check on builder subdomains (such as *.lovable.app or *.vercel.app), where the platform controls the headers.
FAQ
Will HSTS break my site?
It only affects browsers that reach you over HTTPS, and tells them to keep doing so. Problems come from includeSubDomains or preload when some subdomain has no HTTPS yet, so start with max-age alone.
Can I add HSTS with a meta tag?
Set it as an HTTP response header. Browsers read HSTS from the HTTPS response headers, so use your host's header settings.
How long should max-age be?
One year (31536000) is common. A shorter value such as one day (86400) is a cautious first step while you check every page works over HTTPS.
Sources
- Strict-Transport-Security header (MDN) — read 27 Oct 2026
- Custom headers (Netlify Docs) — read 27 Oct 2026
- HTTPS (SSL): HSTS preload (Netlify Docs) — read 27 Oct 2026
- Headers (Cloudflare Pages docs) — read 27 Oct 2026
- Static configuration with vercel.json: headers (Vercel Docs) — read 27 Oct 2026
How this page was made: drafted with AI from the sources listed, reviewed by Pewterkit. Docs checked Oct 27, 2026. Spotted something out of date? Tell us.