a11y-repair

Test with VoiceOver

VoiceOver is the screen reader built into every Mac, iPhone and iPad. A screen reader reads the page aloud and lets a person move through it with keys or touch gestures. The scanner simulates what a screen reader announces. This guide shows how to check the page with VoiceOver itself: by hand on a Mac, by hand on an iPhone, and automatically on a Mac, where a script records every phrase VoiceOver speaks. The commands come from Apple's VoiceOver documentation, listed under Sources.

How to read the key namesVO means Control and Option held together, or Caps Lock. VO-Right Arrow means: hold Control and Option, then press Right Arrow. Keys that name a function key, such as F8, also need Fn on most Mac keyboards.

The three ways to test

PartWhat you needWhat you get
1. By hand on a MacA Mac with Safari, and the checklist from your scan.A checklist marked row by row: what VoiceOver said at each Tab stop, heading and landmark, compared with what the scanner expected.
2. By hand on an iPhone or iPadAn iPhone or iPad with Safari, and the checklist from your scan at phone width.The same check with touch gestures, on the phone layout of the page.
3. Automatically on a MacA Mac where you can change security settings, Terminal, Node.js and the runner script.A file that lists every phrase VoiceOver spoke next to the phrases the scanner's simulation predicted for the same page.

Part 1: set up VoiceOver on a Mac

Do these once. None of them change anything outside Safari and VoiceOver.

StepDo thisWhat it does
1In Safari, choose Safari > Settings, click Advanced, and turn on "Press Tab to highlight each item on a webpage".Tab then moves to links and buttons as well as form fields, the way a keyboard user expects.
2Press Command-F5. On a keyboard with Touch ID, you can instead hold Command and press Touch ID 3 times quickly.Turns VoiceOver on. The same keys turn it off. The first time, VoiceOver may show a welcome screen; close it or follow it.
3Press VO-Fn-Command-F10.Shows or hides the caption panel, which prints what VoiceOver says. Leave it on: you can compare the printed words with the checklist.
4Optional: press VO-Fn-Command-F8.Opens Apple's VoiceOver tutorial, which teaches the basic keys in a few short lessons.
5Press Control at any time.Stops VoiceOver speaking. Press it again to resume.

Part 1: test the page by hand

Open the checklist for your scan in a second window. It lists every Tab stop, heading and landmark on the page with what the scanner expects a screen reader to announce. Scan the page first; the checklist is built from the scan. For each row, choose As expected, Different or Not heard, and type what you heard when it differs.

StepDo thisCheckWCAG criterion
1With VoiceOver on, open the page in Safari.VoiceOver speaks the page title, and the title names the page.2.4.2 Page Titled
2Press Tab to move through the page, and Shift-Tab to go back. Compare each announcement with its row in the checklist's Tab stops table.Each stop says a name that matches the visible label, a role (link, button, checkbox) and any state (expanded, checked, selected). The order follows the page. You can see where focus is at every stop.4.1.2 Name, Role, Value
2.4.3 Focus Order
2.4.7 Focus Visible
3Press VO-U to open the rotor, a menu of lists. Press Left Arrow or Right Arrow until you reach Headings. Up Arrow and Down Arrow move through the list, Return jumps to a heading, Escape closes the rotor.Every section title appears, at a level that matches the page outline. Text that only looks like a heading is missing from the list; that is a failure.1.3.1 Info and Relationships
2.4.6 Headings and Labels
4In the rotor, move to the Landmarks list. Landmarks are the named regions of a page: banner (the header), navigation, main, contentinfo (the footer).The main content is a main landmark. When there are 2 navigation regions, each has its own name.1.3.1 Info and Relationships
2.4.1 Bypass Blocks
5In the rotor, move to the Links list.Read alone, each link name says where it goes. "Learn more" 6 times over fails unless the text around each one explains it.2.4.4 Link Purpose
6Press VO-Command-J to move from one form control to the next. Submit a form with a required field left empty.Each field says its label and whether it is required. After the failed submit, VoiceOver reads the error message, and the message names the field.3.3.2 Labels or Instructions
3.3.1 Error Identification
7Open each menu, drawer and dialog with VO-Space, then press Escape.VoiceOver says the menu is expanded or that a dialog opened. Focus moves into the dialog and stays there. Escape closes it and puts focus back on the button that opened it.4.1.2 Name, Role, Value
2.4.3 Focus Order
2.1.2 No Keyboard Trap
8Do the actions that change part of the page: add a product to the cart, run a search, apply a filter.VoiceOver announces the result, such as "Added to cart" or "24 results", without you moving to it.4.1.3 Status Messages
9Go to the top and press VO-Right Arrow through the page, item by item.Informative images are read with a description of what they show. Decorative images are skipped. No item reads as a file name or as "image" alone.1.1.1 Non-text Content
10In the checklist, click Download checklist results. Turn VoiceOver off with Command-F5.The file holds each row with your mark and note. Keep it with the scan report.None

Part 2: test on an iPhone or iPad

With VoiceOver on, one tap selects an item and a double tap activates it. Use the phone-width checklist for your scan, and repeat the checks from Part 1, steps 1 to 9.

StepDo thisWhat it does
1Go to Settings > Accessibility > VoiceOver and turn it on, or ask Siri to "Turn on VoiceOver".Turns VoiceOver on. Turn it off the same way.
2Optional: in Settings > Accessibility > VoiceOver, open VoiceOver Practice.Lets you try the gestures below.
3Open the page in Safari. Swipe right to move to the next item, left for the previous one.VoiceOver reads each item in page order, the same as VO-Right Arrow on a Mac.
4Turn 2 fingers on the screen as if turning a dial, to choose Headings, Landmarks, Links or Form Controls. Then swipe down for the next one of that kind, up for the previous one.This is the rotor. It covers the heading, landmark, link and form checks.
5Swipe up with 2 fingers.Reads the whole page from the top. A 2-finger tap stops and resumes speech.
6Swipe up or down with 3 fingers.Scrolls one screen.

Part 3: record VoiceOver automatically

The runner script opens the page in a WebKit window (the engine inside Safari), starts VoiceOver, and moves through the page with VoiceOver's own next-item command, 80 times by default. It saves every phrase VoiceOver speaks. Then it builds the scanner's simulation of the same page and saves both lists in one file. It uses Guidepup, an open-source library that controls screen readers from code.

Before you run itWhile the runner works, VoiceOver speaks aloud and takes over the Mac's keyboard focus. Do not type or click until it finishes. The runner stops itself after 6 minutes. The setup below changes security settings; the last table shows how to undo each one.

Settings the runner needs

SettingWhereWhyUndo
Allow VoiceOver to be controlled with AppleScriptOpen VoiceOver Utility (in Applications > Utilities, or press VO-Fn-F8 while VoiceOver is on). On the General tab, tick the setting.Lets a script start VoiceOver and send it commands.Untick the same setting.
Terminal in the Accessibility listSystem Settings > Privacy & Security > Accessibility. Click +, add Terminal (or the app you run the script from), enter your administrator password, and turn it on.Lets apps started from Terminal control the computer, which the runner needs to send VoiceOver its commands.Select Terminal in the list and click −.
Automation promptOn the first run, macOS may ask whether Terminal may control VoiceOver. Click Allow.Same reason as above, asked separately by macOS.System Settings > Privacy & Security > Automation: under Terminal, turn off the item you allowed.

Guidepup also has a setup tool, npx @guidepup/setup --macos-ignore-tcc-db, which writes the 3 settings below. The runner does not need it if you made the changes above by hand. Without the --macos-ignore-tcc-db option, the tool also tries to edit the macOS permissions database directly, which works only with System Integrity Protection turned off; do not turn it off for this.

Setting the tool writesWhat it doesUndo in Terminal
com.apple.VoiceOver4/default SCREnableAppleScript = trueThe AppleScript setting from the first table.defaults delete com.apple.VoiceOver4/default SCREnableAppleScript
com.apple.VoiceOverTraining doNotShowSplashScreen = trueSkips the VoiceOver welcome screen that can appear when VoiceOver starts.defaults delete com.apple.VoiceOverTraining doNotShowSplashScreen
com.apple.HIToolbox AppleDictationAutoEnable = falseTurns off the macOS setting that turns dictation on automatically.defaults delete com.apple.HIToolbox AppleDictationAutoEnable

Run it

StepDo thisWhat happens
1Install Node.js from nodejs.org. Get the runner: download link, set at launch. Open Terminal in its folder and run npm install, then npx playwright install webkit chromium.Installs Guidepup, Playwright (a library that controls a browser from code) and the 2 browser engines the runner uses.
2Make the setting changes above. Turn VoiceOver off, and quit apps that play sound so you can hear VoiceOver.The runner starts VoiceOver itself.
3Run npx tsx scripts/voiceover-run.mjs https://example.com/page --steps 80 --i-set-up-voiceover with your page address. --steps sets how many items to move through. --i-set-up-voiceover confirms you made the setting changes; the runner refuses to start without it.A WebKit window opens, VoiceOver starts and reads the page item by item. VoiceOver stops and the window closes at the end.
4Open the file the runner names at the end, voiceover-<site>-<number>.json, in the same folder.heard lists what VoiceOver said, in order. simulated lists what the scanner predicted. The two lists may not line up row by row, because VoiceOver can group or split items differently. Look for names that are missing or different.
5Undo the settings, using the Undo columns above.The Mac is back as it was, apart from Node.js and the runner folder, which you can delete.

If the run stops with a permission error, check the first 2 rows of the settings table. If VoiceOver does not start, check that the AppleScript setting is ticked.

Sources

DocumentUsed for
Turn VoiceOver on or off on Mac (Apple)Part 1, step 2
VoiceOver general commands on Mac (Apple)Caption panel, tutorial, VoiceOver Utility keys
Use the VoiceOver rotor on Mac (Apple)Part 1, steps 3 to 5
VoiceOver web commands on Mac (Apple)Part 1, steps 6 and 9
Change Advanced settings in Safari on Mac (Apple)Part 1 setup, step 1
Use VoiceOver gestures on iPhone (Apple)Part 2
Control VoiceOver using the rotor on iPhone (Apple)Part 2, step 4
Manual VoiceOver setup (Guidepup)Part 3 settings
Guidepup setup tool, source code (Guidepup)The 3 settings the setup tool writes