How to Bulk Check SSL/TLS & HTTPS Health at Scale 2026
Probe SSL/TLS and HTTPS reachability across thousands of domains at once: TLS handshake status, HTTP code, latency, redirects and classified errors. No API key.
Checking one domain’s TLS is trivial — openssl s_client and you’re done. Checking a thousand is a different problem. You need parallelism without hammering small servers, error classification that separates a dead certificate from a DNS failure, and a machine that never crashes on a bad host mid-run. Third-party SSL SaaS tools solve the parallelism but throttle you hard — SSL Labs’ public API is famously rate-limited — and they charge per lookup. This guide covers how to run bulk TLS and HTTPS reachability probing yourself, what a client-side TLS handshake actually tells you, and how to get one clean row per domain across a large list.
What this actually checks
Be precise about what “SSL check” means here, because it drives everything downstream. This tool performs client-side TLS handshakes and HTTPS reachability probing — it connects to each host on port 443, completes (or fails) the TLS handshake, follows redirects, and reports the outcome. It is a reachability-and-TLS-health checker, not a certificate-field parser. Here’s exactly what each row contains:
domain— the queried host, normalized (scheme, path, port and trailing dot stripped, lowercased).hasTls—"true"if the host completed a TLS handshake and served content over HTTPS, or failed specifically with a TLS/certificate error;"false"for DNS failures, refused connections and timeouts. This is the headline reachability signal.statusCode— the HTTP status returned over HTTPS ("200","301","403");nullif the request failed before a response.latencyMs— round-trip time in milliseconds from connection start to response or failure.finalUrl— the URL the host resolves to after following up to 3 redirects;nullon failure.error— the raw error message when the handshake or connection failed;nullon success.errorType— a classified failure bucket, present only on failed rows:tls_error,timeout,connection_errororunknown.checkedAt— ISO 8601 timestamp of the scan.
The value is in the classification. A row with errorType: "tls_error" and error: "certificate has expired" is a certificate problem you need to fix. A row with errorType: "connection_error" is a DNS or firewall issue — a different team, a different ticket. The tool never conflates the two.
How the probing works
There’s no external API in the loop. The actor opens a direct HTTPS connection to each host from the Apify runtime — the same thing a browser does when it loads a site — and inspects the result. No SSL Labs, no third-party SaaS, no per-lookup quota.
Input is just a domain list; everything else is optional:
{
"domains": ["google.com", "github.com", "stackoverflow.com", "wikipedia.org"],
"maxConcurrency": 10,
"proxyConfiguration": { "useApifyProxy": true }
}
Input parsing is deliberately forgiving. You can paste bare domains (example.com), subdomains (api.example.com), or full URLs with schemes and paths (https://example.com/some/path) — the actor strips the scheme, path, port and any trailing dot, lowercases the host, and removes duplicates. Bare domains give the cleanest output, but you can dump a messy list and let it normalize.
maxConcurrency controls parallel connections: default 10, up to 100. Higher is faster on large lists but can overwhelm small origin servers or trip their rate limiting — a real consideration if you’re scanning your own infrastructure. Every domain always produces exactly one row, success or failure, so the run never dies partway through a list because one host is broken.
In practice, the concurrency you pick tracks the job. A modest portfolio audit of a few dozen company domains runs comfortably at the default 10. Deliberately probing a set of known-broken hosts — expired, self-signed, hostname-mismatch — to validate your alerting works fine at 20. A large reachability sweep across hundreds of subdomains benefits from 50, provided the targets can absorb it. The knob is yours to match to both list size and target resilience.
▶ Run the Bulk SSL/TLS Checker on Apify — paste thousands of domains, get one row each with TLS status, HTTP code, latency and a classified error type. No API key, no SSL Labs rate limits. Export to CSV or JSON.
The access reality
This is one of the rare scraping-adjacent tasks with almost no adversary. You’re making standard HTTPS connections to publicly reachable hosts — there’s no bot wall to defeat. The friction is operational rather than defensive:
- You’re rate-limited by the targets, not by an API. There’s no SSL Labs quota to respect, but if you point
maxConcurrency: 100at a cluster of small servers you control, you can generate real load. Tune concurrency to the size and resilience of what you’re scanning. - IP-based rate limiting from targets is real. Some hosts throttle by source IP. Routing outbound connections through Apify Proxy (recommended, on by default) spreads the load and avoids a single IP getting flagged.
- HTTP-only hosts fail by design. A domain with no HTTPS listener produces
hasTls: "false"with the reason inerror/errorType. That’s a correct result, not a bug — it tells you the host isn’t serving TLS at all. hasTls: "true"doesn’t mean healthy. A host that fails with an expired or self-signed certificate is still markedhasTls: "true"— TLS is present but broken. Always readerrorTypealongsidehasTls; the combination is what distinguishes a working host from a broken-cert host from an unreachable one.
Example output
A healthy host and a broken-certificate host, side by side:
{
"domain": "github.com",
"hasTls": "true",
"statusCode": "200",
"latencyMs": "312",
"finalUrl": "https://github.com/",
"error": null,
"checkedAt": "2026-07-06T12:00:00.000Z"
}
{
"domain": "expired.badssl.com",
"hasTls": "true",
"statusCode": null,
"latencyMs": "1084",
"finalUrl": null,
"error": "certificate has expired",
"errorType": "tls_error",
"checkedAt": "2026-07-06T12:00:00.000Z"
}
The second row is the pattern you filter for in a monitoring pipeline: errorType equals tls_error surfaces expired, self-signed and hostname-mismatch certificates across your whole estate in one pass.
Who uses this
- DevOps and SRE teams monitoring HTTPS uptime across a domain portfolio — flag any host where
hasTlsflips to"false"before customers hit it. - Security engineers running TLS posture audits — filter
errorType: "tls_error"to inventory every broken certificate at once. - IT admins managing large domain estates who need a single reachability sweep instead of checking hosts one by one.
- Penetration testers and bug-bounty hunters triaging a target’s hosts — which serve valid HTTPS, which are misconfigured, how fast they respond.
- Compliance analysts collecting HTTPS-health evidence for audits and remediation tickets.
- Agencies auditing client infrastructure at scale and diffing results over time.
Cost and effort: build vs. managed
Rolling your own bulk TLS checker is deceptively involved. The naive openssl loop is single-threaded and slow. A real one needs a proper async connection pool, per-connection timeouts, redirect following with a hop cap, error classification that distinguishes TLS from DNS from timeout, input normalization, and the discipline to never crash the whole run on one bad host. That’s a few days to build and harden — and then you’re maintaining a scanning fleet and paying for the IPs it runs from.
The managed actor is pay-per-result: you pay per domain checked, no separate platform fees to reason about. Thousands of domains per run land in single-digit dollars, proxy included. Against a commercial SSL-monitoring SaaS that charges per monitored endpoint per month, an on-demand bulk sweep is dramatically cheaper for one-off audits and portfolio inventories.
Common pitfalls
Things that trip people up with TLS reachability scanning specifically:
- Don’t read
hasTlsalone."true"covers both healthy hosts and broken-certificate hosts. The signal you usually want — “TLS present and working” — ishasTls: "true"and noerrorType. statusCodeis null on TLS failures. If the handshake fails, there’s no HTTP response, sostatusCodeandfinalUrlcome back null. Don’t treat a null status as a 5xx.- Concurrency is a load knob, not just a speed knob. Cranking
maxConcurrencyagainst small servers you own can cause the very outage you’re trying to detect. Match it to target resilience. - Normalize expectations, not just input. The actor lowercases and strips domains, so
HTTPS://Example.com/andexample.comcollapse to one row. If you’re joining results back to a source list, join on the normalizeddomain. - This is reachability, not a certificate dossier. If you need the certificate’s exact expiry date, issuer or SAN list as structured fields, that’s a different job — this tool reports whether TLS works and classifies why it doesn’t, which is what monitoring and audit workflows actually act on.
- Redirects cap at 3 hops.
finalUrlreflects up to three redirects. A host behind a longer redirect chain will report the URL at hop three, not the ultimate destination.
Wrapping up
Bulk TLS and HTTPS reachability checking is a solved problem you shouldn’t re-solve every time. The engineering — async connections, timeouts, redirect handling, error classification, crash-proof per-host rows — is done once and reused. If you need to sweep a domain portfolio for broken certificates and dead HTTPS, or triage a target’s hosts, paste the list and read the classified results.
▶ Open the Bulk SSL/TLS Checker on Apify — one run probes thousands of domains and returns TLS status, HTTP code, latency, final URL and a classified error type per host, exportable to CSV, Excel or JSON. No API key, no SSL Labs limits. Start on Apify’s free monthly credit.
Related guides
How to Build a Deep-Research Retrieval Layer for AI Agents
Give an agent a topic and get ranked web sources, full-page Markdown, and recent news with citations — keyless multi-source retrieval for RAG and grounding.
How to Extract Structured Data from Any URL in 2026
Turn any web page into clean JSON without an LLM: parse schema.org JSON-LD, OpenGraph, tables, prices and contacts deterministically — no API key, no browser.
How to Add Live Web Search to AI Agents (No API Key)
Give your LLM fresh, citable search results without a Tavily or SerpAPI key. How live SERP extraction works: ranked results plus Markdown page content for RAG.