Skip to content

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

config.yaml
############################################################################################################
# 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:

  1. Profile-specific settings (highest priority)
  2. Global shared settings
  3. 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:

sync_rules:
  review: false
  user_rating: false

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 is dropped or paused, keep the current status instead. If there is no current status, use current
  • disable_user_rating_and_review: prevents user_rating and review from syncing
  • prevent_regressions: prevents syncing a lower value for status, progress, repeats, finished_at, and started_at by keeping the current value instead
  • promote_rewatch: if the current status is repeating or completed and the computed status is current, promotes the computed status to repeating

Usage example:

sync_rules:
  templates: [prevent_regressions, promote_rewatch]
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:

  • if is optional and when omitted, the rule always matches (equivalent to if: true)
  • set is 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 changes
  • computed: the list entry state AniBridge computed for the sync
  • vars: values declared under sync_rules.vars
  • ctx: 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.

  1. Prior to syncing, a batch of requests is created to retrieve all the entries that will be worked on.
  2. 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.

library_provider_config:
  provider_namespace:
    option1: ...
    option2: ...

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.

list_provider_config:
  provider_namespace:
    option1: ...
    option2: ...

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:

provider_classes: ["my_providers.MyCustomProvider"]

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:

command: /bin/sh -c "pip install git+https://github.com/example/my_provider.git && python /app/main.py"

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..."