# Testing your site with a screen reader in 20 minutes

> Automated checks find about a third of accessibility problems. A scripted 20-minute pass with VoiceOver or NVDA finds much of the rest; here are the keys, the script and the fixes.

Updated 2026-09-25 · Accessibility · HTML version: https://getreport.app/guides/testing-with-a-screen-reader

You do not need to be an accessibility specialist to test a page with a screen reader. You need one that is already on your computer or free to download, about ten keystrokes, and a script that tells you what to listen for. This guide gives you all three. After 20 minutes you will have a list of concrete problems on one page, each with the fix, and a much better sense of what your site sounds like to the people who cannot see it.

## Quick answer

- **Mac**: VoiceOver is built in. Cmd+F5 turns it on, Safari works best with it.
- **Windows**: NVDA is free. Use it with Firefox or Chrome.
- **Phones**: VoiceOver on iPhone, TalkBack on Android, both under Settings → Accessibility.
- Run the [accessibility checker](https://getreport.app/tools/accessibility-checker) first so you are not spending your 20 minutes on what a machine finds in seconds.
- Then, in order: list the headings, list the landmarks, Tab through the page, check the images, fill in a form, and complete the page's main task.
- Write down what you heard, what you expected and which element it was.

## Why a manual pass matters

Automated tools, including getReport's, catch roughly 30–40 % of WCAG problems. They are good at facts a machine can read from the page: this image has no `alt`, this input has no label, this text is below 4.5:1. They cannot judge meaning. An image with `alt="image"` passes. A heading that says "Welcome" passes. A cookie banner that grabs keyboard focus and never lets go passes. A button that adds a product to the cart without telling anyone passes.

A screen reader pass catches those, because you hear the page as a blind visitor does: in a line, one piece at a time, in source order. Twenty minutes is enough on one page because most problems are template problems. If the product page's gallery traps keyboard focus, it does so on every product. Test one page per template (home, category, product, article, checkout) over a few days and you have covered most of the site.

## How getReport checks it

> **Free tool:** [Accessibility checker (WCAG 2.2)](https://getreport.app/tools/accessibility-checker): axe-core violations by impact, colour contrast, landmarks, form labels, link names, tap targets and zoom — measured on the rendered page, with the selectors to fix.

The checker renders the page in Chromium, runs axe-core, and reads a few structural signals from the rendered page: which landmarks exist and whether a skip link is among the first focusable elements. These are the findings that tell you what the screen reader pass will sound like before you start (the rest of what the machine reports is covered in [fixing the top accessibility checker findings](https://getreport.app/guides/accessibility-checker-top-findings)):

> **Check: Page landmarks are in place.** Screen reader users jump between header, navigation, main content and footer instead of reading top to bottom. Without these landmarks they have to listen to the whole page to find the content.
>
> 1. Wrap the page content in <main>, the site header in <header>, the menu in <nav> and the bottom area in <footer>.
> 2. If the theme uses <div id="content">, change the tag rather than adding a wrapper; most page builders offer semantic wrappers in their settings.

![The landmarks finding on a page without main or navigation landmarks: the title names what is missing and the technical line counts the main, header, nav and footer elements found](https://getreport.app/guides/img/testing-with-a-screen-reader/landmarks.webp "A page built only from div elements has no landmarks to jump between, so a screen reader user has to listen from the top.")

The landmarks check counts `<main>`, `<header>`, `<nav>` and `<footer>` and their ARIA role equivalents. It reports a page without `<main>`, and a page with none of header, navigation or footer.

> **Check: A skip link leads to the main content.** Keyboard users tab through every menu item on every page before they reach the content. A "Skip to content" link, visible on focus, takes them there in one keystroke.
>
> 1. Add <a href="#main" class="skip-link">Skip to content</a> as the first element in <body> and give <main> the id "main".
> 2. Hide it off-screen until it receives focus; do not use display none, which removes it from the tab order.

The skip link check looks at the first three focusable elements for a same-page link whose text or `aria-label` contains the word "skip". A skip link written in another language ("Preskoči na sadržaj") can be missed, so confirm it with the Tab key.

> **Check: Heading levels follow a logical order.** Headings are the page's outline. When it jumps from H1 to H3, screen readers and search engines assume a level of content is missing, and the structure is harder to follow.
>
> 1. Use H2 for each main section and H3 for details inside it; never skip a level going down.
> 2. Pick heading levels by structure and let CSS decide the size. In page builders, change the "HTML tag" of the heading block.

> **Check: Every link and button has an accessible name.** Icon-only links and buttons are read out as "link" or "button" with nothing else, so screen reader users cannot tell the cart from the search. Search engines also use link text to understand the target page.
>
> 1. Add visible text, or aria-label="…" on the link or button, that says where it goes or what it does.
> 2. For icon buttons, put the text inside the button and hide it visually with a screen-reader-only class.

> **Check: Every image has alternative text.** Alt text is what screen readers speak and what appears when an image does not load. Without it, product photos and infographics are silent for blind visitors and invisible to image search.
>
> 1. Add alt="…" describing what the image shows, in one sentence, to every informative image.
> 2. Use alt="" (empty) for purely decorative images so screen readers skip them.

> **Check: The natural tab order is not changed.** Positive tabindex values force keyboard focus to jump around the page in an order that does not match what is on screen, which is disorienting for keyboard and switch users.
>
> 1. Remove tabindex values above 0; use tabindex="0" to make custom controls focusable and tabindex="-1" for focus targets.
> 2. Order elements in the HTML the way they appear on screen so the natural tab order is right.

The tab order finding only appears when something changes the order, usually a positive `tabindex`. A real keyboard trap (focus goes in and cannot get out) cannot be detected by any automated tool; that is one of the things the manual pass is for.

## Step by step

### 1. Set up (2 minutes)

**VoiceOver on a Mac.** Press Cmd+F5 (on some keyboards Fn+Cmd+F5) to turn it on and off. The VoiceOver key, written VO, is Control+Option held together. Open the page in Safari, and in Safari → Settings → Advanced, turn on "Press Tab to highlight each item on a webpage"; without it, Tab skips links.

**NVDA on Windows.** Download it free from NV Access and install it. The NVDA key is Insert (or Caps Lock, if you choose the laptop layout). Open the page in Firefox or Chrome. NVDA+Q quits.

In both, press Control to stop speech at any time. Slow the speech rate down at first; speed comes with practice.

The keystrokes you need:

| Action | VoiceOver (Mac) | NVDA (Windows) |
| --- | --- | --- |
| Read from here | VO+A | NVDA+Down arrow |
| Next / previous item | VO+Right / VO+Left | Down / Up arrow |
| List headings, links, landmarks | VO+U (rotor), Left/Right to switch lists | NVDA+F7 (elements list) |
| Next heading | VO+Cmd+H | H (1–6 for a level) |
| Next landmark | via the rotor's Landmarks list | D |
| Next form field | VO+Cmd+J | F |
| Next focusable element | Tab | Tab |
| Activate | VO+Space | Enter |

On an iPhone (Settings → Accessibility → VoiceOver), swipe right and left to move, double-tap to activate, and turn two fingers like a dial to open the rotor. On Android, TalkBack uses the same swipe and double-tap gestures; its built-in tutorial shows the gestures for your version.

### 2. Headings list (3 minutes)

Open the rotor (VO+U) or the elements list (NVDA+F7) and choose Headings. This list is how many screen reader users skim a page, the way sighted users skim bold text. Check:

- There is one H1, and it says what the page is ("Alpina Pro trekking shoe", not "Welcome").
- The headings read like a table of contents for the page, in order.
- No level is skipped going down (H2 then H4).
- No text that looks like a heading is missing from the list (bold paragraphs styled as headings), and nothing is in the list that is not a heading (a whole promo box marked up as H2).

### 3. Landmarks list (3 minutes)

Switch the list to Landmarks. A well-built page has a banner (the header), one or more navigation regions, one main, and a content info region (the footer). Press Enter on "main": you should land at the start of the content, not in the middle of the menu. Two navigation regions should have different names ("Main", "Footer"), otherwise they both sound like "navigation".

### 4. Tab through the page (4 minutes)

Press Tab from the top of the page and keep going. Look and listen:

- **First Tab**: is there a "Skip to content" link, and does it work?
- **Focus is visible** on every stop: you can see where you are without guessing.
- **Order matches the screen**: left to right, top to bottom. No jumps to the footer and back.
- **Every link and button says what it does** when heard on its own: "Add to cart", not "button"; "Size guide", not "click here".
- **Nothing invisible gets focus**: items of a closed mobile menu or a hidden slider panel should not be Tab stops.
- **No traps**: a cookie banner, a chat widget or a video player should let you Tab out, and Escape should close pop-ups.

### 5. Images (2 minutes)

Move through the page item by item (or jump between images with G in NVDA; VO+Cmd+G in VoiceOver). Product photos and infographics should be described in a sentence. Decorative images (dividers, background textures) should be silent. File names ("IMG_4412.jpg"), "image" and "photo" are failures, even though a machine counts them as alt text.

### 6. One form (3 minutes)

Pick the newsletter box or the contact form. Tab into each field and listen: each should announce its label, its type, and "required" if it is. Submit it empty. Is the error announced, and can you get to it? Is it clear which field it belongs to? The fixes are in [form labels: every input needs one](https://getreport.app/guides/form-labels-every-input-needs-one).

### 7. The main task (3 minutes)

Do the one thing the page exists for, with the keyboard and screen reader only: add a product to the cart, book a slot, download the brochure. Choose a size from the size selector. Press "Add to cart". Did you hear anything? A cart that updates silently leaves a blind visitor unsure whether it worked. Does a pop-up take focus, and can you close it?

### 8. Write it down as you go

For each problem, one line is enough. The format that gets fixed fastest:

```text
Page: https://example.com/shoes/alpina-pro/
Tool: NVDA 2026.1 + Firefox
What I did: Tabbed to the size selector, pressed Down arrow
What I heard: "combo box" (no label)
Expected: "Size, combo box, 42"
Element: select#size (product form)
Impact: blocks buying a specific size
```

A list like this, plus the getReport link for the automated findings, is a ticket a developer can act on without a meeting.

## Fixing the four problems you will hear most

### Landmarks

Replace the generic containers of the page layout with the semantic elements. This is usually one template file (the theme's `header.php` and `footer.php` in WordPress, `theme.liquid` in Shopify, the layout component elsewhere). See the [landmarks learn page](https://getreport.app/learn/landmarks) for the details.

```html
<body>
  <a class="skip-link" href="#main">Skip to content</a>
  <header>
    <a href="https://getreport.app/"><img src="https://getreport.app/logo.svg" alt="Example Shop home"></a>
    <nav aria-label="Main">…</nav>
  </header>
  <main id="main" tabindex="-1">
    <h1>Alpina Pro trekking shoe</h1>
    …
  </main>
  <footer>
    <nav aria-label="Footer">…</nav>
  </footer>
</body>
```

### A skip link

The link is the first element in `<body>`, hidden off-screen until it receives focus, so sighted keyboard users see it too:

```css
.skip-link {
  position: absolute;
  left: 1rem;
  top: -3rem;
  padding: 0.5rem 1rem;
  background: #1f1f1f;
  color: #ffffff;
  z-index: 1000;
}
.skip-link:focus { top: 1rem; }
```

Do not hide it with `display: none`; that removes it from the tab order entirely. `tabindex="-1"` on `<main>` lets browsers move focus there reliably when the link is used. The [skip links learn page](https://getreport.app/learn/skip-links) covers the variations.

### Headings

One H1 per page, H2 for each section, H3 inside an H2. Choose the level by structure and let CSS set the size. In page builders, every heading widget has an "HTML tag" setting separate from its style; that is where an H4 that should be an H2 gets fixed.

### Link and button text

Every link and button needs words that make sense on their own. Icon buttons get visually hidden text; repeated "Read more" links get the target added:

```html
<button type="button" class="cart-button">
  <svg aria-hidden="true" focusable="false"><use href="#icon-cart"></use></svg>
  <span class="visually-hidden">Cart, 2 items</span>
</button>

<a href="https://getreport.app/blog/waterproof-boots/">Read more<span class="visually-hidden">: how to waterproof boots</span></a>
```

The `.visually-hidden` class is in the form labels guide. For a cart that updates without a page load, add a status region that the script fills in; screen readers announce its text when it changes:

```html
<div role="status" class="visually-hidden" id="cart-status"></div>
<script>
  // after a successful add-to-cart request
  document.getElementById('cart-status').textContent = 'Alpina Pro, size 42, added to cart. 2 items in cart.';
</script>
```

## Platform notes

### WordPress

Most landmark, skip-link and heading problems come from the theme or the page builder, not the content. The default themes and themes tagged "accessibility-ready" in the WordPress theme directory have landmarks and a skip link; many commercial themes and builder layouts do not. In Elementor and similar builders, set the section or container's HTML tag to `header`, `main`, `nav` or `footer` in its layout settings, and fix heading levels in each heading widget's "HTML tag".

### Shopify

Dawn and most current Theme Store themes have landmarks and a skip link in `layout/theme.liquid`. Problems usually come from apps: pop-ups that do not trap and release focus properly, review widgets with unlabelled star buttons, and cart drawers that update silently. Test with the apps switched on, because that is what customers get.

## Verify

- Run the accessibility checker again: landmarks and skip link pass, and the link names, image alt and heading order findings are clear or down to items you chose to accept.
- Repeat the 20-minute script on the same page. The headings list reads like a table of contents, the landmarks list has a main, and the main task can be completed without looking at the screen.
- Do the same pass on the next template. Problems shared by every template are fixed once in the theme.
- If the pass turned up mostly faint text and invisible focus rings, [colour contrast: fixing the most common finding](https://getreport.app/guides/colour-contrast-fixing-the-most-common-finding) has the fixes.

## Common mistakes

- **Testing with the mouse still in hand.** Clicking moves the screen reader's position and hides keyboard problems. Put the mouse away for the full 20 minutes.
- **Pairing the screen reader with an unusual browser.** Each screen reader is used, and tested, mostly with particular browsers: VoiceOver with Safari, NVDA with Firefox or Chrome. Other pairings show bugs that most real users never meet.
- **Adding `aria-label` everywhere after the first test.** It replaces visible text, so voice control users cannot say what they see. Fix the HTML first: real labels, real headings, real buttons.
- **Adding `role="main"` to a `<div>` inside another `<main>`.** Two mains confuse the landmark list. One per page.
- **Treating one pass as done.** The site changes, apps update, a new banner arrives. Re-run the checker after each release, and repeat the manual pass when a template changes.
