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
| Action | What it does |
|---|---|
| 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. |
| 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. |
| 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. |
| 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. |
| Get scan history | Get a website's past Observatory scans, newest first, and whether its grade has improved or slipped over that period. |
| 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. |
| 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. |
| Get the scanner version | Get the version of the HTTP Observatory scanner that is answering. |
| 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. |
| 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. |
| Rescan a website | Scan a website again right now and get the full report, rather than the stored result. |
| 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. |
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
- Website
hosttextRequired - 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 grade
minimum_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 score
minimum_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 first
rescantrue/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
- Websites
hoststextRequired - 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
- Website
hosttextRequired - 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 test
testtextRequired - 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
- Website
hosttextRequired - 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 headers
headerslist - 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 headers
other_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
- Website
hosttextRequired - 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 after
scanned_fromdate - Optional. Only scans from this date onwards. Leave blank to start at the earliest scan on record.
- Scanned on or before
scanned_todate - Optional. Only scans up to this date. Leave blank to run up to the most recent one.
- Number of scans
limitnumber - Optional. How many scans to return. Between 1 and 200; 25 by default.From 1 to 200. Default:
25. - Oldest first
oldest_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
- Website
hosttextRequired - 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 place
gradetext - 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 tests
testslist - 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
- Website
hosttextRequired - 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.
- Show
outcometext - 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 tests
testslist - 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
- Website
hosttextRequired - 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
- Website
hosttextRequired - 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
}