Website Security Headers & TLS Audit
Pricing
from $10.00 / 1,000 domain auditeds
Website Security Headers & TLS Audit
Grade any website's security from A+ to F: HTTPS redirect, HSTS, CSP, clickjacking protection, cookie flags, TLS certificate expiry, security.txt and e-mail spoofing protection (SPF, DMARC). Passive and polite.
Pricing
from $10.00 / 1,000 domain auditeds
Rating
0.0
(0)
Developer
Helvetic Labs
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
19 days ago
Last modified
Categories
Features
Share
Grade the security of up to 5,000 websites per run from A+ to F, with a concrete fix for
every finding. One run checks HTTPS and the HTTP to HTTPS redirect, the security headers
(HSTS, CSP, X-Frame-Options and more), cookie flags, the SSL/TLS certificate and its expiry,
security.txt, and the domain's e-mail spoofing protection (SPF and DMARC). For agencies,
security teams, developers and IT administrators who want a quick, passive and repeatable
security check of many domains.
What is Website Security Headers & TLS Audit?
It is a bulk security headers checker, SSL certificate checker and SPF/DMARC checker in one Actor. You enter domains or URLs; for each host it looks at what every browser and every mail server can see anyway, scores the web security from 0 to 100, turns the score into a grade from A+ to F, scores the e-mail protection separately, and lists every check as pass, warn, fail or info, with a short fix for each problem.
The audit is passive. Per domain it requests the home page over HTTPS and over HTTP without
reading the page body, fetches /.well-known/security.txt, makes one TLS handshake and runs a
few DNS lookups. There are no port scans, no probing of paths, no login attempts and no load
on the site. It respects robots.txt and identifies itself with an honest user agent.
What does it check?
Web security (score 0 to 100, graded A+ to F):
- HTTPS: the home page answers over HTTPS with a valid certificate.
- HTTP to HTTPS redirect:
http://ends on an HTTPS URL. - HSTS (
Strict-Transport-Security): present,max-age,includeSubDomainsandpreload. - Content-Security-Policy: present, whether it allows inline scripts (
'unsafe-inline'without nonces, hashes or'strict-dynamic'), whether it allows'unsafe-eval', and whether it hasframe-ancestors. - Clickjacking protection: CSP
frame-ancestorsorX-Frame-Options: DENYorSAMEORIGIN. X-Content-Type-Options: nosniff,Referrer-PolicyandPermissions-Policy.- Cookie flags: how many cookies the home page sets, and how many lack
Secure,HttpOnlyorSameSite. Counts only, never cookie names or values. - Software version disclosure: whether
ServerorX-Powered-Byshows a version number. - TLS and SSL certificate: TLS version, certificate issuer, expiry date and days left.
security.txt(RFC 9116): published at/.well-known/security.txtwith aContactfield, whether it has anExpiresfield, and whether it is expired.
E-mail spoofing protection (scored 0 to 100 separately):
- SPF: present, exactly one record, and how it ends (
-all,~all,?all,+all). - DMARC: present, policy (
none,quarantine,reject),pct, whether aggregate reports are requested (yes or no, never the address), and for subdomains the policy they inherit from a parent domain. - MX: the number of mail servers.
Also reported:
- CAA records: whether the domain restricts which certificate authorities may issue certificates for it, and which ones.
Use cases
- Client audits for agencies: run all client domains at once, sort by grade and send each client the findings with their fixes.
- Security reviews of your own domains: find the forgotten marketing site without HSTS, the subdomain with an expiring certificate or the brand domain without DMARC.
- SSL certificate expiry monitoring: schedule a daily run and alert on
tls.days_leftbelow your threshold, before visitors see a certificate warning. - E-mail spoofing checks: check SPF and DMARC across a portfolio of domains, including
parked domains that should publish
v=spf1 -alland a DMARC reject policy. - Release checks: after a deployment, confirm that the security headers are still set and that the grade did not drop.
- Supplier and partner overviews: get a quick, passive view of the public security posture of the domains you work with, where you are allowed to check them.
- Tracking progress: run the same list every month and compare the scores over time.
How to use Website Security Headers & TLS Audit
- Open the Actor in Apify Console (click Try for free or Start on this page).
- Enter your domains or URLs in Domains or URLs, one per line.
- Keep Check e-mail DNS (SPF, DMARC) on to get the e-mail score, or turn it off to audit only the web side.
- Optionally change the timeout.
- Set a maximum cost per run in the run options if you want a hard spending limit.
- Click Start. When the run is done, open the Output tab, sort by grade or score, and download the results as JSON, CSV, Excel, XML or HTML.
- Create a Schedule to repeat the audit daily, weekly or monthly.
Input
| Field | Type | Default | What it does |
|---|---|---|---|
domains | array of strings | (required) | Domains (example.com) or URLs (https://www.example.com/page). |
checkEmailDns | boolean | true | Also check SPF, DMARC and MX of the domain. |
timeoutSecs | integer, 5 to 60 | 15 | How long to wait for each response, in seconds. |
Tips:
- One host per line. From a URL only the host name is used, and the home page of that host
is audited; the path is ignored.
example.comandwww.example.comare different hosts and are audited (and charged) separately, so enter the one your visitors use, or both if you want to compare. - E-mail checks use the domain without
www.Forwww.example.com, SPF and DMARC are looked up forexample.com. - IP addresses can be audited for HTTPS and headers; the e-mail and CAA checks are then skipped.
- Limits: up to 5,000 entries per run; further entries are ignored. Exact duplicates are audited once.
- API input: besides strings, you can pass objects like
{"url": "https://example.com/"}.
Example input:
{"domains": ["example.com", "https://www.example.org/", "shop.example.net"],"checkEmailDns": true,"timeoutSecs": 15}
Output
One dataset item per domain, in the order of your input. A complete example:
{"input": "example.com","domain": "example.com","checked_at": "2026-10-18T09:00:00Z","https": {"ok": true, "status": 200, "final_url": "https://example.com/", "http_version": "HTTP/1.1", "error": ""},"http_to_https": true,"tls": {"ok": true, "version": "TLSv1.3", "issuer": "Let's Encrypt", "valid_until": "2027-01-05", "days_left": 79, "error": ""},"headers": {"hsts": {"present": true, "max_age": 31536000, "include_subdomains": true, "preload": false},"csp": {"present": false, "frame_ancestors": false, "unsafe_inline_scripts": false, "unsafe_eval": false},"x_frame_options": "sameorigin","x_content_type_options": true,"referrer_policy": "strict-origin-when-cross-origin","permissions_policy": false,"server_version_disclosed": false},"cookies": {"count": 2, "without_secure": 0, "without_httponly": 1, "without_samesite": 1},"security_txt": {"present": true, "has_contact": true, "has_expires": true, "expired": false},"error": "","score": 75,"grade": "B","email": {"domain": "example.com","mx_count": 2,"spf": {"present": true, "records": 1, "all": "-all"},"dmarc": {"present": true, "policy": "quarantine", "pct": 100, "reports": true, "inherited_from": null, "invalid": false}},"email_score": 95,"caa": {"present": true, "issuers": ["letsencrypt.org"]},"findings": [{"check": "http_redirect", "status": "pass", "detail": "HTTP redirects to HTTPS.", "fix": ""},{"check": "hsts", "status": "pass", "detail": "HSTS max-age 31536000 s.", "fix": ""},{"check": "csp", "status": "fail", "detail": "No Content-Security-Policy header.", "fix": "Add a Content-Security-Policy, starting with default-src 'self'."},{"check": "framing", "status": "pass", "detail": "The site cannot be framed by others.", "fix": ""},{"check": "nosniff", "status": "pass", "detail": "X-Content-Type-Options: nosniff is set.", "fix": ""},{"check": "referrer", "status": "pass", "detail": "A privacy-friendly Referrer-Policy is set.", "fix": ""},{"check": "permissions", "status": "warn", "detail": "No Permissions-Policy.", "fix": "Add a Permissions-Policy that turns off unused features (camera, microphone, geolocation)."},{"check": "cookies", "status": "warn", "detail": "Some cookies lack HttpOnly or SameSite.", "fix": "Set HttpOnly and SameSite on every cookie scripts do not need."},{"check": "disclosure", "status": "pass", "detail": "No software versions in the headers.", "fix": ""},{"check": "tls", "status": "pass", "detail": "TLSv1.3, certificate valid until 2027-01-05.", "fix": ""},{"check": "security_txt", "status": "pass", "detail": "security.txt is published.", "fix": ""},{"check": "spf", "status": "pass", "detail": "SPF record ends with -all.", "fix": ""},{"check": "dmarc", "status": "pass", "detail": "DMARC policy quarantine.", "fix": ""}]}
An entry that is not a public domain is listed like this, free of charge:
{"input": "typo-domain.example", "domain": null, "grade": null, "error": "dns_error"}
Output fields
| Field | Type | Meaning |
|---|---|---|
input | string | Your entry as given (trimmed, at most 500 characters). |
domain | string or null | The audited host name; null when the entry could not be audited. |
checked_at | string | When the domain was audited, in UTC. |
https.ok | boolean | The HTTPS home page answered (status below 500) and ended on an HTTPS URL. |
https.status | integer or null | Status code of the HTTPS home page. |
https.final_url | string or null | Where the HTTPS home page ends up after redirects. |
https.http_version | string or null | HTTP version of that answer. |
https.error | string | Why HTTPS did not work, for example tls_error or timeout. |
http_to_https | boolean or null | http:// ends on an HTTPS URL; null when the HTTP request failed (scored as no redirect). |
tls.ok | boolean | The TLS handshake on port 443 worked and the certificate is valid for the host. |
tls.version | string or null | Negotiated TLS version, for example TLSv1.3. |
tls.issuer | string or null | The certificate issuer's organization (or common name). |
tls.valid_until | string or null | Certificate expiry date (YYYY-MM-DD). |
tls.days_left | integer or null | Days until the certificate expires. |
tls.error | string | Why the handshake failed, for example a certificate verification message. |
headers.hsts | object | present, max_age (seconds), include_subdomains, preload. |
headers.csp | object | present, frame_ancestors, unsafe_inline_scripts, unsafe_eval. |
headers.x_frame_options | string or null | The X-Frame-Options value in lower case. |
headers.x_content_type_options | boolean | X-Content-Type-Options is nosniff. |
headers.referrer_policy | string or null | The effective Referrer-Policy value. |
headers.permissions_policy | boolean | A Permissions-Policy header is set. |
headers.server_version_disclosed | boolean | Server or X-Powered-By contains a version number. |
cookies | object | count, without_secure, without_httponly, without_samesite for the cookies set by the final response of the HTTPS home page. |
security_txt | object | present (has a Contact field), has_contact, has_expires, expired (null when there is no readable Expires date). |
error | string | Empty, or why the domain could not be audited (invalid_url, not_public_address, dns_error, blocked_by_robots, robots_unavailable, internal: ...). |
score | integer or null | Web security score 0 to 100; null when robots.txt did not allow reading the headers. |
grade | string or null | A+, A, B, C, D or F; null as for score. |
email.domain | string | The domain used for the e-mail checks (without www.). |
email.mx_count | integer or null | Number of MX records; null when no DNS resolver answered. |
email.spf | object | present, records (number of SPF records), all (how the record ends). |
email.dmarc | object | present, policy, pct, reports, inherited_from (the parent domain whose record applies), invalid (more than one DMARC record). |
email_score | integer or null | E-mail protection score 0 to 100; null when the DNS answers were not available. |
caa | object | present and issuers (up to 10 certificate authorities allowed to issue). |
findings | array | Every check as {check, status, detail, fix}; status is pass, warn, fail or info. |
The email and email_score fields are left out when checkEmailDns is off.
Dataset view
The Overview table shows domain, grade, score, email_score, the certificate expiry
date, the findings and error, so you can sort a whole portfolio by grade.
How the score works
| Check | Points | Partial points |
|---|---|---|
| HTTP redirects to HTTPS | 10 | |
HSTS with max-age of at least 180 days (15,552,000 s) | 15 | 8 for a shorter max-age |
| Content-Security-Policy without inline scripts | 15 | 8 when it allows inline scripts |
Clickjacking protection (frame-ancestors or X-Frame-Options) | 10 | |
X-Content-Type-Options: nosniff | 10 | |
Strict Referrer-Policy | 5 | |
Permissions-Policy | 5 | |
All cookies with Secure, HttpOnly and SameSite (or no cookies) | 10 | 5 when all have Secure but some lack the others |
No software versions in Server or X-Powered-By | 5 | |
| TLS 1.2 or 1.3 and at least 14 days left on the certificate | 10 | 5 when TLS works but the version is older or the certificate expires within 14 days |
security.txt with Contact, not expired | 5 |
A strict Referrer-Policy is one of no-referrer, same-origin, strict-origin,
strict-origin-when-cross-origin, origin or origin-when-cross-origin. If HTTPS does not
work at all, the score is 0.
| Score | Grade |
|---|---|
95 to 100, with HSTS includeSubDomains | A+ |
85 to 94 (or 95 and more without includeSubDomains) | A |
| 70 to 84 | B |
| 55 to 69 | C |
| 40 to 54 | D |
| below 40, or no working HTTPS | F |
E-mail score: one SPF record gives 30 points, plus 20 when it ends with -all or 10 with
~all. A DMARC record gives 30 points, plus 20 for p=reject or 15 for p=quarantine. More
than one SPF record counts as none, because receivers ignore them; more than one DMARC record
is reported as invalid and scores like no DMARC record.
How much does it cost?
This Actor uses pay-per-event pricing: you pay USD 0.01 per domain audited (USD 10 per 1,000 domains), plus Apify's standard actor start event of USD 0.00005 per run. With pay-per-event pricing the platform usage of the run is included in these prices.
| Domains audited | Domain events | Actor start | Total |
|---|---|---|---|
| 10 | USD 0.10 | USD 0.00005 | USD 0.10005 |
| 100 | USD 1.00 | USD 0.00005 | USD 1.00005 |
| 1,000 | USD 10.00 | USD 0.00005 | USD 10.00005 |
| 5,000 (the maximum per run) | USD 50.00 | USD 0.00005 | USD 50.00005 |
What is charged and what is free:
- Charged: every domain the audit contacted, whatever the result, including a domain
whose
robots.txtdid not allow reading the headers (the e-mail checks still run). - Free: entries that are not valid domains or URLs, hosts that do not resolve, hosts on non-public addresses, and entries that failed with an internal error. They are listed with their error code but not charged.
Set a maximum cost per run and the audit respects it: if your limit covers fewer domains than your list has, only the first ones are audited. Apify's free plan includes monthly platform credit, which you can use to try the Actor.
Tips and best practices
- Start with the fails. Each finding has a
fix. Fixing thefailitems first gives the biggest score gains: CSP and HSTS are worth 15 points each. - Aim for A+ deliberately. A+ needs at least 95 points and HSTS with
includeSubDomains. AddincludeSubDomainsonly when every subdomain serves HTTPS. - Monitor certificates. Schedule a daily run and alert when
tls.days_leftis low; the TLS check already turns towarnbelow 14 days. - Check parked domains too. Domains that never send mail should publish
v=spf1 -alland a DMARC record withp=reject; the e-mail score shows which ones do not. - Compare apex and www. Headers often differ between
example.comandwww.example.com; audit both when in doubt. - Allow the audit on your own site. It obeys
robots.txtrules for the product tokenHelveticLabs-WebCheck. If your site blocks bots, allow that token to get a grade.
Limitations
- It is not a penetration test. It shows common best practices that are visible from outside, not vulnerabilities in the application.
- Home page only. Headers and cookies are read from the home page of each host; other pages may send different headers.
- robots.txt is respected. When
robots.txtdisallows the home page, or answers with a server error, the headers are not read:scoreandgradearenull, and the e-mail checks still run. security.txtis read only from/.well-known/security.txt, must be served astext/plainand is read up to 64 KB.- TLS is checked with one handshake on port 443 with a timeout of 10 seconds; it does not list every cipher or protocol version the server supports.
- SPF is checked for presence, count and its
allending;include:chains and the DNS lookup limit are not evaluated, and a record that ends withredirect=is shown as having noall. - DMARC for subdomains walks up to four parent names, never to the top-level domain.
- Only public addresses are contacted; up to 5,000 entries per run.
FAQ
Is it legal to use? The audit only reads what every browser and mail server sees: public headers, the certificate and public DNS records. It sends no attacks and probes no paths. Audit only domains you own or may check, and see the fair use rules at the end of this page.
Does it respect robots.txt? Yes. If robots.txt disallows the home page, the headers are
not read and the result says so.
Does it store personal data? No. It returns flags, dates and counts. It never returns
cookie names or values, the e-mail addresses from DMARC records (it only says whether reports
are requested), security.txt contacts or the CAA iodef contact.
How fast is it? Domains are audited in groups of 20 at a time, with at most 10 web requests in flight and a polite pause between requests to the same host. The duration depends on how fast the servers answer.
Can I schedule it? Yes, with a schedule in Apify Console, for example daily for certificate monitoring or monthly for a portfolio review.
Can I use it from Python, JavaScript or the API? Yes, see Integrations below.
Can AI agents use it? Yes, through Apify's MCP server, for example to answer "what is the security grade of these domains and what should we fix first?".
Why was a domain not charged? Entries that are not valid, do not resolve or point to a non-public address are free, as are entries that failed with an internal error.
Why is the grade empty? The site's robots.txt does not allow automated clients on the
home page, or answered with a server error. The e-mail checks are still in the result.
How is it different from a one-domain-at-a-time online header checker? It audits
thousands of domains in one run, covers headers, TLS, security.txt and e-mail DNS together,
gives one consistent grade and returns structured data for spreadsheets, dashboards and
automations.
What happens on errors and timeouts? A failed request becomes a finding (for example "HTTPS does not work (timeout)") and the run goes on with the next domain. Results written before a run timeout stay in the dataset.
Integrations
The actor ID is HelveticLabs/security-audit.
Python (pip install apify-client):
from decimal import Decimalfrom apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("HelveticLabs/security-audit").call(run_input={"domains": ["example.com", "example.org"], "checkEmailDns": True},max_total_charge_usd=Decimal("1"), # optional spending limit for this run)# apify-client 3.x; with older versions use run["defaultDatasetId"]for item in client.dataset(run.default_dataset_id).iterate_items():print(item["domain"], item.get("grade"), item.get("email_score"))
JavaScript (npm install apify-client):
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('HelveticLabs/security-audit').call({ domains: ['example.com', 'example.org'], checkEmailDns: true },{ maxTotalChargeUsd: 1 },);const { items } = await client.dataset(run.defaultDatasetId).listItems();for (const item of items) console.log(item.domain, item.grade, item.tls?.days_left);
HTTP API: POST https://api.apify.com/v2/acts/HelveticLabs~security-audit/runs with the
input as the JSON body; add maxTotalChargeUsd as a query parameter to cap the cost.
No-code and automation: connect the Actor to Make, Zapier or n8n, or add a webhook that fires when a run finishes, for example to open a ticket when a grade drops or a certificate has fewer than 30 days left.
AI agents (MCP): Apify's MCP server lets AI agents and MCP clients run this Actor as a tool;
pass maxTotalChargeUsd in the call options to cap the spend.
Related HelveticLabs actors
| Actor | What it does |
|---|---|
| URL Status & Redirect Checker | Status code, redirect chain, final URL and response time for up to 100,000 URLs. |
| Website Health Audit: Broken Links & SEO Checker | Crawls a site for broken links, redirects and on-page SEO issues. |
| Sitemap URL Extractor & Validator | Every URL from a site's sitemaps, with lastmod dates. |
| AI Crawler Access Checker | Which AI bots a site's robots.txt allows, plus llms.txt. |
Support and feedback
Questions, wrong results or ideas for further checks? Open an issue in the Issues tab on this Actor's page, or write to contact@helveticlabs.org. Include the run ID if a run is involved.
Provider, privacy and fair use
Provider: HelveticLabs, sole proprietorship of Marvin Krieg, c/o SwissMailBox 170, 12 Rue Le Corbusier, 1208 Genève, Switzerland. E-mail: contact@helveticlabs.org. Imprint: https://www.helveticlabs.org/imprint
Privacy: This Actor runs on the Apify platform, in your Apify account. It processes only the URLs or domains you enter and the public technical data the checked servers return (status codes, headers, certificates, DNS records, sitemap URLs, links). It does not collect personal data: it never stores or returns page text (where a page's HTML is read, it is read in memory only, to find links and measure tags), and it leaves out e-mail addresses, cookie names and values and similar values. Your input and results stay in your Apify account and are stored by Apify under its own terms (https://apify.com/privacy-policy). The provider sees only the usage statistics Apify shows to Actor authors (such as the number of users and runs), not your input or results, unless you share a run for support. Questions about privacy: contact@helveticlabs.org.
Fair use: Check only sites you own or may check. Do not use the results to attack systems or people. The Actor respects robots.txt, identifies itself, and keeps a polite pace per site.
No warranty: The results are automated checks and can be incomplete. They are not a penetration test, legal advice or a compliance certificate.