Mixed Content Warnings: HTTP Resources on HTTPS Pages - VibeDoctor 
← All Articles 🌐 Live Website Analysis High

Mixed Content Warnings: HTTP Resources on HTTPS Pages

Your HTTPS site loads images or scripts over HTTP? Browsers block mixed content. Learn how to find and fix mixed content issues.

WEB-005 WEB-003 WEB-004

Quick Answer

Mixed content occurs when an HTTPS page loads resources - images, scripts, stylesheets, or API calls - over HTTP. Modern browsers block mixed content by default, which means those resources silently fail to load. In AI-built apps, this typically stems from hardcoded HTTP URLs in source code, third-party embeds, or assets referenced from a CMS or database with old URLs.

Why Mixed Content Is a Browser-Level Security Block

When your site runs on HTTPS, the browser establishes an encrypted connection that protects everything transmitted between your server and the user. Loading any resource over HTTP breaks that guarantee. An attacker on the same network could intercept and modify the HTTP resource - injecting malicious JavaScript into a script file, replacing an image, or altering a stylesheet - before it reaches the user, even though the page itself is served securely.

For this reason, browsers do not just warn about mixed content - they actively block it. According to the W3C Mixed Content specification, "active mixed content" (scripts, stylesheets, iframes, and fetch requests) is always blocked, while "passive mixed content" (images, audio, video) generates a warning and may be blocked depending on browser settings and security policies.

Chrome's security team reported that mixed content blocking has prevented a significant class of network interception attacks, particularly on public Wi-Fi networks. The transition from permissive to blocking behavior, completed across major browsers by 2020, means that any site with mixed content is experiencing real functional failures - not just theoretical security warnings.

For vibe-coded apps deployed on Vercel or Netlify - which automatically provision HTTPS via Let's Encrypt - mixed content is an especially common issue because the AI generates code assuming HTTP in many contexts, and the HTTPS layer is added by the deployment platform rather than the developer.

Where Mixed Content Comes From in AI-Built Apps

Source Example Type
Hardcoded API URLs fetch('http://api.example.com/data') Active (blocked)
External script tags <script src="http://cdn.example.com/lib.js"> Active (blocked)
Image src attributes <img src="http://images.example.com/photo.jpg"> Passive (warning/blocked)
CSS background images background: url('http://cdn.example.com/bg.png') Passive (warning)
Iframe embeds <iframe src="http://embed.example.com/"> Active (blocked)
WebSocket connections new WebSocket('ws://...') instead of wss:// Active (blocked)
Database-stored URLs User-uploaded content with old HTTP URLs Passive or Active

What AI Code Generates That Causes Mixed Content

When Cursor or Bolt scaffolds a Next.js app and you ask it to "add a video embed" or "fetch data from an external API," it commonly generates HTTP URLs in several patterns:

// ❌ BAD - HTTP URLs that cause mixed content on an HTTPS site
const API_BASE = 'http://api.myservice.com';

// Hardcoded HTTP fetch
const res = await fetch('http://api.myservice.com/products');

// External script loaded over HTTP
// (placed by AI in _document.js or layout.tsx)


// WebSocket connection over ws:// instead of wss://
const socket = new WebSocket('ws://realtime.myservice.com:3001');

// Image from a CMS URL stored without protocol upgrade
{product.name}

These are not theoretical issues. They are patterns that appear in real Cursor, Bolt, and Lovable-generated codebases daily. The AI has no way to know that your deployment will be served over HTTPS; it generates the URL it has context for, which is often the development or staging endpoint using HTTP.

How to Fix Mixed Content Issues

The fix depends on the source of the mixed content, but the principle is always the same: upgrade every resource URL to use https:// or use a protocol-relative URL (//) where supported.

// ✅ GOOD - Protocol-safe API calls and resource URLs

// Use HTTPS explicitly in environment variables
const API_BASE = process.env.NEXT_PUBLIC_API_URL; // Set to https:// in Vercel env vars

// Protocol-relative URL (inherits https from the page)


// WebSocket using wss:// (TLS-secured WebSocket)
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const socket = new WebSocket(`${wsProtocol}//realtime.myservice.com`);

// Upgrade image URLs before rendering
const secureImageUrl = imageUrl.replace(/^http:\/\//i, 'https://');
{product.name}

For environment variables used in fetch calls, ensure that the values you set in Vercel's dashboard always use the https:// scheme. A common mistake is setting NEXT_PUBLIC_API_URL=http://... during development and forgetting to update it for production.

The Upgrade-Insecure-Requests Header

As a belt-and-suspenders defense, you can instruct browsers to automatically upgrade HTTP sub-resource requests to HTTPS before they are blocked. This is done via a Content Security Policy directive or an HTTP response header:

// ✅ GOOD - Add to next.config.js headers for automatic protocol upgrade
// This catches any remaining HTTP URLs and upgrades them to HTTPS
const securityHeaders = [
  {
    key: 'Content-Security-Policy',
    value: "upgrade-insecure-requests; default-src 'self' https:;"
  }
];

// next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/(.*)',
        headers: securityHeaders,
      },
    ];
  },
};

The upgrade-insecure-requests directive tells browsers to replace http:// with https:// for all resource loads on the page. It is not a substitute for fixing the URLs at their source - a resource that does not exist over HTTPS will still fail - but it prevents the browser from blocking resources that do exist on both protocols.

How to Scan for Mixed Content on Your Live Site

There are three practical ways to identify mixed content on a deployed site:

Browser DevTools: Load each page of your app in Chrome, open DevTools (F12), and check the Console tab for mixed content warnings (shown in yellow) and the Network tab filtered by "blocked" or HTTP requests from an HTTPS origin. This is thorough but manual and does not scale across a large site.

Automated headless browser scan: A Playwright or Puppeteer script can load every page of your site and capture all mixed content warnings programmatically. This can be integrated into your CI/CD pipeline on Vercel as a post-deploy check.

Tools like VibeDoctor (vibedoctor.io) automatically scan your live website for mixed content issues, page weight problems, and request count anomalies and flag specific URLs and resource paths. Free to sign up.

CSP reporting: Deploying a Content Security Policy with a report-uri or report-to directive sends violation reports to an endpoint you control whenever a browser blocks a resource. Services like Report URI aggregate these reports across all real user sessions, giving you a comprehensive view of mixed content in the wild.

Page Weight and Request Count: Related Issues

While fixing mixed content, it is worth addressing two related WEB checks that affect the same pages. The WEB-003 and WEB-004 checks cover excessive page weight and excessive HTTP request count - issues that frequently co-exist with mixed content in AI-built apps.

Vibe-coded apps often load dozens of external scripts (analytics, chat widgets, A/B testing tools, font providers) that were added across multiple AI prompting sessions without considering their cumulative impact. Each external HTTP request adds latency, and each script that loads over HTTP triggers a mixed content block. A single audit of your page's Network tab often reveals 10-20 external requests that can be consolidated, deferred, or removed entirely.

According to the HTTP Archive's annual Web Almanac, the median web page makes over 70 HTTP requests on desktop. Pages with excessive requests score poorly on Lighthouse, rank lower in Google's Core Web Vitals assessment, and are measurably more likely to generate mixed content warnings when any of those external resources uses HTTP.

FAQ

My browser shows a padlock icon - does that mean I have no mixed content?

Not necessarily. Modern browsers show a secure padlock even when passive mixed content (images, audio) is present, because they no longer downgrade the indicator for passive resources. The padlock only confirms the page's main document was served over HTTPS. Open DevTools and check the Console for mixed content warnings to get the full picture.

What is the difference between active and passive mixed content?

Active mixed content includes resources that can modify the DOM or execute code: scripts, stylesheets, iframes, XMLHttpRequest, fetch, and WebSockets. These are always blocked. Passive mixed content includes images, audio, and video - resources that cannot execute code. These generate warnings and are blocked in some contexts. From a security standpoint, active mixed content is the critical category to resolve first.

Does Vercel automatically serve my site over HTTPS?

Yes, Vercel automatically provisions a TLS certificate via Let's Encrypt for every deployment, including preview deployments. However, this only secures the main document - your source code is still responsible for ensuring all sub-resources are loaded over HTTPS. Vercel does not upgrade HTTP resource URLs in your code.

My Supabase Storage images are loading over HTTP - how do I fix that?

Supabase Storage URLs always support HTTPS. If you are getting HTTP URLs from the Supabase client, check whether you are calling getPublicUrl() correctly - it returns a full URL including protocol. Ensure your Supabase project URL in NEXT_PUBLIC_SUPABASE_URL uses https://, as the Storage client derives the base URL from your project configuration.

Can upgrade-insecure-requests break anything on my site?

It can break resources that genuinely do not exist over HTTPS. If you embed content from a third-party service that only supports HTTP, upgrading the request to HTTPS will cause a connection failure. This is a signal that you should replace that resource with an HTTPS-capable alternative rather than keeping an insecure dependency. In practice, almost every CDN and public API has supported HTTPS for years, so breakage from this directive is rare on modern stacks.

Scan your codebase for this issue - free

VibeDoctor checks for WEB-005, WEB-003, WEB-004 and 128 other issues across 15 diagnostic areas.

SCAN MY APP →
← Back to all articles View all 129+ checks →