Grammar Checker

Check English grammar, spelling and style with Harper, an open-source rules engine that downloads once and then runs on your own device.

🌐 Español

🔒 Private by design: your text is processed locally in your browser and never uploaded to any server.

Harper, not a language model

The checker behind this page is Harper, an Apache-2.0 licensed English grammar and style engine compiled to WebAssembly. Nothing about it is generative. The module imports Harper’s worker-backed linter, hands it your text, and formats whatever comes back as a report. There is no prompt in the code, no API key, and no model endpoint, which also means there is no per-request cost and no quota waiting to run out on you.

The class the module reaches for is the one Harper describes as spinning up a dedicated web worker so that linting happens on a separate thread. The practical effect is that a long document does not lock up the tab while it is being checked. It also means the engine is a genuine dependency with a pinned version rather than a service that can change its answers underneath you.

The one-time download, and what the CDN does with it

The engine is not bundled into this site’s build. The module constructs a URL pinned to the exact installed version and fetches the binary at the moment of your first real check. I downloaded that exact URL while writing this page: 18,231,217 bytes, served as application/wasm, with an open cross-origin header and a cache directive of public, max-age=31536000.

It is tempting to describe what follows as loading the engine once and keeping it warm in the tab. That is not what happens. The module wraps the lint in a try block and calls the linter’s dispose method from the matching finally, so the worker is torn down after every single check, successful or not. A second check builds a fresh linter. What makes it feel instant is that year-long cache entry, not an engine held in memory.

Four steps from draft to issue list

  1. Paste the English text you want checked into the box at the top of the page.
  2. Set English dialect if you need to. The choices are American English (default), British English, Australian English, Canadian English and Indian English, and any value the module does not recognise falls back to American.
  3. Click Grammar Checker. On a fresh browser profile most of that first wait is the download described above.
  4. Read the report, then use Copy to clipboard to take it with you, or Process another to clear the page.

The shape of a single report entry

The output is a plain-text report rather than an annotated copy of your writing, for the reason given in the FAQ: the shared paste-in box is a textarea and cannot draw anything on top of your words. It opens with a === GRAMMAR CHECK RESULTS === banner and a count that has its own singular and plural forms, so one problem reads as “1 issue found:” and two read as “2 issues found:”.

Each entry below that is four lines. The first carries a bracketed index number, the issue kind Harper assigned it, then a dash and a 1-based line and column. The second quotes the exact flagged text in double quotes. The third is Harper’s own explanation of the problem. The fourth is always present and reads Suggested fix(es): followed either by the proposed replacements joined with commas, or by a literal (none) when Harper flagged something without offering a rewrite.

The line and column come from a small helper that walks the text counting newlines up to the issue’s start offset, and clamps an out-of-range offset into the text rather than throwing. So the numbers always point somewhere real in what you pasted.

Two reports that contain no issues at all, and what each one means

If Harper finds nothing wrong, the report reads “No issues found. Nice writing!” beneath the usual banner. If your input is nothing but whitespace, it reads “No text provided.” instead.

The second message is harder to reach than it looks. The action button stays disabled while the box holds no characters at all, so the only way to see it is to paste spaces, tabs or empty lines. That branch is also worth knowing about for a different reason: it returns before the dynamic import of the engine ever runs, so a whitespace-only check costs you no download whatsoever.

The dialect select, and the round trip that changing it costs

The dialect is not a spelling list bolted on after the fact. It is passed to the linter at construction time, so the whole run happens under that dialect’s conventions. The module maps the five option values onto the library’s dialect enum by key name rather than by number, deliberately, so that a future release which renumbers that enum cannot silently start checking your British draft against Canadian rules.

The awkward part is the surrounding form. Once a check completes, the input box, the dialect select and the action button are all unmounted and replaced by the result. There is no path to changing the dialect and re-running against the same text: Process another resets everything and empties the box, so you paste again. If you plan to compare two dialects on one draft, keep a copy of it somewhere before the first run.

English only, and what to reach for alongside it

Harper checks English. The dialect list covers five varieties of it, and text in another language will produce noise at best. There is no non-English path here.

What a grammar report cannot tell you is how long or how readable the writing is. Word Counter handles the first, counting words, characters and sentences and estimating a reading time from a Reading speed (words per minute) field that starts at 225. Readability Checker handles the second, with Flesch Reading Ease and a grade level. And when you want to see precisely what an edit changed, paste the before and after into Text Diff Checker and switch its Diff view to word-by-word, which is built for prose rather than code. The first two live with the other writing utilities on the text tools hub; the diff tool sits with the developer tools.

Frequently asked questions

Does this hand my writing to an AI model?

No. The code path imports harper.js, constructs a linter and calls its lint method on your text; there is no prompt, no API key and no model endpoint anywhere in it. The only network request the tool makes on its own account is the fetch for the engine binary, and that request carries none of your text.

How large is the one-time engine download, exactly?

18,231,217 bytes, which is roughly 18 MB. That figure comes from fetching the exact pinned URL the module uses, not from an estimate. The CDN returns it with a one-year cache header, so the cost lands once per browser profile rather than once per check.

Why does the report give line and column numbers instead of highlighting the words?

The paste-in box this tool shares with the site's other text utilities is a plain textarea, which cannot draw coloured underlines beneath individual words. The report compensates by printing a 1-based line and column for every issue next to the exact flagged text, so the position is unambiguous even in a long document.

I wanted to change the dialect after checking and my text had gone. What happened?

The form is replaced by the result the moment a check finishes, and the only route back to the dialect select also clears the input box. Copy your draft before the first run if you plan to compare two dialects, then paste it back for each one.

What happens if I paste nothing but blank lines?

You get a short report saying no text was provided, and you get it without downloading the engine, because that case is handled before the import ever runs. The action button stays disabled while the box is completely empty, so spaces and blank lines are the only way to reach that message at all.

Can it check Markdown, code comments, or a second language?

The linter is told explicitly to treat your input as plain text, which overrides the library's own Markdown default, so heading marks and code punctuation are read as ordinary prose and may well be flagged. English is the only language available, in the five dialects listed; anything else produces unreliable output rather than a clear refusal.

Related tools