Mixed Content Blocked: Fix http on https Pages
Mixed content blocking stops https pages loading http resources.
20+ years shipping production JavaScript and front-end systems at scale. Notes here come from systems that actually shipped.
- ✓A site served over https
- ✓Browser DevTools Security panel access
- ✓Ability to edit templates or server headers
- Mixed content means your https page requested an http subresource, and the browser blocked it to protect the secure page.
- Active content like scripts, XHR, and iframes is always blocked. Passive content like images may load with a warning or degrade.
- Fix it by serving every subresource over https, rewriting hardcoded http: URLs, and proxying third parties that lack TLS.
- Harden with upgrade-insecure-requests plus HSTS so future http slips upgrade automatically instead of breaking.
Think of an https page as a sealed armored truck. Every package inside was verified at loading. An http subresource is an unverified parcel someone tries to toss through the window mid-route. The browser, acting as security, refuses the parcel because one unverified item voids the whole truck's guarantee. The fix is never to argue with security. It is to order every parcel through the verified channel, which means https URLs for everything on the page.
Your site finally runs on https, the padlock shines, and then the console fills with Mixed Content warnings while scripts refuse to run and styles vanish. The page worked perfectly on http yesterday. Nothing in your code changed except the scheme, yet half the resources now fail with blocked:the page was loaded over https but requested an insecure resource.
The frustration comes from the partial failure. Your HTML and main bundle load fine while a jQuery plugin, a font, or an API call dies quietly. Each blocked resource has its own hardcoded http: URL buried in a template, a CMS field, or a third-party snippet you pasted years ago. The page is secure except for the holes, and browsers refuse to pretend otherwise.
This guide maps every hole. You will learn the active-versus-passive split that decides block versus warning, how to inventory every insecure URL with DevTools, why protocol-relative URLs lost to https-everywhere, how upgrade-insecure-requests and HSTS shield you server-side, and how to handle third parties that still lack TLS. The padlock stays lit when you finish.
Active vs Passive: Why Some http Calls Die and Others Warn
Browsers sort mixed content by how much damage it can do. Active content can take over the page: scripts execute code, stylesheets restyle everything, iframes embed whole documents, and fetch calls move data. An attacker rewriting any of these in transit owns the session, so browsers block them outright with no override. When your checkout script or API call uses http on an https page, it never leaves the browser at all.
Passive content cannot directly execute: images, audio, and video render but do not run. Browsers historically loaded these with a padlock downgrade, warning rather than blocking. That leniency is shrinking every year as vendors push toward blocking all mixed content, and fonts already sit in the blocked camp in modern Chrome. Any plan that tolerates passive http is a plan with an expiry date.
The practical rule is therefore simple: treat every http subresource as blocked. Images that warn today will block tomorrow, and the padlock degradation alone costs trust on commerce pages. Users cannot distinguish your secure checkout from an attacked one when the indicator turns grey, and support tickets about scary warnings follow.
The snippet audits the live page for http subresources across scripts, images, links, and media. Paste it in the console on any https page and it prints each offender with its tag, so your inventory reflects what actually loaded rather than what templates suggest.
Finding Every Insecure URL With DevTools
The Security panel is the fastest starting point. Open DevTools, load the page fresh, and read the panel's verdict: secure means clean, secure with warnings names passive offenders, and blocked entries name active ones. Each finding links to the Network request, which shows the exact URL, initiator chain, and which script or tag triggered it. The initiator chain matters because injected resources hide behind loaders.
The Console filter comes next. Type mixed content into the filter box to isolate every related message across reloads. Click through to the Sources line for each: hardcoded URLs point at your templates, while VM or extension-context lines point at injected third-party code. That distinction decides whether you edit your repo or reconfigure a vendor.
Codebase search catches what runtime misses on untested pages. Grep templates, stylesheets, JS configs, and environment files for http://, then extend the same search to CMS exports and translation files. Third-party snippets deserve individual review since vendors quietly update endpoints. One pass across code plus content plus vendors is the only complete inventory.
Record the inventory before fixing. A checklist of URLs with owners turns a scavenger hunt into a work queue, and re-running the audit after each fix proves progress. Pages with dozens of offenders get fixed fastest when nobody re-discovers the same URL twice.
Protocol-Relative URLs and Why https-Everywhere Won
Protocol-relative URLs, those starting with //cdn.example.com, were the fashionable fix a decade ago. They inherit the page's scheme, loading https on secure pages and http elsewhere. That cleverness is now a liability. On the rare http page they preserve insecurity, in emails and non-web contexts they resolve unpredictably, and they hide the real question of whether the vendor supports TLS at all.
The modern rule is blunt: link https directly, everywhere. If the vendor supports TLS, the link works on every page and context. If it does not, the failure is loud and immediate instead of silently downgrading. Explicit https turns an invisible risk into a visible decision about the vendor.
Migration is mechanical. Replace http:// with https:// for first-party resources you control, then verify each third-party endpoint over https before swapping. Where a vendor genuinely lacks TLS, proxy through your own https host or drop the dependency. Protocol-relative leftovers get rewritten to https in the same pass.
The snippet rewrites hardcoded http: URLs to https: across common attributes for a quick page-level test. It is triage tooling, not a fix: permanent correction belongs in the source templates and CMS fields. Use it to prove https works, then commit the real change.
upgrade-insecure-requests and HSTS: Server-Side Shields
Two response headers turn human error into self-healing upgrades. Content-Security-Policy with upgrade-insecure-requests instructs the browser to rewrite every http subresource request to https before sending it. A pasted http image, a forgotten config URL, even a vendor snippet, all upgrade silently. It is the highest-value single header for mixed content because it protects against URLs you have not found yet.
Strict-Transport-Security plays the longer game. With max-age set in seconds, browsers remember to use https for your entire domain, including navigation and subresources, for months. Include subdomains when your assets live across them, and consider preload submission once stable. HSTS closes downgrade tricks where attackers strip TLS, which header rewriting alone cannot do.
Deploy in order: CSP upgrade first, since it fixes breakage immediately and visibly. Watch reports for a week to catch vendors whose https endpoints fail. Then enable HSTS with a short max-age, verify nothing regresses, and extend to the long value. Reversing HSTS is slow by design, so the staged rollout matters.
The snippet is a tiny middleware that emits both headers on every response. Mount it early in any Node server to see the exact header values, then translate them into your Nginx, CDN, or platform config for production.
Fixing Third-Party Widgets, Fonts, and API Calls
Third parties cause the stubborn remainder because you cannot edit their servers. Fonts, analytics, chat widgets, ad tags, and payment SDKs each arrive as snippets with their own URL habits. The playbook is fixed: check for an https endpoint first, pin it when it exists, proxy when it does not, and replace vendors that leave you stranded. Nine times in ten the https endpoint already exists and only the docs are stale.
Fonts deserve attention because they sit at the active-passive boundary across browser versions. A font that warns on one Chrome release blocks on the next, so font URLs are never safe to leave on http. Self-hosting fonts on your own https origin removes the vendor variable entirely and usually improves load times through better caching.
API calls have no flexibility at all. Fetch and XHR to http endpoints from https pages are active mixed content and always blocked, with no header able to exempt them. Update every environment config's base URL, confirm the API's certificate covers the hostname, and fix CORS origins to the https app origin in the same pass since the origin changes with the scheme.
The snippet builds API URLs from a single https base so environments cannot drift back to http. Centralize the base URL in one config value per environment and the whole class of API mixed content becomes a one-line review.
A Deploy Checklist That Keeps https Green
Lock the win with a checklist that runs on every deploy. Scan code and CMS content for http:// on a schedule, not once. Run the console audit on critical pages with all tag managers enabled. Assert the CSP upgrade header and HSTS header are present in staging responses. Probe API base URLs per environment over https with certificate checks. Each step is cheap and together they catch every recurrence vector.
Gate content entry where editors work. CMS link fields should warn or reject http URLs on save, with an override that logs who bypassed it. Marketing pixels get reviewed against an allowlist of https-capable vendors. Human workflows produce http slips at a steady rate, so the control belongs at the point of entry.
Monitor the outcome, not just the inputs. A synthetic check that loads checkout over https and asserts a clean Security panel catches whatever the scans miss, including injected third-party URLs. Alert on padlock degradation the same way you alert on downtime, because on commerce pages it costs nearly as much.
Review quarterly as browsers tighten. Each Chrome release reclassifies more passive content as blocked, so a page that merely warns today can break silently tomorrow. The checklist keeps you ahead of the browser instead of chasing it.
An http Font URL Greyed the Padlock on Black Friday
- Scans must cover database content, not just templates. CMS fields bypass every code review and lint rule that guards the migration.
- Passive mixed content still costs money. Warnings never page anyone, so padlock state needs its own synthetic monitor on revenue pages.
- CSP upgrade-insecure-requests is the seatbelt for human error. It converts the next pasted http link into a silent upgrade instead of an incident.
| File | Command / Code | Purpose |
|---|---|---|
| mixed-audit.js | function auditMixedContent() { | Active vs Passive |
| scheme-upgrade.js | function previewUpgrade() { | Protocol-Relative URLs and Why https-Everywhere Won |
| security-headers.js | function securityHeaders(req, res, next) { | upgrade-insecure-requests and HSTS |
| api-base.js | const API_BASES = { | Fixing Third-Party Widgets, Fonts, and API Calls |
Key takeaways
Common mistakes to avoid
5 patternsRelying on protocol-relative // URLs
Scanning code but ignoring CMS content
Assuming passive content is safe to leave
Enabling long-max-age HSTS before auditing subdomains
Fixing the page audit while tags are disabled
Interview Questions on This Topic
What is mixed content and why do browsers block it?
Frequently Asked Questions
20+ years shipping production JavaScript and front-end systems at scale. Notes here come from systems that actually shipped.
That's Browser. Mark it forged?
5 min read · try the examples if you haven't