A Strict-Transport-Security header tells browsers to use only HTTPS for the host that sent it, for max-age seconds. includeSubDomains extends that rule to every name under the host, internal ones included. preload asks browser makers to build the rule into the browser itself, where changing your header no longer switches it off quickly.
What each directive commits you to
| Directive | Defined by | Covers | Lasts | To back out |
|---|---|---|---|---|
max-age=<seconds> |
RFC 6797, section 6.1.1 | Only the host that sent the header | That many seconds after the latest response carrying it | Send max-age=0 over HTTPS; each browser forgets the policy only when it receives that response |
includeSubDomains |
RFC 6797, section 6.1.2 | The host and every name below it | The same max-age |
The same, and the max-age=0 has to come from the host that set the policy |
preload |
hstspreload.org’s submission rules, not RFC 6797 | The listed domain and, for entries submitted through hstspreload.org, all its subdomains, in every browser that ships the list | Until browser releases drop the entry | Remove preload, request removal, and wait 6-12 weeks for most Chrome users, longer for other browsers |
Three rules turn these directives into real commitments:
- HTTPS only. Browsers ignore the header when it arrives over plain HTTP (MDN), so a first visit over
http://is unprotected unless the name is preloaded. - No click-through. Once a host is a known HSTS host, RFC 6797 requires the browser to end the connection on any TLS error (section 8.4), and browsers give the user no way to click past it (section 12.1; MDN). An expired or mismatched certificate on a covered name is an outage, not a warning.
- First header wins. If a response carries more than one
Strict-Transport-Securityfield, browsers process only the first (section 8.1).
What 100 developer platforms send
In our survey of 100 developer platforms, we recorded the header on each apex domain’s first HTTPS response on 26 September 2026.
| What the apex’s first HTTPS response sent | Domains |
|---|---|
max-age + includeSubDomains + preload |
35 |
max-age only |
31 |
max-age + includeSubDomains |
7 |
max-age + preload |
5 |
| No header | 22 |
Recorded by the survey, 26 September 2026 (14:59 to 15:12 UTC). Five raw values, exactly as the servers sent them:
| Domain | Strict-Transport-Security on the apex’s first response |
|---|---|
| vercel.com | max-age=31536000; includeSubDomains; preload |
| github.com | max-age=31536000; includeSubdomains; preload |
| akamai.com | max-age=31536000 ; includeSubDomains ; preload |
| codeberg.org | max-age=63072000; includeSubDomains; preload; |
| linear.app | max-age=63072000; includeSubDomains |
The variations are all valid. Directive names are case-insensitive, so includeSubdomains works. RFC 6797 builds its grammar on implied whitespace and allows empty directives, so spaces around semicolons and a trailing semicolon are harmless.
Across the 100 domains, 31 headers meet the preload list’s minimum: a max-age of at least 31536000 seconds (one year), plus includeSubDomains and preload. Nine more headers include preload without qualifying: four have a max-age under a year and five lack includeSubDomains. One domain sent max-age=0, which tells browsers to drop the policy.
The apex’s own response carries the subdomain policy
includeSubDomains covers the host that sent it and the names below that host, nothing sideways. MDN’s example: a policy set by secure.example.com covers login.secure.example.com but not example.com or insecure.example.com. A policy that only www.example.com sends therefore never reaches api.example.com.
That makes the apex’s redirect the important response on a www-canonical site. hstspreload.org requires an HTTPS redirect to carry the header, and its checker flags an http:// apex that jumps straight to https://www.. The checker’s reason (code redirects.http.www_first) is that the extra hop to HTTPS on the same host makes browsers record the policy for the top-level domain, not just for www.
In the survey, 38 apexes redirected to www. 27 of them sent HSTS on that redirect, and 13 included includeSubDomains there.
Live capture, 26 September 2026 (15:25 UTC). The cloudflare.com apex and its www host:
curl -sI https://cloudflare.com/ | grep -iE '^(HTTP|location|strict-transport-security)'
curl -sI https://www.cloudflare.com/ | grep -iE '^(HTTP|strict-transport-security)'
HTTP/2 301
location: https://www.cloudflare.com/
strict-transport-security: max-age=15780000; includeSubDomains
HTTP/2 103
HTTP/2 200
strict-transport-security: max-age=31536000; includeSubDomains
The redirect carries its own policy, with includeSubDomains, so a browser that follows it records a rule for cloudflare.com and everything under it. The final page on www sends a longer max-age. The 103 line is an Early Hints response that comes before the final 200. When you check your own site, look at every hop, not just the page that loads.
A preload entry is not a header
The preload list is a file in the Chromium source tree. Other major browsers use lists based on it, according to hstspreload.org. Your header only signals eligibility and consent when you submit. What browsers enforce is the list entry.
Live capture, 26 September 2026 (15:15 UTC). The hstspreload.org status API for two surveyed domains:
curl -s "https://hstspreload.org/api/v2/status?domain=github.com"
curl -s "https://hstspreload.org/api/v2/status?domain=cloudflare.com"
{
"name": "github.com",
"status": "preloaded",
"bulk": true,
"preloadedDomain": "github.com"
}
{
"name": "cloudflare.com",
"status": "preloaded",
"bulk": false,
"preloadedDomain": "cloudflare.com"
}
Both are preloaded, yet only github.com’s header contains preload today. In the Chromium file, github.com’s entry has the policy bulk-18-weeks, while cloudflare.com’s has custom rather than one of the bulk policies, which matches the API’s "bulk": false.
The survey shows the same mismatch in both directions. Matched against the list fetched at 15:14 UTC, 34 of the 100 domains are covered. 27 of the 40 domains that send preload are on it, 13 are not, and 7 covered domains leave preload out of the header on the apex’s first response. Dropping preload from the header does not remove an entry. Removal needs a header without preload, a request on hstspreload.org, and browser releases that ship the change.
.dev, .app, and other preloaded suffixes
Chromium’s list can also hold whole public suffixes. Google Registry preloaded .google in 2015 and began rolling out .foo and .dev in 2017. The list fetched during our survey held 94,778 entries, 57 of them with the policy public-suffix.
Live capture, 26 September 2026 (15:15 UTC). Searching the current list source for app, dev, and our own .guide and and.guide:
curl -s 'https://chromium.googlesource.com/chromium/src/+/main/net/http/transport_security_state_static.json?format=TEXT' \
| base64 --decode \
| grep -E '"name": "(app|dev|guide|and\.guide)"'
{ "name": "app", "policy": "public-suffix", "mode": "force-https", "include_subdomains": true },
{ "name": "dev", "policy": "public-suffix", "mode": "force-https", "include_subdomains": true },
app and dev each have one entry with include_subdomains: true, so every domain registered under them is covered. Neither .guide nor and.guide appears. The status API reports suffix coverage through preloadedDomain:
curl -s "https://hstspreload.org/api/v2/status?domain=go.dev"
{
"name": "go.dev",
"status": "preloaded",
"bulk": false,
"preloadedDomain": "dev"
}
Five surveyed domains sit under these suffixes: go.dev, pub.dev, react.dev, convex.dev, and linear.app. Their headers range from max-age=63072000 alone (react.dev) to the full preload form (go.dev and pub.dev). In browsers that ship the list, all five are HTTPS-only either way. A single name cannot opt out, because the entry belongs to the whole suffix. In those browsers, every hostname you create under a .dev or .app domain needs a valid certificate before it will load. Keep plain-HTTP local work on reserved names such as .test, as in our local development guide.
Where includeSubDomains breaks things
hstspreload.org warns that preloading applies to all subdomains, including internal ones that are not publicly reachable. The same holds for a plain includeSubDomains header in every browser that has seen it. Before you send it, look for names like these:
- internal dashboards and admin tools reachable only from an office or VPN, which may use self-signed or private-CA certificates
- printers, NAS boxes, and router admin pages given names under the domain
- vendor-hosted names (a CNAME to a SaaS product) where the vendor serves plain HTTP or a certificate for its own name
- staging and preview hosts that serve plain HTTP
- names that point at
127.0.0.1for local development
A browser holding the policy rewrites http:// to https:// for each of these names and refuses to proceed past any certificate error. To know which names exist, inventory public DNS, internal DNS, and vendor CNAMEs, as described in subdomain inventory and cleanup. Then verify each certificate from the command line (inspecting a TLS certificate) before any of them falls under the policy.
A ramp-up you can still back out of
hstspreload.org recommends raising max-age in stages and waiting out each one:
- Inventory every name under the domain, and give each one a valid certificate or move it to a separate domain that will not carry the policy.
- Send
max-age=300; includeSubDomainson every HTTPS response, including redirects. Check for broken pages and watch your traffic. - Move to
max-age=604800; includeSubDomains(one week) once no problems remain, and wait the full week. - Move to
max-age=2592000; includeSubDomains(one month) and wait the full month. - Raise
max-ageto at least 31536000 (one year), the minimum hstspreload.org accepts. - Add
preloadonly when you intend to submit, then submit on hstspreload.org. New entries can take several months to reach stable Chrome.
If you have a group of employees or beta users, hstspreload.org suggests trying the first stages on them, then starting over from the beginning for everyone.
Until step 6, max-age=0 over HTTPS clears the policy in each browser that fetches it. Browsers that never come back keep the old policy until its max-age runs out. After preloading, you also have to drop preload and file a removal. hstspreload.org asks that the domain never send preload again unless you are ready to be preloaded again.
On Cloudflare, the HSTS setting on the Edge Certificates page adds the header at the edge. It offers max-age values from 1 to 12 months and separate switches for subdomains and preload, and Cloudflare warns that subdomains without HTTPS become inaccessible. On Cloudflare Pages, a _headers rule applies to static assets but not to responses generated by Pages Functions.
Checking a domain, with and.guide as the example
Four checks cover most questions: the header on the apex, the plain-HTTP redirect, the preload status, and what the preload checker would say.
Live capture, 26 September 2026 (15:15 UTC). Our own apex over HTTPS, then over HTTP:
curl -sI https://and.guide/
HTTP/2 200
date: Sat, 26 Sep 2026 15:15:03 GMT
content-type: text/html; charset=utf-8
access-control-allow-origin: *
cache-control: public, max-age=0, must-revalidate
...
vary: Accept
referrer-policy: strict-origin-when-cross-origin
x-content-type-options: nosniff
...
server: cloudflare
cf-ray: a41338cbdf9cfc1a-ICN
alt-svc: h3=":443"; ma=86400
curl -sI http://and.guide/
HTTP/1.1 301 Moved Permanently
Date: Sat, 26 Sep 2026 15:15:03 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Location: https://and.guide/
...
Server: cloudflare
CF-RAY: a41338cc2c453058-ICN
alt-svc: h3=":443"; ma=86400
There is no strict-transport-security line in the HTTPS response. The trimmed lines are the long link, report-to, and nel headers in the first response and Report-To and Nel in the second. Plain HTTP redirects to HTTPS on the same host, which is the redirect order hstspreload.org asks for. The status and preloadable endpoints agree:
curl -s "https://hstspreload.org/api/v2/status?domain=and.guide"
curl -s "https://hstspreload.org/api/v2/preloadable?domain=and.guide"
{
"name": "and.guide",
"status": "unknown",
"bulk": false,
"preloadedDomain": ""
}
{
"errors": [
{
"code": "response.no_header",
"summary": "No HSTS header",
"message": "Response error: No HSTS header is present on the response."
}
],
"warnings": []
}
unknown means hstspreload.org has no submission or list entry for the domain, and .guide is not a preloaded suffix (the list search above found no entry). As of this capture, and.guide’s protection is the HTTP-to-HTTPS redirect alone, and the stages above are the path to changing that. The preloadable endpoint makes hstspreload.org fetch the site itself, so point it at domains you operate. For anyone else’s domain, the header and the status API are enough.