First CH AppsSmall apps that need a server

日本語

First CH Apps / Mixed Content Checker

Mixed Content Checker

Enter a URL and we pull every http:// reference out of the page's HTML, with its line number, the tag itself and how to fix it. References browsers block outright (scripts, stylesheets, iframes) are separated from the ones they silently upgrade to https (images, audio, video). We never request the resources we find — this is static analysis of the HTML only.

Grading CSP and HSTS belongs to the Security Header Grader; dead links belong to the Link & Alt Checker; the certificate itself belongs to the SSL Certificate Checker. This page answers one question: what http:// references are still sitting inside your https page?

An http:// URL works too — you can find what would become mixed content before you switch the site over.

How to fix it

For resources on the same site, rewrite them as root-relative paths (e.g. /img/logo.png). With no scheme and no host you never have to touch them again when the domain or the protocol changes.

For resources on another site, switch them to https://. If that site has no https support your only options are to host a copy yourself or drop the reference — over http it simply will not load.

A CMS such as WordPress keeps old http:// URLs inside the database (post bodies, custom fields, options). Changing the theme settings is not enough; run a database-wide search and replace (wp search-replace or similar) with a tool that keeps serialized values intact.

If you cannot edit the HTML right now, returning Content-Security-Policy: upgrade-insecure-requests makes browsers rewrite the references to https. Resources without https support still fail, so this is a stopgap rather than a fix.

Protocol-relative references (//example.com/x.js) still work but are discouraged today — write https:// explicitly.

After fixing, confirm in your browser's developer tools (Console and Network) that the Mixed Content warnings are gone. References injected later by JavaScript are invisible to a server-side check like this one.

How it is checked

Only the HTML of the single URL you enter is fetched. We never request the http:// URLs we find, so we do not know whether they exist or whether https would answer.

Blocked (active mixed content): scripts, stylesheets, iframes, object/embed, web app manifests, text tracks, CSS @import and CSS web fonts. The W3C Mixed Content spec classes these as blocking — an https page never loads them.

Upgraded (passive mixed content): images, audio, video and video posters, favicons and CSS background images. The spec calls these optionally-blockable; major browsers rewrite them to https and only block them if that fails.

Because CSS url() targets are never fetched, we treat .woff/.woff2/.ttf/.otf/.eot as web fonts (blocked) and everything else as images (upgraded).

Review: form actions, canonical, alternate and a href are not mixed content and browsers never block them. They are still SSL-migration leftovers, so anchors are counted and the rest are listed.

Relative URLs (/img/a.png, a.png) follow the page's own scheme, so they are never mixed content. Even if you enter an http:// URL we judge the page as it would be after the switch — except when <base href="http://…"> is present, because then relative URLs really do resolve over http.

Only the first 512KB of HTML is scanned (to stay inside the free-tier CPU limit), and at most 100 references are listed; anything beyond that is reported as a count.

References that JavaScript injects at runtime (document.createElement and friends) are invisible server-side. Use this alongside your browser's developer tools.

SERVER PROCESSING — what we send and what we keep

Sent: only the URL you type. Our server (Cloudflare Workers) fetches it once with a public GET. No cookies and no credentials are sent, and we never touch the http:// URLs found inside the page.

Stored: nothing. The check lives entirely inside one request and writes neither the URL nor the result to any database (no KV, no D1). It leaves memory when the request ends.

Returned: the extracted URLs, line numbers, a short excerpt of each tag and our verdicts — nothing else. We never re-serve a fetched page (this app cannot be used to browse other sites through us). Tag excerpts are truncated to 200 characters.

Note: public GET only. URLs pointing at internal networks, localhost or private IPs are rejected.

Use it as an API

POST /mixed-content/api/check with JSON ({"url": "https://example.com/"}) or a form body and you get the same result back as JSON.