OneWebDesk

Fixing Mixed Content Warnings

Why mixed content warnings appear on HTTPS pages and how to fix active vs passive resources.

Your page is served over HTTPS, yet the padlock disappears or flips to “Not secure,” and the console fills up with Mixed Contentwarnings. This is not a broken certificate — it’s a signal that an HTTPS page is loading some of its resources over plain HTTP. The document itself is encrypted, but if a few images, scripts, or stylesheets travel as cleartext, the browser stops treating the page as fully secure.

This is called mixed content, and ignoring it is more than a cosmetic padlock issue. Active mixed content is outright blocked in modern browsers, so the script or stylesheet never runs — layouts break and features die. This guide explains exactly what mixed content is, how to find where it leaks, and how to fix each type, with a concrete worked example.

Active vs passive mixed content

Not all mixed content is treated equally. Browsers split it into two buckets based on how much control the resource has over the page. Active content can rewrite the whole page, so it is blocked immediately; passive content only affects what is displayed, so it is flagged with a warning instead.

TypeTypical resourcesBrowser behavior
Active<script>, <iframe>, <link rel="stylesheet">, fetch()/XHR, web fontsBlocked — never loads. A “blocked” error in the console.
Passive<img>, <audio>, <video>, some <object>Loads but is flagged — the padlock drops and a console warning appears.

The rule of thumb: if only the padlock is gone, a passive resource like an image is usually the culprit; if your styles break or buttons stop working, a blocked active resource (CSS or JS) is to blame.

Finding the offenders

Before you can fix anything, you need to know exactly which HTTP requests are mixed into the page. Use two passes.

  • Browser DevTools: open the console with F12 and every blocked or flagged item is listed with its full URL. Filter the Network tab to http:// requests to see them at a glance.
  • A full-page scan: the console only shows what is “currently loaded,” so it easily misses resources behind a click or injected dynamically. To audit a page in one shot, run it through Mixed Content Check, which scans the HTML and lists every HTTP reference so nothing slips through.

Fixes by type

Once you have the list, almost every case reduces to one of three fixes.

  1. Change http:// to https:// — the basic, recommended fix. First confirm the resource supports HTTPS by opening the https:// URL directly, then swap it in.
  2. Avoid protocol-relative URLs (//host/asset.js) — once common, now discouraged. With HTTPS everywhere, writing an explicit https:// makes intent clear and avoids surprises when the page is opened from file:// or other non-HTTP contexts.
  3. Upgrade in bulk with Content-Security-Policy: upgrade-insecure-requests— a safety net when you can’t touch every line of HTML. This directive tells the browser to silently rewrite the page’s http:// requests to https:// before they go out. Verify the header is actually applied with Security Headers Check.

Worked example: an HTTP image on an HTTPS page

Suppose a product page at https://shop.example.com contains this markup.

  • The offending code: <img src="http://cdn.example.com/p/1.jpg">
  • Symptom: the image shows, but the padlock disappears and the console logs Mixed Content: ... was loaded over HTTP.
  • First check: open https://cdn.example.com/p/1.jpg in the browser to confirm it serves over HTTPS.
  • Proper fix: <img src="https://cdn.example.com/p/1.jpg"> — adding a single s does it.
  • Bulk fix: if the same pattern is scattered through the page, add Content-Security-Policy: upgrade-insecure-requests to the response headers to promote them all at once.

After the fix, hard-reload (Ctrl+Shift+R) to clear the cache, confirm the padlock is back, and re-run Mixed Content Check to verify zero remaining HTTP references.

Frequently asked questions

The image loads, so why does it say 'Not secure'?
Images are passive content: they load instead of being blocked, but the moment one arrives over HTTP the page is no longer fully encrypted. So the content appears yet the padlock drops or shows 'Not fully secure.' Switching the src to https resolves it.
My scripts or CSS aren't applying.
Scripts, stylesheets, and iframes are active content, so when requested over HTTP the browser blocks them entirely. The load fails outright, which breaks layout or functionality. Take the URL from the console's 'blocked: mixed-content' error and change it to https.
Is it OK to use protocol-relative URLs like //cdn.example.com/x.js?
It technically works but is no longer recommended. It was a habit from the era of mixed HTTP/HTTPS sites; today everything is HTTPS, so an explicit https:// is clearer in intent and avoids confusion in contexts like local file:// pages.
Is enabling upgrade-insecure-requests enough on its own?
It's a very useful safety net because it auto-promotes http URLs for HTTPS-capable resources. But if the target server doesn't support HTTPS, the upgraded request can fail. The safest approach is to fix the source to https and use this header as an additional layer of defense.
I fixed it but the warning persists.
It's most likely browser or CDN caching. Do a hard reload (Ctrl+Shift+R) or clear the cache, and invalidate your CDN cache if you use one. If it still shows, the console may have missed a dynamic resource that only appears after a click, so rescan the whole page.

Tools to use with this guide