Rule Options
Configure individual rule thresholds, limits, and behavior
The [rule_options] section allows fine-tuning individual audit rules with custom thresholds and parameters.
Configuration
[rule_options]
[rule_options."core/meta-title"]
min_length = 30
max_length = 60
[rule_options."content/word-count"]
min_words = 300
warn_threshold = 500
[rule_options."adblock/element-hiding"]
maxMatchesToReport = 20How rule options work
Structure
Rule options use TOML table syntax:
[rule_options."<rule-id>"]
option1 = value1
option2 = value2<rule-id>- Full rule ID (e.g.,core/meta-title,content/word-count). It must be the exact ID: a category pattern such ascore/*configures nothing.- Option names are rule-specific and spelled exactly as the rule reads them. Most are
snake_case, but some arecamelCase(excludePatterns,maxMatchesToReport), so copy them from the rule’s page. - All options have defaults (configuration is optional)
Where to find a rule’s options
Each rule’s page in the Rules reference has an Options table listing every option the rule reads, with its type and default. A rule with no Options table takes no options, for example a11y/skip-link: to stop one of those running, disable it instead.
What happens to a mistake
squirrel config validate checks every [rule_options] table against the rule it names, and squirrel audit checks them again before it crawls. Each message names the table and the option:
-
An unknown rule ID or option name changes nothing: the rule runs on its defaults.
config validatereports it and exits 1, andsquirrel auditprints a warning and carries on. The message suggests a rule with the same name in another category, or lists the options the rule takes:Invalid config: [rule_options."performance/ttfb"]: no rule has this id, so the table changes nothing (did you mean "perf/ttfb"?) Invalid config: [rule_options."core/meta-description"] no_such_option: not an option of core/meta-description, so it changes nothing (options: min_length, max_length) -
A value of the wrong type would fail the rule.
config validatereports it, andsquirrel auditstops before crawling when the audit runs that rule. On a rule the audit does not run, it is a warning.Error: [rule_options."core/meta-title"] min_length: Invalid input: expected number, received string -
An
enabledthat is nottrueorfalseis ignored, and reported like an unknown option.
Common rule options
Core rules
core/meta-title
Control title tag length requirements.
Options:
[rule_options."core/meta-title"]
min_length = 30 # Minimum title length (characters)
max_length = 75 # Maximum title length (characters)Defaults:
min_length: 30max_length: 75
Examples:
Strict title requirements:
[rule_options."core/meta-title"]
min_length = 40
max_length = 55Lenient title requirements:
[rule_options."core/meta-title"]
min_length = 20
max_length = 70Behavior: a title shorter than min_length or longer than max_length → warn. A missing or empty title fails whatever the options say.
Why configure:
- Different industries have different conventions
- Brand names may require more characters
- Mobile SERPs show fewer characters (~50)
core/meta-description
Control meta description length requirements.
Options:
[rule_options."core/meta-description"]
min_length = 120 # Minimum description length
max_length = 160 # Maximum description lengthDefaults:
min_length: 120max_length: 160
Examples:
Google’s recommended length:
[rule_options."core/meta-description"]
min_length = 120
max_length = 158Allow longer descriptions:
[rule_options."core/meta-description"]
min_length = 100
max_length = 200Behavior: a description outside min_length to max_length → warn. A missing description fails whatever the options say.
Why configure:
- Google truncates ~160 characters
- Longer descriptions provide more context
- E-commerce may need more details
Content rules
content/word-count
Set minimum word count for content quality.
Options:
[rule_options."content/word-count"]
min_words = 300 # Minimum acceptable word count
warn_threshold = 500 # Optimal word count thresholdDefaults:
min_words: 300warn_threshold: 500
Examples:
Blog posts (longer content):
[rule_options."content/word-count"]
min_words = 500
warn_threshold = 1000Product pages (shorter acceptable):
[rule_options."content/word-count"]
min_words = 150
warn_threshold = 300Landing pages (minimal):
[rule_options."content/word-count"]
min_words = 100
warn_threshold = 200Why configure:
- Blog posts need more words (800-2000+)
- Product pages can be shorter (200-500)
- Landing pages focus on conversion
Behavior:
min_words = 300
warn_threshold = 500- < 300 words →
warn(thin content) - 300-499 words →
info(could be longer) - ≥ 500 words →
pass(good length)
content/keyword-stuffing
Detect keyword over-optimization.
Options:
[rule_options."content/keyword-stuffing"]
density_threshold = 3 # Maximum keyword density, in percent
min_occurrences = 5 # A word must appear more often than this to be flagged
whitelist = [] # Words never flagged, such as a product name your domain doesn't carryDefaults:
density_threshold: 3(3%)min_occurrences: 5whitelist: []
density_threshold is a percentage: 3 means 3%. A fraction such as 0.03 means 0.03%, which flags nearly every word that appears more than min_occurrences times.
Examples:
Strict (avoid over-optimization):
[rule_options."content/keyword-stuffing"]
density_threshold = 2 # 2% maxLenient, and ignore a product name (the name in your domain is already ignored):
[rule_options."content/keyword-stuffing"]
density_threshold = 5 # 5% max
whitelist = ["squirrelscan"]Why configure:
- Different content types have different natural repetition
- Technical docs may repeat terms more
- E-commerce descriptions can be repetitive
How density is calculated:
density = (keyword_occurrences / total_words) × 100Example:
- “widget” appears 30 times
- Page has 1000 words
- Density = 30/1000 × 100 = 3%
Words are counted from the page’s body text (scripts and styles excluded) as runs of three or more letters a to z, in any case, so “SEO” counts and “AI” does not. Pages with fewer than 100 such words are not checked (info). Generic button and link labels such as “Learn more” and “Add to cart” are then taken out of both counts. A word is flagged when its density is above density_threshold and it appears more than min_occurrences times, and common words are never flagged.
content/article-links
Check that articles link to other pages and cite external sources, scaled to the article’s length. It only runs on article pages (an article page type or Article structured data).
Options:
[rule_options."content/article-links"]
short_max_words = 800 # Under this many words, an article is short
long_min_words = 1500 # From this many words, an article is long (medium in between)
short_min_internal = 1 # Minimum internal links, by length
medium_min_internal = 2
long_min_internal = 3
short_min_external = 1 # Minimum external links, by length
medium_min_external = 2
long_min_external = 2Defaults: as shown above.
Examples:
Require more citations (journalism):
[rule_options."content/article-links"]
short_min_external = 3
medium_min_external = 4
long_min_external = 5No external link requirement:
[rule_options."content/article-links"]
short_min_external = 0
medium_min_external = 0
long_min_external = 0Behavior: an article with fewer internal or external links than its length band requires → warn, one check each for internal and external links.
Why configure:
- Academic/news needs citations
- Product pages may not need external links
- E-E-A-T prefers authoritative sources
Link rules
URL patterns
links/orphan-pages, links/dead-end-pages and crawl/all-noindex-pages take lists of URL patterns. There are three forms, and no * or ** globs:
"/thank-you"matches any URL containing that text."/blog/"(starting and ending with/) matches the path/blogand everything under/blog/, but not/blog-archive.'regex:^/blog/\d{4}/'matches the path against a regular expression. Add flags after a colon:'regex:^/blog:i'. Use single quotes (a TOML literal string), because TOML rejects\dinside double quotes.
links/orphan-pages
Detect pages with too few incoming internal links.
Options:
[rule_options."links/orphan-pages"]
minInboundLinks = 2 # Pages with fewer incoming links are flagged
excludePatterns = ["/404", "/.well-known/"] # Pages never flaggedDefaults:
minInboundLinks: 2excludePatterns: []
Examples:
Ignore utility pages:
[rule_options."links/orphan-pages"]
excludePatterns = [
"/sitemap.xml",
"/robots.txt",
"/404",
"/500",
"/.well-known/"
]Flag only pages nothing links to:
[rule_options."links/orphan-pages"]
minInboundLinks = 1Why configure:
- Some pages are intentionally unlinked
- Utility pages don’t need internal links
- Reduce false positives
links/dead-end-pages
Find pages with no outgoing internal links.
Options:
[rule_options."links/dead-end-pages"]
excludePatterns = ["/thank-you", "/confirmation"] # Pages allowed to be dead ends
minLinks = 1 # Fewer outgoing internal links than this is a dead end
countAnchorLinks = false # Count #section links (useful for single-page apps)Defaults:
excludePatterns: ["/thank-you", "/confirmation", "/download", "/success", "/submitted"]minLinks: 1countAnchorLinks: false
Setting excludePatterns replaces the default list, so include the defaults you still want.
Examples:
Ignore conversion pages:
[rule_options."links/dead-end-pages"]
excludePatterns = [
"/thank-you",
"/confirmation",
"/download",
"/success",
"/submitted",
"/checkout/success"
]Why configure:
- Conversion pages often have no links (by design)
- Focus user on one action
- Reduce false positives
links/internal-links
Control internal linking recommendations.
Options:
[rule_options."links/internal-links"]
min_internal_links = 1 # Minimum internal links per page
max_internal_links = 100 # Maximum internal links per pageDefaults:
min_internal_links: 1max_internal_links: 100
Examples:
Require more internal linking:
[rule_options."links/internal-links"]
min_internal_links = 5Allow large navigation menus:
[rule_options."links/internal-links"]
max_internal_links = 250Behavior: fewer than min_internal_links or more than max_internal_links → warn.
Why configure:
- Landing pages may have fewer links
- Blog posts benefit from more internal links
- E-commerce categories need many links
Performance rules
perf/ttfb
Time to First Byte threshold.
Options:
[rule_options."perf/ttfb"]
good_threshold = 600 # Under this is good (ms)
poor_threshold = 1000 # From this is poor (ms)Defaults:
good_threshold: 600poor_threshold: 1000
Examples:
Strict performance (fast hosting):
[rule_options."perf/ttfb"]
good_threshold = 300
poor_threshold = 600Lenient (slow hosting):
[rule_options."perf/ttfb"]
good_threshold = 1000
poor_threshold = 2000Why configure:
- Shared hosting is slower
- CDN hosting is faster
- Geographic distance affects TTFB
Behavior:
good_threshold = 600
poor_threshold = 1000- < 600ms →
pass - 600-999ms →
warn - ≥ 1000ms →
fail
perf/dom-size
DOM size, depth and width limits.
Options:
[rule_options."perf/dom-size"]
warn_threshold = 1500 # Warning threshold (elements)
error_threshold = 3000 # Error threshold (elements)
max_depth = 32 # Deepest nesting before a warning
max_children = 60 # Most children of one <body> element before a warningDefaults:
warn_threshold: 1500error_threshold: 3000max_depth: 32max_children: 60
Examples:
Simple sites:
[rule_options."perf/dom-size"]
warn_threshold = 800
error_threshold = 1500Complex apps:
[rule_options."perf/dom-size"]
warn_threshold = 2000
error_threshold = 4000
max_depth = 40Behavior: fewer elements than warn_threshold → pass, fewer than error_threshold → warn, otherwise fail. Depth over max_depth and an element inside <body> with more than max_children children each warn on their own. <head> children are not counted for max_children.
Why configure:
- Simple pages have fewer elements
- Complex apps have more elements
- Mobile performance more sensitive
Security rules
security/http-to-https
Probe whether the http:// versions of your URLs redirect to HTTPS. The rule requests a sample of URLs over plain HTTP and lists the ones that redirect.
Options:
[rule_options."security/http-to-https"]
sampleLimit = 20 # Most URLs to probe (1 to 100)Default:
sampleLimit: 20
Examples:
Probe more of a large site:
[rule_options."security/http-to-https"]
sampleLimit = 100Why configure:
- A larger sample covers more of a big site
- A smaller one makes fewer live requests to your server
Crawl rules
crawl/all-noindex-pages
Count the pages blocked from indexing and list a sample, and raise the severity for sections that must stay indexable.
Options:
[rule_options."crawl/all-noindex-pages"]
errorOnPatterns = ["/products/"] # A blocked page here fails
warnOnPatterns = ["/blog/"] # A blocked page here warnsDefaults:
errorOnPatterns: []warnOnPatterns: []
Examples:
Treat any blocked product or blog page as a release blocker:
[rule_options."crawl/all-noindex-pages"]
errorOnPatterns = ["/products/", "/blog/"]Why configure:
- Staging sites should be fully noindexed
- Production sites shouldn’t be noindexed
- Detect misconfiguration
Behavior: pages blocked by a noindex meta tag or header, or by robots.txt, are reported as info with a count (the first ten listed). Blocked pages matching warnOnPatterns → warn, and ones matching errorOnPatterns → fail, each with a count and the first five listed. The patterns use the URL pattern forms.
Blocking rules
adblock/element-hiding
Check for elements that ad blockers would hide. This is a cloud rule: it needs squirrel auth login, and the cloud matches your selectors against the full EasyList cosmetic rules. The filter list is not configurable.
Options:
[rule_options."adblock/element-hiding"]
maxMatchesToReport = 10 # Matching selectors to list in detailDefault:
maxMatchesToReport: 10
Examples:
List more matches:
[rule_options."adblock/element-hiding"]
maxMatchesToReport = 20adblock/blocked-links
Check for links and resources that ad blockers (EasyList) would block. Also a cloud rule, with no list choice.
Options:
[rule_options."adblock/blocked-links"]
maxMatchesToReport = 10 # Blocked links to list in detailDefault:
maxMatchesToReport: 10
Configuration examples
Blog site
[rule_options."core/meta-title"]
min_length = 40
max_length = 60
[rule_options."content/word-count"]
min_words = 500
warn_threshold = 1000
[rule_options."content/article-links"]
short_min_external = 3
medium_min_external = 3
long_min_external = 3Why:
- Blog posts need longer titles
- Content should be comprehensive
- External citations improve E-E-A-T
E-commerce site
[rule_options."core/meta-title"]
min_length = 30
max_length = 55 # Shorter for mobile
[rule_options."content/word-count"]
min_words = 150
warn_threshold = 300 # Product pages are shorter
[rule_options."links/dead-end-pages"]
excludePatterns = ["/thank-you", "/confirmation", "/checkout/success"]Why:
- Product titles often shorter
- Product descriptions concise
- Conversion pages are dead-ends
Documentation site
[rule_options."content/word-count"]
min_words = 200
warn_threshold = 400
[rule_options."links/internal-links"]
min_internal_links = 5 # Docs should cross-reference
[rule_options."content/keyword-stuffing"]
density_threshold = 5 # Percent; technical terms repeatWhy:
- Docs can be shorter (reference material)
- Cross-referencing improves UX
- Technical terms naturally repeat
Landing pages
[rule_options."content/word-count"]
min_words = 100
warn_threshold = 200 # Conversion-focused
[rule_options."links/internal-links"]
min_internal_links = 1 # Focus on CTA
[rule_options."links/dead-end-pages"]
excludePatterns = ["/lp/"] # Landing pagesWhy:
- Landing pages are concise
- Minimize distractions from CTA
- Dead-ends by design
- Single page focus
Checking your options
squirrel config show prints the [rule_options] you have set (it does not list defaults). squirrel config validate checks each table against the rule it names:
squirrel config validateInvalid config: [rule_options."core/meta-title"] min_length: Invalid input: expected number, received stringFix it and validate again:
# Before (fails the audit)
[rule_options."core/meta-title"]
min_length = "thirty"# After
[rule_options."core/meta-title"]
min_length = 30Complete example
[project]
name = "myblog"
[crawler]
max_pages = 500
[rules]
enable = ["*"]
disable = ["ai/*"]
# Rule-specific configuration
[rule_options."core/meta-title"]
min_length = 40
max_length = 60
[rule_options."core/meta-description"]
min_length = 120
max_length = 160
[rule_options."content/word-count"]
min_words = 500
warn_threshold = 1000
[rule_options."content/article-links"]
short_min_external = 2
medium_min_external = 2
long_min_external = 2
[rule_options."links/orphan-pages"]
excludePatterns = ["/404", "/500", "/.well-known/"]
[rule_options."perf/ttfb"]
good_threshold = 600
poor_threshold = 1000This configuration:
- Requires longer titles (40-60 chars)
- Enforces substantial content (500+ words)
- Expects external citations
- Ignores utility pages in orphan check
- Sets strict TTFB thresholds
Related
- Rules Configuration - Enable/disable rules
- Rules Reference - All available rules
- Examples - Common configurations