You installed an SSL certificate, forced HTTPS across your site, and then opened Chrome's developer tools to find a wall of red warnings. The padlock is gone, replaced by a grey info icon or a "Not Secure" label. Your site is serving HTTPS but still loading some resources over plain HTTP, and browsers treat that as a security violation. This is a mixed content error, and it is one of the most common post-SSL problems webmasters face. The good news is that every single mixed content error is fixable, usually in under an hour, once you know where to look.
What Mixed Content Actually Means
When a browser loads an HTTPS page, it expects every resource on that page, images, scripts, stylesheets, fonts, iframes, API calls, to also come over an encrypted connection. If even one resource is requested over HTTP, the browser flags the entire page. There are two severity levels:
- Passive mixed content — images, audio, and video loaded over HTTP. Browsers usually still display them but show a warning or remove the padlock. Chrome and Firefox are making this stricter with each release.
- Active mixed content — scripts, stylesheets, iframes, and XHR/fetch requests over HTTP. Browsers block these entirely because a HTTP script can rewrite the page and steal data. If your JavaScript or CSS loads over HTTP, it simply will not run.
Both types need to be fixed. Passive mixed content is a reputation problem today and a breakage problem tomorrow as browsers continue tightening restrictions.
Why Mixed Content Errors Happen
Understanding the root causes saves you from chasing symptoms. The most common triggers are:
- Hard-coded HTTP URLs in your database or theme — a WordPress post saved years ago with src="http://yourdomain.com/image.jpg" will survive an SSL migration unchanged.
- Third-party embeds and widgets — an old YouTube embed URL, a weather widget, an ad network snippet, or a payment badge that still points to an HTTP endpoint.
- CDN or asset URLs not updated — you switched to HTTPS but your CDN origin or asset base URL in the CMS config still reads http://.
- External fonts or libraries pulled from HTTP — a Google Fonts or jQuery CDN link using http:// instead of https://.
- Relative protocol-less URLs that resolve wrong — URLs written as //example.com/resource that resolve to HTTP if there is an intermediate redirect issue.
- Plugins or page builders that hard-code the site URL at install time and never update when you switch to HTTPS.
Step 1: Find Every Mixed Content Error
You cannot fix what you cannot see. Use all three of these methods to build a complete picture before touching any files.
Browser Developer Tools
Open your site in Chrome or Firefox. Press F12 (or Cmd+Option+I on Mac) and click the Console tab. Mixed content warnings appear in yellow or red and show the exact URL of every offending resource. Click the Network tab, reload, and filter by the type (JS, CSS, Img) to isolate blocked resources. Copy every flagged URL into a text file.
Command-Line Crawl with curl or wget
For a quick check of a specific page's source, run:
This greps the raw HTML for any attribute pointing to an HTTP URL. Pipe to a file if the output is long:
Online Scanners
Tools like Why No Padlock, SSL Shopper, and JitBit's Mixed Content Checker crawl your pages and report every HTTP resource they find. Run your homepage and a few key landing pages through these before and after your fix to confirm everything is clean.
Step 2: Fix Mixed Content in WordPress
WordPress is where the majority of mixed content problems live because the site URL is stored in the database, and every post, image attachment, and option record can carry an http:// prefix from before your SSL migration.
Use the Better Search Replace Plugin
- Install and activate Better Search Replace from the WordPress plugin directory.
- Go to Tools > Better Search Replace.
- In the Search for field, enter: http://yourdomain.com
- In the Replace with field, enter: https://yourdomain.com
- Select all tables (Ctrl+A or Cmd+A).
- Run a dry run first by checking Run as dry run and clicking Run Search/Replace. It will tell you how many rows would change without touching anything.
- Uncheck the dry run option and run it for real. The plugin handles serialized data correctly, which is critical in WordPress.
Use WP-CLI on the Command Line
If you have SSH access, this is faster and more reliable for large databases:
The --precise flag handles serialized PHP data safely. The --skip-columns=guid prevents breaking WordPress's internal GUID tracking for posts.
Update WordPress Site URL Settings
Even after a database search-replace, confirm these settings under Settings > General in the WordPress admin. Both WordPress Address (URL) and Site Address (URL) must start with https://. If they do not, update them manually and save.
Step 3: Force HTTPS at the Server Level
A server-level rewrite catches anything your CMS misses and redirects stray HTTP requests before they can create mixed content.
Apache (.htaccess)
Place this at the top of your .htaccess file, before any WordPress or application rewrites. Test with curl -I http://yourdomain.com and confirm you see a 301 redirect to the HTTPS version.
Nginx (nginx.conf or site config)
After editing the config, test for syntax errors and reload:
Step 4: Fix Mixed Content in Themes, Plugins, and Custom Code
If your theme or a plugin hard-codes HTTP URLs, the database search-replace will not always catch them because they live in PHP files, not the database.
Search your theme and plugin files recursively:
When you find a hard-coded HTTP URL in a file you control, edit it to https://. For third-party plugins you cannot edit, check whether an update exists that resolves the issue, or contact the developer. Some older unmaintained plugins need to be replaced entirely.
For external libraries like jQuery, Bootstrap, or Google Fonts, update every CDN link. Replace:
With the HTTPS version:
Or better still, use protocol-relative URLs where appropriate, though full HTTPS URLs are clearer and less error-prone.
Step 5: Use a Content Security Policy Upgrade Header as a Safety Net
Once your content is mostly clean, you can add an HTTP response header that instructs browsers to automatically upgrade any remaining HTTP sub-requests to HTTPS. This does not fix the root cause but acts as a fallback while you track down the last few stragglers.
In Apache's .htaccess or server config, add:
In Nginx:
This header tells the browser: if you see an HTTP URL for a sub-resource, silently request it over HTTPS instead. It works for resources that actually exist on HTTPS. If the resource genuinely does not support HTTPS at all, it will fail to load rather than load insecurely, which is the correct browser behaviour.
Step 6: Fix Mixed Content on Non-WordPress Sites
For static HTML sites, the approach is straightforward: search all HTML, CSS, and JavaScript files recursively and replace HTTP asset URLs with HTTPS:
Be careful with the sed command: use it only on files you have backed up, and limit the search to your own domain to avoid accidentally rewriting legitimate references to other sites.
For Drupal sites, the Drupal core provides a path to run a database search-replace via Drush:
Run this carefully in a staging environment first. Drupal stores content in many tables, so a full database dump and targeted search across all text fields is the safest approach.
How to Verify the Fix
After making changes, clear every cache: your browser cache, your server-side cache (Varnish, Redis, W3 Total Cache, WP Super Cache, LiteSpeed Cache), and your CDN cache (Cloudflare, Fastly, AWS CloudFront). Then:
- Open the page in Chrome in an incognito window to bypass local cache.
- Open DevTools (F12), go to the Console tab, and reload. Zero mixed content warnings means success.
- Check the Network tab and filter by each resource type. Every request should show https:// in the URL column.
- Run the page through Why No Padlock or SSL Shopper again. Both tools should now report a clean padlock.
- Verify the padlock icon in the browser address bar is solid and shows a valid certificate when clicked.
How to Prevent Mixed Content in the Future
Fixing mixed content once is frustrating. Fixing it repeatedly is avoidable with a few guardrails in place:
- Always use HTTPS-first asset URLs when writing new content or adding new embeds. Train your content team to do the same.
- Audit your site quarterly using a crawler. New plugins, new embeds, and new posts can introduce HTTP URLs at any time.
- Keep the upgrade-insecure-requests CSP header in place even after the initial cleanup. It is lightweight and catches edge cases.
- Test SSL configuration on staging before deploying changes to production. A staging environment with the same SSL setup catches problems before your visitors do.
- Use a relative URL base tag or configure your CMS to always generate absolute URLs using the HTTPS site URL setting so that auto-generated links never produce HTTP.
- Check third-party scripts regularly. A widget or ad network that switches to HTTP overnight will break your padlock without you touching a single file.
Summary
Mixed content errors are almost always a migration artifact or a hard-coded URL problem. The fix follows a consistent pattern: find every HTTP resource using DevTools and command-line grep, update the database and files to use HTTPS, enforce HTTPS at the server level with a 301 redirect, and add the upgrade-insecure-requests header as a fallback. After clearing your caches and verifying with DevTools, your padlock should be solid green and your site's security posture measurably improved.