Configuration
AniBridge reads configuration from a YAML file named config.yaml that lives inside the AniBridge data directory. You can set the data path through the $AB_DATA_PATH environment variable (defaults to ./data).
A config editor is also available through the web UI.
Tip
This documentation may seem long, but most of the options have sane defaults and can be left unset. The only required settings are the library_provider and list_provider for each profile (and their corresponding library_provider_config and list_provider_config). You can start with a minimal config and then customize additional options as needed.
Example
############################################################################################################
# This is a template configuration file for AniBridge. #
# All optional configuration fields are commented out with their default values. #
# Required fields are uncommented and indicated by a placeholder `...`. #
# #
# Please refer to the documentation for more details: https://anibridge.eliasbenb.dev/configuration/ #
############################################################################################################
#== Shared Settings ==#
global_config:
library_provider: ...
list_provider: ...
# scan_modes: [periodic, poll, webhook]
# scan_interval: 86400
# full_scan: false
# destructive_sync: false
# empty_sync: false
# sync_rules:
# templates: [prevent_regressions]
# review: false
# user_rating: false
# backup_retention_days: 30
# batch_requests: false
# search_fallback_threshold: -1
# dry_run: false
#== Provider Settings ==#
library_provider_config: {} # Refer to provider-specific configuration documentation
list_provider_config: {} # Refer to provider-specific configuration documentation
#== Profile Settings ==#
# profiles:
# example:
# $field: $value
#== App Settings ==#
# log_level: INFO
# mappings_url: "https://github.com/anibridge/anibridge-mappings/releases/download/v3/mappings.json.zst"
# provider_classes: []
# web:
# enabled: true
# host: ""
# port: 4848
# allow_config_without_auth: false
# basic_auth:
# username: null
# password: null
# htpasswd_path: null
# realm: "AniBridge"
Configuration Hierarchy
AniBridge supports having multiple, concurrently active profiles, each with its own set of configuration options. This allows you to sync different libraries or users with tailored settings.
To simplify configuration management, settings can also be shared across all profiles by defining them under the top-level global_config key.
To define profile-specific settings, use the profiles key in the configuration file with the profile name as a sub-key. Any settings defined under a profile will override the corresponding global settings for that profile.
Settings are applied with the following priority:
- Profile-specific settings (highest priority)
- Global shared settings
- Built-in defaults (lowest priority)
For example, if global_config.scan_interval is defined as 900 and profiles.personal.scan_interval is defined as 1800, the profile named personal will use the overridden value of 1800. If scan_interval is not defined under either the profile or global settings, the built-in default of 86400 will be used.
Profile Configuration
These settings can be defined per-profile under the profiles key or globally under
the global_config key since they share the same schema.
library_provider
str (required)
Specifies the media library provider to use (e.g., plex, jellyfin, emby).
list_provider
str (required)
Specifies the list provider to use (e.g., anilist, mal).
scan_modes
list[Enum("periodic", "poll", "webhook")] (optional, default: [periodic, poll, webhook])
Determines the triggers for scanning:
periodic: Scan all items at the specified scan interval.poll: Poll for incremental changes at the specified poll interval.webhook: Trigger scans via webhook payloads from the library provider.
Setting scan_modes to None or an empty list will cause the application to perform a single scan on startup and then exit.
By default, all three modes are enabled, allowing for instant, incremental updates via polling and webhooks, as well as a full periodic scan every scan_interval seconds (default: 24 hours) to catch any failed/missed updates.
Webhooks
Using the webhooks scan mode will require configuring your library provider (e.g., Plex) to send webhook payloads to AniBridge. Refer to the documentation of your library provider for instructions on setting up webhooks.
A prerequisite for using webhooks is that the web interface is enabled and accessible to the library provider.
With webhooks enabled, set your library provider to send webhooks to /webhook/{provider}, where {provider} is the namespace of your library provider (e.g., plex).
Once webhooks are setup, it is recommended to disable the poll scan mode as it becomes redundant.
Note: not all library providers may support webhooks.
scan_interval
int | CronStr (optional, default: 86400)
Interval in seconds or a cron string to trigger periodic scans when using the periodic scan mode.
poll_interval
int | CronStr (optional, default: 60)
Interval in seconds or a cron string to poll for changes when using the poll scan mode.
Polling is designed to be a lightweight way to keep your list provider up-to-date with just recent watch activity. It only checks for changes since the last successful sync and is not intended to be a complete scan of the entire library.
full_scan
bool (optional, default: False)
When enabled, the scan process will include all items, regardless of watch activity. By default, only watched items are scanned.
Full Scan Use Cases
Full scans will essentially be a no-op unless unless combined with empty_sync or destructive_sync.
Performance Warning
Enabling full scans will significantly increase API usage and scan times. Only enable this option if you have a specific need to.
destructive_sync
bool (optional, default: False)
Allows list entry deletions. When enabled, if an item has an existing list entry and no library watch activity, that entry will be deleted to reflect the unwatched status.
Full Scan Interaction
If full_scan is disabled, destructive sync will only delete entries for items that have partial watch activity (e.g., watched a different season in the same show).
If you'd like to delete all unwatched entries, enable both full_scan and destructive_sync.
Data Loss Warning
Enable only if you understand the implications.
Destructive sync allows for deleting list entries that have no watch activity.
empty_sync
bool (optional, default: False)
Allows list entry creations with no watch activity. Empty syncs will use the 'planning' status by default.
Full Scan Interaction
If full_scan is disabled, empty sync will only create entries for items that have partial watch activity (e.g., watched a different season in the same show).
If you'd like to create entries for all unwatched items, enable both full_scan and empty_sync.
sync_rules
dict (optional, default: {"templates": ["disable_user_rating_and_review"]})
Declaratively customize how sync results are calculated and applied on a per-field basis.
It can be used for simple customization like disabling a field, or for defining advanced rules with Python expressions when finer control in needed. Templates are also available for common rule presets. Expand the sections below for different usage examples.
Disabling a Field
As a basic short-hand, you can disable syncing of an entire field by setting its value to false.
Usage example:
Available Fields
Custom rules can be defined for any of the following fields: status, progress, repeats, review, user_rating, finished_at, and started_at.
Performance Gains
Disabling a field this way prevents it from being processed, which can lead to performance gains if the field is expensive to compute (e.g., requires additional API calls or complex logic).
Templates
Templates are pre-defined rule presets for common sync behaviors. They are useful as a starting point, and can be combined with custom rules when you need more control.
Templates are applied in order. For a given field, user-defined rules are evaluated first, followed by template rules.
Available templates include:
disable_dropped_and_paused: if the computed status isdroppedorpaused, keep the current status instead. If there is no current status, usecurrentdisable_user_rating_and_review: preventsuser_ratingandreviewfrom syncingprevent_regressions: prevents syncing a lower value forstatus,progress,repeats,finished_at, andstarted_atby keeping the current value insteadpromote_rewatch: if the current status isrepeatingorcompletedand the computed status iscurrent, promotes the computed status torepeating
Usage example:
Custom Rules
For more advanced behavior, you can define custom rules for a field as a list of dictionaries with if conditions and set transformations.
Rules are evaluated in order, and the first matching rule will determine the final value of the field. If no rules match, the computed value will be used unmodified.
Rule behavior:
ifis optional and when omitted, the rule always matches (equivalent toif: true)setis required and defines the value to write when the rule matches- Rules are evaluated in order
- The first matching rule wins
- If a field has rules and none match, the computed value is used unmodified
Expressions
Both if and set are written as Python expressions with access to the current, computed, and vars namespaces. See the "Expression Environment" section below for more details on available variables and syntax.
Usage example:
sync_rules:
status:
- name: Promote rewatch to repeating
if: current.status in ("repeating", "completed") and computed.status == "current"
set: repeating
- name: Keep the current status for planning
if: computed.status == "planning"
set: current.status
finished_at:
- name: Offset finished_at by one hour
if: computed.finished_at is not None
set: computed.finished_at.replace(hour=computed.finished_at.hour + 1)
Available Fields
Custom rules can be defined for any of the following fields: status, progress, repeats, review, user_rating, finished_at, and started_at.
Variables
The vars key lets you define reusable expressions once and reference them from multiple rules.
Usage example:
sync_rules:
vars:
has_review: computed.review is not None and len(computed.review) > 0
is_review_long: vars.has_review and len(computed.review) > 200
review:
- name: Truncate long reviews
if: vars.is_review_long
set: computed.review[:197] + "..."
- name: Keep empty reviews cleared
if: not vars.has_review
set: null
Expression Environment
Expressions are validated with AST checks and run in a semi-sandboxed Python environment.
Available variables:
current: the list entry state before AniBridge makes changescomputed: the list entry state AniBridge computed for the syncvars: values declared undersync_rules.varsctx: additional sync context
Available ListEntry fields:
- progress
- repeats
- review
- status
- user_rating
- finished_at
- started_at
ctx currently exposes:
- ctx.list_media_key
- ctx.item
- ctx.child
- ctx.grandchildren
Safe built-ins:
- abs
- all
- any
- bool
- date
- datetime
- float
- int
- len
- max
- min
- round
- str
- sum
- timedelta
backup_retention_days
int (optional, default: 30)
Controls how many days AniBridge keeps AniList backup snapshots before pruning older files. Set to 0 to disable automatic cleanup and retain all backups indefinitely.
batch_requests
bool (optional, default: False)
When enabled, list API requests are made in batches before and after syncing.
- Prior to syncing, a batch of requests is created to retrieve all the entries that will be worked on.
- Post-sync, a batch of requests is created to update all the entries that were changed.
This can significantly reduce rate limiting, but at the cost of atomicity. If any request in the batch fails, the entire batch will fail.
For example, if a sync job finds 10 items to update with batch_requests enabled, all 10 requests will be sent at once. If any of the requests fail, all 10 updates will fail.
List Provider Support
Batch requests are only supported by list providers that implement the corresponding batch API methods. If a provider does not support batch requests, this setting will have negative effects on stability and performance.
Of the built-in providers, only AniList currently supports batch requests.
First Run
The primary use case of batch requests is going through the first sync of a large library. It can significantly reduce rate limiting from AniList.
For subsequent syncs, your data is pre-cached, and the benefit of batching is reduced.
search_fallback_threshold
int (optional, default: -1)
Determines how similar a title must be to the search query as a percentage to be considered a match.
The default behavior (-1) is to disable searching completely and only rely on the community and local mappings database.
The higher the value, the more strict the title matching. A value of 100 requires an exact match, while 0 will match the first result returned by AniList, regardless of similarity.
dry_run
bool (optional, default: False)
When enabled:
- List entry data is not modified.
- Logs show what changes would have been made.
First Run
Run with dry_run enabled on first launch to preview changes without modifying your list data.
Provider Settings
Each provider may consume additional configuration options. Refer to the documentation of each provider for details:
library_provider_config
This is a dictionary where each key is the namespace of a library provider (e.g., plex, jellyfin, emby), and the value is another dictionary containing configuration options that will be passed to that provider.
list_provider_config
This is a dictionary where each key is the namespace of a list provider (e.g., anilist, mal), and the value is another dictionary containing configuration options that will be passed to that provider.
App Settings
These settings apply to the entire application and are not profile-specific. They are defined at the top level of the configuration file (not under global_config or profiles).
log_level
Enum("DEBUG", "INFO", "SUCCESS", "WARNING", "ERROR", "CRITICAL") (optional, default: INFO)
Sets logging verbosity for the entire application.
Minimal Logging
For minimal logging, set the verbosity to SUCCESS which only logs successful operations like syncing entries.
Debugging
For the most detailed logs, set this to DEBUG.
mappings_url
str (optional, default: "https://github.com/anibridge/anibridge-mappings/releases/download/v3/mappings.json.zst")
URL to the upstream mappings source. This can be a JSON or YAML file, optionally compressed with Zstandard (*.zst).
This option is only intended for advanced users who want to use their own upstream mappings source or disable upstream mappings entirely. For most users, it is recommended to keep the default value.
Custom Mappings
This setting works in tandem with custom mappings stored in the mappings/ directory inside the data path. Custom mappings will overload any upstream mappings.
Disabling Upstream Mappings
To disable upstream mappings, set this to an empty string: "". This will effectively make AniBridge depend solely on your local custom mappings.
provider_classes
list[str] (optional, default: [])
A list of Python provider class paths to load. This is an advanced option to load additional library or list providers beyond the built-in options. Each item should be a string in the format module.submodule.ClassName that points to a valid LibraryProvider or ListProvider subclass.
For example, to load a hypothetical MyCustomProvider class from the my_providers module, you would set:
It is up to the user to ensure that the specified classes are available in the Python environment and that they adhere to the required provider interfaces. AniBridge will attempt to load and initialize these providers at startup, and any errors during loading will be logged.
Installing Providers in Docker
If you're running AniBridge in Docker, the best way to install additional providers is to create a custom Docker image that inherits from the official AniBridge image and includes the necessary provider packages. However, as a quick-and-dirty alternative, you can also override the container's CMD to install the provider package at runtime before launching AniBridge. For example, if your provider is available on GitHub and can be installed via pip, you could use a command like this:
web.enabled
bool (optional, default: True)
When enabled, the web interface is accessible.
web.host
str (optional, default: "")
The host address to bind the web interface to. E.g. 0.0.0.0 to listen on all IPv4 interfaces, :: for all IPv6 interfaces, or 127.0.0.1 to only listen on localhost.
Dual Stack IPv4/IPv6
To listen on both IPv4 and IPv6 interfaces, set this to an empty string "". This is the default behavior and is recommended for most users.
web.port
int (optional, default: 4848)
The port to bind the web interface to.
web.allow_config_without_auth
bool (optional, default: False)
When enabled, allows access to configuration endpoints without authentication. By default, the configuration endpoints (which contain read/write access to sensitive data) are disabled unless authentication is properly set up.
It is recommended to keep this option disabled unless you have other security measures in place (e.g., network restrictions, reverse proxy with authentication).
This option has no effect if basic authentication is enabled via web.basic_auth or an htpasswd file, as authentication will be required regardless.
Security Risk
Enabling web.allow_config_without_auth can expose sensitive configuration data and allow unauthorized modifications if the web interface is accessible to untrusted users. Use with caution and ensure proper security measures are in place.
web.basic_auth.username
str | None (optional, default: None)
HTTP Basic Authentication username for the web UI. Basic Auth is enabled only when both the username and password are provided (or an htpasswd file is used). Leave unset to disable authentication.
web.basic_auth.password
str | None (optional, default: None)
HTTP Basic Authentication password for the web UI. Basic Auth is enabled only when both the username and password are provided (or an htpasswd file is used). Leave unset to disable authentication.
web.basic_auth.htpasswd_path
str | None (optional, default: None)
Path to an Apache htpasswd file containing user credentials for HTTP Basic Authentication. When set, the web UI validates requests against this file. Only bcrypt (recommended) and SHA1 (insecure) hashed passwords are supported.
Providing an htpasswd file allows you to manage multiple users and rotate passwords without exposing plaintext credentials in the configuration.
Generate htpasswd Entries
web.basic_auth.realm
str (optional, default: "AniBridge")
Realm label presented in the browser Basic Auth prompt and WWW-Authenticate response header.
Advanced Examples
Multiple Users
This example demonstrates configuring three profiles for different Plex and AniList users.
# Global settings shared by all profiles
global_config:
library_provider: "plex"
list_provider: "anilist"
library_provider_config:
plex:
url: "http://localhost:32400"
scan_modes: ["periodic"]
profiles:
nitta:
library_provider_config:
plex:
token: "EzF..."
list_provider_config:
anilist:
token: "eYJ..."
hina:
library_provider_config:
plex:
token: "Gd3..."
list_provider_config:
anilist:
token: "sKf..."
guest:
library_provider_config:
plex:
# Using a Plex Home user with the owner's token
token: "EzF..."
home_user: "Home User"
list_provider_config:
anilist:
token: "gHt..."
sync_rules:
review: false
user_rating: false
started_at: false
finished_at: false
Per-section Profiles
This example demonstrates configuring separate profiles for different Plex sections, allowing for tailored sync settings based on content type.
# Global settings shared by all profiles
global_config:
library_provider: "jellyfin"
list_provider: "anilist"
library_provider_config:
jellyfin:
token: "EzF..."
user: "takopi"
url: "http://localhost:32400"
list_provider_config:
anilist:
token: "eYJ..."
scan_modes: ["periodic"]
profiles:
# For movies, perform full, destructive scans every 30 minutes
movies:
library_provider_config:
jellyfin:
sections: ["Anime Movies"]
full_scan: true
destructive_sync: true
scan_interval: 1800
# For shows, use the built-in defaults
shows:
library_provider_config:
jellyfin:
sections: ["Anime"]
One User, Multiple List Providers
This example demonstrates configuring a single Plex user to sync with multiple list providers (AniList and MyAnimeList).
global_config:
library_provider: "plex"
library_provider_config:
plex:
token: "EzF..."
url: "http://localhost:32400"
user: "takopi"
scan_modes: ["periodic", "webhook"]
profiles:
anilist:
list_provider: "anilist"
list_provider_config:
anilist:
token: "eYJ..."
mal:
list_provider: "mal"
list_provider_config:
mal:
token: "XyZ..."