Keyword stuffing: measuring density around your CTAs
Repeating a term unnaturally is a spam policy violation. squirrel measures density while discounting repeated call-to-action labels.
What keyword stuffing is
Keyword stuffing is repeating a word or phrase far beyond what the writing needs, in order to signal relevance to a search engine. Google’s spam policies name it explicitly, and it has not worked for a long time.
Measuring it naively produces false positives. A product listing with fifty “Add to cart” buttons repeats those words fifty times without saying anything, and a page about socks will legitimately use the word “socks” a lot. So density alone is not the test.
What squirrel checks
The rule runs on every crawled page over the body text with scripts, styles and noscript excluded, matching words of three or more letters. It emits a single check named keyword-stuffing:
- Skipped when there is no
<body>. Message:No body content to analyze. - Info below 100 words. Message:
Content too short for keyword density analysis. - Warn when any word crosses both thresholds. Message:
2 word(s) may be overused, each item labelled"widget" (4.7%)with its count and density. Severity warning, weight 5. - Pass otherwise. Message:
No keyword stuffing detected.
A word is flagged when its density is above density_threshold, 3% by default, and its count is above min_occurrences, 5 by default. Two subtractions come first. A list of roughly fifty function words and generic verbs is excluded outright, covering articles, pronouns, auxiliaries and words like get and here that read as high density on any page. Then generic call-to-action labels on <a> and <button> elements are counted, and their words are subtracted from both the word’s own count and the denominator, so a page of “Learn more” buttons is measured on its prose. Nested controls are counted once, from the outermost element.
The site’s own brand or product name is never flagged: a one-product landing page repeats its name because that is what the page is for. The name is read from the page’s domain (acme.com, and launch-style variants such as getacme.com or acmehq.io resolve to acme), plus any word of og:site_name or application-name that the domain also carries. A site name the domain does not carry is not exempt, so a page cannot excuse a stuffed keyword by naming itself after it. Add other brand or product names to whitelist.
How to fix it
Rewrite the passage. Use synonyms and related terms where the exact phrase is not needed, and write the sentence you would write if nobody were counting.
Add your brand name or a genuinely repeated product term to whitelist rather than editing around it. A page about one product will name that product often, and that is not stuffing.
| Rule ID | content/keyword-stuffing |
| Category | Content |
| Scope | Per-page |
| Severity | warning |
| Weight | 5/10 |
Options
| Option | Type | Default | Description |
|---|---|---|---|
density_threshold | number | 3 | Keyword density percentage threshold |
min_occurrences | number | 5 | Minimum word occurrences to flag |
whitelist | array of strings | [] | Words to ignore (for example a brand name) |
Configuration example
[rule_options."content/keyword-stuffing"]
density_threshold = 4
whitelist = ["acme", "squirrelscan"]Enable / disable
Disable this rule
[rules]
disable = ["content/keyword-stuffing"]Disable all Content rules
[rules]
disable = ["content/*"]Enable only this rule
[rules]
enable = ["content/keyword-stuffing"]enable replaces the default ["*"], so this is the only rule selected. Leave disable out: a rule that matches any disable pattern is skipped even when enable names it. Only an enabled setting under a rule’s own [rule_options] table overrides both lists.
Related rules
- content/hidden-text: keywords hidden from readers rather than repeated at them.
- integrity/seo-doorway: injected pages built entirely out of this pattern.
- content/quality: an LLM read of whether the writing is any good.
- content/reading-level: the other readability measurement over the same text.
Content findings ship in every audit next to the SEO, performance and agent experience rules. See Fix SEO issues with AI for how an agent works through a report.
References
Check your site
Run squirrel audit https://example.com and open the Content section of the report. Each overused word is listed with its count and density. Signed-out local audits need no account and cost nothing. Signed-in audits spend credits.