Grammar and spelling checks are useful for blogs, support replies, product descriptions, emails, user-generated content, and AI-generated drafts.
If your app accepts text, you can use Python to catch basic mistakes before the text goes live. You can check typos, grammar issues, repeated words, punctuation problems, and style warnings. You can also return suggestions in JSON so your app can show corrections inside an editor.
In this guide, we’ll build a simple grammar and spelling checker with Python. We’ll start with language_tool_python, add a pure Python spell checker, and then show how to turn the checks into a small API.
Quick answer
The fastest way is to use LanguageTool through the Python wrapper language_tool_python. Its docs say the library can detect grammar errors and spelling mistakes from Python code or the command line.
Install it:
pip install language-tool-python
Then run:
import language_tool_python
tool = language_tool_python.LanguageTool("en-US")
text = "This are a simple sentence with a spelling mistke."
matches = tool.check(text)
for match in matches:
print(match.message)
print(match.replacements)
Example output:
The verb 'are' does not agree with the subject 'This'.
['is']
Possible spelling mistake found.
['mistake']
That gives you a practical grammar checker in a few minutes.
Why can we write this
We’ve spent around 6 years working with AI APIs, NLP workflows, text tools, and developer-focused automation. We also researched current Python grammar and spelling tools for this article, including LanguageTool, pyspellchecker, spaCy, and grammar correction research.
The simple version is: use LanguageTool for grammar and spelling suggestions, use a spell checker for lightweight typo checks, and add review logic before auto-fixing user text.
What can Python check?
A grammar checker can catch different types of issues.
| Issue type | Example | Possible fix |
| Spelling | mistke | mistake |
| Subject-verb agreement | This are good | This is good |
| Repeated words | the the text | the text |
| Punctuation | Lets go | Let’s go |
| Capitalization | i am ready | I am ready |
| Style | very very good | very good |
| Word confusion | their going home | they’re going home |
A basic spell checker works well for typos. Grammar needs more context, so a tool like LanguageTool is usually a better first choice.
Research on grammatical error correction also backs this up. The ERRANT paper introduced a toolkit for grammar error annotation and evaluation, which shows how grammar correction is usually measured by edit types rather than only “right or wrong.” In real apps, this means you want error categories, suggestions, and confidence, not just a red underline.
Option 1: Check grammar with LanguageTool
LanguageTool is one of the easiest options for Python grammar checks.
Install:
pip install language-tool-python
Basic code:
import language_tool_python
tool = language_tool_python.LanguageTool("en-US")
text = "She go to school every day. This sentence have a error."
matches = tool.check(text)
for match in matches:
print("Issue:", match.message)
print("Text:", text[match.offset:match.offset + match.errorLength])
print("Suggestions:", match.replacements)
print("Rule:", match.ruleId)
print()
Example output:
Issue: The pronoun 'She' is usually used with a third-person or singular verb.
Text: go
Suggestions: ['goes']
Issue: The verb 'have' does not agree with the subject 'This sentence'.
Text: have
Suggestions: ['has']
This is already useful for an editor, CMS, chatbot, or content QA tool.
Return clean JSON
Most apps need structured output.
Here is a helper function:
import language_tool_python
tool = language_tool_python.LanguageTool("en-US")
def check_text(text):
matches = tool.check(text)
issues = []
for match in matches:
issues.append({
"message": match.message,
"error_text": text[match.offset:match.offset + match.errorLength],
"offset": match.offset,
"length": match.errorLength,
"suggestions": match.replacements[:5],
"rule_id": match.ruleId,
"category": match.category
})
return {
"text": text,
"issue_count": len(issues),
"issues": issues
}
sample = "This are a test sentence with bad grammer."
print(check_text(sample))
Example output:
{
"text": "This are a test sentence with bad grammer.",
"issue_count": 2,
"issues": [
{
"message": "The verb 'are' does not agree with the subject 'This'.",
"error_text": "are",
"offset": 5,
"length": 3,
"suggestions": ["is"],
"rule_id": "THIS_NNS",
"category": "GRAMMAR"
},
{
"message": "Possible spelling mistake found.",
"error_text": "grammer",
"offset": 35,
"length": 7,
"suggestions": ["grammar"],
"rule_id": "MORFOLOGIK_RULE_EN_US",
"category": "TYPOS"
}
]
}
This is the format you can send to a frontend.
Auto-correct text
LanguageTool can also apply suggestions.
import language_tool_python
tool = language_tool_python.LanguageTool("en-US")
text = "This are a test sentence with bad grammer."
matches = tool.check(text)
corrected = language_tool_python.utils.correct(text, matches)
print(corrected)
Output:
This is a test sentence with bad grammar.
Auto-correction is nice for drafts, but use it carefully. Some suggestions can change the meaning. For user-facing tools, it is often better to show suggestions and let the user accept them.
A 2024 study on grammar correction in Japanese learner writing found that one model had high adjusted precision but much lower recall after human review, meaning it was careful but missed many errors. The paper is about Japanese, but the lesson fits many grammar tools: grammar checks can help a lot, yet they still miss context-heavy mistakes. You can read the study here: Assessing the Efficacy of Grammar Error Correction.
Option 2: Check spelling with pyspellchecker
For simple spell checks, pyspellchecker is lightweight. Its docs say it uses Levenshtein distance to find likely corrections.
Install:
pip install pyspellchecker
Use it:
from spellchecker import SpellChecker
spell = SpellChecker()
text = "This sentense has a few speling mistakes."
words = text.split()
misspelled = spell.unknown(words)
for word in misspelled:
print(word, "->", spell.correction(word))
Example output:
sentense -> sentence
speling -> spelling
You can also get multiple candidates:
print(spell.candidates(“speling”))
Example:
{‘spelling’, ‘spieling’}
This works well for fast typo checks, search boxes, small forms, and lightweight text QA.
When to use LanguageTool vs pyspellchecker
Here is the simple split.
| Need | Better choice |
| Grammar checks | LanguageTool |
| Spelling checks | LanguageTool or pyspellchecker |
| Pure Python typo detection | pyspellchecker |
| Style suggestions | LanguageTool |
| Multi-language grammar | LanguageTool |
| App-level JSON issue output | LanguageTool |
| Very lightweight checks | pyspellchecker |
Use LanguageTool if you want a practical all-in-one grammar and spelling checker.
Use pyspellchecker if you only need typo detection and want a tiny setup.
Option 3: Add spaCy for text preprocessing
spaCy is not mainly a grammar checker, but it is useful around grammar workflows. Its docs explain that spaCy uses processing pipelines that tokenize text and add linguistic annotations. You can use it to split sentences, inspect tokens, find parts of speech, or prepare text before checking.
Install:
pip install spacy
python -m spacy download en_core_web_sm
Use it:
import spacy
nlp = spacy.load("en_core_web_sm")
text = "This are a sentence. It has two parts."
doc = nlp(text)
for sentence in doc.sents:
print(sentence.text)
Output:
This are a sentence.
It has two parts.
This helps when you want to check long content sentence by sentence.
def split_sentences(text):
doc = nlp(text)
return [sent.text.strip() for sent in doc.sents]
print(split_sentences("This are wrong. This is fine."))
For large articles, checking one sentence or paragraph at a time can make results easier to show in an editor.
Build a full grammar check function
Here is a practical function that combines grammar checks with a clean score.
import language_tool_python
tool = language_tool_python.LanguageTool("en-US")
def grammar_report(text):
matches = tool.check(text)
issues = []
for match in matches:
issues.append({
"message": match.message,
"error_text": text[match.offset:match.offset + match.errorLength],
"suggestions": match.replacements[:5],
"category": match.category,
"rule_id": match.ruleId,
"offset": match.offset,
"length": match.errorLength
})
word_count = len(text.split())
issue_rate = len(issues) / max(word_count, 1)
if issue_rate == 0:
quality = "clean"
elif issue_rate < 0.03:
quality = "minor_issues"
elif issue_rate < 0.08:
quality = "needs_editing"
else:
quality = "needs_review"
return {
"word_count": word_count,
"issue_count": len(issues),
"issue_rate": round(issue_rate, 3),
"quality": quality,
"issues": issues
}
text = """
This are a short paragraph with bad grammer.
It also have some spelling mistkes.
"""
print(grammar_report(text))
This gives your app a simple quality label:
| Quality | Meaning |
| clean | No detected issues |
| minor_issues | A few small fixes |
| needs_editing | Several issues |
| needs_review | Send to editor or review flow |
Build a Small API with FastAPI
If you want to check text from a web app, wrap the checker in an API.
Install:
pip install fastapi uvicorn language-tool-python
Create app.py:
from fastapi import FastAPI
from pydantic import BaseModel
import language_tool_python
app = FastAPI()
tool = language_tool_python.LanguageTool("en-US")
class TextRequest(BaseModel):
text: str
@app.post("/check")
def check_grammar(request: TextRequest):
text = request.text
matches = tool.check(text)
issues = []
for match in matches:
issues.append({
"message": match.message,
"error_text": text[match.offset:match.offset + match.errorLength],
"suggestions": match.replacements[:5],
"category": match.category,
"offset": match.offset,
"length": match.errorLength
})
return {
"issue_count": len(issues),
"issues": issues
}
Run it:
uvicorn app:app –reload
Test it:
curl -X POST “http://127.0.0.1:8000/check” \
-H “Content-Type: application/json” \
-d ‘{“text”:”This are a bad sentence with a typoo.”}’
Example response:
{
"issue_count": 2,
"issues": [
{
"message": "The verb 'are' does not agree with the subject 'This'.",
"error_text": "are",
"suggestions": ["is"],
"category": "GRAMMAR",
"offset": 5,
"length": 3
},
{
"message": "Possible spelling mistake found.",
"error_text": "typoo",
"suggestions": ["typo"],
"category": "TYPOS",
"offset": 34,
"length": 5
}
]
}
Now you have a simple grammar checker API.
Add language support
LanguageTool supports many languages, so you can change the language code.
tool = language_tool_python.LanguageTool(“en-GB”)
Examples:
| Language | Code |
| American English | en-US |
| British English | en-GB |
| German | de-DE |
| French | fr |
| Spanish | es |
| Ukrainian | uk-UA |
Always test with real text in that language. Grammar correction is harder across languages because each language has its own morphology, punctuation rules, and common learner errors.
A 2025 paper on multilingual grammatical error annotation makes this point well: grammar evaluation needs both language-agnostic structure and language-specific flexibility. In plain words, a grammar checker that works well for English may still need special rules for Korean, Ukrainian, German, or Romanian.
Should you auto-fix everything?
For simple typos, auto-fix can be fine.
For grammar, be more careful.
| Issue type | Auto-fix? |
| Clear typo | Usually safe |
| Repeated word | Usually safe |
| Missing period | Usually safe |
| Subject-verb agreement | Review first |
| Word choice | Review first |
| Style suggestion | Review first |
| Legal/medical/finance text | Human review |
A grammar tool can suggest a technically valid fix that changes tone or meaning. For articles, emails, and product copy, show suggestions. For user-generated content, you can flag issues and let users accept fixes.
Use LLMs for style and rewrite suggestions
Grammar checkers are good for errors. LLMs are better for style, tone, clarity, and rewrites.
For example, LanguageTool can catch:
This are incorrect.
An LLM can help with:
Make this paragraph clearer and more casual.
A useful workflow:
- User text
- LanguageTool catches grammar and spelling issues
- Python returns issue list
- User accepts fixes
- LLM suggests optional rewrite
- Final text goes to editor/review
If you use LLMAPI, you can route basic rewrite tasks to a cheaper model and more complex editing tasks to a stronger model. You can also keep grammar checks separate from style rewrites, which makes the workflow easier to debug.
A practical content QA workflow
For blogs, landing pages, support replies, and AI-generated text, use a simple QA pipeline:
- Text draft
- Grammar and spelling check
- Style check
- Plagiarism/originality check if needed
- PII check if user data exists
- Human review
- Publish
For finance, legal, healthcare, or immigration content, keep a human in the loop. A grammar checker can catch surface errors, but it cannot confirm that the advice is correct.
Common mistakes
| Mistake | Better approach |
| Auto-fixing every suggestion | Let users review grammar and style fixes |
| Checking huge files at once | Split by paragraph or section |
| Ignoring language variant | Use en-US vs en-GB correctly |
| Using only a spell checker | Add grammar checks too |
| Treating suggestions as perfect | Show confidence and review options |
| Not storing offsets | Keep offsets so frontend can highlight issues |
| Checking only final text | Check drafts before publish |
| No test samples | Test with your real content |
Full copy-paste example
Here is the complete version:
import language_tool_python
tool = language_tool_python.LanguageTool("en-US")
def check_text_quality(text):
matches = tool.check(text)
issues = []
for match in matches:
issues.append({
"message": match.message,
"error_text": text[match.offset:match.offset + match.errorLength],
"suggestions": match.replacements[:5],
"category": match.category,
"rule_id": match.ruleId,
"offset": match.offset,
"length": match.errorLength
})
word_count = len(text.split())
issue_rate = len(issues) / max(word_count, 1)
if issue_rate == 0:
quality = "clean"
elif issue_rate < 0.03:
quality = "minor_issues"
elif issue_rate < 0.08:
quality = "needs_editing"
else:
quality = "needs_review"
corrected_text = language_tool_python.utils.correct(text, matches)
return {
"word_count": word_count,
"issue_count": len(issues),
"issue_rate": round(issue_rate, 3),
"quality": quality,
"issues": issues,
"corrected_text": corrected_text
}
if __name__ == "__main__":
sample = """
This are a short paragraph with bad grammer.
It have several spelling mistkes.
"""
report = check_text_quality(sample)
print(report)
Final thoughts
You can check grammar and spelling in Python with a simple setup.
Use language_tool_python when you need grammar, spelling, punctuation, and style suggestions. Use pyspellchecker when you only need lightweight typo detection. Add spaCy if you want sentence splitting, tokenization, and better preprocessing for longer content.
For real apps, return structured JSON with issue messages, offsets, categories, and suggestions. Let users review fixes before you apply them. If you need rewriting, tone changes, or content polishing, add an LLM step after the grammar check.
For a larger text workflow, use LLMAPI to route grammar-adjacent tasks like rewriting, summarization, tone checks, and content QA across different models without rebuilding the whole pipeline every time.