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.
| Type | Typical resources | Browser behavior |
|---|---|---|
| Active | <script>, <iframe>, <link rel="stylesheet">, fetch()/XHR, web fonts | Blocked — 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.
- Change
http://tohttps://— the basic, recommended fix. First confirm the resource supports HTTPS by opening thehttps://URL directly, then swap it in. - Avoid protocol-relative URLs (
//host/asset.js) — once common, now discouraged. With HTTPS everywhere, writing an explicithttps://makes intent clear and avoids surprises when the page is opened fromfile://or other non-HTTP contexts. - 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’shttp://requests tohttps://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.jpgin the browser to confirm it serves over HTTPS. - Proper fix:
<img src="https://cdn.example.com/p/1.jpg">— adding a singlesdoes it. - Bulk fix: if the same pattern is scattered through the page, add
Content-Security-Policy: upgrade-insecure-requeststo 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.