Our own app · published unedited · measured 16 August 2026

SuppLab

Audit ID
bd1bf437-a5d6-4f32-bd47-f336806d69c5
Rule catalog
v2.5.0
Schema
v1.2
Build digest
sha256:ab9221d7806adadda9bbea971c5a50b0ab6e5e303c0b9d93df90c806c580e658
readyaudit-bundle-sha256/1 · SuppLab.app · 14 files · 21186470 bytes

This report is our own app, published unedited — verify the bundle digest yourself. It was measured on 16 August 2026. The crawl has changed since: it no longer attempts to pass through a system permission sheet, so the engine running today reaches fewer screens on this same build. A re-audit with the current engine is in progress and will replace this report. SuppLab on the App Store, and how to check the digest: download the build, run readyaudit-package verify over it, and compare the hash with the one printed above. This report previously carried a line reading “This report is what two independent audits of that artifact agreed on.” That line was wrong. A defect in our convergence mechanism let one audit's measurement be read twice instead of two audits being performed. The run directory was keyed on part of the audit id rather than all of it, so the second complete audit inherited the first one's directory, could not start its test runner at all, and read the first one's accessibility dumps as its own.The claim was withdrawn from the document the same day it was found, the mechanism now requires each run to name the dumps it read, and a re-audit is in progress. Found 2026-08-25. Every report this engine produced with a convergence block. It affected 4 of our reports. Every number below was measured 3 times per condition, which is unaffected — see the method.

findings at 84.2% coverage
20 findings, at 84.2% coverage

IOS v1.0

  • 1 critical
  • 9 major
  • 10 minor

15/24 runs · 1 tasks × 8 variants

84.2% coverage · 499 checks · 257 pass · 53 fail

Listing not live yet — what a credit costs

Interactive PDF export lives in the Mac app.

No category median on this report. That row appears once a category has at least 20 completed audits, and the projection always excludes the audit being reported — otherwise the first customer in a category would be shown their own result as the bar. While the readiness score is in shadow (Karar 81) this row does not appear at all: a median is a score belonging to other apps, and we do not put a number in front of a customer that we decline to print for the app in front of us.

Exposure Not legal advice

1 unresolved critical findings map to obligations under:

  • WCAG 1.4.4
  • EN 11.1.4.4

Scope was not declared for this audit, so no EU penalty range is shown as a figure for this app. Whether the Act reaches it turns on two facts nobody has stated: a service in an Article 2(2) sector sold to EU consumers, from a company above the microenterprise threshold.

If both hold, the maxima reported by member states are Germany €100,000 (per non-compliant product); France €50,000 (plus repeat / additional obligations); Italy up to 5% of turnover (proportionate to revenue).

United States · ADA $25k–$75k+ reported per-suit settlement range

Reported figures, subject to national implementation and change. This is a technical readiness perspective, not legal advice — confirm exposure with counsel.

Coverage

Every active rule, on every screen the crawl reached, with the result. Published beside the finding count on purpose — one number is what we found, the other is how much of the target we actually reached.

84.2%

Checks
499
Pass
257
Fail
53
Not applicable
110
Not testable
79
Rules active
21 / 74
Coverage matrix: 21 rules by 18 screens, each cell a verdict.
Rule Onboarding stepOnboarding step 2Onboarding step 3Your BaselinePermission promptTodaySettingsLibraryStackAnalyticsPaywallOmega-3 (Fish Oil)Log SupplementCompact phone screenScenario T1 · OnboardingScenario T2 · Core navigationScenario T3 · Sign-inScenario T4 · Conversion
AP-LBL-001 Interactive element has no accessibility label WCAG 4.1.2 A EN 11.4.1.2 Pass Pass Fail Pass Pass Pass Fail Pass Pass Pass Pass Pass Pass Not testable Not evaluated Not evaluated Not evaluated Not evaluated
AP-LBL-002 Decorative image exposed to assistive technology WCAG 1.1.1 A EN 11.1.1.1 Pass Pass Pass Pass Not applicable Pass Pass Pass Pass Pass Pass Pass Pass Not testable Not evaluated Not evaluated Not evaluated Not evaluated
AP-LBL-004 Visible label text is not contained in the accessibility name WCAG 2.5.3 A EN 11.2.5.3 Not testable Not testable Not testable Not testable Not testable Pass Pass Pass Not testable Not applicable Pass Not testable Not testable Not testable Not evaluated Not evaluated Not evaluated Not evaluated
AP-LBL-005 Accessibility label repeats the element's role not scored Pass Pass Pass Pass Pass Pass Pass Pass Pass Pass Pass Pass Pass Not testable Not evaluated Not evaluated Not evaluated Not evaluated
AP-LBL-006 Link or button purpose is not determinable from its name WCAG 2.4.4 A EN 11.2.4.4 Pass Pass Pass Pass Pass Pass Pass Pass Pass Pass Pass Pass Pass Not testable Not evaluated Not evaluated Not evaluated Not evaluated
AP-STA-001 Interactive element exposes no role or trait WCAG 4.1.2 A EN 11.4.1.2 Pass Pass Pass Pass Pass Pass Pass Pass Pass Pass Pass Not testable Not testable Not testable Not evaluated Not evaluated Not evaluated Not evaluated
AP-STA-004 Disabled control does not expose its disabled state WCAG 4.1.2 A EN 11.4.1.2 Not testable Not testable Not testable Not testable Not testable Not testable Not testable Not testable Not testable Not testable Not testable Not testable Not testable Not testable Not evaluated Not evaluated Not evaluated Not evaluated
AP-STA-005 Adjustable control exposes no value or adjustment actions WCAG 4.1.2 A EN 11.4.1.2 Not applicable Not applicable Not applicable Not applicable Not applicable Not applicable Fail Not applicable Not applicable Not applicable Not applicable Not applicable Not applicable Not testable Not evaluated Not evaluated Not evaluated Not evaluated
AP-STR-002 Accessibility reading order does not match the meaningful sequence WCAG 1.3.2 A EN 11.1.3.2 Fail Fail Fail Pass Pass Pass Fail Pass Pass Pass Pass Fail Fail Not testable Not evaluated Not evaluated Not evaluated Not evaluated
AP-STR-007 Screen exposes no accessibility elements at all WCAG 1.3.1 A EN 11.1.3.1 Pass Pass Pass Pass Pass Pass Pass Pass Pass Pass Pass Pass Pass Not testable Not evaluated Not evaluated Not evaluated Not evaluated
AP-DYN-001 Content clipped or truncated at large Dynamic Type WCAG 1.4.4 AA EN 11.1.4.4 Not applicable Not applicable Not applicable Not applicable Not applicable Not applicable Not applicable Not applicable Not applicable Not applicable Not applicable Not applicable Not applicable Not testable Not evaluated Not evaluated Not evaluated Not evaluated
AP-TGT-001 Touch target smaller than 44pt WCAG 2.5.8 AA Pass Fail Fail Fail Pass Fail Fail Fail Fail Pass Fail Pass Fail Not testable Not evaluated Not evaluated Not evaluated Not evaluated
AP-TGT-006 Adjacent targets overlap or sit inside each other's spacing allowance WCAG 2.5.8 AA Not applicable Pass Pass Pass Not applicable Pass Fail Pass Pass Pass Pass Pass Pass Not testable Not evaluated Not evaluated Not evaluated Not evaluated
AP-FRM-001 Input field has no label or instruction WCAG 3.3.2 A EN 11.3.3.2 Not applicable Not applicable Not applicable Not applicable Not applicable Not applicable Fail Pass Not applicable Not applicable Not applicable Not applicable Pass Not testable Not evaluated Not evaluated Not evaluated Not evaluated
AP-TRP-002 Task cannot be completed with VoiceOver voiceover Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Pass Not evaluated Not evaluated Not evaluated
AP-TRP-001 Interaction trap: element cannot be dismissed or escaped with assistive tech WCAG 2.1.2 A EN 11.2.1.2 voiceover Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Pass Pass Not evaluated Pass
AP-NAV-001 Repeated navigation is not in a consistent order WCAG 3.2.3 AA EN 11.3.2.3 voiceover Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Pass Not evaluated Not evaluated
AP-NAV-002 The same function is identified differently on different screens WCAG 3.2.4 AA EN 11.3.2.4 voiceover Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Pass Not evaluated Not evaluated
AP-FRM-006 Previously entered information must be entered again WCAG 3.3.7 A voiceover Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not applicable Not evaluated
AP-FRM-007 Authentication requires a cognitive function test with no alternative WCAG 3.3.8 AA voiceover Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not applicable Not evaluated
AP-FRM-008 Irreversible action has no confirmation, reversal or review WCAG 3.3.4 AA EN 11.3.3.4 voiceover Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Not evaluated Pass
  • Pass — evaluated, threshold met
  • Fail — evaluated, threshold missed; see findings
  • Not applicable — the rule's condition was not present
  • Not testable — we could not reach it; this is the only verdict that lowers coverage

The four tasks, one at a time

Each task is a different walk through the app, not one crawl counted four times. Reached says whether the walk got to the thing the task promises: a first-run-only flow, a second screen, a surface behind sign-in, the last step before a purchase. A task that did not get there says so — and says what it did establish instead. Rows is how many checks in the table above were measured during that walk, so a task cannot claim it was reached without evidence that says the same.

Per-task coverage: runs completed, surfaces recorded, check rows measured, and whether the task was reached.
Task Runs Surfaces Rows Reached
T2 Crawl 15 / 24 13 479 Yes
This flow requires a system permission sheet; the automated crawl does not pass through it — the recorded device pass covers it.

These runs are not part of the coverage percentage above. Coverage is arithmetic over the check rows; a second denominator mixed into it would make checking less the cheapest way to score higher.

What we could not reach, and what opens it

These rows are subtracted from coverage rather than quietly dropped: a report that hides the screens it never opened is worth less than one that names them. A named gap with no way past it is still no use — the reader cannot tell a locked door from an engine that opens none — so each one below carries the thing that removes it. The counts are recounted from the matrix above, not asserted here.

  • Outside what an automated pass can measure

    65 checks blocked · 13 screens · 13 points of coverage

    • The controls on this surface paint their own text and iOS publishes no field carrying it, so the name cannot be compared against what is drawn on the control. Re-running cannot change this; a human pass on a physical device answers it.
    • No element on this surface was proven interactive by a tap, and XCUITest publishes no handler list, so a missing control trait cannot be distinguished from a plain label. Re-running cannot change this; a human pass on a physical device answers it.
    • XCUITest derives isEnabled from the notEnabled trait rather than from the view, so the announcement cannot be checked against the state it is meant to describe. Re-running cannot change this; a human pass on a physical device answers it.

    Nothing to send — this row is answered by the human verification pass

    The screen was reached, captured and measured; the rule needs a property that iOS does not publish to an automated test at all. XCUITest reports no isAccessibilityElement of its own, its isEnabled is read back from the notEnabled trait rather than from the view, and text a control paints on itself never appears in the tree. Checking those against themselves would manufacture a pass on every app ever built, so the row stays open and goes to a person with the app in their hand and a screen reader running. The criterion still applies to your build — this says which pass answers it, not that nobody will.

    Outside automated instrument reach; covered by human verification on physical device. No re-run is offered for this cause, because no re-run could move it: the field is absent from every dump of every app, so sending the build again would return the identical blank.

  • Needs a physical device

    14 checks blocked · 1 screen · 2.8 points of coverage

    • This audit ran on a machine with no compact phone simulator installed, so the layout of this app at that screen size was not measured — it was not measured on a different screen and labelled as this one. Installing the missing simulator and re-running closes this at no cost to you.

    Invite audits@readyaudit.dev as a TestFlight tester

    iOS Simulator does not run VoiceOver and cannot be network-throttled by simctl, so these variants have no honest reading here. A TestFlight invite is one click — no UDID registration, no provisioning profile, no re-signing — and the same checks are measured on real hardware with a screen reader actually running.

    No extra charge: the device pass is part of the human-verification step already included in the audit.

Every action above needs the build again, except the one that asks for nothing because no second run could change its answer. For the rest: we hold your build for the retention window published in the privacy policy, so a re-measure asked for inside that window has nothing to re-send — send the audit id and the item above from the contact box in the app. Once the window has passed, submit the build again from the app, which is the only channel that carries one. The run is treated as a re-measure of this report rather than a new audit: the blocked checks are re-read and the coverage figure reissued. Never e-mail a build — a message can carry the id, not the bundle.

What a pass asserts, rule by rule

A pass is a bounded claim, not a clean bill of health. Each line below is the exact assertion the tick marks in that row make — and nothing wider.

AP-LBL-001 · Interactive element has no accessibility label
Every interactive element in this surface's accessibility tree carries a non-empty name. It does not assert the names are good ones — see AP-LBL-006.
  • Onboarding step 1/1 interactive elements named
  • Onboarding step 2 2/2 interactive elements named
  • Your Baseline 3/3 interactive elements named
  • Permission prompt 1/1 interactive elements named
  • Today 8/8 interactive elements named
  • Library 15/15 interactive elements named
  • Stack 7/7 interactive elements named
  • Analytics 6/6 interactive elements named
  • Paywall 3/3 interactive elements named
  • Omega-3 (Fish Oil) 7/7 interactive elements named
  • Log Supplement 24/24 interactive elements named
AP-LBL-002 · Decorative image exposed to assistive technology
No image judged decorative is announced by the screen reader on this surface.
  • Onboarding step 1/1 exposed images named
  • Onboarding step 2 5/5 exposed images named
  • Onboarding step 3 2/2 exposed images named
  • Your Baseline 1/1 exposed images named
  • Today 9/9 exposed images named
  • Settings 10/10 exposed images named
  • Library 11/11 exposed images named
  • Stack 6/6 exposed images named
  • Analytics 6/6 exposed images named
  • Paywall 8/8 exposed images named
  • Omega-3 (Fish Oil) 11/11 exposed images named
  • Log Supplement 1/1 exposed images named
AP-LBL-004 · Visible label text is not contained in the accessibility name
Every control on this surface can be activated by Voice Control using the words a sighted user can read on it.
  • Today 1/1 controls match their visible text
  • Settings 2/2 controls match their visible text
  • Library 4/4 controls match their visible text
  • Paywall 2/2 controls match their visible text
AP-LBL-005 · Accessibility label repeats the element's role
No label on this surface duplicates the role the trait already announces.
  • Onboarding step 1/1 labels free of a repeated role
  • Onboarding step 2 2/2 labels free of a repeated role
  • Onboarding step 3 2/2 labels free of a repeated role
  • Your Baseline 3/3 labels free of a repeated role
  • Permission prompt 1/1 labels free of a repeated role
  • Today 8/8 labels free of a repeated role
  • Settings 11/11 labels free of a repeated role
  • Library 15/15 labels free of a repeated role
  • Stack 7/7 labels free of a repeated role
  • Analytics 6/6 labels free of a repeated role
  • Paywall 3/3 labels free of a repeated role
  • Omega-3 (Fish Oil) 7/7 labels free of a repeated role
  • Log Supplement 24/24 labels free of a repeated role
AP-LBL-006 · Link or button purpose is not determinable from its name
No control on this surface is named with a word that carries no destination or outcome.
  • Onboarding step 1/1 names specific, none generic
  • Onboarding step 2 2/2 names specific, none generic
  • Onboarding step 3 2/2 names specific, none generic
  • Your Baseline 3/3 names specific, none generic
  • Permission prompt 1/1 names specific, none generic
  • Today 8/8 names specific, none generic
  • Settings 10/10 names specific, none generic
  • Library 14/14 names specific, none generic
  • Stack 7/7 names specific, none generic
  • Analytics 6/6 names specific, none generic
  • Paywall 3/3 names specific, none generic
  • Omega-3 (Fish Oil) 7/7 names specific, none generic
  • Log Supplement 23/23 names specific, none generic
AP-STA-001 · Interactive element exposes no role or trait
Every tappable element on this surface tells the screen reader what kind of control it is.
  • Onboarding step 1/1 tappable elements expose a role
  • Onboarding step 2 1/1 tappable elements expose a role
  • Onboarding step 3 1/1 tappable elements expose a role
  • Your Baseline 1/1 tappable elements expose a role
  • Permission prompt 1/1 tappable elements expose a role
  • Today 1/1 tappable elements expose a role
  • Settings 2/2 tappable elements expose a role
  • Library 1/1 tappable elements expose a role
  • Stack 1/1 tappable elements expose a role
  • Analytics 2/2 tappable elements expose a role
  • Paywall 1/1 tappable elements expose a role
AP-STR-002 · Accessibility reading order does not match the meaningful sequence
Swiping through this surface reads it in the order it is laid out.
  • Your Baseline 8/8 elements in visual reading order · passed in 3 of 3 attempts
  • Permission prompt 3/3 elements in visual reading order · passed in 2 of 2 attempts
  • Today 14/14 elements in visual reading order · passed in 2 of 2 attempts
  • Library 16/16 elements in visual reading order · passed in 2 of 2 attempts
  • Stack 11/11 elements in visual reading order · passed in 2 of 2 attempts
  • Analytics 16/16 elements in visual reading order · passed in 2 of 2 attempts
  • Paywall 21/21 elements in visual reading order · passed in 2 of 2 attempts
AP-STR-007 · Screen exposes no accessibility elements at all
A screen reader reaches at least one element on this surface instead of finding nothing to announce.
  • Onboarding step 7 elements reachable by a screen reader · passed in 3 of 3 attempts
  • Onboarding step 2 16 elements reachable by a screen reader · passed in 3 of 3 attempts
  • Onboarding step 3 10 elements reachable by a screen reader · passed in 3 of 3 attempts
  • Your Baseline 8 elements reachable by a screen reader · passed in 3 of 3 attempts
  • Permission prompt 3 elements reachable by a screen reader · passed in 2 of 2 attempts
  • Today 14 elements reachable by a screen reader · passed in 2 of 2 attempts
  • Settings 25 elements reachable by a screen reader · passed in 2 of 2 attempts
  • Library 17 elements reachable by a screen reader · passed in 2 of 2 attempts
  • Stack 11 elements reachable by a screen reader · passed in 2 of 2 attempts
  • Analytics 16 elements reachable by a screen reader · passed in 2 of 2 attempts
  • Paywall 21 elements reachable by a screen reader · passed in 2 of 2 attempts
  • Omega-3 (Fish Oil) 32 elements reachable by a screen reader · passed in 2 of 2 attempts
  • Log Supplement 47 elements reachable by a screen reader · passed in 2 of 2 attempts
AP-TGT-001 · Touch target smaller than 44pt
Every interactive frame measured on this surface is at least 44×44pt. Measured from the accessibility tree, not from the drawn glyph — the tappable area is what matters, and the two are often different.
  • Onboarding step smallest target 52pt · required 44pt · 1 measured · passed in 3 of 3 attempts
  • Permission prompt smallest target 48pt · required 44pt · 1 measured · passed in 2 of 2 attempts
  • Analytics smallest target 52pt · required 44pt · 6 measured · passed in 2 of 2 attempts
  • Omega-3 (Fish Oil) smallest target 44pt · required 44pt · 7 measured · passed in 2 of 2 attempts
AP-TGT-006 · Adjacent targets overlap or sit inside each other's spacing allowance
No two targets on this surface are close enough that the spacing exception in SC 2.5.8 is breached.
  • Onboarding step 2 closest pair 56.2px apart · required 24px · passed in 3 of 3 attempts
  • Onboarding step 3 closest pair 56.2px apart · required 24px · passed in 3 of 3 attempts
  • Your Baseline closest pair 225px apart · required 24px · passed in 3 of 3 attempts
  • Today closest pair 28.3px apart · required 24px · passed in 2 of 2 attempts
  • Library closest pair 68.1px apart · required 24px · passed in 2 of 2 attempts
  • Stack closest pair 68.1px apart · required 24px · passed in 2 of 2 attempts
  • Analytics closest pair 68.1px apart · required 24px · passed in 2 of 2 attempts
  • Paywall closest pair 129.3px apart · required 24px · passed in 2 of 2 attempts
  • Omega-3 (Fish Oil) closest pair 68.1px apart · required 24px · passed in 2 of 2 attempts
  • Log Supplement closest pair 66.5px apart · required 24px · passed in 2 of 2 attempts
AP-FRM-001 · Input field has no label or instruction
Every input on this surface has a label that survives once the user starts typing.
  • Library 1/1 inputs labelled, none placeholder-only
  • Log Supplement 1/1 inputs labelled, none placeholder-only
AP-TRP-002 · Task cannot be completed with VoiceOver
The task named in the check row was completed end to end with VoiceOver on. This is the only rule in the catalog that measures an outcome rather than a property.
  • Scenario T1 · Onboarding The task was completed end to end with VoiceOver on · passed in 1 of 1 attempts
AP-TRP-001 · Interaction trap: element cannot be dismissed or escaped with assistive tech
Every overlay reached on this surface was exited using only assistive technology, within the step budget stated in the check row.
  • Scenario T1 · Onboarding Every screen this scenario reached could be dismissed or left with VoiceOver · passed in 1 of 1 attempts
  • Scenario T2 · Core navigation Every screen this scenario reached could be dismissed or left with VoiceOver · passed in 1 of 1 attempts
  • Scenario T4 · Conversion Every screen this scenario reached could be dismissed or left with VoiceOver · passed in 1 of 1 attempts
AP-NAV-001 · Repeated navigation is not in a consistent order
The shared navigation was in the same order everywhere the crawl saw it.
  • Scenario T2 · Core navigation Repeated navigation appeared in the same order on every screen this scenario reached · passed in 1 of 1 attempts
AP-NAV-002 · The same function is identified differently on different screens
No function seen twice in the crawl was called two different things.
  • Scenario T2 · Core navigation The same function was named the same way on every screen this scenario reached · passed in 1 of 1 attempts
AP-FRM-008 · Irreversible action has no confirmation, reversal or review
Every destructive or committing action on this surface could be undone, reviewed or confirmed first.
  • Scenario T4 · Conversion The irreversible action offered a confirmation or a way back · passed in 1 of 1 attempts

Rule catalog v2.5.0 · 21 of 74 rules active in this engine release · 53 defined but not yet evaluated, and therefore not counted above

20 findings

Sorted critical first · catalog v2.5.0

AP-DYN-001 CRITICAL Critical severity

1 control is drawn off the screen at the largest text size

Raised from major At the largest accessibility text size this control is drawn past the end of a screen that does not scroll, so there is no gesture that reaches it: the function it performs is unavailable to the people this text size exists for.

  • Onboarding step
  • Get Started
  • xxl-font
  • iPhone 17 Pro (simulator)
  • T2 · Crawl

Evidence

xxl-font · Onboarding step runs/bd1bf437/t2/xxl-font/iphone-17-pro/r1/step-00.png

Screenshot from the audited build, unedited. SuppLab is our own app — see the build digest above to check the artifact this frame came out of.

bottom_pt
1046.3
clipped
4
elements
'Get Started'
fixed_elements
7
screen_height_pt
874

Reproduced in 3 of 3 attempts

Seen on 1 of 1 recorded states of this screen

Suggested fix

Put this screen's content in a ScrollView, so that what does not fit at the largest text size can still be reached. Fixed-height layouts sized for the default text size lose their bottom rows at the accessibility sizes.

ScrollView {
    VStack(spacing: 24) { … }
        .frame(maxWidth: .infinity)
        .padding()
}
// and stop pinning heights that the text has to fit inside
WCAG 1.4.4 EN 301 549 11.1.4.4
AP-LBL-001 MAJOR Major severity

1 interactive element has no accessibility label

  • Settings
  • unnamed date picker at 300,583
  • dark
  • iPhone 17 Pro (simulator)
  • T2 · Crawl

Evidence

dark · Settings runs/bd1bf437/t2/dark/iphone-17-pro/r1/step-09.png

Screenshot from the audited build, unedited. SuppLab is our own app — see the build digest above to check the artifact this frame came out of.

elements
'unnamed date picker at 300,583'
interactive_elements
12
unnamed
1

Reproduced in 2 of 2 attempts

Seen on 2 of 2 recorded states of this screen

Suggested fix

Give each control a name that says what it does. VoiceOver announces the trait already, so the label is the verb, not the widget.

DatePicker("Start date", selection: $startDate, displayedComponents: .date)
    .accessibilityLabel("Start date")
WCAG 4.1.2 EN 301 549 11.4.1.2
AP-LBL-001 MAJOR Major severity

1 interactive element has no accessibility label

  • Onboarding step 2
  • unnamed button at 16,704
  • locale-de
  • iPhone 17 Pro (simulator)
  • T2 · Crawl

Evidence

locale-de · Onboarding step 2 runs/bd1bf437/t2/locale-de/iphone-17-pro/r1/step-02.png

Screenshot from the audited build, unedited. SuppLab is our own app — see the build digest above to check the artifact this frame came out of.

elements
'unnamed button at 16,704'
interactive_elements
2
unnamed
1

Reproduced in 2 of 3 attempts

Seen on 3 of 6 recorded states of this screen

Suggested fix

Give each control a name that says what it does. VoiceOver announces the trait already, so the label is the verb, not the widget.

Button(action: send) { Image(systemName: "paperplane") }
    .accessibilityLabel("Send")
WCAG 4.1.2 EN 301 549 11.4.1.2
AP-STR-002 MAJOR Major severity

Accessibility order does not match the layout order

  • Onboarding step
  • Step 1 of 3
  • default
  • iPhone 17 Pro (simulator)
  • T2 · Crawl

Evidence

default · Onboarding step runs/bd1bf437/t2/default/iphone-17-pro/r1/step-00.png

Screenshot from the audited build, unedited. SuppLab is our own app — see the build digest above to check the artifact this frame came out of.

drawn_at_position
1
element
Step 1 of 3
elements
7
out_of_order
1
reached_at_position
7

Reproduced in 3 of 3 attempts

Seen on 4 of 4 recorded states of this screen

Suggested fix

Swiping reaches 'Step 1 of 3' at position 7 of 7, and the screen draws it at position 1. 1 element is out of place on this surface. Reorder the views, or state the order explicitly, so swiping follows the way the screen reads.

// Example pattern — adapt it to the view that draws this element.
container
    .accessibilityElement(children: .contain)
    .accessibilitySortPriority(1)
WCAG 1.3.2 EN 301 549 11.1.3.2
AP-STR-002 MAJOR Major severity

Accessibility order does not match the layout order

  • Onboarding step 2
  • Step 2 of 3
  • default
  • iPhone 17 Pro (simulator)
  • T2 · Crawl

Evidence

default · Onboarding step 2 runs/bd1bf437/t2/default/iphone-17-pro/r1/step-01.png

Screenshot from the audited build, unedited. SuppLab is our own app — see the build digest above to check the artifact this frame came out of.

drawn_at_position
1
element
Step 2 of 3
elements
16
out_of_order
1
reached_at_position
16

Reproduced in 3 of 3 attempts

Seen on 6 of 6 recorded states of this screen

Suggested fix

Swiping reaches 'Step 2 of 3' at position 16 of 16, and the screen draws it at position 1. 1 element is out of place on this surface. Reorder the views, or state the order explicitly, so swiping follows the way the screen reads.

// Example pattern — adapt it to the view that draws this element.
container
    .accessibilityElement(children: .contain)
    .accessibilitySortPriority(1)
WCAG 1.3.2 EN 301 549 11.1.3.2
AP-STR-002 MAJOR Major severity

Accessibility order does not match the layout order

  • Onboarding step 3
  • Step 3 of 3
  • default
  • iPhone 17 Pro (simulator)
  • T2 · Crawl

Evidence

default · Onboarding step 3 runs/bd1bf437/t2/default/iphone-17-pro/r1/step-04.png

Screenshot from the audited build, unedited. SuppLab is our own app — see the build digest above to check the artifact this frame came out of.

drawn_at_position
1
element
Step 3 of 3
elements
10
out_of_order
3
reached_at_position
10

Reproduced in 3 of 3 attempts

Seen on 5 of 5 recorded states of this screen

Suggested fix

Swiping reaches 'Step 3 of 3' at position 10 of 10, and the screen draws it at position 1. 3 elements are out of place on this surface. Reorder the views, or state the order explicitly, so swiping follows the way the screen reads.

// Example pattern — adapt it to the view that draws this element.
container
    .accessibilityElement(children: .contain)
    .accessibilitySortPriority(1)
WCAG 1.3.2 EN 301 549 11.1.3.2
AP-STR-002 MAJOR Major severity

Accessibility order does not match the layout order

  • Settings
  • Terms of Use
  • dark
  • iPhone 17 Pro (simulator)
  • T2 · Crawl

Evidence

dark · Settings runs/bd1bf437/t2/dark/iphone-17-pro/r1/step-09.png

Screenshot from the audited build, unedited. SuppLab is our own app — see the build digest above to check the artifact this frame came out of.

drawn_at_position
22
element
Terms of Use
elements
25
out_of_order
4
reached_at_position
17

Reproduced in 2 of 2 attempts

Seen on 2 of 2 recorded states of this screen

Suggested fix

Swiping reaches 'Terms of Use' at position 17 of 25, and the screen draws it at position 22. 4 elements are out of place on this surface. Reorder the views, or state the order explicitly, so swiping follows the way the screen reads.

// Example pattern — adapt it to the view that draws this element.
container
    .accessibilityElement(children: .contain)
    .accessibilitySortPriority(1)
WCAG 1.3.2 EN 301 549 11.1.3.2
AP-STR-002 MAJOR Major severity

Accessibility order does not match the layout order

  • Omega-3 (Fish Oil)
  • lock.fill
  • dark
  • iPhone 17 Pro (simulator)
  • T2 · Crawl

Evidence

dark · Omega-3 (Fish Oil) runs/bd1bf437/t2/dark/iphone-17-pro/r1/step-17.png

Screenshot from the audited build, unedited. SuppLab is our own app — see the build digest above to check the artifact this frame came out of.

background_layers_excluded
1
drawn_at_position
24
element
lock.fill
elements
31
out_of_order
2
reached_at_position
26

Reproduced in 2 of 2 attempts

Seen on 2 of 2 recorded states of this screen

Suggested fix

Swiping reaches 'lock.fill' at position 26 of 31, and the screen draws it at position 24. 2 elements are out of place on this surface. Reorder the views, or state the order explicitly, so swiping follows the way the screen reads.

// A decorative image has no place in the sequence at all:
Image("hero")
    .accessibilityHidden(true)
WCAG 1.3.2 EN 301 549 11.1.3.2
AP-STR-002 MAJOR Major severity

Accessibility order does not match the layout order

  • Log Supplement
  • Search supplements
  • dark
  • iPhone 17 Pro (simulator)
  • T2 · Crawl

Evidence

dark · Log Supplement runs/bd1bf437/t2/dark/iphone-17-pro/r1/step-18.png

Screenshot from the audited build, unedited. SuppLab is our own app — see the build digest above to check the artifact this frame came out of.

drawn_at_position
43
element
Search supplements
elements
47
out_of_order
12
reached_at_position
47

Reproduced in 2 of 2 attempts

Seen on 2 of 2 recorded states of this screen

Suggested fix

Swiping reaches 'Search supplements' at position 47 of 47, and the screen draws it at position 43. 12 elements are out of place on this surface. Reorder the views, or state the order explicitly, so swiping follows the way the screen reads.

// Example pattern — adapt it to the view that draws this element.
container
    .accessibilityElement(children: .contain)
    .accessibilitySortPriority(1)
WCAG 1.3.2 EN 301 549 11.1.3.2
AP-FRM-001 MAJOR Major severity

1 input field has no persistent label

  • Settings
  • unnamed date picker at 300,583
  • dark
  • iPhone 17 Pro (simulator)
  • T2 · Crawl

Evidence

dark · Settings runs/bd1bf437/t2/dark/iphone-17-pro/r1/step-09.png

Screenshot from the audited build, unedited. SuppLab is our own app — see the build digest above to check the artifact this frame came out of.

elements
'unnamed date picker at 300,583'
inputs
1
placeholder_only
0
without_label
1

Reproduced in 2 of 2 attempts

Seen on 2 of 2 recorded states of this screen

Suggested fix

Attach a label that survives typing. A placeholder vanishes at the first keystroke, taking the only description of the field with it.

// The placeholder disappears as soon as a date is chosen.
DatePicker("Start date", selection: $startDate, displayedComponents: .date)
WCAG 3.3.2 EN 301 549 11.3.3.2
AP-STA-005 MINOR Minor severity

1 adjustable control exposes no value or adjustment action

  • Settings
  • unnamed date picker at 300,583
  • dark
  • iPhone 17 Pro (simulator)
  • T2 · Crawl

Evidence

dark · Settings runs/bd1bf437/t2/dark/iphone-17-pro/r1/step-09.png

Screenshot from the audited build, unedited. SuppLab is our own app — see the build digest above to check the artifact this frame came out of.

adjustable_controls
1
elements
'unnamed date picker at 300,583'
incomplete
1

Reproduced in 2 of 2 attempts

Seen on 2 of 2 recorded states of this screen

Suggested fix

Publish the current value and the adjustable trait, so the rotor can read the control and change it with a swipe.

DatePicker("Start date", selection: $startDate, displayedComponents: .date)
    .accessibilityValue(startDate.formatted(date: .abbreviated, time: .omitted))
WCAG 4.1.2 EN 301 549 11.4.1.2
AP-TGT-001 MINOR Minor severity

1 touch target is smaller than 44pt

  • Onboarding step 2
  • Skip for now
  • default
  • iPhone 17 Pro (simulator)
  • T2 · Crawl

Evidence

default · Onboarding step 2 runs/bd1bf437/t2/default/iphone-17-pro/r1/step-01.png

Screenshot from the audited build, unedited. SuppLab is our own app — see the build digest above to check the artifact this frame came out of.

below_threshold
1
elements
'Skip for now' 94×20pt
min_pt
20.3
required_pt
44
targets
2

Reproduced in 3 of 3 attempts

Seen on 11 of 11 recorded states of this screen

Suggested fix

Grow the tappable frame to at least 44×44pt. The glyph can stay small — it is the hit area that has to be reachable.

Button("Skip", action: skip)
    .frame(minWidth: 44, minHeight: 44)
    .contentShape(Rectangle())
WCAG 2.5.8
AP-TGT-001 MINOR Minor severity

1 touch target is smaller than 44pt

  • Your Baseline
  • Continue
  • default
  • iPhone 17 Pro (simulator)
  • T2 · Crawl

Evidence

default · Your Baseline runs/bd1bf437/t2/default/iphone-17-pro/r1/step-05.png

Screenshot from the audited build, unedited. SuppLab is our own app — see the build digest above to check the artifact this frame came out of.

below_threshold
1
elements
'Continue' 96×36pt
min_pt
36
required_pt
44
targets
3

Reproduced in 3 of 3 attempts

Seen on 3 of 3 recorded states of this screen

Suggested fix

Grow the tappable frame to at least 44×44pt. The glyph can stay small — it is the hit area that has to be reachable.

Button("Skip", action: skip)
    .frame(minWidth: 44, minHeight: 44)
    .contentShape(Rectangle())
WCAG 2.5.8
AP-TGT-001 MINOR Minor severity

1 touch target is smaller than 44pt

  • Today
  • Log a supplement
  • dark
  • iPhone 17 Pro (simulator)
  • T2 · Crawl

Evidence

dark · Today runs/bd1bf437/t2/dark/iphone-17-pro/r1/step-08.png

Screenshot from the audited build, unedited. SuppLab is our own app — see the build digest above to check the artifact this frame came out of.

below_threshold
1
elements
'Log a supplement' 338×22pt
min_pt
22.7
required_pt
44
targets
8

Reproduced in 2 of 2 attempts

Seen on 4 of 4 recorded states of this screen

Suggested fix

Grow the tappable frame to at least 44×44pt. The glyph can stay small — it is the hit area that has to be reachable.

Button("Skip", action: skip)
    .frame(minWidth: 44, minHeight: 44)
    .contentShape(Rectangle())
WCAG 2.5.8
AP-TGT-001 MINOR Minor severity

8 touch targets are smaller than 44pt

  • Settings
  • Terms of Use
  • dark
  • iPhone 17 Pro (simulator)
  • T2 · Crawl

Evidence

dark · Settings runs/bd1bf437/t2/dark/iphone-17-pro/r1/step-09.png

Screenshot from the audited build, unedited. SuppLab is our own app — see the build digest above to check the artifact this frame came out of.

below_threshold
8
elements
'Terms of Use' 76×14pt; 'Privacy Policy' 80×14pt; 'Restore Purchases' 338×20pt; 'Delete All Data' 338×20pt; 'unnamed switch at 309,532' 63×28pt
min_pt
14.3
required_pt
44
targets
14

Reproduced in 2 of 2 attempts

Seen on 2 of 2 recorded states of this screen

Suggested fix

Grow the tappable frame to at least 44×44pt. The glyph can stay small — it is the hit area that has to be reachable.

Button("Skip", action: skip)
    .frame(minWidth: 44, minHeight: 44)
    .contentShape(Rectangle())
WCAG 2.5.8
AP-TGT-001 MINOR Minor severity

5 touch targets are smaller than 44pt

  • Library
  • All
  • dark
  • iPhone 17 Pro (simulator)
  • T2 · Crawl

Evidence

dark · Library runs/bd1bf437/t2/dark/iphone-17-pro/r1/step-10.png

Screenshot from the audited build, unedited. SuppLab is our own app — see the build digest above to check the artifact this frame came out of.

below_threshold
5
elements
'All' 32×22pt; 'Sleep & Recovery' 124×22pt; 'Immunity & Mood' 123×22pt; 'Cardiovascular' 108×22pt; 'viewfinder' 30×36pt
min_pt
22.3
required_pt
44
targets
15

Reproduced in 2 of 2 attempts

Seen on 4 of 4 recorded states of this screen

Suggested fix

Grow the tappable frame to at least 44×44pt. The glyph can stay small — it is the hit area that has to be reachable.

Button("Skip", action: skip)
    .frame(minWidth: 44, minHeight: 44)
    .contentShape(Rectangle())
WCAG 2.5.8
AP-TGT-001 MINOR Minor severity

1 touch target is smaller than 44pt

  • Stack
  • plus
  • dark
  • iPhone 17 Pro (simulator)
  • T2 · Crawl

Evidence

dark · Stack runs/bd1bf437/t2/dark/iphone-17-pro/r1/step-11.png

Screenshot from the audited build, unedited. SuppLab is our own app — see the build digest above to check the artifact this frame came out of.

below_threshold
1
elements
'plus' 27×36pt
min_pt
27.3
required_pt
44
targets
7

Reproduced in 2 of 2 attempts

Seen on 4 of 4 recorded states of this screen

Suggested fix

Grow the tappable frame to at least 44×44pt. The glyph can stay small — it is the hit area that has to be reachable.

Button("Skip", action: skip)
    .frame(minWidth: 44, minHeight: 44)
    .contentShape(Rectangle())
WCAG 2.5.8
AP-TGT-001 MINOR Minor severity

1 touch target is smaller than 44pt

  • Paywall
  • xmark.circle.fill
  • dark
  • iPhone 17 Pro (simulator)
  • T2 · Crawl

Evidence

dark · Paywall runs/bd1bf437/t2/dark/iphone-17-pro/r1/step-13.png

Screenshot from the audited build, unedited. SuppLab is our own app — see the build digest above to check the artifact this frame came out of.

below_threshold
1
elements
'xmark.circle.fill' 34×36pt
min_pt
34
required_pt
44
targets
3

Reproduced in 2 of 2 attempts

Seen on 4 of 4 recorded states of this screen

Suggested fix

Grow the tappable frame to at least 44×44pt. The glyph can stay small — it is the hit area that has to be reachable.

Button("Skip", action: skip)
    .frame(minWidth: 44, minHeight: 44)
    .contentShape(Rectangle())
WCAG 2.5.8
AP-TGT-001 MINOR Minor severity

24 touch targets are smaller than 44pt

  • Log Supplement
  • Took
  • dark
  • iPhone 17 Pro (simulator)
  • T2 · Crawl

Evidence

dark · Log Supplement runs/bd1bf437/t2/dark/iphone-17-pro/r1/step-18.png

Screenshot from the audited build, unedited. SuppLab is our own app — see the build digest above to check the artifact this frame came out of.

below_threshold
24
elements
'Took' 52×22pt; 'Skipped' 71×22pt; 'Took' 52×22pt; 'Skipped' 71×22pt; 'Took' 52×22pt
min_pt
22.3
required_pt
44
targets
24

Reproduced in 2 of 2 attempts

Seen on 2 of 2 recorded states of this screen

Suggested fix

Grow the tappable frame to at least 44×44pt. The glyph can stay small — it is the hit area that has to be reachable.

Button("Skip", action: skip)
    .frame(minWidth: 44, minHeight: 44)
    .contentShape(Rectangle())
WCAG 2.5.8
AP-TGT-006 MINOR Minor severity

3 pairs of targets sit closer than 24px apart

  • Settings
  • unnamed date picker at 300,583
  • dark
  • iPhone 17 Pro (simulator)
  • T2 · Crawl

Evidence

dark · Settings runs/bd1bf437/t2/dark/iphone-17-pro/r1/step-09.png

Screenshot from the audited build, unedited. SuppLab is our own app — see the build digest above to check the artifact this frame came out of.

elements
'unnamed date picker at 300,583' / 'Time Picker' 0px apart; 'Terms of Use' / 'books.vertical.fill' 19px apart; 'Privacy Policy' / 'chart.bar.xaxis' 20px apart
min_center_distance_px
0
pairs_below_threshold
3
required_center_distance_px
24

Reproduced in 2 of 2 attempts

Seen on 2 of 2 recorded states of this screen

Suggested fix

Space adjacent targets at least 24px centre to centre, or enlarge them. Targets this close are mistapped by anyone whose hands are not steady.

// Example pattern — adapt it to the view that draws this element.
HStack(spacing: 16) {
    first.frame(width: 44, height: 44)
    second.frame(width: 44, height: 44)
}