The top 10 compliance issues we see on SMB sites, and how to fix them
Most SMB sites trip on the same short list of compliance issues. Nine of them a scanner can catch; one it cannot, and we say which. All are fixable in under a day with the right snippet.
These are the issues we see most often on SMB sites. We are deliberately not attaching a percentage to that: our production scan corpus is nowhere near large enough to support one, and an invented prevalence figure is exactly the kind of claim this blog exists to argue against. What follows is the judgement of the people who wrote the rule packs. Nine of the ten are findings the Veracly engine emits on its own; number ten is a manual check and is labelled as one. None require a rebuild; all are fixable in a single PR. For each: the regulation it breaches, the typical Veracly severity, and the developer fix.
1. Tracking pixels firing before consent
What: Meta Pixel, Google Ads, GA4, LinkedIn Insight loading on first page view, before the cookie banner has been clicked.
Regulation: ePrivacy Article 5(3), GDPR Article 7. CNIL and the Italian Garante have issued seven-figure fines for this exact pattern.
Severity: Critical.
Fix: Move every non-essential script behind a consent gate. The simplest pattern: set type="text/plain" on the <script> tag at first load and flip it to text/javascript when the user accepts. Most CMP vendors ship a helper for this; if you do not use a CMP, a 20-line vanilla helper does the job.
2. Form inputs without labels
What: Inputs with placeholder text but no associated <label> or aria-label.
Regulation: WCAG 2.1 AA Success Criterion 1.3.1 (Info and Relationships) and 4.1.2 (Name, Role, Value). Caught by every accessibility scanner and every screen reader.
Severity: Critical. The axe label rule is mapped critical in every one of our rule packs, EAA, ADA and UK Equality Act alike, because an unlabelled input is not a degraded experience, it is a form a screen-reader user cannot complete.
Fix: <label for="email">Email</label> paired with <input id="email" ... />. If a visible label is not in the design, use aria-label="Email" on the input. Never rely on placeholder alone, it disappears the moment the user starts typing.
3. Insufficient color contrast on body text
What: Gray-on-white body text with a contrast ratio below 4.5:1.
Regulation: WCAG 2.1 AA Success Criterion 1.4.3 (Contrast, Minimum).
Severity: High.
Fix: Darken the gray, but check the number before you touch a token. color: #9ca3af on #ffffff is 2.54:1 and fails outright. #6b7280 is 4.83:1 and already passes for normal text, if that is your body color, leave it alone. #475569 is 7.58:1 and passes with room to spare. Pair this with a one-time pass through your design tokens; the issue usually lives in 3-4 CSS variables, not on individual elements.
4. Missing accessibility statement
What: No accessibility statement resolving on your own domain. That is the whole test, and it is worth being precise about it: we check presence, never content and never freshness. There is no date or version check on any policy document in the engine, so a statement written in 2019 and never touched since passes exactly like one reviewed last week. Keeping it current is a calendar item you own, not a finding you will get.
Regulation: European Accessibility Act Article 13(2) and Annex V, which require a service provider to explain, in the general terms and conditions, how the service meets the accessibility requirements. The prescriptive statement template most people picture, conformance status, feedback mechanism, enforcement contact, comes from Article 7 of the Web Accessibility Directive (EU) 2016/2102 and binds the public sector; in the UK that lands as the 2018 accessibility regulations plus procurement law.
Severity: Critical, and it only fires when an EAA member state is in your scan scope. Outside the EAA there is no accessibility-statement rule in our packs at all, so a US-only or UK-only scan will not raise it, which is not the same as saying you do not need one.
Fix: Publish /accessibility on your own host, a statement parked on a vendor domain is not accepted by the check, with: the conformance target (WCAG 2.1 AA), the known limitations, a contact path for accessibility reports, and a last-reviewed date. Put the annual re-review in a calendar; nothing in the scan will remind you.
5. Cookie banner with no “reject all” option
What: A banner with “Accept all” on a prominent button but “reject all” buried two clicks deep, or missing entirely.
Regulation: GDPR Article 7(3), ePrivacy. The CNIL, the Garante and the AEPD have all fined for asymmetric consent, the design choice is itself the violation. In Germany, enforcement against private websites sits with the sixteen Land authorities, not the BfDI, which supervises federal public bodies and the telecoms and postal sector.
Severity: High.
Fix: Reject and accept must be on the same surface, same visual weight. The standard CNIL test: a reasonable person presented with the banner could decline as easily as accept. Most CMPs have a “banner parity” toggle shipped off-by-default, turn it on.
6. Self-hosted Google Fonts violation (live load)
What: The page loads fonts from fonts.googleapis.com or fonts.gstatic.com at runtime.
Regulation: LG München I 2022 ruling, live-loading Google Fonts transmits visitor IP addresses to Google without consent, violating GDPR Article 6. Class actions in Germany have followed.
Severity: Medium, inside GDPR scope. There is no country modifier on this rule, contrary to what the Munich origin story suggests: it grades medium whether your primary market is Germany or Portugal. Outside GDPR scope it is not graded low, it is not graded at all, because the rule lives only in the GDPR pack.
Fix: Self-host the font files. If you are on Next.js, the next/font/google API does this at build time automatically, drop the external <link> tags. For static sites, download the woff2 files and serve from your own origin.
7. Third parties that appear nowhere in the privacy policy
What: A vendor is observed loading on the page, Hotjar, Clarity, TikTok, Intercom, whose name appears nowhere in the published privacy text.
Regulation: GDPR Article 13 (information to be provided); in the UK, PECR alongside UK GDPR Article 13. The most common cause of a regulator follow-up question.
Severity: Medium, and only inside GDPR scope.
Fix: Name every third party you actually load, and say what it does. Two honest caveats on this rule. It deliberately under-reports: any mention of the vendor in any form counts as disclosed, so a pass means “the name is present”, not “the disclosure is adequate”. And nothing in Veracly compares a published cookie table against the cookies we actually saw set, that completeness check does not exist in our engine and we are not going to imply it does. Run a fresh inventory yourself from the browser’s Application tab, and re-check it on every third-party addition.
8. Missing alt text on meaningful images
What: Product photos, infographics, team headshots without an alt attribute.
Regulation: WCAG 2.1 AA SC 1.1.1 (Non-text Content).
Severity: Medium.
Fix: alt="descriptive text" on meaningful images, alt="" (empty string) on decorative ones. The empty alt is correct, not lazy, screen readers skip it. The bug is omitting the attribute entirely, and that is exactly as far as automation reaches: axe-core tests whether alt is present, never whether it says anything useful, and it cannot tell a meaningful image from a decorative one. alt="" on your hero product photo passes every scanner on the market, ours included, and still fails the user. Alt-text quality is a human review.
9. Empty headings and paragraphs dressed up as headings
What: An <h2> that contains only an icon, a decorative span, or nothing at all; or a large bold <p> sitting where a heading belongs.
Regulation: WCAG 2.1 AA SC 1.3.1 (Info and Relationships).
Severity: Medium.
Fix: Give every heading element real text, and promote visual pseudo-headings to actual <h2> / <h3> elements. Note the boundary here: empty headings and fake headings are machine-detectable and we fire on both, but whether your heading order is semantically correct is not, and we do not grade it. One <h1> per page with sections that drop a level at a time is still the right pattern, you just will not get a scanner finding when you break it. CSS handles visual size; do not pick a heading element for its font size.
10. Privacy policy missing required clauses (manual, no scanner settles this)
What: The published privacy policy omits one or more required sections, typically the international transfers clause, the data retention table, or the supervisory authority contact.
Regulation: GDPR Articles 13 and 14 enumerate the required disclosures.
Severity: Not scored, and that is the point. Veracly checks that a privacy policy exists and resolves on your own domain. It does not read the text for a controller, a legal basis, a retention period, or a transfer mechanism, there is no clause-level analysis in the engine at all. Any tool that claims to grade the adequacy of your policy is running a keyword search and calling it a legal opinion.
Fix: Run your policy against the Article 13/14 checklist by hand. Common omissions: SCC reference for non-EU transfers, named supervisory authority for your country of establishment, retention periods (not just “as long as necessary”). Re-read it every time you add a processor, and put a lawyer over the final language every couple of years.
The pattern
Nine of these ten issues are fixable by a single developer in under a day. Issue #10 (privacy policy) is the only one that needs a lawyer review on the final language. That is the SMB compliance opportunity in 2026: the bar is low because most sites never check.
See also: Reading your first Veracly report · Cookie banner audit checklist
Common questions
How were these ten chosen?
Engineering judgement, not a prevalence statistic. These are the findings our rule packs fire most often in practice, weighted by severity, and each maps to a specific named regulation rather than a vague "best practice." Nine are automated findings; the tenth, privacy policy clause coverage, is a manual check we include precisely because no scanner can settle it. All ten are fixable in code; none require redesign.
Are these in priority order?
Roughly. We list the legal-exposure issues first (consent, missing legal pages, form labels) because those carry the largest fine surface. Severity in your own report depends on how many pages each issue affects on your site.
Does fixing all ten make my site compliant?
No. It removes the most common and most easily evidenced failures, which is worth doing, but compliance is the long tail: accessibility statements, third-party widget review, the keyboard and screen-reader testing no scanner performs, and ongoing monitoring as your site changes. The top ten are the floor, not the ceiling.
See where your site stands.
Run a free Veracly scan and get a multi-jurisdiction report, EAA, GDPR, ADA, UK Equality Act, AODA, with copy-paste developer fixes.
Run a free scan