Mixed Content: The page was loaded over HTTPS, but requested an insecure resource 'http://...'
This request has been blocked; the content must be served over HTTPS.
Your page is served over HTTPS but tries to load a resource (image, script, API call, font, iframe) over plain HTTP. Browsers block this because an attacker could intercept and modify the insecure resource, compromising the security of your HTTPS page.
Why browsers block mixed content
HTTPS encrypts the connection between the browser and your server. If your page loads a script over HTTP, an attacker on the network (coffee shop WiFi, compromised router) could inject malicious code into that script. The browser would execute it with full access to your HTTPS page β including cookies, form data, and session tokens.
There are two types:
- Active mixed content (scripts, stylesheets, iframes, fetch/XHR, WebSocket) β always blocked. These can modify the page or steal data.
- Passive mixed content (images, audio, video) β may load with a warning in some browsers, but Chrome and Firefox now block these too by default.
Fix 1: Change HTTP URLs to HTTPS
The simplest and most common fix β update the URLs in your code:
<!-- β HTTP β blocked -->
<img src="http://cdn.example.com/image.jpg" />
<script src="http://cdn.example.com/lib.js"></script>
<link rel="stylesheet" href="http://cdn.example.com/style.css" />
<!-- β
HTTPS β works -->
<img src="https://cdn.example.com/image.jpg" />
<script src="https://cdn.example.com/lib.js"></script>
<link rel="stylesheet" href="https://cdn.example.com/style.css" />
Before changing: Verify the resource is available over HTTPS. Open the HTTPS URL in your browser β if it loads, youβre good. If it doesnβt, the server doesnβt support HTTPS and youβll need a different approach (see Fix 6).
Fix 2: Use relative URLs for same-origin resources
If the resource is on the same domain, use a relative path instead of an absolute URL:
<!-- β Absolute URL with protocol β fragile -->
<img src="http://www.mysite.com/images/logo.png" />
<!-- β
Relative URL β always matches the page's protocol -->
<img src="/images/logo.png" />
// β Hardcoded HTTP in API calls
fetch('http://www.mysite.com/api/data');
// β
Relative URL β works on both HTTP and HTTPS
fetch('/api/data');
This is the safest approach for same-origin resources because it automatically uses whatever protocol the page was loaded with.
Fix 3: Fix API calls in JavaScript
A common source of mixed content β API endpoints hardcoded with http://:
// β Hardcoded HTTP
const response = await fetch('http://api.example.com/users');
axios.get('http://api.example.com/data');
// β
Use HTTPS
const response = await fetch('https://api.example.com/users');
// β
Use environment variables
const API_URL = process.env.NEXT_PUBLIC_API_URL; // Set to https:// in production
const response = await fetch(`${API_URL}/users`);
// β
Or detect protocol dynamically
const protocol = window.location.protocol; // "https:"
const response = await fetch(`${protocol}//api.example.com/users`);
Fix 4: Add upgrade-insecure-requests CSP header
This tells the browser to automatically upgrade all HTTP requests to HTTPS before sending them:
<!-- In your HTML head -->
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
Or as a server header (preferred β canβt be removed by injected HTML):
# Nginx
add_header Content-Security-Policy "upgrade-insecure-requests" always;
# Apache
Header always set Content-Security-Policy "upgrade-insecure-requests"
// Express.js
app.use((req, res, next) => {
res.setHeader('Content-Security-Policy', 'upgrade-insecure-requests');
next();
});
Important: This only works if the resource server actually supports HTTPS. If it doesnβt, the upgraded request will fail with a connection error instead of a mixed content warning.
Fix 5: Find all mixed content on your site
Browser DevTools: Open the Console tab β mixed content warnings show the exact URLs causing the problem. The Network tab also flags blocked requests with a warning icon.
Search your codebase:
# Find hardcoded http:// URLs in your source
grep -rn "http://" src/ --include="*.html" --include="*.js" --include="*.tsx" --include="*.css" | grep -v "localhost\|127.0.0.1"
Online tools:
- Why No Padlock β scans a page for mixed content
- Chrome DevTools β Security tab β shows mixed content details
- Lighthouse audit flags mixed content issues
Fix 6: Third-party resources without HTTPS
If a third-party service doesnβt support HTTPS:
<!-- β Old embed code from a service that only supports HTTP -->
<iframe src="http://old-service.com/widget"></iframe>
<!-- Options: -->
<!-- 1. Find an alternative service that supports HTTPS -->
<!-- 2. Proxy through your own server -->
<!-- 3. Remove the resource if it's not critical -->
Proxy approach (last resort):
// Your server fetches the HTTP resource and serves it over HTTPS
app.get('/proxy/widget', async (req, res) => {
const response = await fetch('http://old-service.com/widget');
const data = await response.text();
res.send(data);
});
Fix 7: Database or CMS content with HTTP URLs
If your content is stored in a database (WordPress, CMS, user-generated content) with HTTP URLs:
-- Update all HTTP URLs to HTTPS in your database
UPDATE posts SET content = REPLACE(content, 'http://cdn.example.com', 'https://cdn.example.com');
UPDATE posts SET content = REPLACE(content, 'http://www.mysite.com', 'https://www.mysite.com');
For WordPress specifically:
# Use WP-CLI
wp search-replace 'http://www.mysite.com' 'https://www.mysite.com' --all-tables
Fix 8: WebSocket connections
// β Insecure WebSocket on HTTPS page
const ws = new WebSocket('ws://api.example.com/socket');
// β
Use secure WebSocket (wss://)
const ws = new WebSocket('wss://api.example.com/socket');
// β
Auto-detect
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const ws = new WebSocket(`${protocol}//api.example.com/socket`);
Prevention
- Always use
https://in your code β never hardcodehttp://for production resources - Add
upgrade-insecure-requestsCSP header as a safety net - Use relative URLs (
/api/data) for same-origin resources - Add a CI check that scans for
http://URLs in your codebase (excluding localhost) - Test after deploying with browser DevTools console open
- Configure your CDN to serve everything over HTTPS and redirect HTTP to HTTPS
FAQ
Does upgrade-insecure-requests fix everything automatically?
No. It only works if the target server supports HTTPS. If you reference http://old-server.com/image.jpg and that server doesnβt have an SSL certificate, the upgraded HTTPS request will fail. You still need to fix the underlying URLs or find HTTPS alternatives.
Why do I see mixed content warnings in development but not production?
If your dev server runs on HTTP (localhost:3000) and youβre loading resources from HTTPS CDNs, thatβs technically mixed content too β but browsers allow it for localhost. The reverse (HTTPS page loading HTTP resources) is what gets blocked in production.
Can mixed content affect my SEO?
Indirectly. If mixed content causes images or resources to not load, it degrades user experience and page quality. Google also considers HTTPS as a ranking signal, and a page with mixed content warnings may not get the full HTTPS benefit.
Is protocol-relative (//cdn.example.com/...) still recommended?
No. It was useful when sites served both HTTP and HTTPS, but today all sites should be HTTPS-only. Use explicit https:// instead. Protocol-relative URLs can cause issues with some tools and are considered a legacy pattern.