upgrade-insecure-requests: upgrade every insecure request before it fires

upgrade-insecure-requests is a CSP directive that rewrites http:// URLs to https:// before the browser sends them. Add the header, find the insecure URLs first, and keep HSTS for the links this directive cannot touch.

Crawling & Indexing6 min read2091 views
upgrade-insecure-requests: upgrade every insecure request before it fires

upgrade-insecure-requests is a Content-Security-Policy directive that rewrites an insecure URL to HTTPS before the browser sends the request. Add one response header, and every http:// subresource on the page is fetched over https:// instead. It is a rewrite, not a repair: if the secure URL does not answer, the request fails with no fallback. It also does not replace HSTS, because links to other hosts are left alone.

What upgrade-insecure-requests changes

It acts earlier than mixed-content blocking. The W3C specification says the mechanism upgrades a priori insecure resource requests “before fetching them”, and the rewrite happens before Mixed Content or CSP checks take effect, so an upgraded request is not reported as mixed content (Upgrade Insecure Requests, W3C Candidate Recommendation, 8 October 2015, read 2026-11-03). MDN describes the same behaviour and marks the feature Baseline widely available since April 2018 (MDN, read 2026-11-03).

That timing is the whole value. The browser never makes the insecure request, so there is nothing for mixed-content blocking to catch.

RequestUpgraded?If HTTPS fails
First-party image over http://YesImage fails; no HTTP retry
Third-party script over http://YesScript fails; no HTTP retry
Same-origin link (navigation)YesPage fails; no fallback
Link to another host over http://NoBrowser follows HTTP
Asset served only over HTTPYesRequest fails outright

The fourth row is the one people miss. A same-origin navigation is upgraded; a navigation to a different host is not (Upgrade Insecure Requests, section 1.2.2, read 2026-11-03). That is why this directive is not a substitute for HSTS.

How to add the directive

One response header is enough. Put it on every HTML response that can contain an insecure URL.

Content-Security-Policy: upgrade-insecure-requests

If the host cannot set response headers, the meta element is the fallback. It covers the document that carries it, and nothing else.

<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

Do not pair it with block-all-mixed-content. MDN marks that directive deprecated, and the W3C specification says upgrade-insecure-requests is evaluated first, which makes block-all-mixed-content effectively a no-op when both are present (MDN, read 2026-11-03). Set one directive or the other.

Find the insecure URLs before you enforce

Start by counting what you have. The two commands below take a minute and give you a list you can argue with. They do not find every insecure URL: JavaScript-built URLs and URLs inside CSS are invisible to the second command.

# 1. Does the page already send the directive?
curl -sI https://example.com | grep -i '^content-security-policy'

# 2. Which resource URLs are still http://?
curl -s https://example.com \
  | grep -oE '(src|href)="http://[^"]+' \
  | sort -u

Run the second command on the templates that render the most pages, not just the homepage. A checkout page, a blog post and a landing page often have different third-party embeds. If you are still seeing mixed-content warnings after the fix, the diagnosis is in how to fix mixed content.

A report-only deployment gives you the real list. The browser sends violation reports but does not rewrite anything, so you can compare what it reports with what your source scan found.

Content-Security-Policy-Report-Only: upgrade-insecure-requests; report-uri /csp-reports

report-uri is the older reporting mechanism. report-to is the newer endpoint configuration, but the two are not interchangeable on every host. We did not test report delivery across CDNs for this chapter, so check your own endpoint and confirm that reports actually arrive before you trust an empty report as proof.

Where the directive stops

Three limits matter more than the syntax.

  1. Third-party navigations. A link to another host over http:// is not upgraded. The user still leaves your page over HTTP, and this directive cannot stop it.
  2. Missing HTTPS. There is no fallback. If the upgraded URL does not answer over HTTPS, the request fails, and the page loses that asset.
  3. HSTS. The directive does not replace Strict-Transport-Security. HSTS protects future visits and first-time navigations; this directive protects the requests made by the current page.

The specification also handles WebSocket connections separately. An insecure ws:// connection is upgraded to wss:// when the directive applies (section 5, read 2026-11-03). We did not test a live WebSocket endpoint against this rule, so treat that as documented behaviour rather than a measured result.

There is also a crawler question we did not answer. We did not test whether Googlebot or any AI crawler honours this directive. A crawler that renders like a current browser should get the rewrite, but we have no measurement to prove it for each one, and we will not present a guess as a result.

A migration order that does not break the page

This is the sequence I would use on a site with years of hardcoded http:// URLs.

  1. Inventory the templates. Run the two commands on the pages that matter, not only the homepage, and keep the output as a file.
  2. Fix what you control. Move same-origin images, fonts and scripts to HTTPS first. Those are the failures you can see and fix in one deploy.
  3. Check every third party. Ask for an HTTPS URL. If a vendor has none, replace or remove the asset before you enforce.
  4. Run report-only for one crawl cycle. Compare the reports with your inventory. Anything in the reports but not in the inventory is a URL your source scan missed.
  5. Enforce, then verify. Switch to the enforcing header, reload with the network panel open, and confirm no request is still http://. Keep HSTS as a separate decision.

The deliverable is the inventory plus the report comparison, not the header line. The header takes ten seconds. The inventory is the work.

Three ways this goes wrong

All three fail quietly on the first load, and two of them look like a CDN problem.

  1. Enforcing before a vendor supports HTTPS. The request is rewritten, the vendor's server does not answer on 443, and the asset disappears. No HTTP retry happens.
  2. Assuming it covers top-level links. A link to a partner site over http:// still sends the visitor over HTTP. HSTS is the header for that job.
  3. Setting both CSP directives. block-all-mixed-content is deprecated and does nothing when the upgrade directive is present. Two lines look safer; one line is the accurate configuration.

When not to use it

If the page still depends on an HTTP-only third-party script, enforcement breaks that script on the first load. If you need to protect the first visit from SSL stripping, HSTS is the tool, with its own max-age and preload decisions. If you have only a handful of insecure URLs, edit them directly; this directive is for the long tail you cannot fix this week.

We cannot tell you how much traffic an upgrade failure costs. That depends on which asset fails and what the page does without it. Measure the page, not the header.

Common questions

Is upgrade-insecure-requests the same as HSTS?

No. HSTS tells the browser to use HTTPS for future requests to a host. upgrade-insecure-requests rewrites insecure requests made by the current page. The W3C specification keeps the two separate and says this directive does not replace HSTS (read 2026-11-03).

Does it fix mixed content warnings?

It prevents most mixed-content requests from being made insecurely, because the URL is rewritten before the mixed-content check. It does not fix a resource that has no HTTPS version. That request fails instead.

Does it work in a meta tag?

Yes, on the document that carries the meta tag. A response header covers every HTML response you configure; a meta tag covers only the page that includes it.

What is the Upgrade-Insecure-Requests request header?

That is a different header. Browsers send Upgrade-Insecure-Requests: 1 to tell the server they can upgrade. A server can use it to return a 307 redirect for insecure requests. It is feature detection, not the enforcement directive.

Can I use it with a CDN?

Yes, if the CDN passes the response header through. Check one response with curl -sI after you deploy. We did not test every CDN's header handling for this chapter, so verify your own edge.

Does Googlebot honour it?

We did not test Googlebot or any AI crawler against this directive. Confirm with your own logs or a rendered fetch before you rely on it.

Next step

Once the page loads only over HTTPS, the next question is whether the crawler receives the same HTML you see. Check what an AI crawler actually receives, then use QueryWin's page view when you need to compare the request and the rendered result side by side.

Part of the QueryWin handbook · Level 2

upgrade-insecure-requests: upgrade every insecure request before it fires