Skip to main content
Anubis uses proof-of-work challenges to distinguish legitimate browsers from bots. This page covers challenge difficulty settings and available challenge methods.

Challenge Settings

Challenges can be configured globally (via command-line flags) or per-rule (in the policy file).

Global Configuration

# Set default difficulty for all challenges
anubis --difficulty 2

# Or via environment variable
export DIFFICULTY=2
Default difficulty: 2

Per-Rule Configuration

bots:
  - name: suspicious-browsers
    user_agent_regex: "(?i:bot|crawler)"
    action: CHALLENGE
    challenge:
      difficulty: 4
      algorithm: fast

Challenge Parameters

Difficulty

Difficulty controls the number of leading zero bits required in the proof-of-work hash.
FieldTypeRangeDefault
difficultyint0-642
Valid range: 0 to 64
  • Too low (< 0): ErrChallengeDifficultyTooLow
  • Too high (> 64): ErrChallengeDifficultyTooHigh
DifficultySolve TimeUse Case
0InstantDevelopment/testing only
1< 100msMeta refresh challenges
2~200msDefault for most traffic
3~500msModerate suspicion
4~1sHigh suspicion
8~10sExtreme cases (use with care)
16+MinutesEffectively blocks all traffic
Solve times are approximate and depend on client device performance.

Algorithm

Anubis supports multiple challenge algorithms:
AlgorithmDescriptionClient Support
fastSHA-256 proof-of-workModern browsers
metarefreshHTML meta refresh (no JavaScript)All browsers
preactReact-based challenge UIModern browsers
slowDeprecated SHA-256 (use fast instead)Legacy
Default: fast

Challenge Methods

SHA-256 proof-of-work challenge using WebCrypto API:
challenge:
  algorithm: fast
  difficulty: 2
Advantages:
  • Fast client-side computation
  • No external dependencies
  • Works in all modern browsers
Requirements:
  • JavaScript enabled
  • WebCrypto API support (all modern browsers)

Meta Refresh

HTML-only challenge using <meta http-equiv="refresh">:
challenge:
  algorithm: metarefresh
  difficulty: 1
Advantages:
  • No JavaScript required
  • Works in text browsers (lynx, w3m)
  • Accessible to screen readers
Limitations:
  • Lower difficulty only (recommend difficulty: 1)
  • Slower user experience
  • Cannot use client-side computation
Use cases:
  • Accessibility requirements
  • JavaScript-disabled environments
  • Low-suspicion traffic

Preact

React-based UI with visual feedback:
challenge:
  algorithm: preact
  difficulty: 2
Advantages:
  • Better user experience
  • Progress indicators
  • Error handling UI
Requirements:
  • Modern JavaScript support
  • Same as fast algorithm

Slow (Deprecated)

Legacy algorithm. Use fast instead:
challenge:
  algorithm: slow  # Don't use this
  difficulty: 2
Anubis will log a warning if slow is detected. Update to fast when possible.

Challenge Configuration Examples

Lightweight Protection

bots:
  - name: generic-browser
    user_agent_regex: "Mozilla"
    action: CHALLENGE
    challenge:
      algorithm: metarefresh
      difficulty: 1

Standard Protection

bots:
  - name: browsers
    user_agent_regex: "Mozilla"
    action: CHALLENGE
    challenge:
      algorithm: fast
      difficulty: 2

Heavy Protection

bots:
  - name: suspicious-traffic
    user_agent_regex: "(?i:bot|crawler)"
    action: CHALLENGE
    challenge:
      algorithm: fast
      difficulty: 4

Graduated Protection with Weights

thresholds:
  - name: minimal-suspicion
    expression: weight < 0
    action: ALLOW

  - name: low-suspicion
    expression:
      all:
        - weight >= 0
        - weight < 10
    action: CHALLENGE
    challenge:
      algorithm: metarefresh
      difficulty: 1

  - name: moderate-suspicion
    expression:
      all:
        - weight >= 10
        - weight < 20
    action: CHALLENGE
    challenge:
      algorithm: fast
      difficulty: 2

  - name: high-suspicion
    expression: weight >= 20
    action: CHALLENGE
    challenge:
      algorithm: fast
      difficulty: 4

Custom Status Codes

By default, challenges return HTTP 200 to deceive scrapers. You can customize this:
status_codes:
  CHALLENGE: 200  # Default
  DENY: 200       # Default

# Or use standard codes
status_codes:
  CHALLENGE: 403  # Forbidden
  DENY: 429       # Too Many Requests
Valid range: 100-599

Challenge Cookies

Successful challenge solutions are stored in cookies:
# Cookie domain (for subdomain sharing)
anubis --cookie-domain example.com

# Dynamic domain (auto-detect from request)
anubis --cookie-dynamic-domain

# Cookie expiration (default: 24 hours)
anubis --cookie-expiration-time 48h

# Cookie security flags
anubis --cookie-secure=true        # HTTPS only (default)
anubis --cookie-same-site None     # None, Lax, Strict, Default
anubis --cookie-partitioned        # CHIPS support
Cookies are prefixed (default: anubis):
# Custom prefix
anubis --cookie-prefix myapp

# Results in cookies:
# - myapp-auth
# - myapp-cookie-verification

JWT Signing

Challenge solutions are signed with Ed25519 or HMAC-SHA512. See Security for key configuration.

Validation

Common configuration errors:

Missing Algorithm

challenge:
  difficulty: 2
  # Error: ErrChallengeMustHaveAlgorithm
Fix: Always specify algorithm:
challenge:
  algorithm: fast
  difficulty: 2

Invalid Difficulty

challenge:
  algorithm: fast
  difficulty: 100  # Error: ErrChallengeDifficultyTooHigh
Fix: Use difficulty between 0-64:
challenge:
  algorithm: fast
  difficulty: 4

CHALLENGE without Challenge Config

- name: browsers
  action: CHALLENGE
  # Error if no global default set
Fix: Either set global default or specify per-rule:
- name: browsers
  action: CHALLENGE
  challenge:
    algorithm: fast
    difficulty: 2

Performance Considerations

Client-Side

  • Difficulty 2: ~200ms on modern devices
  • Difficulty 4: ~1s on modern devices, ~5s on older devices
  • Difficulty 8+: May timeout on mobile devices

Server-Side

Challenges are stateless and require no server computation. Server load comes from:
  • Challenge page delivery (minimal)
  • JWT verification (fast)
  • Storage backend operations (depends on backend)

Testing Challenges

Test challenge configuration without blocking traffic:
# Force all requests to show challenge
anubis --debug-benchmark-js
This bypasses all rules and presents challenges to every request.

Next Steps

Build docs developers (and LLMs) love