Fix Mixed Content Blocked: The page was loaded over HTTPS, but requested an insecure resource

intermediate๐Ÿ”’ SSL/TLS2026-04-15| All browsers (Chrome, Firefox, Edge, Safari) on any OS โ€” affects any HTTPS website that references HTTP resources

Error Message

Mixed Content: The page was loaded over HTTPS, but requested an insecure resource. This request has been blocked.
#ssl#mixed-content#https#http

What's happening

Your page loads over HTTPS, but one or more resources โ€” a script, image, stylesheet, iframe, or API call โ€” are still being fetched over plain HTTP. Browsers treat this as a security hole. A man-in-the-middle attacker could swap that HTTP resource for something malicious, even though your page itself is encrypted.

Chrome 86+ blocks all mixed content automatically, including passive resources like images. Older browsers would only block active resources (scripts, iframes) and just warn about passive ones. Either way, the resource fails to load and you get this in the console:

Mixed Content: The page was loaded over HTTPS, but requested an insecure resource. This request has been blocked.

For images, the softer warning looks like this:

Mixed Content: The page at 'https://example.com' was loaded over HTTPS, but contains a link to an insecure image 'http://example.com/photo.jpg'. This content should also be served over HTTPS.

Find every offending resource

The fastest way to locate them: open DevTools (F12), go to the Console tab, and filter by "Mixed Content". Each blocked URL appears there with the exact line that triggered it. Also check the Network tab โ€” filter the request URL column by http://.

For a site-wide scan without clicking every page, the mixed-content-scanner CLI tool crawls your entire site and reports every offending URL:

npx mixed-content-scanner https://example.com

Or pull raw HTML and grep for HTTP references directly:

curl -s https://example.com | grep -Eo 'http://[^"\x27 >]+' | sort -u

Quick fix โ€” enable the upgrade-insecure-requests CSP header

Add the Content-Security-Policy header to your server. It tells the browser to silently rewrite http:// to https:// for every sub-resource before making the request โ€” no code changes needed.

Nginx

add_header Content-Security-Policy "upgrade-insecure-requests;";

Apache (.htaccess)

Header always set Content-Security-Policy "upgrade-insecure-requests;"

HTML meta tag (when you can't touch the server)

<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

Place it inside <head> before any other resource tags. Resources that appear before this tag in the HTML won't be upgraded.

One catch: upgrade-insecure-requests rewrites the URL but can't conjure an HTTPS endpoint out of thin air. If the remote server doesn't support HTTPS at all, the request fails just the same โ€” just with a different error. Fix those resources permanently using the methods below.

Permanent fix โ€” update every HTTP reference in your code

1. Hardcoded URLs in HTML/templates

Run a find-and-replace across your codebase. This catches the vast majority of cases in a few seconds:

# Find all http:// references in your templates
grep -r 'http://' ./src --include='*.html' --include='*.jsx' --include='*.tsx' --include='*.vue'

# Replace http://example.com with https://example.com across all files
find ./src -type f \( -name '*.html' -o -name '*.jsx' -o -name '*.tsx' \) \
  -exec sed -i 's|http://example.com|https://example.com|g' {} +

2. Protocol-relative URLs (for third-party embeds)

Drop the scheme entirely and let the browser inherit the current page's protocol โ€” HTTPS on your live site, HTTP on local dev:

<!-- Before -->
<script src="http://cdn.example.com/lib.js"></script>

<!-- After -->
<script src="//cdn.example.com/lib.js"></script>

3. WordPress sites

WordPress stores URLs in the database, so a file-level find-and-replace isn't enough. Run a database search-replace โ€” WP-CLI is the safest approach:

-- Via WP-CLI (handles serialized data correctly)
wp search-replace 'http://example.com' 'https://example.com' --all-tables

-- Or directly in MySQL
UPDATE wp_posts SET post_content = REPLACE(post_content, 'http://example.com', 'https://example.com');
UPDATE wp_postmeta SET meta_value = REPLACE(meta_value, 'http://example.com', 'https://example.com');
UPDATE wp_options SET option_value = REPLACE(option_value, 'http://example.com', 'https://example.com');

After the database update, install the Really Simple SSL plugin. It patches mixed content at the PHP output buffer level in real-time, catching anything the database update missed โ€” theme files, widgets, dynamic output.

4. Fetch / XHR in JavaScript

Any fetch() or XMLHttpRequest call with an absolute HTTP URL gets blocked. Use relative URLs where possible โ€” they're shorter and always inherit the right protocol:

// Bad
fetch('http://api.example.com/data')

// Good โ€” relative URL (inherits protocol automatically)
fetch('/api/data')

// Good โ€” explicit HTTPS for external APIs
fetch('https://api.example.com/data')

5. CSS background images and @import

/* Bad */
.hero {
  background-image: url('http://example.com/hero.jpg');
}

/* Good */
.hero {
  background-image: url('https://example.com/hero.jpg');
}

When the resource doesn't support HTTPS at all

Some older third-party CDNs or self-hosted assets only serve over HTTP. You have three ways out:

  • Self-host it โ€” download the file and serve it from your own HTTPS domain. Works for fonts, libraries, anything static.
  • Switch to an HTTPS CDN โ€” jsDelivr, cdnjs, and unpkg serve every package over HTTPS. Swap the URL and you're done.
  • Proxy it โ€” route the request through your own HTTPS endpoint that fetches and forwards the HTTP resource. More work, but sometimes unavoidable for live data feeds.

Verify the fix

  • Hard-reload the page (Ctrl+Shift+R / Cmd+Shift+R) to bypass cache.
  • Open DevTools โ†’ Console. Zero mixed content warnings means you're done.
  • Check the padlock icon in the address bar โ€” no warning triangle, just a clean closed padlock.
  • In Chrome, click the padlock โ†’ Connection is secure โ†’ Certificate is valid.
  • Run a final crawl: npx mixed-content-scanner https://example.com โ€” it should report 0 issues.

Related Error Notes