HSTS and mixed content get lumped together because they both live in the HTTPS world. But they solve different problems, fail in different ways, and trip up different teams.

If you’re building or maintaining a site, you need to understand the gap between them:

  • HSTS tells the browser to always use HTTPS for your domain.
  • Mixed content happens when an HTTPS page still loads some resources over HTTP.

That distinction matters. I’ve seen teams proudly enable HSTS and assume they’re done, while their pages still pull images, scripts, or CSS over plain HTTP. That’s not “mostly secure.” That’s a site with sharp edges.

The short version

HSTS

A response header that instructs browsers to rewrite future HTTP requests to HTTPS.

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

Mixed content

A browser security issue triggered when an HTTPS page loads insecure subresources.

<!-- Bad -->
<script src="http://cdn.example.com/app.js"></script>
<img src="http://example.com/logo.png" alt="Logo">
<link rel="stylesheet" href="http://example.com/styles.css">

These are related, but not interchangeable.

What HSTS actually gives you

HSTS stands for HTTP Strict Transport Security. It’s a browser-enforced rule: once the browser sees the header on a secure response, it remembers that your domain must only be contacted over HTTPS for the duration of max-age.

A typical production header looks like this:

Strict-Transport-Security: max-age=31536000; includeSubDomains

If you want preload eligibility:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

Pros of HSTS

1. It kills protocol downgrade attacks

Without HSTS, a user typing example.com may start on HTTP and then get redirected to HTTPS. That first hop is a weak point. HSTS removes that after the browser learns the policy.

Users, bookmarks, old docs, and third-party links still point to http:// more often than people admit. HSTS helps clean that up automatically in the browser.

3. It reduces accidental insecure access

Developers and ops teams make mistakes. HSTS gives you a safety net at the browser layer.

4. It works well at scale

Once enabled correctly, it’s low maintenance. Set the header at your edge or app server and keep it consistent.

Cons of HSTS

1. It does not fix mixed content

This is the big misunderstanding. HSTS upgrades navigation to your domain. It does not magically sanitize every insecure resource reference in your HTML, CSS, or JS.

2. Bad rollout can break subdomains

If you use includeSubDomains, every subdomain must support HTTPS correctly. That includes weird legacy hosts nobody has touched in five years.

3. Preload is hard to undo

If you submit your domain to browser preload lists, rollback is slow and painful. Don’t preload unless you’re sure your house is in order.

4. First visit is still special unless preloaded

Normal HSTS only starts after the browser receives the header once over HTTPS. Until then, the first connection can still be exposed to downgrade attacks. Preload helps, but comes with that operational commitment.

What mixed content actually breaks

Mixed content means an HTTPS page requests some resources over HTTP. Browsers hate this for good reason: an attacker on the network can tamper with those insecure resources even if the page itself loaded over TLS.

Example:

<!doctype html>
<html>
  <head>
    <link rel="stylesheet" href="http://static.example.com/site.css">
  </head>
  <body>
    <img src="http://images.example.com/banner.jpg" alt="Banner">
    <script src="http://cdn.example.com/app.js"></script>
  </body>
</html>

That page is not fully trustworthy. The browser may block some of it, auto-upgrade some of it, or show warnings depending on the resource type and browser behavior.

Pros of mixed content handling in browsers

This is a weird category because mixed content itself is bad. But browser enforcement around it does help.

1. Browsers block dangerous resource types

Scripts, stylesheets, iframes, and XHR/fetch requests over HTTP are generally blocked on HTTPS pages. That prevents some truly ugly attacks.

2. Warnings expose insecure dependencies

Mixed content errors often reveal forgotten legacy assets, bad CMS templates, or old third-party integrations.

3. Auto-upgrade helps with some passive resources

Modern browsers may upgrade image/audio/video requests from HTTP to HTTPS when possible. Nice when it works, but I would never rely on it as a strategy.

Cons of mixed content

1. It breaks pages in production

Blocked scripts and CSS don’t fail gracefully. They break layouts, interactions, analytics, payment flows, everything.

2. It creates false confidence

The page has a padlock, so people assume it’s secure. Meanwhile, some image or script source is still plain HTTP.

3. Third-party assets are often the real problem

Your own code may be clean, but some ad tag, widget, font loader, or old marketing snippet drags in HTTP.

4. It gets buried in templates and generated content

Mixed content is often hidden in CMS fields, Markdown content, WYSIWYG editors, email templates, or JavaScript-generated URLs.

HSTS vs mixed content: side-by-side

Here’s the cleanest way to compare them.

Topic HSTS Mixed Content
What it is Security response header Browser security issue
Main goal Force HTTPS for future requests Prevent insecure resources on HTTPS pages
Controlled by Server response header HTML, CSS, JS, third-party resources
Fix type Header/config change Code/content/dependency cleanup
Can it break pages? Yes, if HTTPS isn’t ready everywhere Yes, blocked resources break rendering/functionality
Solves downgrade risk? Yes No
Solves insecure subresource loads? No Detection/enforcement only

That last row is the one developers should remember.

Real-world example: why HSTS doesn’t save a mixed page

Say your server sends:

Strict-Transport-Security: max-age=31536000; includeSubDomains

And your page contains:

<script src="http://assets.example.com/main.js"></script>

What happens?

  • The browser knows example.com should use HTTPS.
  • The page itself loads over HTTPS.
  • The script request is still explicitly http://assets.example.com/main.js.
  • Depending on browser behavior and host setup, that script is blocked or upgraded.
  • If it’s blocked, your app breaks.
  • If assets.example.com doesn’t support HTTPS correctly, upgrade won’t help anyway.

So yes, HSTS improves transport security. No, it doesn’t excuse bad resource URLs.

Best use cases for HSTS

HSTS is a strong fit when:

  • your entire site and subdomains are HTTPS-ready
  • you want to eliminate protocol downgrade risk
  • you control your DNS and TLS setup well
  • you can safely commit to long-lived HTTPS-only behavior

A simple Nginx example:

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

Apache:

Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

Express behind HTTPS termination:

app.use((req, res, next) => {
  res.setHeader(
    "Strict-Transport-Security",
    "max-age=31536000; includeSubDomains"
  );
  next();
});

Start with a shorter max-age if you’re nervous:

Strict-Transport-Security: max-age=300

Then ramp up after validation.

Best use cases for mixed content cleanup

Mixed content work is less glamorous, but it’s usually where the real effort is.

You should prioritize cleanup when:

  • you recently migrated from HTTP to HTTPS
  • you use a CMS with old embedded content
  • you load third-party scripts, fonts, images, or iframes
  • browser consoles show blocked resource errors
  • pages partly work over HTTPS but feel flaky

Typical fixes:

1. Use relative or HTTPS URLs

Prefer explicit HTTPS for external resources.

<script src="https://cdn.example.com/app.js"></script>

2. Stop hardcoding http://

Search templates, content blobs, and JS for insecure URLs.

3. Add CSP upgrade support where it makes sense

This can help as a migration aid, not as a permanent excuse.

Content-Security-Policy: upgrade-insecure-requests

That tells the browser to rewrite insecure resource URLs to HTTPS. Useful during cleanup, but if the target host doesn’t serve HTTPS correctly, things still fail.

4. Audit third-party dependencies

If a vendor still requires HTTP in 2026, I’d seriously question why they’re on the page at all.

Which is more important?

That’s the wrong question. You need both.

If I had to prioritize rollout order for a messy legacy site, I’d usually do this:

  1. Get HTTPS working everywhere
  2. Fix mixed content
  3. Enable HSTS with a safe max-age
  4. Increase max-age
  5. Consider includeSubDomains and preload only after full validation

Why this order? Because HSTS locks in HTTPS expectations, while mixed content cleanup makes the actual page secure and functional. Shipping HSTS onto a half-migrated stack is how you create outages and angry Slack threads.

How to test both

Check headers and page behavior separately.

For HSTS, verify the response header is present on HTTPS responses and configured as intended. For mixed content, inspect browser console errors, network requests, and rendered page behavior.

If you want a quick sanity check on your header setup, run a free scan with HeaderTest. It’s a fast way to catch missing or weak security headers before you start arguing about preload.

My practical take

HSTS is a strong, boring, high-value control. I like boring controls. They save you from common mistakes and quietly reduce risk.

Mixed content is where migrations get exposed. It’s less about policy and more about code quality, asset hygiene, and whether anyone actually audited the long tail of the site.

So the honest comparison is this:

  • HSTS is a seatbelt
  • Mixed content is whether the car still has holes in the floor

Use the seatbelt. Fix the holes too.