What we check
65 checks across 7 categories. Each one below links to a full guide on why it matters and how to fix it.
What a check is
A fixed rule with a stated threshold, not an opinion. Each one names the exact signal it reads, so you can check the same thing by hand and get the same answer. 54 are measured from the page itself; the other 11 come from the questions after the scan, because no crawler can see whether you have a staging environment.
Three outcomes, not two
A check passes, fails, or reports that we could not determine it. The third is the one that matters: a check we could not settle is never counted as a pass, and never moves your score in either direction. A scanner that quietly turns "we did not look" into a green tick is the one to distrust.
How it reaches the score
Every site starts at 100 and each failed check deducts a fixed amount by severity, with a cap per category so one weak area cannot sink the whole number. The arithmetic is public. See exactly how the score is produced.
Exposure 9
Revoke the exposed Slack token
A Slack token can read and post messages in every channel it can reach, letting an attacker read private conversations or impersonate a workspace member.
Rotate the exposed SendGrid API key
A SendGrid API key can send email as the domain's verified sender, which is enough to run a convincing phishing campaign that looks like it came from a trusted source.
Rotate the exposed Supabase service-role key
A Supabase service_role key bypasses row-level security entirely, granting full read and write access to every table in the database rather than the narrow slice an authenticated user is meant to see.
Restrict or rotate the exposed Google API key
An unrestricted Google API key lets anyone who finds it make billable calls against the associated project, running up usage charges or exhausting quota that other features depend on.
Stop shipping source maps publicly
A published source map republishes the original, unminified source (including comments and internal structure never meant to ship), making it far easier to find other vulnerabilities in the same codebase.
Revoke the exposed private key
A private key is the credential a certificate, SSH host, or signing system trusts completely: holding it lets an attacker impersonate that system, decrypt its traffic, or sign as it.
Revoke the exposed GitHub token
A GitHub token inherits its scope's permissions, which can include reading private source code, pushing commits, or reading other secrets stored in the repository or its CI pipeline.
Rotate the exposed Stripe secret key
A live Stripe secret key can issue refunds, create charges, and read customers' payment and order history: whoever holds it can act as the business, not just view its data.
Rotate the exposed AWS access key
An AWS access key inherits whatever permissions are attached to it, which can mean reading files from storage buckets, spinning up billable compute, or altering infrastructure outright.
Security 18
Serve the site over HTTPS
Without HTTPS, browsers flag the site as "Not Secure" and all traffic, including passwords and payment details, travels in plaintext, exposing customers to interception and eroding trust.
Enable HSTS
Without HSTS, a user's first visit or any link they click can be silently downgraded to plain HTTP by an attacker on the network, exposing them to session hijacking even though HTTPS is available.
Fix the Strict-Transport-Security max-age
A Strict-Transport-Security header only protects repeat visitors for as long as its max-age lasts, and a header with no valid max-age at all is ignored outright by browsers. Either state (expired, deliberately zeroed out mid-rollback, or malformed) leaves every visitor as exposed to a downgrade attack on their next visit as if the header had never been sent, even though it's present in every response.
Add a Content-Security-Policy header
Without a Content-Security-Policy, the browser will run any script that ends up on the page, including ones an attacker injects, which is the primary way customer data gets stolen and sessions get hijacked.
Enforce the existing Content-Security-Policy
A report-only policy only logs violations; it does not stop a malicious script from running. The hard part (defining the policy and watching it against real traffic to catch breakage) is already done, so the remaining risk is closed by a one-line header rename, not a redesign.
Add X-Content-Type-Options header
Without nosniff, browsers may reinterpret a file as a different type, for example treating an uploaded image as executable JavaScript, which attackers can exploit to run malicious scripts.
Add clickjacking protection
Without clickjacking protection, an attacker can embed the site in an invisible iframe and trick users into clicking real buttons (like "confirm payment") while they believe they are interacting with another page.
Add a Referrer-Policy header
Without a Referrer-Policy, full page URLs (which may contain session tokens, search terms, or internal paths) are leaked to every third-party site a user navigates to or loads a resource from.
Tighten the Referrer-Policy value
unsafe-url sends the full page URL (including query strings, which can carry session tokens, search terms, or internal paths) to every destination a user navigates to or loads a resource from, even when that destination is reached over a downgraded, insecure connection. It is a one-line value change, not a missing header.
Add a Permissions-Policy header
Without a Permissions-Policy, any script running on the page, including third-party scripts and ads, can request access to the camera, microphone, or location, widening the damage a compromised script can do.
Migrate Feature-Policy to Permissions-Policy
Feature-Policy was renamed and restructured as Permissions-Policy years ago, and current Chromium-based browsers no longer read the old header at all: a site that only ships Feature-Policy is protected in no browser that matters today, even though the restriction was correctly designed once. The syntax is a near-literal translation, so the fix is a rename with a small syntax change, not a redesign.
Mark cookies as Secure
Cookies without the Secure attribute can still be sent over an unencrypted connection if the browser is ever made to request the site over plain HTTP, exposing whatever value the cookie holds to anyone on the same network.
Ask the tracking vendor to mark their cookies Secure
These cookies are written by third-party tracking scripts running on the site (Google Analytics, Google Ads, Microsoft Clarity, Meta Pixel, Microsoft Advertising, and similar), not by the site's own server. "Add Secure to the cookies the app sets" does not apply, because the app never sets them; the vendor's script does, and the vendor's own configuration controls the attributes it uses.
Mark cookies as HttpOnly
Cookies without HttpOnly are readable by any JavaScript on the page, so a single XSS bug is enough for an attacker to steal session cookies and take over accounts.
Stop exposing server software versions
Advertising exact server or framework versions gives attackers a shortcut to find and exploit known vulnerabilities for that specific version, without any extra reconnaissance.
Fix mixed content
Mixed content (HTTP resources loaded on an HTTPS page) is blocked or flagged by modern browsers and gives attackers a way to tamper with an otherwise-secure page by intercepting the insecure resource.
Set up dependency vulnerability scanning
Most breaches exploit known vulnerabilities in outdated dependencies; without automated scanning these sit unnoticed until someone exploits them.
Keep up security hardening
Security posture erodes silently as new code, third-party scripts, or config changes land, so a clean check today does not guarantee a clean check next quarter.
Performance 11
Reduce third-party request volume
On sites already served over HTTP/2 or HTTP/3, first-party bundling stops being the dominant performance cost: third-party tags (analytics, ads, chat widgets, fonts) usually are, and unlike first-party code the owner cannot bundle them at build time, only choose to run fewer of them.
Optimize large images
Oversized images are one of the single biggest, easiest-to-fix causes of slow pages, and slow pages lose visitors before the content even renders.
Resize the oversized images already in a modern format
An oversized image is still wasted bytes on every load even when its format is already efficient: a modern format compresses better per pixel, but delivering an image far larger than its display size throws that saving away.
Speed up page load time
Slow page loads are one of the strongest predictors of visitors leaving before the page even finishes loading, directly costing traffic and conversions.
Enable text compression
Serving HTML/JS/CSS uncompressed can multiply transfer size several times over, directly slowing every page load for every visitor.
Add cache-control headers to static assets
Without cache headers, returning visitors re-download the same images, scripts, and stylesheets on every visit, wasting bandwidth and slowing repeat page loads unnecessarily.
Reduce render-blocking resources
Render-blocking CSS and JS delay the moment visitors see anything on screen, making the site feel slow even when total page weight is reasonable.
Keep an eye on performance
Performance regressions tend to creep in one image or script at a time, so a fast site today can quietly slow down without ongoing checks.
Reduce page weight
Heavier pages take longer to load, especially on mobile networks, and slow load times directly correlate with higher bounce rates and lower conversion.
Reduce the number of requests
Every extra request adds latency, especially on slower connections; an excessive request count is a common, fixable reason pages feel sluggish even when total size looks fine.
Add real-user performance monitoring
Lab scores miss what real users on real devices and networks experience; field data is what Google ranks on and what actually affects conversions.
SEO 12
Add a page title
Without a page title, search engines have no reliable label to show in results and browser tabs are blank, hurting both click-through rate and basic usability.
Fix page title length
Titles that are too short waste an opportunity to describe the page, and titles that are too long get truncated with '...' in search results, hiding the message you're trying to send.
Add a meta description
Without a meta description, search engines auto-generate a snippet from the page's content (often an awkward excerpt), reducing the chance a searcher clicks through.
Fix meta description length
A meta description that's too short under-sells the page, and one that's too long gets cut off in search results. Both reduce click-through rate.
Use exactly one H1 per page
Multiple or missing H1s confuse search engines and screen readers about what the page's main topic actually is, diluting SEO relevance and hurting accessibility.
Add a viewport meta tag
Without a viewport tag, mobile browsers render the page at desktop width and shrink it, making text unreadable and hurting both mobile usability and Google's mobile-first ranking.
Add a canonical link
Without a canonical tag, search engines can split ranking signals across near-duplicate URLs (with tracking params, trailing slashes, etc.), diluting the page's authority.
Allow the page to be indexed
A noindex directive tells search engines to leave the page out of results entirely, and a robots.txt Disallow stops them fetching it in the first place. If either isn't intentional, the page and any traffic or leads it could generate are invisible to search.
Add Open Graph tags
Without Open Graph tags, links shared on social platforms and chat apps show a generic or broken preview, which measurably reduces click-through on shared links.
Add a favicon
A missing favicon makes the site look unfinished or untrustworthy in browser tabs, bookmarks, and history (often one of the first things a visitor notices).
Add a language attribute
Without a declared language, search engines may serve the page to the wrong locale's audience and screen readers may mispronounce content, hurting both reach and accessibility.
Connect Google Search Console
Without Search Console you are blind to indexing errors, manual actions, and the queries that bring you traffic.
Accessibility 4
Add a language attribute
Without a declared language, screen readers may mispronounce every word on the page, making the site effectively unusable for blind and low-vision visitors.
Add alt text to images
Images without alt text are invisible to screen reader users and to search engines, and in many jurisdictions accessible images are a legal requirement, not just best practice.
Add accessibility testing to your process
Inaccessible sites exclude real users and carry legal risk; automated scans plus a screen-reader pass catch most issues cheaply.
Keep accessibility standards up
Accessibility is easy to regress when new components or content are added without the same scrutiny as the initial build, quietly locking out users who rely on assistive tech.
Runtime Errors 3
Fix console errors
Console errors often signal broken functionality (failed API calls, broken integrations) that users experience as things silently not working, even if the page still loads.
Fix uncaught JavaScript errors
Uncaught JavaScript exceptions can halt script execution partway through, breaking forms, navigation, or interactive features for real users without any visible warning.
Fix failed network requests
A request that returns 4xx/5xx, or that never reaches a server at all, means something the page depends on (an API, an image, a script) is not arriving, which can silently degrade or break the user experience.
Best Practices 8
Run your tests automatically on every change (CI)
Without CI, regressions reach production because nothing verifies changes automatically; CI turns "hope it works" into "proven before merge".
Add an HTML5 doctype
Without a doctype, browsers render the page in "quirks mode", which can cause inconsistent layout and CSS behavior across browsers.
Declare a character encoding
Without a declared charset, browsers may guess the encoding incorrectly, causing special characters, accents, or symbols to render as garbled text.
Redirect HTTP to HTTPS
If HTTP requests aren't redirected, visitors and search engines who land on the insecure URL stay on it, exposing them to interception and splitting SEO signal between the HTTP and HTTPS versions.
Add a responsive viewport tag
Without a responsive viewport tag, the page renders at desktop width on phones, forcing visitors to pinch and zoom, which drives them away.
Set up a staging environment
Without a staging environment, every change is tested for the first time in production, turning routine deploys into high-risk events that can take the live site down.
Add uptime monitoring & alerting
Without uptime monitoring, outages and errors are usually discovered by customers complaining rather than by the team, which extends downtime and erodes trust.
Establish a regular release cadence
Shipping less than once a month means fixes and improvements pile up, changes get riskier and harder to review, and the team loses the ability to respond quickly to bugs or opportunities.
Ready to see where you stand?
Scan your site and get your Engineering Score with a prioritized roadmap in under a minute, no signup required.
EngineeringScore