Mixed Content: the page was loaded over HTTPS, but requested an insecure resource
Your site moved to HTTPS and now a script, API call or stylesheet silently fails, the padlock shows a warning, and the console is full of Mixed Content errors. Something on the page still points at plain <code>http://</code>.
What the browser does
| Request over http from an https page | What happens |
|---|---|
<script>, stylesheets, <iframe>, fonts | Blocked (“active” mixed content) |
fetch(), XMLHttpRequest, WebSocket ws:// | Blocked; your code sees a network error |
<img>, <audio>, <video> | Upgraded to https automatically in current Chrome, Firefox and Safari; broken if the server has no https |
Form posting to http:// | Warning before submitting, or blocked |
Links (<a href="http://…">) | Allowed: navigating away isn't mixed content |
The reason: anything loaded over http can be read or changed by whoever sits on the network. A tampered script would control your whole “secure” page.
Find every insecure URL
- The DevTools Console names each blocked URL; the Security panel lists the page's origins.
- Search your code and database for
http://: hard-coded asset URLs, API base URLs in env files, CMS content, third-party embed snippets. - Check generated URLs: if the app builds absolute URLs from the incoming request and TLS ends at a proxy, it thinks it's on http.
Fixes
- Use https URLs. Change
http://tohttps://, or use a relative path (/js/app.js) for your own files. Avoid protocol-relative//cdn…URLs; just use https. - Make sure the other side has HTTPS. If an API only speaks http, call it from your server instead of the browser, or put it behind HTTPS.
- Behind a proxy or tunnel, trust the forwarded scheme: Express
app.set('trust proxy', 1), DjangoSECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https'), LaravelTrustProxies, Railsconfig.force_ssl. Otherwise redirects and asset links come out as http. - WordPress: set both WordPress Address and Site Address to https, then search-replace
http://yourdomainin the database (WP-CLIwp search-replace). - Safety net: the header
Content-Security-Policy: upgrade-insecure-requests(check a whole policy with the CSP header explainer) tells browsers to rewrite your page's http subresource URLs to https before requesting them. It doesn't help if the target has no https.
# nginx: tell the browser to upgrade, and redirect plain http
add_header Content-Security-Policy "upgrade-insecure-requests" always;
server { listen 80; return 301 https://$host$request_uri; }
Localhost and development
http://localhost and http://127.0.0.1 count as potentially trustworthy, so an http page on localhost can load them. But an https page (say your deployed site) calling http://localhost:3000 is still blocked, and Chrome adds extra checks for public sites reaching private networks. Run your dev API over https, or proxy it through the same origin.
Related
TypeError: Failed to fetch · Expired or invalid SSL certificate · CORS errors explained · 301 vs 302 vs 307 vs 308 · Cookie not being set (Secure cookies on http) · Wirebook's lessons on how the web works · ERR_SSL_PROTOCOL_ERROR · X-Frame-Options explainer · WebSocket connection failed · NotAllowedError getUserMedia
Questions
What is mixed content?
An HTTPS page loading a script, style, image, iframe or API call over plain HTTP. The insecure part could be read or altered on the network, so browsers block or upgrade it.
Why is my fetch blocked as mixed content?
fetch and XMLHttpRequest to an http:// URL from an https page are always blocked. Use the https URL of the API, or call it from your server.
Does upgrade-insecure-requests fix mixed content?
It rewrites your page's http subresource URLs to https before loading them, which fixes it as long as those servers support HTTPS.
Are images blocked as mixed content?
Modern browsers auto-upgrade http images, audio and video to https. If the server has no HTTPS, the image fails to load.
Why do I get mixed content behind Cloudflare or a load balancer?
TLS ends at the proxy, so your app sees plain http and builds http URLs. Configure it to trust X-Forwarded-Proto.
Published .