Mozilla HTTP Observatory

App · Compliance & Security · 12 actions

Scan any website's HTTP security with Mozilla's HTTP Observatory, the scanner behind MDN's security report. Get a grade from A+ to F and a score out of 145, then the test-by-test detail behind it: Content Security Policy, HSTS, cookies, CORS, clickjacking protection, referrer policy, subresource integrity and the cross-origin isolation headers, each with what the scanner found and what to change. Read the response headers a site sends and the security ones it is missing, follow a site's grade over time to catch a regression, rank several sites against each other, and fail a release when a site drops below the grade you require. No account or API key required.

Actions

ActionWhat it does
Check a website meets a gradeTest a website against a minimum grade, a minimum score, or both, and get a plain pass or fail to branch on, for a release check or a scheduled audit that should raise an alert when a site slips.
Compare websitesScan several websites and rank them best-graded first, your own properties side by side, or your site against a competitor's. Each host is a full scan, so keep the list to 20 or fewer.
Get one security testCheck one security control on a website: is HSTS still set, did the Content Security Policy survive the release, and get a plain pass or fail to branch on, with what the scanner found and what to change.
Get response headersGet the HTTP response headers a website sent the scanner, either all of them or just the security headers you pick, and, importantly, which of those it is not sending at all.
Get scan historyGet a website's past Observatory scans, newest first, and whether its grade has improved or slipped over that period.
Get scan resultsGet a website's full HTTP Observatory report: the grade and score, every security test with what was found and what to change, the response headers the scanner saw, and the site's past scans.
Get the grade distributionGet how every website the Observatory has ever scanned graded, with each grade's share of the web and the share that did at least as well.
Get the scanner versionGet the version of the HTTP Observatory scanner that is answering.
Get the scoring referenceGet the Observatory's scoring rules: every test it runs, every outcome each one can reach, what that outcome is worth in points, and MDN's advice for it.
List security testsList a website's security tests, filtered to just the ones that failed, just the ones that passed, or all of them, ordered with the most punishing failure first.
Rescan a websiteScan a website again right now and get the full report, rather than the stored result.
Scan a websiteScan a website's HTTP security and get its grade and score: A+ down to F, out of 145, plus how many of the tests it passed.

Check a website meets a grade

Test a website against a minimum grade, a minimum score, or both, and get a plain pass or fail to branch on, for a release check or a scheduled audit that should raise an alert when a site slips. Comes back with the failing tests and what to change, so the alert can say why. No API key required.

Inputs

WebsitehosttextRequired
The site to scan, as a hostname such as example.com. A full URL works too, only its hostname is used. IP addresses cannot be scanned: the scanner needs a name to check a certificate and an HSTS policy against.
Minimum grademinimum_gradetext
The lowest grade that still passes. Set this, Minimum score, or both: at least one is needed.One of: A+, A, A-, B+, B, B-, C+, C, C-, D+, and 3 more.
Minimum scoreminimum_scorenumber
Optional. The lowest score that still passes. A site starts at 100, loses points per failed test, and can reach 145 with bonuses. Finer than a grade: two sites can share a grade and be nine points apart.From 0 to 145.
Scan again firstrescantrue/false
Optional. Scan the site now instead of using the stored result. Turn this on when checking a site straight after a deploy. Off by default.Default: false.

Outputs

details_urltext
The full report on MDN, for a person to open. Put it in the alert.
failed_test_countnumber
How many tests failed.
failed_testslist
Only the tests that failed, most punishing first. Empty when the site passed everything.
gradetext
The letter grade, A+ down to F. Null only when the scan could not grade the site.
grade_mettrue/false
Whether the grade threshold was met. Null when no grade was required.
hosttext
The hostname that was scanned, e.g. example.com. A pasted URL is reduced to its hostname before scanning.
minimum_gradetext
The grade required, or null when none was set.
minimum_scorenumber
The score required, or null when none was set.
passedtrue/false
True when the site met every threshold set. This is the field to branch on.
reasontext
Why it failed, in a sentence ready to put in the alert. Empty when it passed.
recommendationslist
What to change, one line per failing test, most punishing first.
scanned_attext
When this scan ran, as an ISO 8601 UTC instant. May be older than this step: a stored scan is served while it is under 24 hours old.
scorenumber
The score behind the grade. Starts at 100, loses points for each failed test, and earns up to 145 with the bonuses that apply once a site is already at 90.
score_mettrue/false
Whether the score threshold was met. Null when no score was required.
was_rescannedtrue/false
True when this check scanned the site rather than reading the stored result.
Example output
{
  "details_url": "https://developer.mozilla.org/en-US/observatory/analyze?host=example.com",
  "failed_test_count": 1,
  "failed_tests": [
    {
      "description": "Content Security Policy (CSP) header not implemented.",
      "details": {
        "data": null
      },
      "documentation_url": "https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/CSP",
      "expectation": "csp-implemented-with-no-unsafe-default-src-none",
      "name": "content-security-policy",
      "outcome": "failed",
      "passed": false,
      "recommendation": "Implement a Content Security Policy that restricts where content can be loaded from.",
      "result": "csp-not-implemented",
      "score_modifier": -25,
      "title": "Content Security Policy (CSP)"
    }
  ],
  "grade": "B+",
  "grade_met": false,
  "host": "example.com",
  "minimum_grade": "A",
  "minimum_score": null,
  "passed": false,
  "reason": "graded B+, below the required A",
  "recommendations": [
    "Implement a Content Security Policy that restricts where content can be loaded from."
  ],
  "scanned_at": "2026-08-23T18:48:32.850Z",
  "score": 80,
  "score_met": null,
  "was_rescanned": false
}

Compare websites

Scan several websites and rank them best-graded first, your own properties side by side, or your site against a competitor's. Each host is a full scan, so keep the list to 20 or fewer. A host that cannot be scanned is reported without losing the others. No API key required.

Inputs

WebsiteshoststextRequired
The hostnames to compare, separated by commas. Full URLs work too: only the hostname is used. At most 20.

Outputs

average_scorenumber
The mean score across the ranked sites.
bestobject
One site's scan, with its place in the ranking.
countnumber
How many sites were ranked.
failure_countnumber
How many hosts could not be scanned.
failureslist
The hosts that could not be scanned, each with the reason. Empty when every host scanned.
siteslist
The sites that were scanned, best grade first.
worstobject
One site's scan, with its place in the ranking.
Example output
{
  "average_score": 92.5,
  "best": {
    "algorithm_version": 5,
    "details_url": "https://developer.mozilla.org/en-US/observatory/analyze?host=example.com",
    "error": null,
    "grade": "A+",
    "host": "example.com",
    "rank": 1,
    "scan_id": 116498575,
    "scanned_at": "2026-08-23T18:48:32.850Z",
    "score": 105,
    "status_code": 200,
    "tests_failed": 1,
    "tests_passed": 9,
    "tests_quantity": 10
  },
  "count": 2,
  "failure_count": 0,
  "failures": [],
  "sites": [
    {
      "algorithm_version": 5,
      "details_url": "https://developer.mozilla.org/en-US/observatory/analyze?host=example.com",
      "error": null,
      "grade": "A+",
      "host": "example.com",
      "rank": 1,
      "scan_id": 116498575,
      "scanned_at": "2026-08-23T18:48:32.850Z",
      "score": 105,
      "status_code": 200,
      "tests_failed": 1,
      "tests_passed": 9,
      "tests_quantity": 10
    },
    {
      "algorithm_version": 5,
      "details_url": "https://developer.mozilla.org/en-US/observatory/analyze?host=example.com",
      "error": null,
      "grade": "B+",
      "host": "shop.example.com",
      "rank": 2,
      "scan_id": 116498575,
      "scanned_at": "2026-08-23T18:48:32.850Z",
      "score": 80,
      "status_code": 200,
      "tests_failed": 1,
      "tests_passed": 9,
      "tests_quantity": 10
    }
  ],
  "worst": {
    "algorithm_version": 5,
    "details_url": "https://developer.mozilla.org/en-US/observatory/analyze?host=example.com",
    "error": null,
    "grade": "B+",
    "host": "shop.example.com",
    "rank": 2,
    "scan_id": 116498575,
    "scanned_at": "2026-08-23T18:48:32.850Z",
    "score": 80,
    "status_code": 200,
    "tests_failed": 1,
    "tests_passed": 9,
    "tests_quantity": 10
  }
}

Get one security test

Check one security control on a website: is HSTS still set, did the Content Security Policy survive the release, and get a plain pass or fail to branch on, with what the scanner found and what to change. No API key required.

Inputs

WebsitehosttextRequired
The site to scan, as a hostname such as example.com. A full URL works too, only its hostname is used. IP addresses cannot be scanned: the scanner needs a name to check a certificate and an HSTS policy against.
Security testtesttextRequired
Which of the Observatory's tests to report on.One of: content-security-policy (Content Security Policy (CSP)), cookies, cross-origin-resource-sharing (Cross Origin Resource Sharing (CORS)), cross-origin-resource-policy (Cross Origin Resource Policy), redirection, referrer-policy (Referrer Policy), strict-transport-security (Strict Transport Security (HSTS)), subresource-integrity (Subresource Integrity), x-content-type-options, x-frame-options.

Outputs

details_urltext
The full report on MDN, for a person to open. Put it in the alert.
gradetext
The letter grade, A+ down to F. Null only when the scan could not grade the site.
hosttext
The hostname that was scanned, e.g. example.com. A pasted URL is reduced to its hostname before scanning.
outcometext
passed, failed, or not_applicable, lifted out of the test so a condition can read it directly.
passedtrue/false
True when it passed, false when it failed, null when the test did not apply.
scanned_attext
When this scan ran, as an ISO 8601 UTC instant. May be older than this step: a stored scan is served while it is under 24 hours old.
scorenumber
The score behind the grade. Starts at 100, loses points for each failed test, and earns up to 145 with the bonuses that apply once a site is already at 90.
testobject
One security test and how the site did on it.
Example output
{
  "details_url": "https://developer.mozilla.org/en-US/observatory/analyze?host=example.com",
  "grade": "B+",
  "host": "example.com",
  "outcome": "passed",
  "passed": true,
  "scanned_at": "2026-08-23T18:48:32.850Z",
  "score": 80,
  "test": {
    "description": "Preloaded via the HTTP Strict Transport Security (HSTS) preloading process.",
    "details": {
      "data": "max-age=63072000",
      "include_sub_domains": true,
      "max_age": 63072000,
      "preload": false,
      "preloaded": true
    },
    "documentation_url": "https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/TLS#http_strict_transport_security_implementation",
    "expectation": "hsts-implemented-max-age-at-least-six-months",
    "name": "strict-transport-security",
    "outcome": "passed",
    "passed": true,
    "recommendation": null,
    "result": "hsts-preloaded",
    "score_modifier": 5,
    "title": "Strict Transport Security (HSTS)"
  }
}

Get response headers

Get the HTTP response headers a website sent the scanner, either all of them or just the security headers you pick, and, importantly, which of those it is not sending at all. Read off the stored scan, so the site is not fetched again. No API key required.

Inputs

WebsitehosttextRequired
The site to scan, as a hostname such as example.com. A full URL works too, only its hostname is used. IP addresses cannot be scanned: the scanner needs a name to check a certificate and an HSTS policy against.
Security headersheaderslist
Optional. Return only the headers chosen, and report any of them the site does not send. Leave empty for every header the response carried.One or more of: content-security-policy, content-security-policy-report-only, strict-transport-security, x-content-type-options, x-frame-options, referrer-policy, cross-origin-opener-policy, cross-origin-embedder-policy, cross-origin-resource-policy, access-control-allow-origin, and 5 more.
Other headersother_headerstext
Optional. Any further header names to include, separated by commas, for a header not in the list above, such as one of your own.

Outputs

all_header_nameslist
Every header name in the response, sorted, whether or not it was asked for.
details_urltext
The full report on MDN, for a person to open. Put it in the alert.
gradetext
The letter grade, A+ down to F. Null only when the scan could not grade the site.
header_countnumber
How many headers were returned.
headersobject
The response headers the scanner received, keyed by lower-case header name.
hosttext
The hostname that was scanned, e.g. example.com. A pasted URL is reduced to its hostname before scanning.
missing_headerslist
The headers asked for that the site does not send. This is the finding: an absent key would look the same as one never asked for.
scanned_attext
When this scan ran, as an ISO 8601 UTC instant. May be older than this step: a stored scan is served while it is under 24 hours old.
Example output
{
  "all_header_names": [
    "content-type",
    "referrer-policy",
    "strict-transport-security",
    "x-content-type-options",
    "x-frame-options"
  ],
  "details_url": "https://developer.mozilla.org/en-US/observatory/analyze?host=example.com",
  "grade": "B+",
  "header_count": 2,
  "headers": {
    "strict-transport-security": "max-age=63072000",
    "x-frame-options": "DENY"
  },
  "host": "example.com",
  "missing_headers": [
    "content-security-policy"
  ],
  "scanned_at": "2026-08-23T18:48:32.850Z"
}

Get scan history

Get a website's past Observatory scans, newest first, and whether its grade has improved or slipped over that period. The Observatory keeps every scan of every host it has been asked about, so this is where a regression shows up. No API key required.

Inputs

WebsitehosttextRequired
The site to scan, as a hostname such as example.com. A full URL works too, only its hostname is used. IP addresses cannot be scanned: the scanner needs a name to check a certificate and an HSTS policy against.
Scanned on or afterscanned_fromdate
Optional. Only scans from this date onwards. Leave blank to start at the earliest scan on record.
Scanned on or beforescanned_todate
Optional. Only scans up to this date. Leave blank to run up to the most recent one.
Number of scanslimitnumber
Optional. How many scans to return. Between 1 and 200; 25 by default.From 1 to 200. Default: 25.
Oldest firstoldest_firsttrue/false
Optional. Return the oldest scans first instead of the newest. Off by default.Default: false.

Outputs

countnumber
How many scans are in this page.
current_gradetext
The grade the site holds now.
current_scorenumber
The score the site holds now.
details_urltext
The full report on MDN, for a person to open. Put it in the alert.
earliest_gradetext
The grade at the start of the window, whichever order the page is in.
grade_changetext
improved, worsened, unchanged, or unknown. Branch on this to alert only on a slip.
has_moretrue/false
True when more scans matched than this page holds.
historylist
The scans in this page, newest first unless Oldest first is on.
hosttext
The hostname that was scanned, e.g. example.com. A pasted URL is reduced to its hostname before scanning.
latest_gradetext
The grade at the end of the window.
scanned_fromtext
The start of the window applied, YYYY-MM-DD. Null when none was given.
scanned_totext
The end of the window applied, YYYY-MM-DD. Null when none was given.
score_changenumber
Points gained or lost across the window. Negative means the site got worse.
total_countnumber
How many scans fell inside the window, across every page.
Example output
{
  "count": 2,
  "current_grade": "B+",
  "current_score": 80,
  "details_url": "https://developer.mozilla.org/en-US/observatory/analyze?host=example.com",
  "earliest_grade": "A",
  "grade_change": "worsened",
  "has_more": false,
  "history": [
    {
      "grade": "B+",
      "scan_id": 116498575,
      "scanned_at": "2026-08-23T18:48:32.850Z",
      "score": 80
    },
    {
      "grade": "A",
      "scan_id": 108377210,
      "scanned_at": "2026-07-14T09:02:11.104Z",
      "score": 95
    }
  ],
  "host": "example.com",
  "latest_grade": "B+",
  "scanned_from": "2026-07-01",
  "scanned_to": "2026-08-23",
  "score_change": -15,
  "total_count": 2
}

Get scan results

Get a website's full HTTP Observatory report: the grade and score, every security test with what was found and what to change, the response headers the scanner saw, and the site's past scans. Uses the stored scan while it is under a day old; scan again with Rescan a website. No API key required.

Inputs

WebsitehosttextRequired
The site to scan, as a hostname such as example.com. A full URL works too, only its hostname is used. IP addresses cannot be scanned: the scanner needs a name to check a certificate and an HSTS policy against.

Outputs

algorithm_versionnumber
Which version of the scoring rules produced this grade. Grades are only comparable within one version.
details_urltext
The full report on MDN, for a person to open. Put it in the alert.
errortext
What went wrong, when a scan was recorded but could not be completed. Null on a normal scan.
failed_test_countnumber
How many tests failed.
failed_testslist
Only the tests that failed, most punishing first. Empty when the site passed everything.
gradetext
The letter grade, A+ down to F. Null only when the scan could not grade the site.
historylist
This host's earlier scans, oldest first, as the Observatory stored them.
hosttext
The hostname that was scanned, e.g. example.com. A pasted URL is reduced to its hostname before scanning.
passed_all_teststrue/false
True when nothing failed. Branch on this to stay quiet on a clean scan.
recommendationslist
What to fix, most punishing failure first. Empty when nothing failed.
response_headersobject
The response headers the scanner received, keyed by lower-case header name.
scan_idnumber
The Observatory's id for this scan.
scanned_attext
When this scan ran, as an ISO 8601 UTC instant. May be older than this step: a stored scan is served while it is under 24 hours old.
scorenumber
The score behind the grade. Starts at 100, loses points for each failed test, and earns up to 145 with the bonuses that apply once a site is already at 90.
status_codenumber
The HTTP status the site answered the scanner with, e.g. 200.
testslist
The tests, ordered with the most punishing failure first.
tests_failednumber
How many tests the site failed.
tests_passednumber
How many tests the site passed.
tests_quantitynumber
How many tests were run in total.
Example output
{
  "algorithm_version": 5,
  "details_url": "https://developer.mozilla.org/en-US/observatory/analyze?host=example.com",
  "error": null,
  "failed_test_count": 1,
  "failed_tests": [
    {
      "description": "Content Security Policy (CSP) header not implemented.",
      "details": {
        "data": null
      },
      "documentation_url": "https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/CSP",
      "expectation": "csp-implemented-with-no-unsafe-default-src-none",
      "name": "content-security-policy",
      "outcome": "failed",
      "passed": false,
      "recommendation": "Implement a Content Security Policy that restricts where content can be loaded from.",
      "result": "csp-not-implemented",
      "score_modifier": -25,
      "title": "Content Security Policy (CSP)"
    }
  ],
  "grade": "B+",
  "history": [
    {
      "grade": "B+",
      "scan_id": 116498575,
      "scanned_at": "2026-08-23T18:48:32.850Z",
      "score": 80
    },
    {
      "grade": "A",
      "scan_id": 108377210,
      "scanned_at": "2026-07-14T09:02:11.104Z",
      "score": 95
    }
  ],
  "host": "example.com",
  "passed_all_tests": false,
  "recommendations": [
    {
      "documentation_url": "https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/CSP",
      "recommendation": "Implement a Content Security Policy that restricts where content can be loaded from.",
      "score_modifier": -25,
      "test": "content-security-policy",
      "title": "Content Security Policy (CSP)"
    }
  ],
  "response_headers": {
    "content-type": "text/html",
    "referrer-policy": "strict-origin-when-cross-origin",
    "strict-transport-security": "max-age=63072000",
    "x-content-type-options": "nosniff",
    "x-frame-options": "DENY"
  },
  "scan_id": 116498575,
  "scanned_at": "2026-08-23T18:48:32.850Z",
  "score": 80,
  "status_code": 200,
  "tests": [
    {
      "description": "Content Security Policy (CSP) header not implemented.",
      "details": {
        "data": null
      },
      "documentation_url": "https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/CSP",
      "expectation": "csp-implemented-with-no-unsafe-default-src-none",
      "name": "content-security-policy",
      "outcome": "failed",
      "passed": false,
      "recommendation": "Implement a Content Security Policy that restricts where content can be loaded from.",
      "result": "csp-not-implemented",
      "score_modifier": -25,
      "title": "Content Security Policy (CSP)"
    },
    {
      "description": "Preloaded via the HTTP Strict Transport Security (HSTS) preloading process.",
      "details": {
        "data": "max-age=63072000",
        "include_sub_domains": true,
        "max_age": 63072000,
        "preload": false,
        "preloaded": true
      },
      "documentation_url": "https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/TLS#http_strict_transport_security_implementation",
      "expectation": "hsts-implemented-max-age-at-least-six-months",
      "name": "strict-transport-security",
      "outcome": "passed",
      "passed": true,
      "recommendation": null,
      "result": "hsts-preloaded",
      "score_modifier": 5,
      "title": "Strict Transport Security (HSTS)"
    }
  ],
  "tests_failed": 1,
  "tests_passed": 9,
  "tests_quantity": 10
}

Get the grade distribution

Get how every website the Observatory has ever scanned graded, with each grade's share of the web and the share that did at least as well. The context a grade needs: a C is a different story once you know how much of the web scores below it. No API key required.

Inputs

Grade to placegradetext
Optional. Report where one grade sits: how many sites hold it and what share of the web it beats. The full distribution comes back either way.One of: A+, A, A-, B+, B, B-, C+, C, C-, D+, and 3 more.

Outputs

better_than_percentagenumber
The percentage of sites that grade below it: the figure to quote in a report.
distributionlist
Every grade, best first.
gradetext
The grade that was asked about, or null when none was.
grade_countnumber
How many sites hold that grade.
grade_percentagenumber
That grade's share of every site scanned.
most_common_gradetext
The grade the most sites hold.
total_sitesnumber
How many sites the figures cover.
Example output
{
  "better_than_percentage": 89.34,
  "distribution": [
    {
      "at_or_above_percentage": 2.53,
      "count": 73035,
      "grade": "A+",
      "percentage": 2.53
    },
    {
      "at_or_above_percentage": 100.0,
      "count": 1032721,
      "grade": "F",
      "percentage": 35.75
    }
  ],
  "grade": "B+",
  "grade_count": 70705,
  "grade_percentage": 2.45,
  "most_common_grade": "F",
  "total_sites": 2888739
}

Get the scanner version

Get the version of the HTTP Observatory scanner that is answering. Worth storing next to a saved result: the scoring rules change between versions, so a grade is only comparable with another from the same one. Also a quick way to confirm the connection reaches the API. No API key required.

Inputs

None.

Outputs

api_base_urltext
The API this integration calls.
buildtext
The build that produced it, or "unknown" when the deployment does not record one.
committext
The exact commit it was built from.
source_urltext
Where the scanner's source code lives.
versiontext
The scanner's released version, e.g. 1.6.3.
Example output
{
  "api_base_url": "https://observatory-api.mdn.mozilla.net/api/v2",
  "build": "unknown",
  "commit": "22e088df69a0d8734bd8f6ffad8a7ff97da8ddb8",
  "source_url": "https://github.com/mdn/mdn-http-observatory",
  "version": "1.6.3"
}

Get the scoring reference

Get the Observatory's scoring rules: every test it runs, every outcome each one can reach, what that outcome is worth in points, and MDN's advice for it. The rules themselves, not a scan. Look up what a failure would cost before anyone changes anything, or publish the rules alongside a report. No API key required.

Inputs

Limit to these teststestslist
Optional. Return the rules for the controls chosen. Leave empty for every test.One or more of: content-security-policy (Content Security Policy (CSP)), cookies, cross-origin-resource-sharing (Cross Origin Resource Sharing (CORS)), cross-origin-resource-policy (Cross Origin Resource Policy), redirection, referrer-policy (Referrer Policy), strict-transport-security (Strict Transport Security (HSTS)), subresource-integrity (Subresource Integrity), x-content-type-options, x-frame-options.

Outputs

baseline_scorenumber
The score a site starts from before any test has been applied.
countnumber
How many tests are described.
gradeslist
The grade ladder, best first.
maximum_scorenumber
The highest score reachable, with every bonus.
outcome_countnumber
How many scored outcomes in total.
testslist
The tests, each with its scored outcomes.
Example output
{
  "baseline_score": 100,
  "count": 1,
  "grades": [
    "A+",
    "A",
    "A-",
    "B+",
    "B",
    "B-",
    "C+",
    "C",
    "C-",
    "D+",
    "D",
    "D-",
    "F"
  ],
  "maximum_score": 145,
  "outcome_count": 2,
  "tests": [
    {
      "best_score_modifier": 10,
      "documentation_url": "https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/CSP",
      "name": "content-security-policy",
      "outcome_count": 2,
      "outcomes": [
        {
          "description": "Content Security Policy (CSP) implemented with default-src 'none', no 'unsafe' and form-action is set to 'none' or 'self'",
          "name": "csp-implemented-with-no-unsafe-default-src-none",
          "recommendation": null,
          "score_modifier": 10
        },
        {
          "description": "Content Security Policy (CSP) header not implemented",
          "name": "csp-not-implemented",
          "recommendation": "Implement a Content Security Policy that restricts where content can be loaded from.",
          "score_modifier": -25
        }
      ],
      "title": "Content Security Policy (CSP)",
      "worst_score_modifier": -25
    }
  ]
}

List security tests

List a website's security tests, filtered to just the ones that failed, just the ones that passed, or all of them, ordered with the most punishing failure first. The list to paste into a ticket or post to a channel. No API key required.

Inputs

WebsitehosttextRequired
The site to scan, as a hostname such as example.com. A full URL works too, only its hostname is used. IP addresses cannot be scanned: the scanner needs a name to check a certificate and an HSTS policy against.
Showoutcometext
Optional. Which tests to include. Every test by default. A test that did not apply (no cookies to check, a response that is not HTML) costs no points and is not a failure.One of: all (Every test), failed (Only the tests that failed), passed (Only the tests that passed), not_applicable (Only the tests that did not apply). Default: all.
Limit to these teststestslist
Optional. Report only on the controls chosen. Leave empty for every test the scan ran.One or more of: content-security-policy (Content Security Policy (CSP)), cookies, cross-origin-resource-sharing (Cross Origin Resource Sharing (CORS)), cross-origin-resource-policy (Cross Origin Resource Policy), redirection, referrer-policy (Referrer Policy), strict-transport-security (Strict Transport Security (HSTS)), subresource-integrity (Subresource Integrity), x-content-type-options, x-frame-options.

Outputs

countnumber
How many tests are in this list.
details_urltext
The full report on MDN, for a person to open. Put it in the alert.
gradetext
The letter grade, A+ down to F. Null only when the scan could not grade the site.
hosttext
The hostname that was scanned, e.g. example.com. A pasted URL is reduced to its hostname before scanning.
outcome_filtertext
The filter that was applied.
scanned_attext
When this scan ran, as an ISO 8601 UTC instant. May be older than this step: a stored scan is served while it is under 24 hours old.
scorenumber
The score behind the grade. Starts at 100, loses points for each failed test, and earns up to 145 with the bonuses that apply once a site is already at 90.
score_impactnumber
The points these tests add up to. Negative when listing failures: what fixing all of them is worth.
testslist
The tests, ordered with the most punishing failure first.
total_countnumber
How many tests the scan ran in total.
Example output
{
  "count": 1,
  "details_url": "https://developer.mozilla.org/en-US/observatory/analyze?host=example.com",
  "grade": "B+",
  "host": "example.com",
  "outcome_filter": "failed",
  "scanned_at": "2026-08-23T18:48:32.850Z",
  "score": 80,
  "score_impact": -25,
  "tests": [
    {
      "description": "Content Security Policy (CSP) header not implemented.",
      "details": {
        "data": null
      },
      "documentation_url": "https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/CSP",
      "expectation": "csp-implemented-with-no-unsafe-default-src-none",
      "name": "content-security-policy",
      "outcome": "failed",
      "passed": false,
      "recommendation": "Implement a Content Security Policy that restricts where content can be loaded from.",
      "result": "csp-not-implemented",
      "score_modifier": -25,
      "title": "Content Security Policy (CSP)"
    }
  ],
  "total_count": 10
}

Rescan a website

Scan a website again right now and get the full report, rather than the stored result. Use it after a deploy that changed headers. A host can be rescanned once a minute; asked again sooner, the Observatory hands back the scan it already has. No API key required.

Inputs

WebsitehosttextRequired
The site to scan, as a hostname such as example.com. A full URL works too, only its hostname is used. IP addresses cannot be scanned: the scanner needs a name to check a certificate and an HSTS policy against.

Outputs

algorithm_versionnumber
Which version of the scoring rules produced this grade. Grades are only comparable within one version.
details_urltext
The full report on MDN, for a person to open. Put it in the alert.
errortext
What went wrong, when a scan was recorded but could not be completed. Null on a normal scan.
failed_test_countnumber
How many tests failed.
failed_testslist
Only the tests that failed, most punishing first. Empty when the site passed everything.
gradetext
The letter grade, A+ down to F. Null only when the scan could not grade the site.
historylist
This host's earlier scans, oldest first, as the Observatory stored them.
hosttext
The hostname that was scanned, e.g. example.com. A pasted URL is reduced to its hostname before scanning.
passed_all_teststrue/false
True when nothing failed. Branch on this to stay quiet on a clean scan.
recommendationslist
What to fix, most punishing failure first. Empty when nothing failed.
response_headersobject
The response headers the scanner received, keyed by lower-case header name.
scan_idnumber
The Observatory's id for this scan.
scanned_attext
When this scan ran, as an ISO 8601 UTC instant. May be older than this step: a stored scan is served while it is under 24 hours old.
scorenumber
The score behind the grade. Starts at 100, loses points for each failed test, and earns up to 145 with the bonuses that apply once a site is already at 90.
status_codenumber
The HTTP status the site answered the scanner with, e.g. 200.
testslist
The tests, ordered with the most punishing failure first.
tests_failednumber
How many tests the site failed.
tests_passednumber
How many tests the site passed.
tests_quantitynumber
How many tests were run in total.
Example output
{
  "algorithm_version": 5,
  "details_url": "https://developer.mozilla.org/en-US/observatory/analyze?host=example.com",
  "error": null,
  "failed_test_count": 0,
  "failed_tests": [],
  "grade": "A+",
  "history": [
    {
      "grade": "B+",
      "scan_id": 116498575,
      "scanned_at": "2026-08-23T18:48:32.850Z",
      "score": 80
    },
    {
      "grade": "A",
      "scan_id": 108377210,
      "scanned_at": "2026-07-14T09:02:11.104Z",
      "score": 95
    }
  ],
  "host": "example.com",
  "passed_all_tests": true,
  "recommendations": [],
  "response_headers": {
    "content-type": "text/html",
    "referrer-policy": "strict-origin-when-cross-origin",
    "strict-transport-security": "max-age=63072000",
    "x-content-type-options": "nosniff",
    "x-frame-options": "DENY"
  },
  "scan_id": 116498575,
  "scanned_at": "2026-08-23T18:48:32.850Z",
  "score": 105,
  "status_code": 200,
  "tests": [
    {
      "description": "Preloaded via the HTTP Strict Transport Security (HSTS) preloading process.",
      "details": {
        "data": "max-age=63072000",
        "include_sub_domains": true,
        "max_age": 63072000,
        "preload": false,
        "preloaded": true
      },
      "documentation_url": "https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/TLS#http_strict_transport_security_implementation",
      "expectation": "hsts-implemented-max-age-at-least-six-months",
      "name": "strict-transport-security",
      "outcome": "passed",
      "passed": true,
      "recommendation": null,
      "result": "hsts-preloaded",
      "score_modifier": 5,
      "title": "Strict Transport Security (HSTS)"
    }
  ],
  "tests_failed": 0,
  "tests_passed": 10,
  "tests_quantity": 10
}

Scan a website

Scan a website's HTTP security and get its grade and score: A+ down to F, out of 145, plus how many of the tests it passed. The quick check: for the test-by-test breakdown, use Get scan results. No API key required.

Inputs

WebsitehosttextRequired
The site to scan, as a hostname such as example.com. A full URL works too, only its hostname is used. IP addresses cannot be scanned: the scanner needs a name to check a certificate and an HSTS policy against.

Outputs

algorithm_versionnumber
Which version of the scoring rules produced this grade. Grades are only comparable within one version.
details_urltext
The full report on MDN, for a person to open. Put it in the alert.
errortext
What went wrong, when a scan was recorded but could not be completed. Null on a normal scan.
gradetext
The letter grade, A+ down to F. Null only when the scan could not grade the site.
hosttext
The hostname that was scanned, e.g. example.com. A pasted URL is reduced to its hostname before scanning.
passed_all_teststrue/false
True when nothing failed. Branch on this to stay quiet on a clean scan.
scan_idnumber
The Observatory's id for this scan.
scanned_attext
When this scan ran, as an ISO 8601 UTC instant. May be older than this step: a stored scan is served while it is under 24 hours old.
scorenumber
The score behind the grade. Starts at 100, loses points for each failed test, and earns up to 145 with the bonuses that apply once a site is already at 90.
status_codenumber
The HTTP status the site answered the scanner with, e.g. 200.
tests_failednumber
How many tests the site failed.
tests_passednumber
How many tests the site passed.
tests_quantitynumber
How many tests were run in total.
Example output
{
  "algorithm_version": 5,
  "details_url": "https://developer.mozilla.org/en-US/observatory/analyze?host=example.com",
  "error": null,
  "grade": "B+",
  "host": "example.com",
  "passed_all_tests": false,
  "scan_id": 116498575,
  "scanned_at": "2026-08-23T18:48:32.850Z",
  "score": 80,
  "status_code": 200,
  "tests_failed": 1,
  "tests_passed": 9,
  "tests_quantity": 10
}

On this page