Skip to main content
EveryShopper

What the scanner checks, and what it cannot

The scanner runs 27 checks against the HTML of the page you give it. The list of checks on this page is generated from the same file the scanner itself runs, so a check cannot be listed here that the scanner does not run, or run without appearing here. The words beside each check are written by hand in that file, and a description has been wrong about its check before — so those words are reviewed against the code, and pinned by tests where they have drifted. Every check below is listed with what it looks for, what a hit means, how to fix it, and — the part most scanners leave out — what it cannot tell you.

The report also carries 2 page-level facts, which are not checks and are counted separately: a form sending to an unencrypted address, and whether the privacy and terms links the page publishes resolve. The two groups are not mixed anywhere — see page-level facts below for what they are and, more importantly, what they are not.

These are findings from automated checks on the HTML this page's server sent. Automated checks find a subset of real barriers, they do not certify compliance, and they do not replace a human or rendered check.

The two halves of any accessibility check

Checked automatically

27 deterministic or pattern checks, all decidable from the served HTML alone. Where a check fires on an element, the report quotes that element’s own markup as evidence. Where it fires on something absent — no main element, no skip link, a count of headings — there is no element to quote, and the report states what it observed instead.

  • Images (3)
  • Forms (3)
  • Page structure (5)
  • Headings (3)
  • Links and buttons (3)
  • Landmarks (2)
  • Embeds and media (2)
  • Tables (1)
  • Viewport (1)
  • ARIA (4)

Needs a human or rendered check

These are never reported as passed: none of them is a check that runs, and a check that produced no finding is not a pass on any of this. Parts of the list we can test in part — we can flag a blocked zoom, and we can show that alt text or a label exists — but nothing here is ever a verdict. If you want a defensible position on accessibility, this is the work that still has to happen.

  • Colour contrast. Requires the computed colour of text and its actual background, including images, gradients and overlays. A wrong guess here would be worse than saying nothing, so we do not guess.
  • Keyboard operability and focus order. Whether every control can be reached and operated, whether focus is visible, whether a menu traps it. This needs the rendered page and a keyboard.
  • Anything rendered by JavaScript. We fetch and read the HTML the server sends. If your catalogue, basket or menu is injected after load, those parts of the page are not in this report — and that can be the majority of a modern store front end.
  • Quality of the wording we can only count. We can prove alt text, link text, labels and titles exist. We cannot prove they are accurate, useful or in the right language.
  • Screen reader behaviour in practice. Live regions, announcements, and whether a custom widget behaves as its ARIA claims. Needs a screen reader and a person using it.
  • Form error handling and required-field cues. How errors are announced and whether they are tied to the field requires submitting the form and reading the response.
  • Reflow and zoom behaviour. We can flag a blocked zoom, but whether the layout survives 200% text scaling or a 320px viewport needs a rendered page.
  • Motion, timing and media alternatives. Autoplaying animation, session timeouts and whether a transcript or audio description exists require watching the page and reading the content.
  • PDFs, documents and third-party content. Embedded documents, in-frame content and third-party widgets are separate documents with their own accessibility, and are outside this single-page scan.
  • Reading order and meaning. Whether the page makes sense when linearised, and whether the structure matches the visual hierarchy, is a human judgement.

Page-level facts — not accessibility checks

These are not accessibility checks and not pass/fail verdicts. They have no severity, they are not WCAG criteria, and they are not counted among the checks that ran. There are two of them: one is read from the markup of the page itself, the other is the outcome of fetching the privacy and terms links the page itself publishes.

They sit in their own group in every report and are counted separately from the 27 checks. Nothing in that group has a severity, and nothing in it is a pass or a fail: a fact that does not appear is not a pass, and a link we could not fetch is recorded as “could not be checked”, with the reason.

  • A form that sends what a customer types to an unencrypted address

    What it is
    Forms on the page whose action attribute resolves to a plain http:// address — resolved against the page's own address when the attribute is relative, and read as the page's own address when the attribute is absent, which is what a browser does. The evidence is the action attribute exactly as published and the absolute address it resolves to. Only forms with at least one field that collects what a visitor types are reported: a form of nothing but hidden fields sends nothing that was typed.
    What it cannot see
    We read one page's markup at one moment. We cannot tell what the form collects, where the data goes once it arrives, whether the browser would warn the visitor, or whether a script posts the form somewhere other than this attribute. A page we fetched over plain http may still redirect a real browser to a secure address. This is a fact about an address in a page, never a statement about the store or about any law.

Refused by design, and not in the report in any wording: any verdict on cookie banners, any claim about auto-renewal or cancellation, card-skimming or dark patterns, any score that blends these facts into one number, any probe of an address a page does not publish — and no finding labelled “legal”, because a fact about a page is not a legal instrument. We say what we observed and never what it means legally. The cap of 3 links per page and the 8-second link timeout are here so you can hold this page to what the code does.

How we decide severity

  • CriticalA barrier that stops some people using the page at all: content or a control they cannot perceive or name.
  • SeriousA real barrier that affects a group of users or a whole class of assistive technology, and is usually quick to fix.
  • ModerateMakes the page harder to use or understand for some people, or breaks a rule that assistive technology relies on.
  • MinorWorth a look rather than an emergency: either a best-practice point, or a pattern that can be correct in context.

Severity is a priority signal for fixing, not a legal category, and it is not a score you can compare between sites.

How a scan behaves

  • One page, plus its own privacy and terms links

    We fetch the single address you give us, plus one request per redirect hop (up to 4). If that page publishes links that identify themselves as a privacy policy or terms, we then fetch up to 3 of them — the first 3 in document order, one request each, plus their redirect hops. That is the only link-following the scanner does: we never probe an address the page does not publish, we never crawl the rest of the site, and we never load images, scripts or stylesheets. Every link outcome is reported as what it was: an HTTP status, a timeout, a refusal or a failure — and a link we could not fetch is recorded as “could not be checked”, never as a pass.

  • We identify ourselves

    Every request — the page, and each privacy or terms link — carries a user agent naming this scanner. We do not pretend to be a browser to get past a block.

  • 12-second timeout for the page, 8 for a link, 4 MB limit

    A page that does not answer within 12 seconds is reported as a timeout, and a privacy or terms link gets 8 seconds. Pages over 4 MB are read to the limit and the report says so — we never present a partial read as a whole one.

  • HTML only for the page itself

    If the page's response is not HTML (a PDF, an image, JSON, a download), we say so instead of reporting an empty result. A privacy or terms link is different: there we only ask whether the address answers, so a policy delivered as a PDF that answers 200 is reported as resolving — the request never reads what the page says.

  • Private addresses are refused

    The address is resolved before we connect, and every redirect is re-checked — for the page and for each privacy or terms link — so the scanner cannot be pointed at localhost or a private network.

  • No JavaScript is run

    We read the HTML the server sends. Content that appears only after scripts run — catalogue grids, baskets, cookie banners, single-page apps — is not in the report, and we cannot tell you what it would have contained.

  • No login, no session, no cookie

    There is no account and no database in this path: the report is generated when you ask for it and thrown away when you leave, and the page you scanned is never stored against you. We do keep one flat count of page views, using Cloudflare's cookieless analytics — no cookie, and nothing written to your device. That count records which page was loaded — and a report page names the site it is about, so if you open a report link we sent you, that site's address appears in the count. It still cannot tell us who you are, or whether you read more than the first screen. Like any web request it carries the routine facts of a visit — your browser's language and version, an approximate country — but nothing that identifies you.

The checks, one by one

“Deterministic” means the check is decidable from the markup: the pattern is either there or it is not. “Pattern match” means we flagged something that is wrong in most contexts but can be correct in some — read those with a little more care.

Images

  • Critical

    Image has no alt attribute

    deterministic

    image-alt-missing · Related to WCAG 1.1.1 Non-text Content (A)

    What it looks for
    Every <img> that is not hidden (the hidden attribute, aria-hidden, inline display:none/visibility:hidden, or inside <template>/<noscript>), is not marked role="presentation" or role="none", and has no alt attribute at all.
    What a hit means
    A screen reader cannot describe the image, so a person who cannot see it hears the file name or nothing. If the image is a link or a button, the control becomes unusable.
    How to fix it
    Add alt="" if the image is purely decorative. Otherwise write alt text that says what the image conveys in this context — a short phrase, not a file name.
    What it cannot see
    We cannot judge whether alt text is accurate or useful. Only a human can.
  • Minor

    Image has an empty alt="" — confirm it is decorative

    deterministic

    image-alt-empty · Related to WCAG 1.1.1 Non-text Content (A)

    What it looks for
    Images whose alt attribute is present but empty or only whitespace (alt="" or alt=" ").
    What a hit means
    alt="" is correct for a decorative image and a barrier when the image carries meaning — screen readers skip it either way, so the difference is invisible from the outside.
    How to fix it
    Check each one. Decorative divider or background flourish: leave it empty. Product photo, logo, icon that carries meaning, or anything inside a link or button: give it real alt text.
    What it cannot see
    Intent is not in the HTML, so this rule reports a pattern to review rather than a defect.
  • Moderate

    Alt text looks like a file name

    pattern match

    image-alt-is-filename · Related to WCAG 1.1.1 Non-text Content (A)

    What it looks for
    Alt text ending in .jpg, .png, .gif, .webp, .svg or similar — or that is only a camera or export name, such as img001, DSC_1234, photo 12 or screenshot1.
    What a hit means
    A screen reader will read "hero final v2 dot png" instead of describing the image.
    How to fix it
    Replace the file name with a description of what the image shows in this context.
    What it cannot see
    Technical or diagram images can legitimately name their file format; read the text before changing it.

Forms

  • Critical

    Form field has no label

    deterministic

    form-control-no-label · Related to WCAG 1.3.1 Info and Relationships (A), 4.1.2 Name, Role, Value (A), 3.3.2 Labels or Instructions (A)

    What it looks for
    Visible <input>, <select> and <textarea> elements (excluding submit, button, reset, image and hidden inputs) with no accessible name from a <label for>, a wrapping <label>, aria-label, aria-labelledby or title.
    What a hit means
    A screen reader announces the field as an unlabelled edit box, so the person filling it in does not know what to type — a hard stop on checkout and contact forms.
    How to fix it
    Give the field an id and point a <label for="that-id"> at it, or wrap the input inside its <label>. Placeholder text is not a label: it disappears as soon as typing starts.
    What it cannot see
    We see the HTML, not the rendered page. A field labelled only by a script, or by a visually adjacent heading, will be flagged as unlabelled even when it works. A field whose aria-labelledby points at an id that exists but is empty counts as labelled here, even though a screen reader may announce nothing.
  • Moderate

    <label for> points at an element that does not exist

    deterministic

    label-for-no-target · Related to WCAG 1.3.1 Info and Relationships (A)

    What it looks for
    <label for="x"> where no element in the page has id="x".
    What a hit means
    The visible caption is not connected to any field, so activating the text does not focus the input and screen readers may not announce it.
    How to fix it
    Correct the id in the for attribute, or move the input inside the label element.
    What it cannot see
    The target may exist only after JavaScript runs, which this scan does not do.
  • Moderate

    Identity field has no autocomplete attribute

    pattern match

    identity-field-no-autocomplete · Related to WCAG 1.3.5 Identify Input Purpose (AA)

    What it looks for
    Text, email, telephone, password and similar inputs whose name, id, placeholder or label looks like personal information (email, name, phone, address, postcode, username, password) with no autocomplete attribute, or one whose value is empty or reads "off", "on" or "nope" — none of which names the field's purpose.
    What a hit means
    People with motor or cognitive disabilities rely on the browser filling in their own name, address and email. Without the attribute, autofill cannot do that reliably, and on checkout it means typing everything again.
    How to fix it
    Add the standard token: autocomplete="email", "name", "tel", "street-address", "postal-code", "username", "current-password" and so on.
    What it cannot see
    The match is on names in the markup, so an unusually named field can be missed or a false positive reported. We cannot tell whether the field really collects personal data.

Page structure

  • Serious

    Page does not declare its language

    deterministic

    html-lang-missing · Related to WCAG 3.1.1 Language of Page (A)

    What it looks for
    A missing, empty or whitespace-only lang attribute on the <html> element — and a document with no <html> element at all, which has no attribute to read.
    What a hit means
    Screen readers guess the language, and the guess is often wrong: English text read with a French pronunciation is close to unintelligible. It also affects translation tools and hyphenation.
    How to fix it
    Set it on the root element, e.g. <html lang="en">, or "en-GB", "de", "fr" as appropriate.
    What it cannot see
    We check that the attribute exists and looks like a language tag. We do not verify that it matches the text.
  • Minor

    Language code does not look like a valid language tag

    pattern match

    html-lang-invalid · Related to WCAG 3.1.1 Language of Page (A)

    What it looks for
    lang values that do not match a simple language-tag shape (e.g. lang="english", lang="EN_us_2").
    What a hit means
    An invalid tag is ignored, which puts the reader back in the guessing position above.
    How to fix it
    Use a BCP-47 tag: a two or three letter language code, optionally with a region, e.g. "en", "en-GB", "pt-BR".
    What it cannot see
    This is a shape check, not a registry lookup: a well-formed but non-existent code passes.
  • Serious

    Page has no <title>

    deterministic

    page-title-missing · Related to WCAG 2.4.2 Page Titled (A)

    What it looks for
    A document whose head contains no <title> element, or one whose text is empty or only whitespace. A <title> inside an inline SVG names that graphic rather than the page, so a page whose only <title> is an SVG's is reported here.
    What a hit means
    The title is the first thing a screen reader announces and the label used for the browser tab, bookmarks and search results. Without it, every page in a site sounds identical.
    How to fix it
    Add a unique <title> that names the page and the site, e.g. "Delivery options — Example Store".
    What it cannot see
    We check whether a title exists, whether its text is blank, and whether the document holds more than one title element (reported as its own finding). We cannot tell whether the title is descriptive, or whether other pages of the site share it.
  • Moderate

    Document contains more than one <title>

    deterministic

    page-title-duplicate · Related to WCAG 2.4.2 Page Titled (A)

    What it looks for
    More than one <title> element in the document head. A <title> inside an inline SVG names that graphic rather than the page, and is not counted here.
    What a hit means
    Browsers and assistive technology disagree about which one wins, so the page name can differ between users and tools.
    How to fix it
    Keep a single <title> in the document head.
    What it cannot see
    This is about duplicates in one page. Whether two different pages share a title is not something a single-page scan can see.
  • Moderate

    Duplicate id values in the page

    deterministic

    duplicate-id · Related to WCAG 1.3.1 Info and Relationships (A), 4.1.2 Name, Role, Value (A)

    What it looks for
    The same id attribute value used on more than one element the page renders. Markup inside <template> or <noscript> is never rendered, so ids there are not counted.
    What a hit means
    Ids are how labels, aria-labelledby, aria-describedby and skip links find their target. When an id is duplicated, those pointers resolve to the first match, which can attach a label or description to the wrong control.
    How to fix it
    Make ids unique. (Note: WCAG 2.2 retired the standalone parsing criterion that used to cover this, so treat it as a robustness and label-association problem rather than a criterion failure on its own.)
    What it cannot see
    Duplicates introduced by JavaScript after load are not visible to us.

Headings

  • Moderate

    Heading levels skip a level

    deterministic

    heading-level-skipped · Related to WCAG 1.3.1 Info and Relationships (A)

    What it looks for
    Headings in document order, skipping any the markup hides, where one heading's level jumps by more than one from the heading before it — e.g. <h2> followed by <h4>. A hidden <h3> between an <h2> and an <h4> is not counted, so that page is reported as an <h2> → <h4> jump.
    What a hit means
    Screen reader users navigate by heading level and use it as an outline of the page. A jump suggests content that is missing or mis-nested, and makes the outline harder to follow.
    How to fix it
    Use the next level down for the next section (h2 → h3). Pick the level for structure, not for the font size; size it with CSS.
    What it cannot see
    We can only judge the served markup. Component libraries that render headings of their own can produce jumps you did not write by hand.
  • Moderate

    Page has no <h1>

    pattern match

    h1-missing · Related to WCAG 1.3.1 Info and Relationships (A), 2.4.6 Headings and Labels (AA)

    What it looks for
    A page that has at least one heading the markup does not hide, but no <h1> among them. Headings the markup hides are not counted, and a page with no headings at all — or whose only headings are hidden — is not reported by this check.
    What a hit means
    The top-level heading is the quickest way to confirm which page you landed on, and the first stop for heading navigation.
    How to fix it
    Mark the main page heading up as an <h1> — usually one per page.
    What it cannot see
    Not a formal failure of WCAG on its own; it is a structural best practice that makes heading navigation work.
  • Minor

    Page has more than one <h1>

    pattern match

    h1-multiple · Related to WCAG 1.3.1 Info and Relationships (A)

    What it looks for
    More than one visible <h1> in the served HTML.
    What a hit means
    Multiple top-level headings blur the page outline, so heading navigation offers several equally-weighted entry points.
    How to fix it
    Keep one <h1> for the page and use <h2>–<h6> for everything below it. Sectioning elements can make several h1s technically valid, but one is easier to navigate.
    What it cannot see
    Legitimate in some sectioning and templating patterns; treat it as a point to review, not a defect.
  • Critical

    Button has no accessible name

    deterministic

    button-no-accessible-name · Related to WCAG 4.1.2 Name, Role, Value (A)

    What it looks for
    <button> elements, and submit/reset/button inputs, with no name from text, a nested image's alt, aria-label, aria-labelledby, title or value.
    What a hit means
    Screen reader users hear "button" with no label and cannot tell what it does — common on quantity steppers, carousels, close buttons and menu toggles.
    How to fix it
    Add text inside the button (visually hidden if the design shows an icon) or aria-label="Close the basket panel".
    What it cannot see
    As above: names added by client-side JavaScript are invisible to a static scan.

Landmarks

  • Moderate

    No <main> landmark

    deterministic

    main-landmark-missing · Related to WCAG 1.3.1 Info and Relationships (A), 2.4.1 Bypass Blocks (A)

    What it looks for
    A document with no <main> element and no element with role="main" that the markup does not hide, or with more than one such main landmark. A hidden or aria-hidden element is in the markup but is not a landmark, so it is neither a pass here nor one of the ones counted.
    What a hit means
    Landmarks are how screen reader users jump straight to the main content instead of tabbing through header, navigation and footer on every page.
    How to fix it
    Wrap the primary page content in a single <main> element that excludes repeated headers, navigation and footers.
    What it cannot see
    We count elements in the served HTML; how they are announced still depends on the browser and assistive technology pairing.

Embeds and media

  • Serious

    Frame has no title

    deterministic

    iframe-no-title · Related to WCAG 2.4.1 Bypass Blocks (A), 4.1.2 Name, Role, Value (A)

    What it looks for
    Visible <iframe> elements with no non-empty title attribute and no aria-label.
    What a hit means
    An untitled frame is announced as just "frame", so the person has no idea it is a payment form, a map or a video, and cannot decide whether to enter it. On checkout this is where people give up.
    How to fix it
    Add title="Payment, Stripe" or similar to each frame, describing its content rather than its technology.
    What it cannot see
    We can see the title attribute, not what the frame actually renders — content inside a frame, including its own accessibility problems, is not scanned here.
  • Serious

    Video with no captions track

    deterministic

    video-no-captions · Related to WCAG 1.2.2 Captions (Prerecorded) (A)

    What it looks for
    <video> elements with no <track kind="captions"> and no <track kind="subtitles">, other than a video marked muted that has no controls.
    What a hit means
    Deaf and hard-of-hearing users, and anyone watching muted in a public place, cannot access the audio content at all.
    How to fix it
    Publish a captions file (WebVTT) and reference it: <track kind="captions" src="video.en.vtt" srclang="en" label="English">. Captions must cover the speech, not just the dialogue intent.
    What it cannot see
    We cannot tell whether a video has audio. A video marked muted with no controls is treated as a background flourish and not reported; a silent video that is not muted, and any video with controls, is reported even though it may need nothing.

Tables

  • Serious

    Table has data cells but no header cells

    deterministic

    table-no-header-cells · Related to WCAG 1.3.1 Info and Relationships (A)

    What it looks for
    A <table> containing one or more <td> cells and no <th> cells at all.
    What a hit means
    Screen readers announce a data cell together with its header. With no headers, a price or a delivery estimate is read as a bare number with no idea what it refers to — and the data table is exactly where that costs money.
    How to fix it
    Mark the heading row (and column, if it has one) up with <th scope="col"> or <th scope="row">. If the markup is only used for layout, do not use a table for it.
    What it cannot see
    We check for the presence of header cells, not whether each header correctly describes its row or column. We count any <th> inside the table, including one belonging to a table nested within it, and we do not report a table marked role="presentation" or role="none".

Viewport

  • Serious

    Zoom or pinch-to-zoom is disabled

    deterministic

    zoom-disabled-in-viewport · Related to WCAG 1.4.4 Resize Text (AA)

    What it looks for
    A viewport meta tag with user-scalable=no or user-scalable=0, or with a maximum-scale value below 2.
    What a hit means
    People with low vision zoom the page to read it. Blocking pinch-zoom takes away the one remedy they have on a phone, and it is a frequent cause of complaints about e-commerce sites.
    How to fix it
    Remove the restriction, e.g. <meta name="viewport" content="width=device-width, initial-scale=1">. If maximum-scale is used to stop an input zooming on focus, fix the input font size instead.
    What it cannot see
    We read the meta tag in the served HTML. A restriction added by script later is not caught.

ARIA

  • Moderate

    Unrecognised ARIA role

    deterministic

    aria-role-unknown · Related to WCAG 4.1.2 Name, Role, Value (A)

    What it looks for
    role attributes whose tokens are not names in the WAI-ARIA role list (we accept a token if any of its space-separated values is a known role).
    What a hit means
    An invalid role is ignored, so the element is announced as whatever it happens to be — a <div role="buton"> is still a plain div, and the intended behaviour is announced to nobody.
    How to fix it
    Correct the role name, or better, use the native element that already carries it: a button role belongs on <button>.
    What it cannot see
    We validate against the published role list, not against which roles are legal on which elements, and we do not check required states and properties.
  • Serious

    ARIA or label reference points at a missing id

    deterministic

    aria-reference-broken · Related to WCAG 1.3.1 Info and Relationships (A), 4.1.2 Name, Role, Value (A)

    What it looks for
    aria-labelledby, aria-describedby, aria-controls, aria-owns, aria-activedescendant, aria-flowto, aria-details or aria-errormessage listing an id that does not exist in the page. A <label for> pointing at a missing id is reported separately, as its own check.
    What a hit means
    The association silently does nothing. The control keeps its label in the design and loses it in the accessibility tree, which is the worst case: it looks fine to the developer and is broken for the user.
    How to fix it
    Fix the id, or remove the reference. Ids are case-sensitive and must be unique — a duplicated id resolves to the first match (see the duplicate id check).
    What it cannot see
    A missing target may be injected by JavaScript after load, in which case this is a false positive.
  • Serious

    Region hidden from assistive technology contains focusable elements

    deterministic

    aria-hidden-contains-focusable · Related to WCAG 1.3.1 Info and Relationships (A), 4.1.2 Name, Role, Value (A)

    What it looks for
    Elements with aria-hidden="true" that contain a link with href, a button, a form control, or an element whose tabindex is 0 or more. Disabled controls, hidden inputs and elements with a negative tabindex are not counted.
    What a hit means
    The content is removed from the accessibility tree while still reachable by keyboard. A keyboard or screen reader user can land on a control that is announced as nothing — a classic screen-reader-only trap.
    How to fix it
    Hide in a way that also removes focusability (the hidden attribute, display:none) or take those controls out of the tab order with tabindex="-1" and disable them.
    What it cannot see
    We use the markup's idea of focusable. Whether something is actually reachable also depends on CSS and scripts we do not run.
  • Moderate

    Positive tabindex changes the focus order

    deterministic

    tabindex-positive · Related to WCAG 2.4.3 Focus Order (A)

    What it looks for
    Any element with a tabindex value greater than 0.
    What a hit means
    A positive tabindex jumps the element to the front of the tab order, ahead of everything before it in the page. On a real page this produces a keyboard path that no longer matches what is on screen.
    How to fix it
    Use tabindex="0" or "-1" only. Put the elements in the right order in the markup and let the browser follow it.
    What it cannot see
    Removing a positive tabindex can expose a genuine ordering problem elsewhere; testing with a keyboard is still needed.

Severity labels used on this page: Critical, Serious, Moderate, Minor. This page was run through the same scanner it documents on 7 October 2026 — 27 checks, no findings — and our own site is not on the monitoring schedule today.