What this means
Chrome prints: Mixed Content: The page at 'https://...' was loaded over HTTPS, but requested an insecure resource 'http://...'. This request has been blocked; the content must be served over HTTPS. Browsers split mixed content into two groups. Images, audio and video are upgradable, so the browser retries them over HTTPS. Everything else, including scripts, stylesheets, iframes and fetch calls, is blockable and is simply not loaded.
Why it happens
- An API base URL is set to http:// in an environment variable. It worked on localhost, which browsers treat as secure, and broke on the deployed HTTPS site.
- The backend runs on a raw server IP and port with no TLS certificate, a common result of deploying a generated backend by hand.
- Hard-coded http:// links to images, fonts or scripts in generated code or copied snippets.
- Stored content, such as user uploads or CMS entries, contains absolute http:// URLs.
- A WebSocket uses ws:// instead of wss://.
How to fix it
- 1Open the console and list each blocked URL. The message names it.
- 2Search your code and environment variables for http:// and ws://. Change each to https:// or wss:// and check the resource actually loads over HTTPS.
- 3If your own API has no HTTPS, put it behind a host or proxy that provides a certificate, and give it a domain name. Do not ship a production API on a bare IP over http.
- 4If a third party offers no HTTPS, fetch it from your server and pass the result to the browser over your own HTTPS route, or replace the provider.
- 5Fix stored URLs in your database with a one-off update.
- 6Add the upgrade-insecure-requests CSP directive as a safety net for links you missed. It only helps when the target also serves HTTPS.
grep -rnE "(http|ws)://" src .env* --include='*' | grep -v localhost
NEXT_PUBLIC_API_URL=https://api.yourapp.com
Content-Security-Policy: upgrade-insecure-requestsHow to confirm the fix
- Load each main page of your live site with the console open. There should be no Mixed Content messages.
- In the Network tab, add the Scheme column or filter by mixed-content:all in Chrome. Every request should be https or wss.
- Check the API URL your deployed bundle uses. In the Network tab, click an API request and confirm the full URL begins with https://.
- Run curl -I https://api.yourapp.com/health against your own API to confirm it answers over HTTPS with a valid certificate. curl fails loudly if the certificate is wrong.
Frequently asked questions
Why did it work on localhost?
Browsers treat http://localhost as a secure context, and a local page served over http has no HTTPS to mix with. The problem appears once the page itself is on HTTPS.
Does upgrade-insecure-requests fix everything?
No. It rewrites http:// requests to https:// before they are sent. If the other server does not support HTTPS, the request fails instead of being blocked.
Images show a warning but still load. Do I need to fix them?
Yes. Browsers upgrade images to HTTPS automatically, and if the upgraded request fails the image will not load. Use https:// URLs so the result is predictable.