πŸ”§ Error Fixes
Β· 5 min read
Last updated on

Mixed Content Blocked β€” How to Fix It


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 hardcode http:// for production resources
  • Add upgrade-insecure-requests CSP 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.

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.