What mixed content is and how to fix it
What mixed content is, why browsers block it, where it creeps in from and how to find and fix every insecure resource on an HTTPS page for good.
A site can be on HTTPS and still not be secure. If a single image, script or stylesheet on the page loads over plain HTTP, the browser calls it mixed content, and depending on what it is, it either warns or blocks it outright. Here is what that means and how to clear it.
What mixed content is
Mixed content is any resource requested over http:// by a page that was itself served over https://. The page arrived encrypted, then reached back out for something that is not, and the browser has no way to guarantee that part of the page was not tampered with in transit.
It matters because the padlock is a promise about the whole page, not just the HTML. One insecure request breaks that promise, and an attacker on the same network can swap the contents of an unencrypted request for something else.
Passive and active, and why the difference matters
Browsers treat mixed content in two bands.
Passive mixed content is images, audio and video. It cannot change the rest of the page, so most browsers still load it but strip the padlock or mark the page as not fully secure. The visible symptom is a trust problem rather than a broken layout.
Active mixed content is scripts, stylesheets, iframes, fonts and background requests. These can rewrite the whole page, so browsers block them silently. This is the one that breaks sites: a slider stops working, a form will not submit, half the styling disappears, and nothing in the page source looks wrong. The evidence is in the browser console, not the page.
Where it comes from
Almost nobody adds insecure resources on purpose. It arrives through four routes.
Hard-coded URLs in content. An editor pasted an image with a full http:// address years ago and it is still sitting in the page body.
A migration that missed the database. The site moved to HTTPS, the templates were updated, but old absolute URLs stayed in post content, widget settings and theme options.
Old themes and plugins. Anything unmaintained may still be requesting a library or font over HTTP from a URL that has not been touched in a decade.
Third-party embeds. Maps, chat widgets, tracking pixels, ad tags and video players from suppliers who never moved their own assets across.
How to find every instance
Open the page, open the browser console and look for warnings mentioning mixed or insecure content. That catches the current page, which is fine for a spot check and useless for a 400-page site.
For a whole-site answer you need to crawl every template and every content type: the home page, a blog post, a product page, a form page, a page with an embed. Mixed content clusters in the places editors touch, so check content-heavy pages rather than just the templates.
The free mixed content checker lists every insecure request on a URL, with the type of each one, so you know immediately whether you are looking at a padlock problem or a broken-page problem.
How to fix it
Work through it in this order.
- Switch the URL to HTTPS and test it. Most resources are already available over HTTPS at the same address. Change the protocol and confirm the resource still loads.
- Use relative URLs for your own assets.
/img/logo.pngfollows whatever protocol the page used, so it cannot drift back. - Search and replace the database. On WordPress and similar platforms, run a proper serialised search-replace from
http://yourdomaintohttps://yourdomain. Do not hand-edit the SQL dump, because serialised data stores string lengths and a raw replace corrupts it. Back up first. - Replace what will not move. If a third-party resource has no HTTPS version, it is abandoned. Host a copy yourself or drop the supplier.
- Add a safety net. The
upgrade-insecure-requestsContent-Security-Policy directive tells the browser to retry HTTP requests over HTTPS automatically. It is a backstop for content you do not control, not a substitute for fixing the source, because it does nothing if the resource genuinely has no HTTPS version.
Avoid protocol-relative URLs like //example.com/script.js. They were the workaround before HTTPS was universal and they now just hide which protocol you are actually getting.
Keep it from coming back
Mixed content is a regression, not a one-off. Every new blog post, embedded video and plugin update is another chance for an http:// to reappear, and the failure is quiet: the padlock goes, or a script stops loading, and nobody tells you.
Janitor checks for mixed content on every site you manage on a schedule and flags it alongside security headers, certificates and the rest of the security category in a branded report, so a stray insecure request shows up in your inbox rather than in a client’s.