Domain Security Scanner: SSL, DMARC, Subdomains, Tech Stack avatar

Domain Security Scanner: SSL, DMARC, Subdomains, Tech Stack

Pricing

from $80.00 / 1,000 full exposure reports

Go to Apify Store
Domain Security Scanner: SSL, DMARC, Subdomains, Tech Stack

Domain Security Scanner: SSL, DMARC, Subdomains, Tech Stack

Passive security report for a domain: SSL/TLS, headers, SPF/DKIM/DMARC, subdomains, tech stack and known CVEs, scored 0-100 with fixes. Use this when vetting a vendor or your own domain.

Pricing

from $80.00 / 1,000 full exposure reports

Rating

0.0

(0)

Developer

mohamed senator

mohamed senator

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Domain Security & Tech Stack Report (MCP) — SSL, DMARC, Subdomains, KEV

Use this tool when an AI agent (or a person) needs a decision-ready answer about a domain's external security posture from public data: is this vendor/partner/target domain healthy, what should be fixed first, and what changed since last week? One domain in, one compact, scored JSON report out — with a 0–100 score, an A–F grade, a prioritized machine-readable fixes array, and a sources list (URL + fetch time) behind every fact.

Domain Exposure Intel demo

▶ Watch the full video

It is a normal pay-per-event (PPE) Actor — not Standby — so it works from the Apify MCP server (https://mcp.apify.com), the API, schedules and agent-payment flows. Everything is passive: DNS lookups, RDAP, certificate-transparency logs, one HTTPS page fetch and public vulnerability feeds. No port scanning, no brute forcing, no exploit attempts, no logins, no paywalled sources.

Example report: a score with grade B and fixes listed critical first

Modes (one tool per mode)

Set mode in the input. Each mode has its own price (see Pricing).

modeUse it to…Returns
full_reportGet the whole picture in one call (due diligence, vendor risk, triage)score + grade, fixes, DNS, RDAP, email, TLS/headers, tech, CVE/KEV/EPSS, subdomains
tech_stackSee what a site runstechnologies with version, confidence 0–100 and the evidence that matched
subdomainsMap the attack surfaceCT-log subdomains, live/dead, takeover candidates
email_securityJudge spoofing/phishing exposureSPF (lookup count vs 10), DMARC, DKIM, MTA-STS, BIMI — each pass/warn/fail with a fix
tlsCheck transport securitychain validity, issuer, days to expiry, protocol, HSTS/CSP/other headers, security.txt
diffMonitor on a scheduleonly what changed since the last run: subdomains, certificate, tech, new KEV matches, email policy

Vulnerability matching (vulns) is part of full_report and diff; it is never charged separately.

Calling it from an MCP client

{ "tool": "<your-username>/domain-exposure-intel", "arguments": { "mode": "email_security", "domain": "example.com" } }

Bulk: pass domains: ["a.com", "b.com", …] (max 100). You get one dataset item per domain and each item is charged separately — only when it contains data.

The six modes: full_report, tech_stack, subdomains, email_security, tls and diff

Output at a glance

Every dataset item has:

  • outcome — found | no_match | unavailable | error. Only found is ever charged.
  • summary — one agent-readable paragraph.
  • score — { value 0-100, grade A-F, coverage[], breakdown[] } where a score applies. Categories that could not be evaluated are left out of the score, not counted as zero.
  • fixes[] — { id, priority (critical|high|medium|low), area, title, action, evidence, impact }, critical first.
  • sources[] — { url, fetchedAt } for every fact (each section also carries its own sources).
  • billing — { event, priceUsd } (or event: null for free results).

The examples below were produced from the project's offline test fixtures for the fictional domain acme.example. They show the exact shape of real output (long arrays are shortened with "..."), not measurements of a real site.

full_report — $0.08

Input: { "mode": "full_report", "domain": "acme.example" }

{
"domain": "acme.example",
"apex": "acme.example",
"mode": "full_report",
"outcome": "found",
"summary": "acme.example: exposure score 64/100 (grade D). 2 urgent fixes: jQuery 1.12.4 (detected) matches 2 known vulnerabilities, 1 in CISA KEV; Possible subdomain takeover: old-shop.acme.example; TLS cert valid, 54d to expiry, TLSv1.3; SPF pass (1/10 lookups), DMARC pass (p=quarantine); stack: WordPress 6.3.1, PHP 7.4.3, nginx 1.18.0, jQuery 1.12.4, Bootstrap 4.3.1; 8 CVEs match detected versions (1 in CISA KEV); 7 subdomains (6 live of 7 resolved), 2 takeover candidates.",
"checkedAt": "2026-10-06T12:00:00.000Z",
"score": {
"value": 64,
"grade": "D",
"coverage": [
"email_security",
"tls_transport",
"security_headers",
"known_vulnerabilities",
"subdomain_hygiene",
"dns_and_registration"
],
"breakdown": [
{
"category": "email_security",
"points": 20,
"max": 20
},
{
"category": "tls_transport",
"points": 17,
"max": 17
},
{
"category": "security_headers",
"points": 5,
"max": 14
},
"..."
]
},
"fixes": [
{
"id": "vuln-jquery",
"priority": "critical",
"area": "vulns",
"title": "jQuery 1.12.4 (detected) matches 2 known vulnerabilities, 1 in CISA KEV",
"action": "Upgrade jQuery to 3.5.0 or later, or confirm the version and any vendor backports.",
"evidence": "KEV: CVE-2020-11022; max EPSS 23.1%",
"impact": 10.5
},
{
"id": "subdomain-takeover-old-shop.acme.example",
"priority": "high",
"area": "subdomains",
"title": "Possible subdomain takeover: old-shop.acme.example",
"action": "Remove the dangling DNS record for old-shop.acme.example (CNAME oldshop.azurewebsites.net) or re-create the Azure App Service resource under your control.",
"evidence": "CNAME target oldshop.azurewebsites.net does not exist (NXDOMAIN); Azure App Service names can often be re-registered. Verify manually; do not claim.",
"impact": 6
},
{
"id": "headers-csp",
"priority": "medium",
"area": "headers",
"title": "Content-Security-Policy missing or weak",
"action": "Add a Content-Security-Policy (start with default-src 'self' in report-only mode).",
"evidence": "No Content-Security-Policy header.",
"impact": 4
},
{
"...": "10 more fixes"
}
],
"sources": [
{
"url": "dns://acme.example?type=A,AAAA,MX,NS,TXT,CAA",
"fetchedAt": "2026-10-06T12:00:00.000Z"
},
{
"url": "https://rdap.org/domain/acme.example",
"fetchedAt": "2026-10-06T12:00:00.000Z"
},
{
"url": "dns://acme.example?type=MX,TXT",
"fetchedAt": "2026-10-06T12:00:00.000Z"
},
{
"...": "21 more"
}
],
"dns": {
"status": "ok",
"a": [
"93.184.216.34"
],
"mx": [
{
"priority": 10,
"exchange": "mail.acme.example"
}
],
"ns": [
"ns1.acme.example",
"ns2.acme.example"
],
"caaPresent": true,
"...": "txt, caa, sources"
},
"whois": {
"registrar": "Example Registrar, Inc.",
"createdAt": "2016-03-14T10:12:00Z",
"expiresAt": "2027-03-14T10:12:00Z",
"daysToExpiry": 158,
"transferLocked": true
},
"email": {
"handlesMail": true,
"spf": {
"status": "pass",
"detail": "SPF present, 1/10 lookups, ends in -all."
},
"dmarc": {
"status": "pass",
"detail": "DMARC enforced with p=quarantine and reporting enabled."
},
"dkim": "...",
"mtaSts": "...",
"bimi": "..."
},
"tls": {
"certificate": {
"issuer": "C=US, O=Let's Encrypt, CN=R11",
"validTo": "2026-11-30T09:00:00.000Z",
"daysToExpiry": 54,
"chainValid": true,
"status": "pass"
},
"protocol": {
"negotiated": "TLSv1.3",
"cipher": "TLS_AES_256_GCM_SHA384",
"status": "pass",
"detail": "TLS 1.3 negotiated."
},
"headers": {
"hsts": {
"status": "warn",
"detail": "HSTS lacks includeSubDomains."
},
"csp": {
"status": "fail"
},
"...": ""
},
"securityTxt": {
"found": true,
"status": "pass"
}
},
"technologies": [
{
"name": "WordPress",
"version": "6.3.1",
"confidence": 98
},
{
"name": "PHP",
"version": "7.4.3",
"confidence": 93
},
{
"name": "nginx",
"version": "1.18.0",
"confidence": 85
},
{
"name": "Google Analytics",
"version": null,
"confidence": 83
},
"..."
],
"subdomains": {
"totals": {
"discovered": 7,
"resolved": 7,
"live": 6,
"dead": 1,
"wildcardNames": 1
},
"subdomains": [
{
"name": "api.acme.example",
"status": "live",
"ips": [
"93.184.216.40"
]
},
{
"name": "blog.acme.example",
"status": "live",
"ips": [
"178.128.137.63"
],
"cname": "acme.ghost.io"
},
"..."
],
"takeoverCandidates": [
{
"subdomain": "docs.acme.example",
"cname": "acme-docs.github.io",
"service": "GitHub Pages",
"label": "candidate",
"evidence": "http_fingerprint",
"confidence": "medium",
"note": "GitHub Pages page for an unclaimed resource is served at docs.acme.example. Verify manually; do not claim."
},
"..."
]
},
"vulnerabilities": {
"totals": {
"findings": 8,
"kev": 1,
"epssAtLeast10pct": 1,
"critical": 0,
"high": 3
},
"findings": [
{
"id": "CVE-2020-11022",
"technology": "jQuery",
"detectedVersion": "1.12.4",
"versionStatus": "detected",
"kev": true,
"epss": 0.231,
"cvss": null,
"fixedVersion": "3.5.0"
},
{
"id": "CVE-2019-11358",
"technology": "jQuery",
"detectedVersion": "1.12.4",
"versionStatus": "detected",
"kev": false,
"epss": 0.01234,
"cvss": null,
"fixedVersion": "3.4.0"
},
"..."
],
"notes": [
"Versions are inferred from banners and asset URLs: matches are \"detected\", not \"confirmed\". Backported patches can make a detected version safe."
]
}
}

tech_stack — $0.015

Input: { "mode": "tech_stack", "domain": "acme.example" }

{
"domain": "acme.example",
"apex": "acme.example",
"mode": "tech_stack",
"outcome": "found",
"summary": "acme.example: stack: WordPress 6.3.1, PHP 7.4.3, nginx 1.18.0, jQuery 1.12.4, Bootstrap 4.3.1.",
"checkedAt": "2026-10-06T12:00:00.000Z",
"score": null,
"fixes": [],
"sources": [
{
"url": "https://acme.example/",
"fetchedAt": "2026-10-06T12:00:00.000Z"
}
],
"technologies": [
{
"name": "WordPress",
"category": "cms",
"version": "6.3.1",
"confidence": 98,
"evidence": [
{
"type": "meta",
"detail": "meta generator=WordPress 6.3.1"
},
{
"type": "html",
"detail": "html /wp-content/"
}
]
},
{
"name": "PHP",
"category": "language",
"version": "7.4.3",
"confidence": 93,
"evidence": [
{
"type": "header",
"detail": "x-powered-by: PHP/7.4.3"
},
{
"type": "cookie",
"detail": "cookie PHPSESSID"
}
]
},
{
"name": "nginx",
"category": "web-server",
"version": "1.18.0",
"confidence": 85,
"evidence": [
{
"type": "header",
"detail": "server: nginx/1.18.0"
}
]
},
"..."
],
"pageUrl": "https://acme.example/"
}

Versions come from headers, <meta name="generator"> and asset URLs. A technology without a visible version has version: null. The signature set (~210 entries: servers, CMSs, frameworks, CDNs, analytics, JS libraries) is curated and written for this Actor; no third-party fingerprint dataset is bundled, because the licences of the popular ones are either proprietary or copyleft and could not be cleared for commercial redistribution.

subdomains — $0.02

Input: { "mode": "subdomains", "domain": "acme.example", "maxSubdomains": 100 }

{
"domain": "acme.example",
"apex": "acme.example",
"mode": "subdomains",
"outcome": "found",
"summary": "acme.example: exposure score 10/100 (grade F). 7 subdomains (6 live of 7 resolved), 2 takeover candidates.",
"checkedAt": "2026-10-06T12:00:00.000Z",
"score": {
"value": 10,
"grade": "F",
"coverage": [
"subdomain_hygiene"
],
"breakdown": [
{
"category": "subdomain_hygiene",
"points": 1,
"max": 10,
"percent": 10
}
]
},
"fixes": [
{
"id": "subdomain-takeover-old-shop.acme.example",
"priority": "high",
"area": "subdomains",
"title": "Possible subdomain takeover: old-shop.acme.example",
"action": "Remove the dangling DNS record for old-shop.acme.example (CNAME oldshop.azurewebsites.net) or re-create the Azure App Service resource under your control.",
"evidence": "CNAME target oldshop.azurewebsites.net does not exist (NXDOMAIN); Azure App Service names can often be re-registered. Verify manually; do not claim.",
"impact": 6
},
"..."
],
"sources": [
{
"url": "https://crt.sh/?q=%25.acme.example&output=json&exclude=expired",
"fetchedAt": "2026-10-06T12:00:00.000Z"
},
{
"...": "2 more"
}
],
"subdomains": {
"discoverySource": "crt.sh",
"totals": {
"discovered": 7,
"resolved": 7,
"live": 6,
"dead": 1,
"wildcardNames": 1
},
"subdomains": [
{
"name": "api.acme.example",
"status": "live",
"ips": [
"93.184.216.40"
]
},
{
"name": "blog.acme.example",
"status": "live",
"ips": [
"178.128.137.63"
],
"cname": "acme.ghost.io"
},
"..."
],
"takeoverCandidates": [
{
"subdomain": "docs.acme.example",
"cname": "acme-docs.github.io",
"service": "GitHub Pages",
"label": "candidate",
"evidence": "http_fingerprint",
"confidence": "medium",
"note": "GitHub Pages page for an unclaimed resource is served at docs.acme.example. Verify manually; do not claim."
},
{
"subdomain": "old-shop.acme.example",
"cname": "oldshop.azurewebsites.net",
"service": "Azure App Service",
"label": "candidate",
"evidence": "cname_target_nxdomain",
"confidence": "high",
"note": "CNAME target oldshop.azurewebsites.net does not exist (NXDOMAIN); Azure App Service names can often be re-registered. Verify manually; do not claim."
}
]
}
}

Names come from certificate-transparency logs (crt.sh JSON, falling back to Cert Spotter), are de-duplicated and resolved live/dead. A takeover candidate is a CNAME that points at a known third-party service whose target is NXDOMAIN, or whose public page shows that service's "unclaimed" fingerprint. These are labelled candidate and are never verified by claiming anything — verify manually.

email_security — $0.005

Input: { "mode": "email_security", "domain": "acme.example" }

{
"domain": "acme.example",
"apex": "acme.example",
"mode": "email_security",
"outcome": "found",
"summary": "acme.example: exposure score 100/100 (grade A). SPF pass (1/10 lookups), DMARC pass (p=quarantine), DKIM pass, MTA-STS pass, BIMI not published.",
"checkedAt": "2026-10-06T12:00:00.000Z",
"score": {
"value": 100,
"grade": "A"
},
"fixes": [
{
"id": "email-bimi",
"priority": "low",
"area": "email",
"title": "BIMI not published or inactive",
"action": "Optional: publish default._bimi TXT with an SVG logo (needs DMARC p=quarantine/reject at pct=100).",
"evidence": "BIMI not published (optional brand-logo standard).",
"impact": 0
}
],
"sources": [
{
"url": "dns://acme.example?type=MX,TXT",
"fetchedAt": "2026-10-06T12:00:00.000Z"
},
{
"...": "6 more"
}
],
"email": {
"spf": {
"status": "pass",
"lookups": 1,
"qualifier": "-all",
"detail": "SPF present, 1/10 lookups, ends in -all."
},
"dmarc": {
"status": "pass",
"policy": "quarantine",
"detail": "DMARC enforced with p=quarantine and reporting enabled."
},
"dkim": {
"status": "pass",
"detail": "DKIM key(s) published on selector(s): google."
},
"mtaSts": {
"status": "pass",
"mode": "enforce",
"detail": "MTA-STS enforced (max_age 604800s)."
},
"bimi": {
"status": "warn",
"detail": "BIMI not published (optional brand-logo standard).",
"fix": "Optional: publish default._bimi TXT with an SVG logo (needs DMARC p=quarantine/reject at pct=100)."
}
}
}

SPF lookups are counted recursively through include/redirect against the RFC 7208 limit of 10. DKIM is checked on ~26 common selectors (add yours with dkimSelectors); "no key found" is a warn, not a fail, because selectors are not enumerable.

tls — $0.005

Input: { "mode": "tls", "domain": "acme.example" }

{
"domain": "acme.example",
"apex": "acme.example",
"mode": "tls",
"outcome": "found",
"summary": "acme.example: exposure score 71/100 (grade C). TLS cert valid, 54d to expiry, TLSv1.3; 2/6 security headers present; security.txt found.",
"checkedAt": "2026-10-06T12:00:00.000Z",
"score": {
"value": 71,
"grade": "C"
},
"fixes": [
{
"id": "headers-csp",
"priority": "medium",
"area": "headers",
"title": "Content-Security-Policy missing or weak",
"action": "Add a Content-Security-Policy (start with default-src 'self' in report-only mode).",
"evidence": "No Content-Security-Policy header.",
"impact": 4
},
{
"id": "headers-xfo",
"priority": "medium",
"area": "headers",
"title": "Clickjacking protection missing",
"action": "Send X-Frame-Options: DENY (or CSP frame-ancestors 'none').",
"evidence": "No X-Frame-Options or CSP frame-ancestors.",
"impact": 2
},
"..."
],
"sources": [
{
"url": "tls://acme.example:443",
"fetchedAt": "2026-10-06T12:00:00.000Z"
},
{
"url": "https://acme.example/",
"fetchedAt": "2026-10-06T12:00:00.000Z"
},
{
"...": "2 more"
}
],
"tls": {
"certificate": {
"issuer": "C=US, O=Let's Encrypt, CN=R11",
"validTo": "2026-11-30T09:00:00.000Z",
"daysToExpiry": 54,
"chainValid": true,
"status": "pass"
},
"protocol": {
"negotiated": "TLSv1.3",
"status": "pass"
},
"httpToHttps": {
"status": "pass",
"detail": "HTTP 301 redirect to HTTPS.",
"redirectsTo": "https://acme.example/"
},
"headers": {
"hsts": {
"present": true,
"status": "warn"
},
"csp": {
"present": false,
"status": "fail"
},
"xFrameOptions": {
"present": false,
"status": "fail"
},
"xContentTypeOptions": {
"present": true,
"status": "pass"
},
"referrerPolicy": {
"present": false,
"status": "warn"
},
"permissionsPolicy": {
"present": false,
"status": "warn"
}
},
"securityTxt": {
"found": true,
"status": "pass",
"contact": [
"mailto:security@acme.example"
],
"expires": "2027-06-30T00:00:00.000Z"
}
}
}

diff — $0.02 (first baseline free)

Input: { "mode": "diff", "domain": "acme.example" } — run it weekly with an Apify Schedule and keep the same snapshotStoreName.

  • First run: stores a snapshot in a named key-value store and returns outcome: "found" with diff.baseline: true — free.
  • Later runs: return only changes. No changes → outcome: "no_match" — free. Changes → outcome: "found" — charged.
  • If a data source is down during a later run, that section is skipped (listed in diff.skippedSections) and its previous snapshot value is kept, so a flaky network never produces fake "removed" changes.
{
"domain": "acme.example",
"apex": "acme.example",
"mode": "diff",
"checkedAt": "2026-10-06T12:00:00.000Z",
"outcome": "found",
"summary": "acme.example: 4 changes since 2026-10-06 — DMARC changed: p=quarantine -> p=none (weaker).",
"score": {
"value": 55,
"grade": "F"
},
"fixes": [
{
"id": "email-dmarc",
"priority": "medium",
"area": "email",
"title": "DMARC not enforced for acme.example",
"action": "Review aggregate reports, then move to p=quarantine and p=reject.",
"evidence": "DMARC policy is p=none (monitoring only); spoofed mail is not blocked.",
"impact": 4
},
"..."
],
"diff": {
"baseline": false,
"changes": [
{
"type": "email_dmarc_changed",
"severity": "high",
"summary": "DMARC changed: p=quarantine -> p=none (weaker)"
},
{
"type": "subdomain_added",
"severity": "info",
"summary": "New subdomain vpn.acme.example"
},
{
"type": "cert_renewed",
"severity": "info",
"summary": "Certificate renewed (new expiry 2027-01-10)"
},
{
"type": "tech_version_changed",
"severity": "info",
"summary": "nginx version 1.18.0 -> 1.20.2"
}
],
"counts": {
"subdomain_added": 1,
"cert_renewed": 1,
"tech_version_changed": 1,
"email_dmarc_changed": 1
},
"skippedSections": []
}
}

Pricing

Pay-per-event. You pay only when an item has outcome: "found". Unreachable domains, empty results, errors and "no changes" cost $0.

ModeEventPrice per domain
full_reportfull-report$0.08
tech_stacktech-stack$0.015
subdomainssubdomain-scan$0.02
email_securityemail-security$0.005
tlstls-check$0.005
diffdiff-report$0.02

When is an item "found" (charged)?

  • full_report: at least 3 of the 6 base sections (DNS, RDAP, email, TLS, tech, subdomains) returned data.
  • tech_stack: the page was fetched and at least one technology matched.
  • subdomains: at least one subdomain was found in CT logs.
  • email_security: DNS answered for the domain (a missing SPF/DMARC record is a finding, and is charged).
  • tls: a TLS handshake or the HTTPS page fetch succeeded.
  • diff: at least one change since the previous snapshot (baseline and no-change runs are free).

Spending limits. The Actor respects your run's maximum cost. When the limit is reached it stops cleanly: the item that would exceed it is not delivered or charged, remaining domains are returned as outcome: "unavailable" with stoppedReason: "max_total_charge_reached", and the run summary says so.

Input

FieldDefaultMaxNotes
modefull_reportsee above
domainone domain/URL (agent shortcut)
domains100 itemsbulk list
maxDomains25100cap on processed domains
maxSubdomains100500how many CT subdomains to resolve
includeVulnstrueCVE matching in full_report/diff
dkimSelectors20 itemsextra selectors
snapshotStoreNamedomain-exposure-snapshotsdiff mode
updateBaselinetruediff mode
maxConcurrency510
requestTimeoutSecs1030every request has a timeout and is retried with backoff

Empty input runs a fast demo on example.com.

Data sources and etiquette

DNS (system resolver, DNS-over-HTTPS fallback), RDAP via rdap.org, crt.sh with Cert Spotter fallback, one HTTPS fetch of / (plus /.well-known/security.txt, MTA-STS policy and an HTTP→HTTPS redirect check), OSV.dev (JS libraries, Drupal, Laravel), NVD CPE matching (server software, WordPress, PHP…), the CISA KEV feed and FIRST EPSS. Vulnerability lookups are cached in a named key-value store.

  • Sends a descriptive User-Agent (DomainExposureIntelBot/…) and honours robots.txt for page fetches (if a site disallows /, tech/header results are unavailable). /.well-known/ standards files are fetched as machine-readable protocol endpoints.
  • Target hosts are checked so private/reserved addresses are never fetched (SSRF guard, re-checked on every redirect).
  • TLS is a normal handshake on port 443 only; nothing else is probed.

Optional environment variables (set them as secret env vars in Actor settings; none are required): NVD_API_KEY (higher NVD rate limit and more lookups per domain), CERTSPOTTER_API_KEY.

Limitations

  • Versions are "detected", never "confirmed". They come from banners, meta tags and asset URLs; vendors backport patches, and many sites hide versions. CVE matches are leads to verify, not proof of vulnerability.
  • Only versions exposed on the homepage and its headers are seen; no JavaScript is executed and no other pages are crawled, so client-rendered or login-gated stacks are under-reported.
  • Subdomain discovery depends on certificate-transparency logs: hosts that never had a public certificate are invisible. crt.sh is occasionally slow or down (Cert Spotter is the fallback; both unavailable ⇒ unavailable, not charged). Very large domains are truncated to maxSubdomains resolved names.
  • Takeover results are candidates from CNAME/NXDOMAIN and public error-page fingerprints; false positives and negatives are possible.
  • DKIM can only be checked on known selectors. MTA-STS/BIMI checks do not validate the BIMI logo or VMC.
  • TLS reports the protocol negotiated with this client; it does not enumerate every supported protocol or cipher.
  • NVD without an API key is throttled (about 5 requests / 30 s) and capped at 4 product lookups per domain; set NVD_API_KEY to raise it. Large bulk full_report runs are therefore slower.
  • diff compares against the previous run's snapshot in your account; deleting the store resets the baseline (free again).
  • Public data only: domains behind login, or sites that block robots, produce partial or unavailable results.

Feedback

Something not working, or a feature you need? Open an issue in the Issues tab with your input and I'll take a look. If the Actor saves you time, a short review on its Store page helps other people find it.

Local development

npm ci
npm run build && npm run lint && npm test # offline unit tests with fixtures
npm run smoke # live: runs every mode against 3 real domains and prints the outputs
apify run # default input = example.com demo