Skip to content
← Back to Learn
Security & HTTPS Critical

Mixed content on HTTPS pages

Insecure HTTP resources on HTTPS pages get blocked by browsers, break rendering, and signal a security misconfiguration to crawlers. How to find and fix them.

A page served over HTTPS that loads any subresource — image, script, stylesheet, iframe, font, XHR — over plain HTTP is “mixed content.” All current browsers block active mixed content (scripts, iframes, XHR) outright. Passive mixed content (images, audio, video) used to be allowed with a warning; modern Chrome and Firefox upgrade or block these too. The page still loads; it just loads broken.

Why it matters

Three concrete failure modes:

  1. Scripts and stylesheets don’t execute. Layout collapses, interactivity dies, hydration fails. To a crawler, the page often looks like an empty shell.
  2. Render-blocking failures cascade into Core Web Vitals collapse. LCP misses because the hero image was blocked. CLS spikes because the stylesheet that sized the layout never loaded.
  3. Search Console flags it as a security issue. Mixed content shows up under Security Issues, and a page that browsers won’t render fully is unlikely to rank.

This is not a soft signal. Browsers actively break the page.

How to detect it

Open DevTools → Console. Mixed content warnings appear as red errors:

Mixed Content: The page at 'https://example.com/' was loaded over HTTPS,
but requested an insecure resource 'http://cdn.example.com/main.js'.
This request has been blocked; the content must be served over HTTPS.

At scale, two production-grade approaches:

  1. CSP report-only. Set a Content Security Policy in report-only mode and collect violations:
Content-Security-Policy-Report-Only: default-src https:; report-uri /csp-reports
  1. Crawl with a headless browser that records all subresource requests, then filter for http:// schemes.

The fix

Two paths. Do them in order.

Step 1 — Fix the source

Find the HTTP URLs in your codebase and switch them to protocol-relative or absolute HTTPS:

<!-- Wrong -->
<img src="http://cdn.example.com/hero.jpg" />
<script src="http://analytics.example.com/tag.js"></script>

<!-- Right -->
<img src="https://cdn.example.com/hero.jpg" />
<script src="https://analytics.example.com/tag.js"></script>

Protocol-relative URLs (//cdn.example.com/hero.jpg) work but are considered legacy — write absolute HTTPS.

Step 2 — Upgrade legacy URLs at the response layer

Some mixed content is unfixable at the source — old database content with hardcoded http:// image URLs, user-generated content, third-party widgets. Use upgrade-insecure-requests to tell the browser to retry every HTTP subresource as HTTPS:

Content-Security-Policy: upgrade-insecure-requests

Or as a meta tag in <head>:

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

This only works if the origin actually serves HTTPS. If http://cdn.example.com/hero.jpg upgrades to https://cdn.example.com/hero.jpg and the CDN doesn’t have a valid cert there, the resource fails entirely. Test before shipping.

WordPress

-- Find legacy http:// references in content
SELECT ID, post_title FROM wp_posts
WHERE post_content LIKE '%http://example.com%';

The Better Search Replace plugin handles this safely (it serializes PHP arrays correctly — a plain UPDATE query will corrupt them).

Nginx

Add the upgrade header globally:

add_header Content-Security-Policy "upgrade-insecure-requests" always;

Apache

Header always set Content-Security-Policy "upgrade-insecure-requests"

Common pitfalls

  • http:// in srcset. Easy to miss in audits that only check src.
  • http:// in inline CSS url(...). Same deal — most scanners check tags, not stylesheets.
  • Iframes from ad networks. Modern ad tags emit HTTPS but legacy creatives sometimes don’t. Lock the ad network into HTTPS-only delivery.
  • Hardcoded http:// in JSON-LD image properties. Search engines fetch these. Broken image URLs in schema = lost rich result eligibility.
  • upgrade-insecure-requests as the only fix. It’s a patch, not a cure — it doesn’t fix the underlying data, and a future CSP change can re-expose the bug.
From diagnosis to deployment

Find the issue. Ship the fix.

Use Learn to understand the problem, then run Serpwise against your own site to see what can be approved and deployed.