Home JavaScript Mixed Content Blocked: Fix http on https Pages
Beginner 5 min · September 23, 2026

Mixed Content Blocked: Fix http on https Pages

Mixed content blocking stops https pages loading http resources.

N
Naren Founder & Principal Engineer

20+ years shipping production JavaScript and front-end systems at scale. Notes here come from systems that actually shipped.

Follow
Production
production tested
September 23, 2026
last updated
1,905
articles · all by Naren
Before you start⏱ 10 min
  • A site served over https
  • Browser DevTools Security panel access
  • Ability to edit templates or server headers
 ● Production Incident 🔎 Debug Guide
Quick Answer
  • 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.
✦ Definition~90s read
What is Mixed Content Blocked Fix?

Mixed content is any http:// subresource requested by a page loaded over https://, and browsers restrict it because it breaks the page's security guarantee. TLS promises confidentiality, integrity, and authentication for the page. An http script or API call carries none of those and can be read or rewritten in transit.

Think of an https page as a sealed armored truck.

Allowing it silently would let attackers inject code into an otherwise secure page, so browsers intervene.

The intervention splits into two classes. Active mixed content, also called blockable content, is always blocked: scripts, stylesheets, iframes, XHR and fetch calls, fonts, and media loaded for scripting. These can alter page behavior completely, so no warning suffices.

Passive mixed content, also called optionally-blockable, covers images, audio, and video: browsers may load them with a degraded padlock or block them depending on version and settings. Chrome's trajectory has been to block more each year, so anything you rely on must move to https regardless of class.

Hardcoded http: URLs are the usual source. Templates written before the TLS migration, CMS content with absolute links, API base URLs in config, and third-party snippets all carry the old scheme. Protocol-relative URLs starting with // once papered over this by inheriting the page scheme, but they break on http pages and hide the real fix, which is why https-everywhere won: link https directly, always.

Two server headers complete the defense. Content-Security-Policy with upgrade-insecure-requests rewrites http subresource requests to https before they leave the browser. Strict-Transport-Security tells browsers to use https for your whole domain for months, closing downgrade tricks. Together they turn future http slips into silent upgrades instead of broken pages.

Plain-English First

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.

mixed-audit.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function auditMixedContent() {
  const found = [];
  const tags = ['script', 'img', 'link', 'iframe', 'source', 'video', 'audio'];
  for (const tag of tags) {
    for (const el of document.querySelectorAll(tag)) {
      const url = el.src || el.href;
      if (url && url.startsWith('http://')) found.push(tag + ': ' + url);
    }
  }
  console.log(found.length ? found.join('\n') : 'no http subresources found');
  return found;
}

auditMixedContent();
Try it live
📊 Production Insight
Monitoring that only watches console errors misses passive mixed content entirely, since browsers log warnings that never page. Add a synthetic check on padlock state for checkout and login pages, or degradation becomes invisible until conversion data tells you weeks later.
🎯 Key Takeaway
Active content like scripts and fetch is always blocked, while passive content warns today and blocks tomorrow. Treat every http subresource as broken.

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.

📊 Production Insight
Initiator chains expose the worst offenders: tag managers and A/B tools injecting http pixels long after your code went clean. Audit with all marketing tags enabled, or the production page carries URLs your staging pass never saw.
🎯 Key Takeaway
Use the Security panel for the verdict, the Console filter for lines, and codebase plus CMS search for the full list. Inventory first, then fix in checklist order.

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.

scheme-upgrade.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function previewUpgrade() {
  const attrs = [['script', 'src'], ['img', 'src'], ['link', 'href']];
  const changed = [];
  for (const [tag, attr] of attrs) {
    for (const el of document.querySelectorAll(tag)) {
      const url = el.getAttribute(attr) || '';
      if (url.startsWith('http://')) {
        el.setAttribute(attr, 'https://' + url.slice(7));
        changed.push(url);
      }
    }
  }
  console.log('upgraded ' + changed.length + ' urls (preview only)');
  return changed;
}

previewUpgrade();
Try it live
📊 Production Insight
Bulk scheme rewrites without endpoint verification trade blocked content for failed TLS handshakes. Verify each host's certificate covers the exact hostname first, or the padlock stays broken under a different error.
🎯 Key Takeaway
Drop protocol-relative URLs and link https explicitly. Verify each vendor endpoint, proxy or replace laggards, and commit the fix at the source.

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.

security-headers.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
function securityHeaders(req, res, next) {
  res.setHeader('Content-Security-Policy', 'upgrade-insecure-requests');
  res.setHeader('Strict-Transport-Security', 'max-age=15552000; includeSubDomains');
  next();
}

console.log('mount early: app.use(securityHeaders)');
console.log('csp:', 'upgrade-insecure-requests');
console.log('hsts:', 'max-age=15552000; includeSubDomains');
Try it live
📊 Production Insight
Enabling HSTS with a long max-age before verifying every subdomain's TLS bricks the forgotten ones until expiry. Stage it: short max-age first, full subdomain audit, then the long value. Recovery from a premature long HSTS is measured in months.
🎯 Key Takeaway
Emit upgrade-insecure-requests to auto-upgrade slips and HSTS to lock the domain to https. Stage HSTS from short to long max-age after auditing subdomains.

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.

api-base.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const API_BASES = {
  development: 'https://api-dev.example.com',
  staging: 'https://api-staging.example.com',
  production: 'https://api.example.com'
};

function apiUrl(env, path) {
  const base = API_BASES[env];
  if (!base || !base.startsWith('https://')) {
    throw new Error('unsafe api base for env: ' + env);
  }
  return base + path;
}

console.log(apiUrl('production', '/items'));
Try it live
📊 Production Insight
Payment SDKs loaded over http are a compliance incident, not just a console warning. Card-data environments require encrypted transport end to end, so an http payment snippet fails audits even where a browser might tolerate it. Pin and verify these first.
🎯 Key Takeaway
Verify each vendor's https endpoint, self-host fonts where possible, and centralize API base URLs on https per environment.

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.

💡Scan Content, Not Just Code
CMS fields, translations, and tag-manager pixels bypass every linter. Schedule the http scan across database content and live pages, or the next incident will come from exactly those blind spots.
📊 Production Insight
The cheapest durable control is rejecting http at content-save time in the CMS. One validation rule there prevents more incidents than a decade of post-deploy scans, because it stops the bad URL where it is born.
🎯 Key Takeaway
Scan code and content on schedule, validate at CMS save time, assert security headers per deploy, and monitor padlock state synthetically.
● Production incidentPOST-MORTEMseverity: high

An http Font URL Greyed the Padlock on Black Friday

Symptom
At 8:02 AM on Black Friday, the trust-badge monitor flagged that product pages served a grey triangle instead of the padlock for roughly 18 percent of sessions. The hero banner's custom font failed to load and fell back to system type. No console errors appeared in standard monitoring because passive mixed content logs a warning, not an error, and conversion dipped 2.1 points during the morning peak.
Assumption
The team assumed the TLS migration was complete because an automated scan of templates reported zero http: URLs the week before. The scan covered code but not CMS content, and the holiday banner went live through the CMS at 7:50 AM. Reviewers previewed it over the staging http origin, where the font loaded perfectly.
Root cause
The banner's font link used an absolute http:// URL to a third-party foundry, pasted by an editor from old brand docs. On the https production origin, Chrome treated it as passive mixed content and degraded the padlock while refusing the font on some versions. The 18 percent figure matched the share of traffic on Chrome versions that block font mixed content outright. Template scans never saw it because the URL lived in the database.
Fix
At 9:26 AM the editor swapped the link to the foundry's https endpoint, restoring the padlock in one CMS publish. The team then added upgrade-insecure-requests to the CSP so future http slips self-upgrade, extended the URL scan to CMS content nightly, and enabled HSTS with a 6-month max-age so downgraded requests cannot recur.
Key lesson
  • 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.
Production debug guideFive steps that inventory every insecure URL and verify the https fix.5 entries
Symptom · 01
Console shows Mixed Content warnings or blocked resource errors
Fix
Open DevTools, filter the Console for mixed content, and click each entry to jump to the requesting line. Switch to the Security panel to see the page's overall state: secure with warnings means passive content slipped through, while blocked scripts mean active content died. List every flagged URL before editing anything.
Symptom · 02
You need the full inventory of http: URLs
Fix
Search the codebase with grep -rn "http://" src/ templates/ --include=".html" --include=".js" and export CMS content to search there too. In the page, run the audit snippet from this guide in the console to list live http subresources including injected ones. Merge both lists so nothing hides.
Symptom · 03
A third-party snippet only offers http
Fix
Test its https endpoint directly by swapping the scheme and reloading. Most vendors added TLS years ago and left docs stale. When https works, pin it. When it truly lacks TLS, proxy the resource through your own https endpoint or replace the vendor.
Symptom · 04
API calls fail after the https migration
Fix
Update the API base URL in every environment config from http://api to https://api, then confirm the certificate covers that hostname. Mixed active content rules block http XHR and fetch unconditionally, so no header or flag client-side can exempt them.
Symptom · 05
You want future slips to self-heal
Fix
Send Content-Security-Policy: upgrade-insecure-requests from your server and confirm in the Network tab that http subrequests upgrade to https. Add Strict-Transport-Security: max-age=15552000 so browsers refuse plain http for your domain outright. Re-run the audit to confirm zero remaining http requests.
Mixed Content Causes Compared
Root CauseHow to ConfirmFixPrevention
Hardcoded http script or stylesheetConsole shows blocked active content naming the URLRewrite to the https endpointGrep templates for http:// in CI
http API base URL in configFetch fails as active mixed content on every callPoint the base URL at https per environmentCentralize the base URL with an https assertion
http URL pasted into CMS contentOffender appears only on content-driven pagesEdit the field to https and republishReject http at CMS save time
Third-party snippet without TLSVendor URL fails over https when tested directlyProxy through your https host or replace vendorAllowlist https-capable vendors only
Missing upgrade safety netSingle slips break pages instead of self-upgradingSend upgrade-insecure-requests plus HSTSAssert both headers in staging on every deploy
⚙ Quick Reference
4 commands from this guide
FileCommand / CodePurpose
mixed-audit.jsfunction auditMixedContent() {Active vs Passive
scheme-upgrade.jsfunction previewUpgrade() {Protocol-Relative URLs and Why https-Everywhere Won
security-headers.jsfunction securityHeaders(req, res, next) {upgrade-insecure-requests and HSTS
api-base.jsconst API_BASES = {Fixing Third-Party Widgets, Fonts, and API Calls

Key takeaways

1
Mixed content is any http subresource on an https page, and it voids the TLS guarantee.
2
Scripts, styles, iframes, and fetch are always blocked; images warn today and block tomorrow.
3
Inventory with the Security panel, console filter, and code plus CMS search.
4
Link https explicitly and verify every vendor endpoint instead of inheriting schemes.
5
Emit upgrade-insecure-requests and stage HSTS from short to long max-age.
6
Monitor padlock state synthetically on revenue pages, not just console errors.

Common mistakes to avoid

5 patterns
×

Relying on protocol-relative // URLs

Symptom
Resources break in emails, apps, and http contexts while hiding vendor TLS gaps.
Fix
Link https explicitly everywhere and resolve vendor gaps loudly instead of inheriting schemes.
×

Scanning code but ignoring CMS content

Symptom
Migrations report clean while editors keep publishing http links from the database.
Fix
Extend the http scan to CMS exports, translations, and tag pixels on a nightly schedule.
×

Assuming passive content is safe to leave

Symptom
Images warn today, fonts block tomorrow, and the padlock degrades the whole time.
Fix
Move every subresource to https regardless of class. Warnings have expiry dates.
×

Enabling long-max-age HSTS before auditing subdomains

Symptom
Forgotten http-only subdomains brick for months with no quick reversal.
Fix
Stage HSTS from a short max-age to the long value only after verifying every subdomain.
×

Fixing the page audit while tags are disabled

Symptom
Staging looks clean but production injects http pixels through the tag manager.
Fix
Audit with all marketing tags enabled and gate new pixels behind https review.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What is mixed content and why do browsers block it?
Q02JUNIOR
What is the difference between active and passive mixed content?
Q03SENIOR
How does upgrade-insecure-requests help?
Q04SENIOR
Why are protocol-relative URLs no longer recommended?
Q05SENIOR
An https page's API calls fail but images load. What is happening?
Q01 of 05JUNIOR

What is mixed content and why do browsers block it?

ANSWER
http subresources on an https page break the TLS guarantees of confidentiality and integrity. An attacker could read or rewrite them in transit, so browsers block active content outright and warn or block passive content.
FAQ · 6 QUESTIONS

Frequently Asked Questions

01
Can I exempt one http script from blocking?
02
Why did my page break only after enabling https?
03
Do protocol-relative URLs fix mixed content?
04
Why do images load while my API calls fail?
05
What does HSTS add beyond CSP upgrading?
06
How do I handle a vendor with no https support?
N
Naren Founder & Principal Engineer

20+ years shipping production JavaScript and front-end systems at scale. Notes here come from systems that actually shipped.

Follow
Verified
production tested
September 23, 2026
last updated
1,905
articles · all by Naren
🔥

That's Browser. Mark it forged?

5 min read · try the examples if you haven't

Previous
Unexpected Token JSON Parse Fix
2 / 3 · Browser
Next
HTTP 403 Forbidden Fix