For the complete documentation index, see llms.txt. This page is also available as Markdown.

Configuration reference

File location, load rules, normalization, and key reference for config.json.

Use this as a reference for config.json.

Defaults and normalization come from cw_platform/config_base.py.

Need the raw, generated default JSON blocks? See Default config values.

CW obtains the encryption key from one of these locations, in priority order:

  1. CW_CONFIG_KEY

  2. CROSSWATCH_CONFIG_KEY

  3. <CONFIG_BASE>/.cw_master_key

Back up .cw_master_key together with config.json.

An encrypted config cannot be recovered without the matching key.

Do not share config.json, .cw_master_key, provider tokens, or unredacted config output.

See Config encryption for the complete key management and recovery process.

Avoid editing config.json by hand.

Most settings are configurable in the UI.

At a glance

Topic
Where
Notes

Config file

<CONFIG_BASE>/config.json

Created if missing.

Docker default

/config/config.json

Used when /app exists.

Manual edits

Avoid

UI covers most settings.

Secrets

Tokens and password hashes

Redact before sharing.

Config file location

CW chooses the config base directory in this order.

Priority
Condition
Base path

1

CONFIG_BASE env var is set

CONFIG_BASE value

2

Running in Docker image (/app exists)

/config

3

Running from source

Project root (one level above cw_platform/)

The file path is always:

  • <CONFIG_BASE>/config.json

Load and save behavior

CW loads config.json, normalizes it, and rewrites managed values when needed.

Defaults and deep merge

CW loads config.json and deep merges it over DEFAULT_CFG.

  • Dictionary values merge recursively.

  • Other values replace their defaults.

  • Unknown keys are retained.

  • Missing default keys are restored during loading.

Version stamping

version is managed by CW and rewritten during save operations.

The value is selected in this order:

  1. api.versionAPI.CURRENT_VERSION

  2. APP_VERSION

  3. Fallback v0.7.0

A leading v is removed before the value is stored.

Secret encryption

Sensitive string values are encrypted before CW writes the config to disk.

Encrypted values use the enc:v1: prefix.

Values are decrypted in memory when CW loads the file.

Sensitive fields include:

  1. API keys

  2. Access and refresh tokens

  3. Client secrets

  4. Plex tokens and home PINs

  5. Session IDs and token hashes

  6. Password hashes and salts

  7. Device and request tokens

  8. Webhook secrets and webhook route IDs

Atomic saves

CW writes a temporary JSON file, then replaces config.json.

This reduces the chance of a partial write after an interrupted save.

Runtime normalization

Config values are normalized during load and save.

The normalized result can differ from the value originally written to config.json.

Webhook route IDs

CW generates a new route ID when one of these values is missing, is not a string, or has fewer than 16 characters:

  1. security.webhook_ids.plextrakt

  2. security.webhook_ids.jellyfintrakt

  3. security.webhook_ids.embytrakt

  4. security.webhook_ids.plexwatcher

Generated values use token_urlsafe(24).

Scheduling

scheduling.mode is normalized to one of:

  1. disabled

  2. hourly

  3. every_n_hours

  4. daily_time

  5. custom_interval

When every_n_hours is 1 or lower, the mode is changed to hourly.

scheduling.daily_time falls back to 03:30 when it is not a valid 24 hour HH:MM value.

scheduling.custom_interval_minutes has a minimum value of 15.

Anime ID Mapping

anime_mapping.refresh_hours has a minimum value of 1.

anime_mapping.stale_after_days has a minimum value of 1.

An invalid anime_mapping.release_tag is replaced with v3.

Empty or invalid provider and feature lists are restored to:

PublicMetaDB

PublicMetaDB page sizes, page limits, contribution limits, and request limits are clamped to supported ranges.

The default request limits are:

User interface

ui.theme is normalized to:

  1. flat-dark

  2. flat-light

  3. original

Recent Activity and Recent Sync display values support:

  1. count:3

  2. count:4

  3. count:5

  4. hours:24

  5. hours:48

  6. hours:72

ui.protocol is normalized to http or https.

ui.tls.valid_days is clamped to 1 through 3650.

UI authentication

UI authentication is mandatory.

app_auth.enabled is normalized to true, even when the raw default or a manually edited configuration contains false.

app_auth.remember_session_days is clamped to 1 through 365.

When reset_required is enabled, active sessions and the previous login timestamp are cleared.

Pair feature normalization

Feature configuration should use an object:

When a feature object omits these fields, CW uses:

A non-object feature value is treated as invalid and normalized to:

Do not use true or false as the complete feature value in config.json.

Ratings feature fields

Allowed values are movies, shows, seasons, and episodes.

The value all expands to all four types.

An empty or invalid list falls back to movies and shows.

Allowed values are:

  1. only_new

  2. from_date

  3. all

Used when mode is from_date.

It is cleared for other modes.

AniList feature fields

Watchlist and Ratings features on pairs containing AniList can contain:

use_anime_mapping

Uses the local AniBridge mapping index to enrich identifiers before comparison and writes.

Enabling it in the pair editor also enables the global Anime ID Mapping service.

anime_only_sync

This requires use_anime_mapping.

When AniList receives data, only items with a usable AniList or MyAnimeList ID are accepted.

Items that would require AniList title search are skipped.

The option is forced to false when Anime ID Mapping is disabled for the feature.

Example:

More detail: AniList pair options.

Redaction

redact_config(cfg) replaces sensitive values with ••••••••.

Redaction covers provider credentials in both the default provider block and provider profiles under instances.

Redacted provider values include credentials for:

  1. Plex

  2. Trakt

  3. SIMKL

  4. AniList

  5. MDBList

  6. PublicMetaDB

  7. Tautulli

  8. Jellyfin

  9. Emby

  10. TMDb

  11. TMDb Sync

The following local authentication values are also redacted:

  1. app_auth.password.hash

  2. app_auth.password.salt

  3. app_auth.session.token_hash

  4. Token hashes inside app_auth.sessions[]

  5. All values under security.webhook_ids

Key reference

Top-level

Key
Type
Notes

version

string

Managed by the app.

security

object

Runtime-generated webhook IDs.

pairs

array

Pair definitions created in the UI.

plex, trakt, …

object

Provider connection and tuning.

publicmetadb

object

PublicMetaDB auth and sync tuning.

sync

object

Global orchestrator defaults.

runtime

object

Logging and guardrails.

metadata

object

TMDb metadata lookup settings.

anime_mapping

object

Anime ID Mapping settings.

scrobble

object

Real-time progress forwarding.

scheduling

object

Periodic runs.

ui

object

UI toggles.

app_auth

object

Mandatory UI authentication.

Security (security)

This node stores webhook route IDs.

CW can auto-generate them.

Key
Type
Notes

security.webhook_ids.plextrakt

string

Plex webhook path ID.

security.webhook_ids.jellyfintrakt

string

Jellyfin webhook path ID.

security.webhook_ids.embytrakt

string

Emby webhook path ID.

security.webhook_ids.plexwatcher

string

Plex Watcher/webhook path id.

Providers

Provider
Stores
Used for

plex

server URL, token, tuning

Sync + scrobble source

jellyfin / emby

server URL, token, tuning

Sync + scrobble source

trakt / simkl

OAuth/API keys

Tracker targets and sources

anilist

OAuth/API keys

Bidirectional watchlist + ratings

mdblist

Device Code or API key auth

Watchlist, ratings, and history

publicmetadb

API key and sync tuning

Watchlist, ratings, history, progress

tmdb

API key

Matching support

tmdb_sync

API key + session

TMDb account sync

tautulli

URL + API key

History import

crosswatch

local paths + snapshot rules

Local backup provider

Provider profiles

Most providers can store multiple profiles under an instances map (config key name).

  • The implicit profile id is default.

  • Additional profile ids are named like PLEX-P01, TRAKT-P02, etc.

Profiles are used by:

  • sync pairs (source_instance, target_instance)

  • Watcher routes (provider_instance, sink_instance)

Guide: Profiles

Plex

Connection

Key
Type
Notes

plex.server_url

string

Example: http://192.168.1.10:32400

plex.verify_ssl

bool

Keep false for self-signed.

plex.account_token

string

Set via UI PIN login.

plex.pms_token

string

Plex Media Server resource token.

plex.client_id

string

Client identifier.

plex.machine_id

string

Targets a specific server.

plex.username

string

Plex Home profile name.

plex.account_id

string

Server-local account ID.

plex.home_pin

string

Optional Plex Home PIN.

plex.timeout

number

Seconds.

plex.max_retries

int

Retry budget.

plex.fallback_GUID

bool

Discover fallback for missing GUID mapping.

Scrobble filters

Key
Type
Notes

plex.scrobble.libraries

array

Shared by Plex Watcher and Plex Webhooks. Empty means all libraries.

History

Key
Type
Notes

plex.history.libraries

array

Whitelist of library GUIDs. Empty = all.

plex.history.include_marked_watched

bool

Include Plex “marked watched” state (add-only behavior).

plex.history_workers

int

Parallel workers for history indexing. 12–16 is ideal on a local NAS.

Ratings

Key
Type
Notes

plex.ratings.libraries

array

Whitelist of library GUIDs. Empty = all.

plex.rating_workers

int

Parallel workers for ratings indexing. 12–16 is ideal on a local NAS.

Watchlist (Discover-driven)

Key
Type
Notes

plex.watchlist_allow_pms_fallback

bool

Allow PMS watchlist fallback when needed. Keep false for strict Discover-only behavior.

plex.watchlist_page_size

int

Discover page size (100–200). Higher is faster, but can trigger 504s.

plex.watchlist_query_limit

int

Max Discover search results per query (10–25).

plex.watchlist_write_delay_ms

int

Optional pacing between Discover writes. Set 50–150 if you hit 429/5xx.

plex.watchlist_title_query

bool

Use title/slug tokens for Discover candidate fetching.

plex.watchlist_use_metadata_match

bool

Try PMS /library/metadata/matches first, then fallback to Discover.

plex.watchlist_guid_priority

array

GUID resolution order (first match wins).

TMDb
Key
Type
Notes

tmdb.api_key

string

TMDb API key used for metadata lookup and ID bridging.

TMDb (Sync)

Used only when you connect TMDb (Sync) for watchlist/ratings syncing.

Key
Type
Notes

tmdb_sync.api_key

string

TMDb v3 API key.

tmdb_sync.session_id

string

User session ID from the connect flow.

tmdb_sync.account_id

string

Optional. Auto-discovered if missing.

tmdb_sync.timeout

number

HTTP timeout in seconds.

tmdb_sync.max_retries

int

Retry budget for transient HTTP errors.

tmdb_sync.debug

bool

Enables extra TMDb sync debug logging.

Trakt

OAuth

Key
Type
Notes

trakt.client_id

string

From your Trakt app.

trakt.client_secret

string

From your Trakt app.

trakt.access_token

string

OAuth2 access token.

trakt.refresh_token

string

OAuth2 refresh token.

trakt.scope

string

Usually public or private.

trakt.token_type

string

Usually Bearer.

trakt.expires_at

int

Epoch seconds.

trakt._pending_device

object

Temporary device code state (PIN flow).

HTTP

Key
Type
Notes

trakt.timeout

int

HTTP timeout (seconds).

trakt.max_retries

int

Retry budget (429/5xx backoff).

Rate limiting

Key
Type
Notes

trakt.rate_limit.get_per_sec

number

GET requests / second

trakt.rate_limit.post_per_sec

number

Writes / second

Rate-limit defaults and tuning: Provider rate limiting

Watchlist

Key
Type
Notes

trakt.watchlist_use_etag

bool

Use ETag + local shadow to skip unchanged lists.

trakt.watchlist_shadow_ttl_hours

int

Refresh ETag baseline periodically even if 304s keep coming.

trakt.watchlist_batch_size

int

Chunk size for add/remove to reduce rate spikes.

trakt.watchlist_log_rate_limits

bool

Log X-RateLimit-* and Retry-After when present.

trakt.watchlist_freeze_details

bool

Persist last status & ids for debugging.

Ratings

Key
Type
Notes

trakt.ratings_per_page

int

Items per page when indexing (10–100).

trakt.ratings_max_pages

int

Safety cap per type.

trakt.ratings_chunk_size

int

Batch size for POST/REMOVE.

History

Key
Type
Notes

trakt.history_per_page

int

Max allowed by Trakt (100).

trakt.history_max_pages

int

Safety cap for large histories.

trakt.history_unresolved

bool

Enable unresolved “freeze” files.

trakt.history_number_fallback

bool

Episode number fallback if episode IDs are missing.

trakt.history_collection

bool

Mirror history adds into your Trakt Collection.

SIMKL
Key
Type
Notes

simkl.access_token

string

OAuth2 access token.

simkl.refresh_token

string

OAuth2 refresh token.

simkl.token_expires_at

int

Epoch seconds.

simkl.client_id

string

From your SIMKL app.

simkl.client_secret

string

From your SIMKL app.

simkl.date_from

string

YYYY-MM-DD (optional backfill start).

Rate limiting

Key
Type
Notes

simkl.rate_limit.get_per_sec

number

GET requests / second

simkl.rate_limit.post_per_sec

number

Writes / second

Rate-limit defaults and tuning: Provider rate limiting

AniList

Authentication

Key
Type
Notes

anilist.client_id

string

Client ID from the AniList application.

anilist.client_secret

string

Client secret from the AniList application.

anilist.access_token

string

OAuth access token.

anilist.user

object

Cached AniList viewer information, normally containing the user ID and name.

AniList Watchlist uses entries with the PLANNING status.

AniList Ratings supports movies and shows.

Seasons and episodes are not supported.

No additional provider-level Watchlist or Ratings tuning is currently required.

AniList does not currently support CW History, Progress, or Playlist sync.

Anime matching is configured globally under anime_mapping and per feature inside the pair.

MDBList

Authentication

MDBList supports Device Code authentication and legacy API key authentication.

New connections should use Device Code authentication.

Key
Type
Notes

mdblist.auth_method

string

Normalized to device_code or api_key.

mdblist.client_id

string

Deprecated. CW supplies this internally.

mdblist.access_token

string

OAuth access token from Device Code auth.

mdblist.refresh_token

string

OAuth refresh token from Device Code auth.

mdblist.token_type

string

OAuth token type. Default is Bearer.

mdblist.scope

string

OAuth scope. Default is write.

mdblist.expires_at

int

Access token expiry as Unix epoch seconds.

mdblist.api_key

string

Legacy API key authentication.

mdblist.timeout

int

HTTP timeout in seconds.

mdblist.max_retries

int

Retry budget.

When Device Code auth is active, the API key is cleared.

When API key auth is active, OAuth token fields are cleared.

Rate limiting

Key
Type
Notes

mdblist.rate_limit.get_per_sec

number

GET requests / second

mdblist.rate_limit.post_per_sec

number

Writes / second

Rate-limit defaults and tuning: Provider rate limiting

Watchlist

Key
Type
Notes

mdblist.watchlist_shadow_ttl_hours

int

Shadow TTL (hours). 0 disables.

mdblist.watchlist_shadow_validate

bool

Validate shadow on every run.

mdblist.watchlist_page_size

int

GET page size for /watchlist/items.

mdblist.watchlist_batch_size

int

Batch size for add/remove writes.

mdblist.watchlist_freeze_details

bool

Store extra details for “not_found” freezes.

Ratings

Key
Type
Notes

mdblist.ratings_per_page

int

Items per page when indexing.

mdblist.ratings_max_pages

int

Max pages to fetch (safety cap).

mdblist.ratings_chunk_size

int

Batch size for POST/REMOVE.

mdblist.ratings_write_delay_ms

int

Optional pacing between writes.

mdblist.ratings_max_backoff_ms

int

Max backoff time for retries.

mdblist.ratings_since

string

First-run baseline; watermark overrides after.

History

Key
Type
Notes

mdblist.history_per_page

int

Items per page for watched delta.

mdblist.history_max_pages

int

Max pages to fetch (safety cap).

mdblist.history_chunk_size

int

Batch size for watched/unwatched writes.

mdblist.history_write_delay_ms

int

Optional pacing between writes.

mdblist.history_max_backoff_ms

int

Max backoff time for retries.

mdblist.history_since

string

First-run baseline; watermark overrides after.

PublicMetaDB

Connection

Key
Type
Notes

publicmetadb.api_key

string

PublicMetaDB API key.

publicmetadb.base_url

string

API base URL. Default is https://publicmetadb.com.

publicmetadb.timeout

number

HTTP timeout in seconds.

publicmetadb.max_retries

int

Retry budget.

Watchlist

Key
Type
Notes

publicmetadb.watchlist_list_id

string

Optional list ID. Empty lets CW discover or create it.

publicmetadb.watchlist_name

string

Default list name. Default is Watchlist.

publicmetadb.watchlist_auto_create

bool

Creates a private CW watchlist when needed.

publicmetadb.watchlist_page_size

int

Normalized to 1 through 500.

History

Key
Type
Notes

publicmetadb.history_per_page

int

Normalized to 1 through 500.

publicmetadb.history_max_pages

int

Normalized to 1 through 100000.

Progress

Key
Type
Notes

publicmetadb.progress_per_page

int

Normalized to 1 through 500.

publicmetadb.progress_max_pages

int

Normalized to 1 through 100000.

Ratings

Key
Type
Notes

publicmetadb.ratings_label

string

Rating label. Default is Overall.

publicmetadb.ratings_submit_per_hour

int

Maximum supported value is 200.

publicmetadb.ratings_update_per_hour

int

Maximum supported value is 100.

Request limiting

Key
Type
Notes

publicmetadb.rate_limit.post_per_sec

number

Normalized to 0 through 3.

publicmetadb.rate_limit.get_per_sec

number

Normalized to 0 through 20.

Tautulli

Connection

Key
Type
Notes

tautulli.server_url

string

Example: http://host:8181

tautulli.api_key

string

Tautulli API key.

tautulli.verify_ssl

bool

Verify TLS certificates.

tautulli.timeout

number

HTTP timeout (seconds).

tautulli.max_retries

int