SSL, TLS, security headers
Fix mixed content warnings on HTTPS pages
Your HTTPS page loads scripts, images, or iframes over HTTP, triggering 'Mixed Content' console errors. Browsers block active content and downgrade the lock icon.
What's happening
Mixed content occurs when an HTTPS page references subresources — scripts, stylesheets, iframes, images, fonts, fetch/XHR — over plain HTTP. The browser distinguishes 'active' mixed content (scripts, stylesheets, iframes, fetch) from 'passive' (images, audio, video). Active mixed content has been blocked outright by Chrome, Firefox, and Safari since 2020. Passive mixed content is auto-upgraded to HTTPS or blocked.
Users see a broken site or missing functionality; developers see 'Mixed Content: The page at https://example.com was loaded over HTTPS, but requested an insecure resource at http://...' in the console. The lock icon downgrades to a 'Not Secure' warning. The TLS handshake to the main page is fine; the issue is the application-layer references.
The fix is to update every subresource URL to HTTPS, or to use protocol-relative URLs and let the browser pick. The longer-term fix is to add a Content-Security-Policy that automatically upgrades insecure requests so a regression cannot ship.
Why it matters
Functionality breaks silently. A blocked analytics script means lost tracking; a blocked checkout iframe means lost revenue. The user sees 'something is wrong' without an error message.
Search engines penalize pages that lose the 'secure' badge. Google has used HTTPS as a ranking signal since 2014, and degraded HTTPS counts as worse than plain HTTP for ranking purposes.
PCI-DSS treats mixed content on a payment page as a control failure because the integrity of the page cannot be guaranteed. Scanners flag it, audits fail.
Common causes
- Hardcoded
http://URLs in CMS content from before the HTTPS migration. - Third-party widgets (chat, analytics, social embeds) that ship HTTP-only fallback URLs.
- Image src attributes pasted from upstream HTTP CDNs.
- A reverse proxy strips the X-Forwarded-Proto header so the application generates absolute URLs with
http://. - Old database rows with absolute URLs that survived the migration script.
Detect this on your site
Run a quick scan with the Full Site Audit. The tool surfaces this exact issue with the records and context needed to apply the fix below.
Open Full Site AuditHow to fix it
- 1
Find every mixed-content reference
Open the page in Chrome DevTools, go to the Console, and filter for 'Mixed Content'. The Network panel with the 'Blocked' filter shows every blocked request. The CheckFast Full Site Audit at /check crawls the whole site and lists every offender by URL.
- 2
Update absolute HTTP URLs in templates and CMS
Search the codebase for
http://references —git grep "http://"is a fast first pass. In WordPress, runwp search-replace 'http://example.com' 'https://example.com' --all-tables. In Drupal, usedrush sql-query "UPDATE {node_field_data} SET ...". Audit any database that stores rendered URLs. - 3
Use HTTPS or protocol-relative URLs for third parties
Every reputable third-party widget publishes an HTTPS URL — use it. Avoid the protocol-relative
//cdn.example.comform on email templates (Gmail rewrites them) but it is safe in HTML. If a third party only offers HTTP, replace the vendor. - 4
Add upgrade-insecure-requests to CSP
Set
Content-Security-Policy: upgrade-insecure-requests(or include the directive in your existing CSP). The browser will automatically upgrade matching subresource requests from HTTP to HTTPS, masking residual references while you clean them up. - 5
Trust X-Forwarded-Proto in the application
If your app generates absolute URLs, make sure it reads X-Forwarded-Proto from the reverse proxy. In Express set
app.set('trust proxy', 1). In Rails setconfig.action_dispatch.tld_lengthand useconfig.force_ssl. In Next.js, when behind a proxy that sets the header, server-side requests will see https inheaders().get('x-forwarded-proto'). - 6
Re-crawl and confirm zero issues
Re-run the Full Site Audit at /check after deploying. Mixed content findings should drop to zero. Add the audit to your CI pipeline so a regression in a new template fails the build.
Example
Content-Security-Policy: upgrade-insecure-requests; default-src 'self' https:; img-src 'self' https: data:;
CSP header that auto-upgrades insecure subresources
Frequently asked
It fixes same-origin and cross-origin subresources where the upgraded URL actually exists. If a third-party CDN does not serve HTTPS at the same path the request will fail rather than load over HTTP. Always verify after enabling.
Not really. They were a bridge during the HTTPS migration era. Today ship explicit https:// URLs — they are clearer in code review and avoid edge cases in email and view-source contexts.
Related fixes
SSL, TLS, security headers
Deploy a Content-Security-Policy to mitigate XSS attacks
SSL, TLS, security headers
Remove unsafe-inline from CSP and adopt nonce-based scripts
SSL, TLS, security headers
Force HTTP-to-HTTPS redirects on every hostname you serve
SSL, TLS, security headers
Add HSTS header to enforce HTTPS and prevent SSL stripping