Real numbers from this tool, line by line.

Thirteen weak points — ten of them high severity — in the age gate of one Manchester vape storefront's landing page, and the whole gate is four lines of JavaScript.
The page looked finished. An overlay asks "Are you over 18?", there is a tick box that says "I am over 18", a box to type a birth date, and a sentence underneath: "By entering this site you confirm you are 18 or older." Click through and the catalogue appears. That gate was written the way almost every small shop gate was written, and it has been out of step with the law since 25 July 2025, when Ofcom's guidance on highly effective age assurance began to apply under the Online Safety Act 2023.
Ofcom's guidance is unusually plain about what does not count. Self-declaration does not count. A birth date typed by the visitor does not count — it is self-declaration wearing a form. A general disclaimer does not count. A payment method that under-18s can also hold does not count. What does count is a listed method: photo-ID matching, facial age estimation, open banking, a mobile network operator check, a digital identity wallet. Ofcom enforces this, and the penalty ceiling is £18 million or 10% of qualifying worldwide revenue, whichever is greater.
The second half of the problem is not in the markup at all, it is in the script. On the test page the pass is written with localStorage.setItem('ageVerified', 'true'), the cookie is set with max-age=31536000, and the overlay is taken away with classList.remove(). Every one of those decisions happens in the browser. The catalogue markup was already delivered before anyone answered anything; the gate only covered it. One key edit in dev tools, or one look at view-source, and the gate is not there.
Age Gate Lint reads one HTML file — markup and inline script together — against eight rules: self-declared clicks, typed birth dates, browser-storage passes, year-long cookies, DOM-resident content uncovered by a class toggle, cards used as proof, disclaimer-only gates, and pages that gate on their own with no listed method anywhere in them. On the test page it returned 13 findings, 10 high and 3 medium, each with a line number and the clause it fails.
The same engine was then run on a rewritten version of that page, where the server renders the catalogue only after a pass comes back from a listed provider and the result is held in a signed session cookie with max-age=1800. That page returned zero findings. The difference between the two files is not politeness or wording; it is where the decision is made.
That is the practical test for any gate you maintain: if a visitor can reach the restricted markup by editing something they own — a key, a cookie, a class — the gate is decorative. If the answer comes back from a listed method and the server holds it, the gate is a gate.
What this cannot do is see your server. A page that gates properly on the back end ships no restricted markup and reads as clean, which is the correct answer. It is a lint over the surface you actually control in the editor, not legal advice.
The free command reads the file you have open and finishes that job: all eight rules, every finding, every line. The engine is the same file that runs the free web page, so the answer is the same in either place. Costed the other way, a freelance web developer bills about $60 an hour and a manual pass over one storefront's gate plus the written note is roughly half a day — near $240, and again after the next redesign.