Accessibility Reporter for Umbraco is an award winning content app/workspace view and dashboard that helps you test the accessibility of your website against common accessibility standards, including the Web Content Accessibility Guidelines (WCAG), Section 508 and best practices, directly in Umbraco.
You want to help make your Umbraco website more accessible by testing it against WCAG success criteria.
It runs an accessibility audit against the current published version of the page that you are editing and displays a report in a tab called 'Accessibility'. The tests are run in an iframe directly in Umbraco or optionally using an Azure function.
You can install Accessibility Reporter using Nuget https://www.nuget.org/packages/Umbraco.Community.AccessibilityReporter. Once installed when you build your project the files needed for Accessibility Reporter will be copied into your App_Plugins folder. That's it!
If you are running Umbraco 17+ use the latest version of Accessibility Reporter, which is version 4 onwards. If you are running Umbraco 10-13, use version 3.5.1.
You can run Accessibility Reporter without adding any configuration options, as it has some sensible defaults. However, you can configure how it runs by adding an AccessibilityReporter section to your appsettings.json file.
- ApiUrl - This is the URL of the API that will run the tests. By default the tests are run in an iframe within Umbraco, however if you website is on a different domain to your Umbraco instance to get around iframe security issues, you can host an API on an Azure function by forking
https://github.com/mattbegent/azure-function-accessibility-reporterand deploying it to Azure. - TestBaseUrl (optional) - If you run Umbraco in a headless way or Accessibility Reporter is having trouble finding the domain to test against, set this to the base URL of your wesbite. If not set Accessibility Reporter will try to infer this from available information in Umbraco. In a multisite install this is used as a fallback only for root nodes that don't have a domain bound and aren't covered by
SiteBaseUrlsbelow - preferSiteBaseUrlswhen you have more than one site. - SiteBaseUrls (optional) - Per-site base URL overrides for multisite/headless installs where different root nodes don't have Umbraco domains bound to them. Keyed by each root node's Key (the Guid shown on that node's Info tab), so a different base URL can be used per site instead of forcing every site onto the single
TestBaseUrl. Not needed if your root nodes already have domains configured in Umbraco - those are resolved automatically per site. - TestsToRun (optional) - This sets which axe-core rules should be run. For example, you may want to test your website against
wcag2aonly. A full list of supported tags can be found in the axe-core documentation. If not set Accessibility Reporter defaults to WCAG A and AA tests. - UserGroups (optional) - Use this option if you want to restrict which user groups can see Accessibility Reporter. By default users with admin, editor or writer permissions can see it.
- ExcludedDocTypes (optional) - Use this option if you want to exclude Accessibility Reporter from showing on certain document types.
- RunTestsAutomatically (optional) - By default Accessibility Reporter runs as soon as you open up a content node. If you instead want Accessibility Reporter to run on demand via a button click, set this option to false.
- IncludeIfNoTemplate (optional) - By default Accessibility Reporter does not run on content without templates. However, if you are using Umbraco in a headless way you will was to set this to true.
- MaxPages (optional) - This sets the maximum number of pages that the dashboard will test against. The default is set to 50.
"AccessibilityReporter": {
"ApiUrl": "https://api.example.com/api/audit",
"TestBaseUrl": "https://example.com",
"SiteBaseUrls": {
"b1a2c3d4-e5f6-7890-abcd-ef1234567890": "https://site-two.example.com"
},
"TestsToRun": [
"wcag2a",
"wcag2aa",
"wcag21a",
"wcag21aa",
"wcag22aa"
],
"UserGroups": [
"admin",
"editor",
"writer"
],
"ExcludedDocTypes": [
"excludedPage"
],
"RunTestsAutomatically": false,
"MaxPages": 20
}
All options are completely optional and if you don't set them, they default to the following:
"AccessibilityReporter": {
"ApiUrl": "",
"TestBaseUrl": "",
"SiteBaseUrls": {},
"TestsToRun": [
"wcag2a",
"wcag2aa",
"wcag21a",
"wcag21aa",
"wcag22aa",
"best-practice"
],
"UserGroups": [
"admin",
"administrators",
"editor",
"editors",
"writer",
"writers",
"translator",
"translators",
"sensitiveData",
"sensitive data"
],
"RunTestsAutomatically": true,
"IncludeIfNoTemplate": false,
"MaxPages": 50
}
If you use Umbraco in a headless way and you do not have a way of previewing the published page within Umbraco, you will have to setup an azure function in order to get Accessibility Reporter working. This is due to cross domain security restrictions within iframes.
To do this deploying the following azure function https://github.com/mattbegent/azure-function-accessibility-reporter and update your websites appsettings.json file. Here is an example:
"AccessibilityReporter": {
"ApiUrl": "https://api.example.com/api/audit/", // your azure function
"TestBaseUrl": "https://www.example.com", // base url of your website
"RunTestsAutomatically": false, // as running in a function costs a small amount you might not to run automatically
"IncludeIfNoTemplate": true // headless content probably doesn't have a template
}
It's worth noting that if you are using Accessibility Reporter in this way the tests will take much longer than if you run Umbraco in a non headless way.
Accessibility Reporter supports Umbraco installs with more than one root content node ("site"):
- The dashboard tests pages from every site, allocating the
MaxPageslimit fairly across them rather than letting one large site use up the whole budget. - If a selected language isn't supported by a particular site, that site's pages are skipped for that run rather than tested with a broken URL.
- Dashboard results and exports show which site each page belongs to whenever more than one site is present in the results.
- If your root nodes have domains bound to them in Umbraco, per-site URLs are resolved automatically - no configuration needed.
- If you run a headless multisite install with no domains bound to root nodes, use
SiteBaseUrls(see Options above) to set a base URL per site instead ofTestBaseUrl. - If a site's public domain is genuinely different to your Umbraco backoffice's own domain, in-browser testing can't cross that boundary directly for browser security reasons (the same restriction described in "How to use with a headless setup") - see "Testing sites on a different domain" below for how to make it work anyway.
If a site's public domain differs from your Umbraco backoffice's own domain (a common multisite or headless setup), Accessibility Reporter can't inject its test script directly into that page for security reasons. There are two ways to make it work anyway - both only ever activate while Accessibility Reporter itself is running a test, so nothing extra loads or runs for ordinary visitors:
Option 1: Add the bridge (recommended, no extra hosting required)
If this site is rendered with Razor (e.g. a multi-domain Umbraco install where the same application serves every site, just on different bound domains), add @using AccessibilityReporter.Extensions to your _ViewImports.cshtml, then add this to a shared layout:
@Html.AccessibilityReporterScript()
If it isn't a Razor site (a genuinely separate/headless frontend), add this small snippet instead, replacing your-umbraco-domain.example.com with wherever your Umbraco backoffice is hosted:
<script>
(function () {
if (window.name !== 'accessibility-reporter-bridge-activate') return;
var s = document.createElement('script');
s.src = 'https://your-umbraco-domain.example.com/App_Plugins/AccessibilityReporter/libs/accessibility-reporter-bridge.js';
document.head.appendChild(s);
})();
</script>
Either way, this is a tiny, inert stub for every normal page view - it checks a marker that's only ever set on the specific iframe Accessibility Reporter creates to run a test, and does nothing else (no network request, no listener registered) unless that marker is present. Only when Accessibility Reporter is actually testing that page does it fetch the real bridge script, which runs the accessibility test and reports the result back over postMessage (which, unlike direct DOM access, is designed to work across origins). Two things worth knowing about that real bridge script, if you ever need to debug it:
- It needs to run promptly - if you end up loading it (or the snippet above) through a tag manager or a consent-gated loader, it may not get the chance to announce itself in time.
- If the page uses a nonce-based Content-Security-Policy, it needs
strict-dynamicfor the bridge's own script load to be allowed - otherwise you'll see an explicit error rather than the test hanging.
Option 2: Configure ApiUrl
See "How to use with a headless setup" above - this runs tests via an external service instead of in the browser, so no changes to the target site are needed, at the cost of needing to deploy and maintain that service, and slower test runs.
The accessibility report runs on the current published page URL you are editing.
Automated accessibility testing is no substitute for manual testing and testing using real users. In a UK government blog article they created a test page with 143 accessibility issues on it and the best automated tool only discovered 37% of the issues. However, automated accessibility testing does help to find common issues and technical failures.
- History. This will mean the dashboard is automatically populated.
- Scheduling.
- Manual test recommendations.
- Localization - if anyone speaks any languages other than English it would be super to get some help.
Copyright © Matt Begent.
All source code is licensed under the Mozilla Public License.
axe-core is licensed under the Mozilla Public License 2.0.
Chart.js is licensed under the MIT License.
SheetJS Community Edition is licensed under the Apache 2.0.
patternomaly is licensed under the MIT License.
