6 min readMar 29, 2026by jakub

Configuration Reference

PRISM is configured via a TOML file (default: /etc/prism/config.toml).

Server

TOML
[server]
address = "0.0.0.0:4000"       # Listen address
origin = "http://localhost:3000" # Your SPA backend
mode = "bot-only"                # "bot-only" or "render-all"
shadow = false                   # Shadow mode: render in background, serve original
drain_timeout_secs = 30          # Graceful shutdown timeout
OptionTypeDefaultDescription
addressstring"0.0.0.0:4000"Address PRISM listens on
originstring"http://localhost:3000"Your SPA origin URL
modestring"bot-only""bot-only": render only for crawlers. "render-all": render for everyone
shadowboolfalseRender in background and log diffs without serving rendered HTML
drain_timeout_secsinteger30Seconds to wait for in-flight renders during shutdown

Mode: bot-only vs render-all

bot-only (default, recommended): Only search engine crawlers and social bots get rendered HTML. Regular users get the normal SPA response. Zero performance impact for human visitors.

render-all: Every request gets rendered HTML. Useful when you want server-side rendering without modifying your SPA code. Higher resource usage -- every page view goes through Chrome.

Shadow Mode

When shadow = true, PRISM renders pages in the background but serves the original (un-rendered) response. It logs any differences between the rendered and original HTML. Useful for testing PRISM before going live.

Render

TOML
[render]
wait_for = "load"                 # When to consider the page "done"
timeout_secs = 10                 # Max render time per page
block_resources = [               # Resource types to skip (faster renders)
    "font", "image", "media", "stylesheet"
]
OptionTypeDefaultDescription
wait_forstring"load"Page readiness signal (see below)
timeout_secsinteger10Maximum seconds per render
block_resourcesarray["font", "image", "media", "stylesheet"]Chrome resource types to block

wait_for Options

ValueDescriptionSpeed
"load"Wait for window.onload eventFast, good default
"domcontentloaded"Wait for DOM ready (before images)Fastest
"networkidle"Wait until no network activity for 500msSlowest, most complete
"selector:css"Wait for a CSS selector to appear, e.g., "selector:.product-loaded"Custom
Blocking resources

Blocking fonts, images, and stylesheets during rendering is safe -- crawlers don't need them. This reduces render time by 30-50% and saves bandwidth.

Chrome Pool

TOML
[render.pool]
tabs = 8                          # Number of Chrome tabs (parallel renders)
max_renders_per_tab = 50          # Recycle tab after N renders (prevents memory leaks)
queue_max = 100                   # Max queued render requests
OptionTypeDefaultDescription
tabsinteger8Number of concurrent Chrome tabs
max_renders_per_tabinteger50Recycle tab after this many renders
queue_maxinteger100Maximum queued requests (rejects above this)

Sizing the Pool

Server RAMRecommended TabsConcurrent Renders
1 GB2-42-4
2 GB4-84-8
4 GB8-168-16
8 GB+16-3216-32

Each Chrome tab uses approximately 50-150 MB of RAM depending on page complexity.

Circuit Breaker

TOML
[render.circuit_breaker]
failure_threshold = 5             # Consecutive failures before opening circuit
recovery_timeout_secs = 30        # Seconds before trying again
half_open_max_requests = 1        # Test requests in half-open state

When Chrome fails repeatedly (crashes, timeouts), the circuit breaker opens and stops sending requests to Chrome. After recovery_timeout_secs, it enters half-open state and tests with a single request. If that succeeds, the circuit closes and normal operation resumes.

Cache

TOML
[cache]
enabled = true
max_entries = 10000               # Maximum cached pages
max_memory_bytes = 268435456      # 256 MiB memory limit
default_ttl_secs = 3600           # 1 hour default TTL
grace_period_secs = 300           # 5 minutes stale serving
respect_cache_control = false     # Respect origin Cache-Control headers
OptionTypeDefaultDescription
enabledbooltrueEnable in-memory cache
max_entriesinteger10000Maximum number of cached pages
max_memory_bytesinteger268435456Memory limit (256 MiB)
default_ttl_secsinteger3600Default time-to-live (1 hour)
grace_period_secsinteger300Serve stale content while re-rendering
respect_cache_controlboolfalseHonor origin's Cache-Control headers

Request Coalescing

When multiple requests arrive for the same URL simultaneously, PRISM renders it once and serves the result to all waiting requests. This prevents "thundering herd" problems where 100 bot requests for the same page would trigger 100 Chrome renders.

SPA Detection

TOML
[detect]
auto = false                      # Auto-detect if a page is an SPA
max_body_text_bytes = 500         # If body text < 500 bytes, probably an SPA
min_script_tags = 2               # If >= 2 script tags, probably an SPA
mount_points = [                  # Common SPA mount point IDs
    "app", "root", "__next", "__nuxt"
]
header = "X-Prism-Render"        # Origin can request rendering via this header

When auto = true, PRISM fetches the page first, inspects the HTML, and decides whether it needs rendering. Useful when PRISM sits in front of a mixed site (some pages are SPAs, some are server-rendered).

Routes

TOML
[routes]
include = ["/**"]                 # Glob patterns to render
exclude = [                       # Glob patterns to skip
    "/api/**",
    "/graphql",
    "**/*.js", "**/*.css", "**/*.json",
    "**/*.png", "**/*.jpg", "**/*.gif", "**/*.svg", "**/*.ico",
    "**/*.woff", "**/*.woff2", "**/*.ttf",
    "/_next/**", "/static/**", "/admin/**",
]

Routes use glob patterns. A request must match an include pattern AND not match any exclude pattern to be rendered.

Always exclude static assets

CSS, JS, images, and fonts should never go through Chrome. The default excludes cover most cases. Add any custom static paths your app uses.

Bot Detection

TOML
[bot]
patterns = [
    "Googlebot", "Bingbot", "Yandex", "Baiduspider",
    "DuckDuckBot", "Slurp", "facebookexternalhit",
    "LinkedInBot", "Twitterbot", "Applebot",
    "GPTBot", "ClaudeBot", "ChatGPT-User",
    "AhrefsBot", "SemrushBot", "MJ12bot",
    # ... 70+ patterns included by default
]

Bot detection uses case-insensitive substring matching on the User-Agent header. The default list includes all major search engines, social crawlers, AI bots, and SEO tools.

Admin API

TOML
[admin]
enabled = true
address = "127.0.0.1:4001"       # Admin listens on separate port
# bearer_token = "your-secret-token"
EndpointMethodDescription
/healthGETHealth check (returns 200 if healthy)
/statusGETUptime, cache stats, pool stats, render counts
/metricsGETPrometheus format metrics
/purge/urlPOSTPurge a single cached URL
/purge/patternPOSTPurge by glob pattern
/purge/allPOSTFlush entire cache
/renderPOSTManually trigger a render
Protect the admin API

Always set bearer_token in production. The admin API can purge your cache and trigger renders.

Security

TOML
[security]
allowed_origins = []              # Empty = allow all origins
block_private_cidrs = true        # Block SSRF to private networks
rate_limit_per_domain = 10        # Max concurrent renders per domain
OptionTypeDefaultDescription
allowed_originsarray[]Restrict which origins PRISM can fetch from
block_private_cidrsbooltrueBlock renders to private IP ranges (SSRF protection)
rate_limit_per_domaininteger10Max concurrent renders per domain
Keep block_private_cidrs enabled

Disabling SSRF protection allows Chrome to access internal services, databases, and cloud metadata endpoints. Only disable for testing.

Logging

TOML
[logging]
level = "info"                    # debug, info, warn, error
format = "pretty"                 # "pretty" (human) or "json" (structured)

Complete Example

TOML
[server]
address = "0.0.0.0:4000"
origin = "https://my-react-app.com"
mode = "bot-only"

[render]
wait_for = "networkidle"
timeout_secs = 15
block_resources = ["font", "image", "media", "stylesheet"]

[render.pool]
tabs = 8
max_renders_per_tab = 50

[cache]
enabled = true
max_entries = 50000
max_memory_bytes = 536870912    # 512 MiB
default_ttl_secs = 7200        # 2 hours
grace_period_secs = 600        # 10 minutes

[routes]
include = ["/**"]
exclude = ["/api/**", "/graphql", "**/*.js", "**/*.css", "**/*.json",
           "**/*.png", "**/*.jpg", "**/*.svg", "**/*.ico",
           "**/*.woff2", "/_next/**", "/static/**", "/admin/**"]

[admin]
enabled = true
address = "127.0.0.1:4001"
bearer_token = "your-secret-token-here"

[security]
block_private_cidrs = true
rate_limit_per_domain = 10

[logging]
level = "info"
format = "json"
Was this page helpful?
PRISM Configuration Reference — Trident PRISM — Trident HTTP Cache Proxy | qoliber Docs