Fix
Your viewport meta tag is blocking pinch zoom
Pinch to zoom is the accessibility feature people use without ever naming it. One meta tag in your head switches it off — and it usually got there years ago, trying to stop an iPhone zooming into a checkout field.
Who this locks out
user-scalable=no locks pinch-zoom away from the people who need it most.
- Shoppers with low vision, for whom pinch zoom is how the web is read
- Older customers reading small product text on a phone
- Anyone in daylight glare, magnifying to check a price or a size chart
The transform
Before
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> After
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2"> Detection
How this is tested here
Every scan runs three independent engines and 19 custom checks against your rendered pages, and records which engine flagged what. These are the real rules behind this fix family.
| Criterion | Level | Detected by | What we do |
|---|---|---|---|
| 1.4.4 Resize Text Most affects: People with low vision | AA | axe-core (meta-viewport) · IBM Equal Access (meta_viewport_zoomable, style_viewport_resizable) | auto |
| 1.4.10 Reflow Most affects: People with low vision | AA | Klarvo probe (klarvo.reflow) | auto |
What Klarvo Access does
Klarvo parses the viewport declaration in the HTML your store serves, applies a corrected content attribute server-side where the repair is lossless, reports anything ambiguous for a human to decide, and re-validates the served page.
Auto-applied
Generated, then applied server-side in the HTML your store actually serves — and independently re-validated in the served page before it counts as resolved.
An automated finding is evidence, not a certificate. Conformance is certified only by the professional audit — how that works.
Do it yourself
Fixing this by hand
What a locked viewport costs your store
A shopper lands on a product page. The care instructions, the fabric composition, the delivery cut-off — all set small, because product pages are dense. She does what everyone with reading glasses somewhere else in the house does: puts two fingers on the glass and spreads them. The page refuses. She tries again, harder, as if the first pinch didn’t register. Then she leaves, and your analytics file it under an ordinary exit.
The refusal comes from one line in your <head>. A viewport meta tag declaring user-scalable=no, or capping maximum-scale at 1, instructs mobile browsers to disable the shopper’s zoom. Two success criteria are on the line. WCAG 1.4.4 Resize Text (Level AA) requires that text can be scaled up to twice its size without losing content or function — and on a phone, pinch zoom is the resize mechanism; the W3C’s own technique for meeting the criterion, G142, is simply to rely on user agents that support zoom, which is exactly what this tag defeats. WCAG 1.4.10 Reflow is its companion: content must remain usable when magnified, without two-directional scrolling. A store that blocks zoom fails the shopper before reflow even gets a chance to.
The tag is almost never hostile — it is archaeology. The most common origin is the iOS input-zoom hack: Safari automatically zooms into a focused field whose text is under 16 pixels, someone found it fiddly on the old checkout, and maximum-scale=1 made the symptom go away. Other times it is app-envy boilerplate (“web apps shouldn’t scale”), or a theme’s “disable zoom on mobile” toggle that shipped switched on.
One honesty that cuts both ways: iOS Safari has ignored user-scalable=no for years, precisely because of the harm it does. Chrome on Android honours it unless the shopper has found a buried accessibility setting. In-app browsers — the WebViews your Instagram and Facebook traffic actually arrives in — mostly honour it. So the directive doesn’t even fail consistently: it fails for the shoppers on the platforms least likely to route around it, and a store relying on browsers to disobey its own markup is not conformant, it is lucky.
The people it locks out are the ones for whom magnification is not optional: shoppers with low vision, for whom pinch zoom is the default way the web is read; older customers, since close focus declines from mid-life onwards; and situationally, anyone on a bright street trying to read a grey size chart at arm’s length.
How it is detected here
This family is decided by Klarvo’s own deterministic parse of the raw bytes your server sends, fetched the way a visitor fetches them.
The engine finds every <meta name="viewport"> in the served source and parses the content attribute against a strict grammar: comma-separated name=value directives, drawn from the small set browsers actually define. Strictness is the point — a repair can only be promised as lossless if the parse was lossless first. A page is flagged when any of these hold:
user-scalableis set tonoor0;maximum-scaleis below 2 — the same floor axe-core’smeta-viewportrule enforces, with its best-practice companionmeta-viewport-largeasking for headroom up to 5;- more than one viewport meta is served, so which declaration wins is a browser implementation detail;
- the content does not parse cleanly: unknown or repeated directives, or scale values outside the range the platform defines.
axe’s rules exist as independent corroboration of the threshold, but the fix decision rides on Klarvo’s own parse, because a byte-precise rewrite needs a byte-precise read of what is actually being rewritten.
What Klarvo does about it
This family is auto tier — with a boundary it refuses to cross, and the boundary is the honest part.
Where the repair is lossless, it is applied automatically. The engine rebuilds the content value keeping every directive exactly as you authored it, with two corrections: user-scalable=no (or 0) is dropped, and a maximum-scale below 2 is raised to 2. Your width=device-width, your initial-scale, anything else legitimate — untouched. The corrected attribute is then applied server-side by a targeted rewrite of that exact meta tag, identified by a byte-for-byte fingerprint of its opening tag, in the HTML your store serves. It is never a script patching the page after load: the markup that leaves your server is the corrected markup, which is what a browser, a scanner and an auditor all read.
Where the repair is not provably lossless, nothing is applied. A duplicate viewport meta, an unparseable content attribute, a user-scalable value that is neither yes nor no, a scale outside the platform’s range — these are reported for a human to decide, with the finding laid out plainly. The engine could guess; on a tag that controls your entire mobile layout, it will not. A wrong guess here would not be a fix, it would be a new incident.
Either way, the result is re-validated independently: the engine re-fetches the page and confirms the exact corrected attribute is present in the newly served source before the finding is recorded as fixed. An automated finding is evidence, not a certificate — the re-fetch is the evidence.
How to fix it yourself
Find where the tag is printed
In a classic theme it is almost always hard-coded in header.php — search the theme with grep -rn 'viewport' wp-content/themes/your-theme/. In a block theme, WordPress core prints a clean width=device-width, initial-scale=1 itself, so a restrictive tag means a plugin, a legacy template part or an optimisation tool is adding one.
If the served source shows two viewport metas, resolve that first, because browsers disagree about which declaration wins and your mobile layout is currently at the mercy of that disagreement. The usual pairing is core or the theme printing the clean tag while a mobile-optimisation or popup plugin injects its restrictive own; deactivate plugins one at a time until the second tag disappears from the source, then look for a setting in the guilty one before resorting to its support forum.
Serve the correct declaration
<meta name="viewport" content="width=device-width, initial-scale=1">
That is the whole thing. No maximum-scale, no user-scalable. In a classic theme, correct it in the child theme’s copy of header.php; if a theme option offers “disable pinch zoom”, switch it off and let the option, not a template edit, carry the fix through updates.
Remove the reason it was added: the 16px rule
If the cap was guarding against iOS zooming into checkout fields, fix the cause. Safari zooms into a focused field whose computed font-size is under 16 pixels; give WooCommerce’s fields 1rem and the behaviour stops on its own:
.woocommerce form .form-row input.input-text,
.woocommerce form .form-row textarea,
.woocommerce form .form-row select,
.wc-block-components-text-input input {
font-size: 1rem;
}
Add it in the child theme stylesheet or Additional CSS. This also quietly improves the checkout for everyone — 16px fields are simply easier to read and hit.
Check reflow while you are in there
Restoring zoom is half of the pair; 1.4.10 asks that the page stay usable once zoomed. On a desktop browser at a 1280-pixel window, zoom to four times — an honest stand-in for a 320-pixel viewport — and walk the shop, a product and checkout. Content should reflow to a single column without the page scrolling in two directions. The usual WooCommerce offender is a table: size charts and order tables should scroll inside their own container rather than stretching the page:
.woocommerce table.shop_table { display: block; overflow-x: auto; }
How you know it worked
- Pick up a real phone and pinch on a product page. It should zoom, smoothly, to at least double. If your traffic arrives from social apps, try it inside one of those in-app browsers too — they are the strictest audience this tag has.
- View the served source and confirm there is exactly one viewport meta, with no
user-scalable=noand nomaximum-scalebelow 2. Use view-source orcurl, not the DevTools inspector, so you are reading what the server sent. - Re-scan. The viewport finding should clear, and where Klarvo applied the repair, its re-validation will already have confirmed the exact corrected attribute in the served page — your re-scan is a second witness, not the first.
- Do the four-times-zoom reflow walk above on the pages that take money: basket and checkout, where small type and dense layout meet.
- Re-check after theme updates. A theme release can restore an old header template, and the tag comes back exactly as silently as it first arrived — which is why this stays monitored rather than fixed once.
Sources: W3C WAI — Understanding SC 1.4.4: Resize Text · W3C WAI — Understanding SC 1.4.10: Reflow · W3C WAI — Technique G142: Using a technology that has commonly-available user agents that support zoom · Deque University — axe rule meta-viewport (axe-core 4.12) · Deque University — axe rule meta-viewport-large (axe-core 4.12) · MDN — Using the viewport meta tag
FAQ
Questions this raises
Safari ignores user-scalable=no anyway. Why does this need fixing?
Some browsers deliberately override the directive because of the harm it does; others honour it — including many of the in-app browsers your social traffic arrives in. A store whose zoom works only where the browser disobeys the store's own markup has not fixed anything, and what is measured, by any scanner and any auditor, is the markup you serve.
I added maximum-scale=1 to stop iOS zooming into my checkout fields.
That auto-zoom happens because the field's text is smaller than 16 pixels — the browser is compensating for type it considers too small to edit. Set your form fields to 1rem (16px) and the zoom-on-focus stops on its own, with no need to cap the shopper's zoom to do it. The cap was suppressing the symptom.
Why was my page reported for a human instead of being fixed automatically?
Two honest reasons. The page serves more than one viewport meta — which one a browser applies is not something the engine will bet your mobile layout on — or the content attribute does not parse cleanly: unknown directives, repeated directives, or scale values outside the range the platform defines. In both cases guessing could change your layout, so nobody guesses; a person decides.
Find out whether your store has this one.
The free scan checks your real pages — home, product, populated basket, hydrated checkout — with all three engines and all 19 Klarvo checks, and tells you exactly what it found and where.