You ran an audit, or a customer emailed you, or a scanner flagged your storefront, and the trail leads back to an app. Not your theme. Not your custom code. An app you installed because it does something you actually need, like a chat widget, a reviews block, a popup, a shipping estimator, or a subscription toggle on the product page. Now that app is injecting accessibility errors into pages you do not fully control, and you do not want to lose the functionality.

This is one of the more frustrating situations in Shopify accessibility work, because the fix often sits in code you did not write and cannot directly edit. But you have more leverage than you think. Here is how to work through it.

Why app issues are different from theme issues

When a theme has an accessibility problem, the fix is usually within reach. You can open the Liquid file, change the markup, add an aria attribute, swap the color, and ship it. Source control, version history, all under your control.

App-injected issues behave differently. The app loads its own JavaScript bundle from the vendor’s CDN. That script writes elements into the DOM after the page has already rendered. Sometimes it does this on page load, sometimes only when a user interacts, sometimes inside a shadow DOM where your own CSS cannot reach it. The markup the app injects can change at any time when the vendor pushes an update, which means a fix you thought was permanent can quietly break six weeks later.

There are three layers you are usually fighting at once. The app’s HTML, which you cannot edit directly. The app’s CSS, which you can sometimes override but not always. And the app’s behavior, which is locked inside the vendor’s JavaScript. Knowing which layer is causing the issue tells you who has to fix it. If it is a missing alt text on a popup image, that is HTML, vendor problem. If the focus ring is invisible because the vendor set outline: none, that is CSS, you can override it. If the modal traps keyboard focus incorrectly, that is behavior, vendor only.

This is also why you cannot rely on a single accessibility overlay or widget to mask app problems. Those tools sit at the document level and often cannot see into a shadow DOM at all. If you are weighing options there, the comparison between widgets, checkers, and code-level fixes is worth reading before you spend any time on an overlay.

The fastest way to isolate the app causing the problem

Before you can fix anything you need to know exactly which app is responsible. Merchants often guess wrong here. The popup that is failing keyboard navigation looks like it belongs to the reviews app because it appears on the product page, but it is actually the upsell app firing on add-to-cart. Guessing wastes hours.

The fastest method I use is the disable-and-reload loop. Open the storefront in an incognito window with developer tools open. Run the scanner or manually reproduce the issue, and note the exact element that is failing. Then go into your Shopify admin and pause the apps one at a time. After each pause, hard reload the storefront and check whether the offending element is still there. The app that, when paused, makes the element disappear is the one that injected it. This sounds tedious, but on most stores you can do it in fifteen or twenty minutes because you only need to test the apps that touch the storefront, not the back-office ones.

If pausing apps is not practical because the store is live and you cannot risk downtime, use the DOM inspector instead. Right-click the broken element, inspect it, and walk up the tree until you find a wrapper with a class or id that names the vendor. Chat widgets almost always wrap their content in something like #tidio-chat-iframe or .intercom-launcher. Review apps tend to use prefixes like .yotpo- or .judgeme-. Shipping estimators often inject inside #shipping-calculator- or similar. The vendor names themselves are usually findable in the script src attribute too, so view source on the page and search for cdn to see who is loading.

Make a short list as you go: app name, what it injects, where it injects it, what the failure is. You will need this list for the rest of the work, and you will need it again when you write your remediation log. Speaking of which, if you do not have a documented audit process yet, the Shopify accessibility audit guide covers how to structure this kind of investigation so the findings hold up later.

What you can fix in the theme right away

Not everything app-related has to wait for the vendor. A surprising number of app issues are actually CSS issues that you can override from the theme, because the app loads its styles before yours and gives your stylesheet the last word.

The most common ones I patch directly:

Focus rings that were removed. A lot of vendors set outline: none on buttons inside their widgets because they think it looks cleaner. Add a global rule in your theme stylesheet that restores a visible focus indicator on any element inside the app’s wrapper, using a high-specificity selector with the vendor’s class as a prefix. Something like .yotpo-widget-instance button:focus-visible { outline: 2px solid #0a58ca; outline-offset: 2px; } will usually win the cascade.

Color contrast on text inside the widget. If the chat widget’s button uses light gray text on a slightly less light gray background, you can override the color with the same prefix-based approach. Get the contrast ratio above 4.5 to 1 for normal text and 3 to 1 for large text. Test it after the override because some widgets use inline styles that you will need !important to beat.

Hidden labels on form inputs. If the popup’s email field has no label, you can sometimes inject one with CSS using ::before and an aria-label attribute set via a MutationObserver in a small theme script. This is not pretty, but it works as a stopgap while you wait for the vendor.

Tiny tap targets. Mobile chat bubbles and popup close buttons are often under the 24 by 24 pixel minimum. You can usually nudge these up with padding rules on the wrapper.

Things you cannot fix from the theme, no matter how clever: missing alt text on images the app injects, missing form labels in shadow DOM, incorrect heading hierarchy inside the widget, broken keyboard order, and missing landmark roles. These need the vendor.

If you want a single drop-in that handles the common CSS overrides automatically, the Shopify Accessibility Fixer plugin covers the focus, contrast, and tap target fixes for most common widget vendors out of the box. It will not fix vendor HTML, but it cuts the theme-side work to nearly zero.

What to send the app vendor

This is the step most merchants skip, and it is the step that actually gets things fixed long-term. Vendors fix what they can reproduce and they ignore what they cannot. Your job is to make the issue impossible to ignore.

A useful vendor report has four parts. The page URL where it happens. The exact element that fails, copied from the inspector, including the selector. The WCAG criterion it violates, written out, for example, “WCAG 2.1 Success Criterion 1.4.3 Contrast Minimum, the chat launcher button has a contrast ratio of 2.8 to 1 against the page background.” And a screenshot or short screen recording showing the failure.

Send this through their official support channel, not via a tweet or a public review. Public pressure feels good but it routes your ticket to marketing, not engineering. Email or in-app support tickets land with the people who can actually patch it. If they say “we’ll look into it,” ask for a tracking number and a target date. If they refuse to commit to either, that is a signal you may need to start planning a replacement, which we will get to in a moment.

For the broader pattern of which violations come from third-party apps and how they tend to cluster, this breakdown of common WCAG violations from Shopify apps is the reference I send to vendors who claim their app is compliant. It cites the criteria and the typical failure modes, and it puts the burden of proof back on them.

One more thing on vendor reports: keep copies of everything. Every email, every ticket number, every response. When a customer or a lawyer asks what you did to remediate, you want a paper trail that shows you reported the issue, followed up, and acted when the vendor did not.

When to replace the app

Sometimes the vendor is the problem. They do not respond, they respond and do nothing, or their roadmap puts accessibility a year out. At that point the question is whether to keep the app and live with the issue or replace it.

I use three filters. First, how central is the app to revenue? A subscription widget on a recurring-revenue store is hard to swap. A second chat widget on a store that already has one is trivial. Second, how visible is the issue to users on assistive tech? A popup that traps focus and cannot be closed with Escape is an emergency. A slightly low-contrast review star is not great but it is not blocking. Third, are there alternatives in the App Store that do the same job with cleaner markup?

For chat widgets specifically, the landscape has improved a lot. Several vendors now ship keyboard-navigable, screen-reader-friendly launchers by default, and switching usually takes an afternoon. For reviews apps, the spread is wider. The most popular reviews app on Shopify is also one of the worst offenders on heading hierarchy and form labels. Swapping it means migrating reviews, which is doable but is a project, not a quick fix.

Subscription widgets and upsell apps are the hardest to replace because they are tied into the checkout flow. If you are looking at issues that touch checkout specifically, the checkout accessibility fixes guide walks through what you can change inside Shopify’s checkout extensibility versus what you cannot.

If you decide to replace, do not just install the new one and uninstall the old one. The leftover JavaScript and CSS from the old app will haunt your theme for weeks. Audit the theme files for hardcoded snippets the old app asked you to paste, remove them, and reload the storefront in incognito to confirm none of the old vendor’s domains are still being requested.

How to document the fix

Documentation is what turns a one-time scramble into a defensible accessibility program. Every fix you make, every vendor ticket you file, every override you add to the theme, needs to land in one place that you can hand to a customer, an auditor, or a lawyer if you have to.

The shape I recommend is a remediation log. For each issue, record the date it was discovered, the page or component affected, the WCAG criterion, the source of the issue (theme, app name, checkout, etc.), what you did about it, when you did it, and the current status. Keep it simple. A spreadsheet works. A markdown file in your repo works better because it versions with your code.

This is different from your accessibility statement, which is the public-facing page that tells visitors what your site supports and how to contact you. The remediation log is internal. The difference between a statement, a policy, and a remediation log is laid out in this breakdown of all three documents. All three serve different audiences and you want all three.

If you are starting from scratch and need a base, the accessibility policy template gives you the internal-facing document that explains how your team handles new issues, vendor communication, and review cadence. It is the policy that justifies the remediation log existing.

If you are working through app accessibility issues, these are the next places to look on the site.

Bottom line

App-injected accessibility issues are not your fault, but they are your responsibility, because the storefront is yours. You do not have to live with them and you do not have to uninstall the apps that earn their keep. Isolate the app first so you know who you are dealing with. Fix what you can from the theme using CSS overrides and small JavaScript helpers, especially focus rings, contrast, and tap targets. Send the vendor a detailed report for everything that requires their HTML or behavior changes, and keep a record of the report. If the vendor will not move, plan a replacement on your own timeline rather than waiting forever. And document every step, because the remediation log is what proves you actually did the work.

The merchants I have seen handle this best are not the ones with the cleanest code. They are the ones who have a workflow. Audit, isolate, override what you can, escalate what you cannot, document everything, review quarterly. Do that consistently and your storefront stays compliant even as apps come and go.