Skip to main content

Automations

Automations are rules that apply actions to torrents that match conditions. Use them to manage speed limits, delete old torrents, and organize torrents with tags and categories.

How automations work​

qui evaluates automations in sort order. For exclusive actions such as delete, the first match wins. Each rule matches torrents with a query builder that supports nested conditions.

  • Automatic: A background service scans torrents every 20 seconds.
  • Per-rule intervals: Each rule can have its own interval (minimum 60 seconds, default 15 minutes).
  • Per-rule notifications: If you configure notification targets, each rule can opt in or out of automation notifications.
  • Manual dry-run: Run "Dry-run now" from the workflow dialog or "Run dry-run now" from the workflow menu.
  • Debouncing: qui does not process the same torrent again within 2 minutes.

Query builder​

The query builder supports complex nested conditions with AND/OR groups. Drag conditions to reorder them.

Available condition fields​

Identity fields​

FieldDescription
NameTorrent display name (supports cross-category operators)
HashInfo hash
Infohash v1BitTorrent v1 info hash
Infohash v2BitTorrent v2 info hash
Magnet URIMagnet link for the torrent
CategoryqBittorrent category
TagsSet-based tag matching
StateStatus filter (see State Values below)
Created ByTorrent creator metadata

Path fields​

FieldDescription
Save PathDownload location
Content PathFull path to content
Download PathSession download path from qBittorrent

Size fields (bytes)​

FieldDescription
SizeSelected file size
Total SizeTotal torrent size
CompletedCompleted bytes
DownloadedBytes downloaded
Downloaded (Session)Downloaded in current session
UploadedBytes uploaded
Uploaded (Session)Uploaded in current session
Amount LeftRemaining bytes
Free SpaceFree space on disk (configurable source, see Free Space source)

Duration fields (seconds)​

FieldDescription
Added AgeTime since added
Completed AgeTime since completed
Inactive TimeTime since last activity
Seen Complete AgeTime since torrent was last complete
ETAEstimated time to completion
Reannounce InSeconds until next announce
Seeding TimeTime spent seeding
Time ActiveTotal active time
Max Seeding TimeConfigured max seeding time
Max Inactive Seeding TimeConfigured max inactive seeding time
Seeding Time LimitTorrent seeding time limit
Inactive Seeding Time LimitTorrent inactive seeding time limit

System time fields​

When qui evaluates a rule, these fields use qui's current system time. Use them for time windows, such as "only run at night" or "apply different actions on weekends".

FieldDescription
System HourCurrent hour (0-23)
System MinuteCurrent minute (0-59)
System Day of WeekCurrent weekday (0=Sun to 6=Sat)
System DayCurrent day of month (1-31)
System MonthCurrent month (1-12)
System YearCurrent year
Ranges that wrap​

On System Hour, System Minute, System Day of Week and System Month, a between range whose minimum is above its maximum wraps past the end of the field. For example, System Hour between 20 and 6 is true from 20:00 through 05:59, and false from 06:00 through 19:59. The minimum is included and the maximum is not, so set the maximum to the hour the window must stop.

System Day and System Year do not wrap. A month boundary depends on the length of the month, and years only go up. On every other numeric field, a minimum above the maximum matches nothing.

Progress fields​

FieldDescription
RatioUpload/download ratio
Ratio LimitConfigured ratio limit
Max RatioqBittorrent max ratio value
Uploaded / SizeUploaded bytes divided by total torrent size. For cross-seeded torrents, use this instead of Ratio.
ProgressDownload progress (0-100%)
AvailabilityDistributed copies available
PopularitySwarm popularity metric

Speed fields (bytes/s)​

FieldDescription
Download SpeedCurrent download speed
Upload SpeedCurrent upload speed
Download LimitConfigured download speed limit
Upload LimitConfigured upload speed limit

Peer/queue fields​

FieldDescription
Active SeedersCurrently connected seeders
Active LeechersCurrently connected leechers
Total SeedersTracker-reported seeders
Total LeechersTracker-reported leechers
Trackers CountNumber of trackers
Queue PriorityTorrent queue priority value

Tracker/status fields​

FieldDescription
TrackerAny tracker of the torrent (URL, domain, or customization display name)
PrivateBoolean: the torrent uses a private tracker
UnregisteredBoolean: the tracker reports unregistered (requires qBittorrent 5.1+)
Tracker statusPer-tracker announce status. See Tracker status values (requires qBittorrent 5.1+).
Tracker messagePer-tracker status message. Use nil for an empty message (requires qBittorrent 5.1+).
CommentTorrent comment field

Tracker matches every tracker the torrent announces to, including trackers that do not work. qui ignores the DHT, PeX, and LSD pseudo-trackers.

If you configured Tracker Customizations (Dashboard → Tracker Breakdown), the condition can also match the display name in addition to the raw URL or domain. A merged tracker group matches by its group name.

On qBittorrent versions before 5.1, qui cannot read the full tracker list. Tracker then sees only the tracker that qBittorrent reports as working. When qui finds no tracker at all, positive operators such as is and contains match nothing, and negative operators such as is not match every torrent.

note

Any tracker condition (Tracker, Trackers (All), Tracker status, or Tracker message) makes qui read the tracker list of every torrent. qui sends one request for each instance and keeps the result for 5 minutes. Rules without a tracker condition, and rules that are turned off, send no extra request.

On a large library, or on an instance whose qBittorrent Web UI is already slow, that request adds a delay to the automation run.

note

Older rules can use a second field named Trackers (All). It now behaves the same as Tracker, so qui no longer offers it for new rules. Your existing rules keep working. To stop seeing it, change the condition to Tracker.

Mode fields​

FieldDescription
Auto-managedManaged by automatic torrent management
First/Last Piece PriorityFirst and last pieces are prioritized
Force StartIgnores queue limits and starts immediately
Sequential DownloadDownloads pieces sequentially
Super SeedingSuper-seeding mode enabled

Release/grouping fields​

FieldDescription
Content TypeDerived from release name parsing (useful for grouping): movie, tv, music, audiobook, book, comic, game, app, adult, or unknown. book also covers magazines; courses are unknown
Effective NameNormalized title derived from release parsing (useful for grouping, can be empty)
Release SourceParsed release specifier (for example WEBDL, WEBRIP, BLURAY, can be empty)
Release ResolutionParsed release specifier (for example 1080p, can be empty)
Release CodecParsed release specifier (for example HEVC, can be empty)
Release HDRParsed release specifier (for example DV, HDR, can be empty)
Release AudioParsed release specifier (for example TrueHD, can be empty)
Release ChannelsParsed release specifier (for example 5.1, can be empty)
Release GroupParsed release specifier (for example NTb, can be empty)
Release YearYear parsed from the torrent name (for example 2021). Numeric, best for movies and dated releases. Releases with no detectable year (including most TV episodes such as S14E05) never match any comparison operator, including !=. The condition's NOT toggle wraps the whole leaf, so NOT (year = X) still matches yearless releases
Group SizeSize of the selected group for this condition (requires grouping. See Grouping).
Is GroupedBoolean: true when selected group size > 1 (requires grouping. See Grouping).

Cross-seed fields​

FieldDescription
Exists on Other InstanceBoolean: a matching torrent exists on at least one other active instance
Seeding on Other InstanceBoolean: a matching torrent is actively seeding on at least one other active instance
Cross-seed Exists on Same InstanceBoolean: another matching torrent exists on this instance
Cross-seed Seeding on Same InstanceBoolean: another matching torrent is actively seeding on this instance
Cross-seed TagsString: the tags of this torrent and all of its same-instance cross-seeds as one set. NOT operators match only when no copy has the tag. Same matching rules as Tags (see Tag conditions). If there are no cross-seeds, qui checks only the torrent's own tags.
Season pack statuspack, packed, unpacked, or empty. Whether this torrent is a season pack, an episode covered by a season pack of the same release on this instance, or an episode with no such pack (see Season pack status)
Season pack status (any instance)Same as Season pack status, but a season pack on any active instance counts

Filesystem fields​

FieldDescription
Hardlink Scopenone, torrents_only, inside_qbittorrent, or outside_qbittorrent (requires local filesystem access, see Hardlink detection)
Hardlink Scope (Cross-Instance)none, torrents_only, inside_qbittorrent, or outside_qbittorrent across all instances (requires local filesystem access)
Has Missing FilesBoolean: a completed torrent has files missing on disk (requires local filesystem access)
Has Skipped FilesBoolean: one or more files are set to Do not download. qui reads file priorities from its files cache, so a priority change made outside qui can take up to 5 minutes to reach this field

State values​

The State field matches these status buckets:

StateDescription
downloadingActively downloading
uploadingActively uploading
completedDownload finished
stoppedPaused by user
activeHas transfer activity
inactiveNo current activity
runningNot paused
stalledNo peers available
stalled_uploadingStalled while uploading
stalled_downloadingStalled while downloading
erroredHas errors
tracker_downTracker unreachable
tracker_errorA tracker returned an explicit error
checkingFile check in progress
checkingResumeDataChecking resume data
movingMoving files
missingFilesFiles not found
unregisteredTracker reports unregistered

tracker_down and tracker_error require qBittorrent 5.1+ (Web API 2.11.4+). On older instances, the query builder disables these values.

Tracker status values​

If any of a torrent's real trackers reports the selected status, the Tracker status field matches. qui ignores qBittorrent's DHT/PeX/LSD pseudo-trackers. Pick a value from the dropdown:

StatusDescription
Not contactedThe client did not contact the tracker yet
WorkingThe client contacted the tracker and it works
UpdatingA tracker update is in progress
ErrorAnnounce failed (generic)
Tracker errorThe tracker returned an explicit error
UnreachableThe client cannot connect to the tracker

Tracker message matches the per-tracker status message with standard string operators. To match an empty or non-empty message, use the literal value nil with is or is not.

Both fields require qBittorrent 5.1+ (Web API 2.11.4+). On older instances, the query builder disables them.

Operators​

String: equals, not equals, contains, not contains, starts with, ends with, matches regex

Numeric: =, !=, >, >=, <, <=, between

A between range includes both ends. The one exception is a range that wraps on a clock field, described in Ranges that wrap.

Boolean: is, is not

State: is, is not

Cross-Category (Name field only):

  • EXISTS_IN: exact name match in the target category
  • CONTAINS_IN: partial name match in the target category. The comparison is case-insensitive and accent-insensitive, and treats ., _ and - as spaces, so "Amélie.2001" matches "Amelie 2001".

Regex support​

There are two ways to use regex in filter conditions:

The matches regex operator treats the value as a regex pattern. If the pattern matches anywhere in the field value, the condition is true.

The regex toggle (.* button) appears next to the value input on the other string operators: equals, contains, not contains, starts with, and ends with. When you enable the toggle, qui treats the value as a regex pattern.

Regex toggle changes the selected operator

When the regex toggle is on, equals, contains, starts with, and ends with all behave as matches regex. Exact, containment, prefix, and suffix matching do not apply.

not equals and not contains invert the regex result. They are true only when the pattern does not match.

You can also negate a regex match with the NOT toggle (the IF / IF NOT button at the start of the condition row) together with the matches regex operator.

qui supports full RE2 (Go regex) syntax. Patterns are case-insensitive by default. A regex is not anchored. Use ^ and $ for a full-string match (example: ^BHD$).

Field notes:

  • Tracker: qui checks the pattern against multiple candidates for each tracker (raw URL, extracted domain, and the optional customization display name). If a regex is negative, it passes only when none of the candidates match.
  • Tags: If you do not use regex, qui applies string operators per tag. If you turn regex on, qui matches the pattern against the full raw tags string.

The UI validates patterns and shows an error for invalid regex.

Tag conditions​

Each tag condition checks against a single value. The value field does not support comma-separated lists. If you enter tag1, tag2, tag3 as the value, qui treats it as one literal string, not three tags.

If you do not use regex, tag operators (equals, not equals, contains, not contains) compare the condition value against each of the torrent's tags.

  • equals / not equals: exact tag membership (case-insensitive)
  • contains / not contains: substring match per tag (case-insensitive)
Tag operators: contains is substring matching

Tags contains tag1 also matches torrents tagged tag10. For exact tag membership, use equals / not equals with one condition per tag and combine them with an OR group.

Matching any of multiple tags​

To check whether a torrent has any one of several tags, create an OR group with one condition per tag (exact match):

#FieldOperatorValue
1Tagsequalstag1
2Tagsequalstag2
3Tagsequalstag3

Group these conditions with OR logic. When at least one tag is present, the rule matches.

To exclude torrents that have any of several tags, create an AND group of not equals conditions (exact match):

#FieldOperatorValue
1Tagsnot equalstag1
2Tagsnot equalstag2
3Tagsnot equalstag3

Group these conditions with AND logic. All three must be true, so none of those tags is present.

Using regex for tag matching​

As an alternative to multiple conditions, you can use regex to match several tags in one condition. If you enable regex, the pattern matches against the full raw tag string (for example cross-seed, noHL, racing), not each tag on its own.

For example, to exclude torrents tagged with tag1 or tag2, use a single condition:

  • Field: Tags
  • Toggle: IF NOT (negate the match)
  • Operator: matches regex
  • Value: (^|,\s*)(tag1|tag2)(\s*,|$)

qui evaluates the regex against the raw tags string. The delimiter-aware pattern prevents tag1 from matching tag10. The IF NOT toggle negates the result. The condition evaluates to true only for torrents that have neither tag.

Live impact preview and dry-run​

When you edit workflows, qui provides immediate feedback for delete and category workflows:

  • When conditions and actions change, the Live impact preview in the workflow dialog updates.
  • It shows the current impacted count and a preview list of matching torrents.
  • For category rules, the preview summary splits direct matches and cross-seed expansions.

When you enable a delete or category workflow, qui opens a confirmation dialog that loads the same preview. The preview does not block the save. Click Save without preview while it loads, or after it fails, to enable the workflow at once. The workflow then acts on every matching torrent on its next run.

To run a dry-run immediately without waiting for interval execution:

  • Workflow dialog: Dry-run now
  • Workflow list menu: Run dry-run now

A dry-run executes the current workflow configuration as a simulation and writes results to automation activity. A dry-run reports the same torrents as the live impact preview, because it deletes nothing.

No-match behavior:

  • If nothing matches, manual dry-runs log a dry_run_no_match summary row.
  • To avoid event noise, scheduled dry-run rules do not log no-match rows.

Torrent sorting and scoring​

By default, qui processes matched torrents oldest first. Set the Torrent Priority to control which torrents qui processes first. This priority setting affects actions such as Delete combined with Free Space, where priority decides which torrents qui removes first to free space.

Priority types​

TypeDescription
DefaultStandard oldest-first priority.
SimplePrioritize by one numeric, duration, or string field (for example Size, Added Age, Name) in ascending or descending order.
ScoreRule-based priority. qui scores torrents with custom rules and sorts them by total score, ascending or descending.

Score-based priority​

Score-based priority ranks torrents by combined factors. You define Score Rules. Each rule evaluates the torrent and adds to its total score.

Available score rule types:

  • Field Multiplier: Extracts a numeric value from the torrent (such as Size or Time Active), multiplies it by a configured multiplier, and adds the result to the score.
  • Conditional: Evaluates a standard query condition (see Query builder). If the condition is true, qui adds a static value to the score.

qui processes torrents by their final score. The Live impact preview shows the computed scores.

Tracker matching​

You can also scope trackers with a Tracker condition, but the tracker pattern field remains available.

PatternExampleMatches
All*Every tracker
Exacttracker.example.comOnly that domain
Glob*.example.comSubdomains
Suffix.example.comDomain and subdomains

Separate multiple patterns with commas, semicolons, or pipes. All matching is case-insensitive.

Grouping​

Grouping allows an automation to treat related torrents as one unit for:

  • Group-aware conditions: GROUP_SIZE, IS_GROUPED
  • Group expansion: Apply an action to every torrent in the group, not only the matched torrent.
  • Strict matching: Grouped expansion runs only when all members satisfy the action conditions.

Group-scoped condition fields​

You can scope GROUP_SIZE and IS_GROUPED per condition row:

  • If you want explicit per-row grouping, set groupId on each GROUP_SIZE / IS_GROUPED condition.
  • If a grouped condition row has no groupId, qui uses conditions.grouping.defaultGroupId.
  • If no default is configured, legacy unscoped grouped conditions fall back to cross_seed_content_save_path.

Multiple grouped conditions can then live in the same workflow, each with a different grouping strategy.

Action expansion​

Some actions accept a groupId. When you set groupId on an action, qui expands the action to all torrents in that group.

Group expansion uses strict semantics:

  • Every member in the expanded group must satisfy the action condition checks for that rule.
  • If any member fails or qui cannot resolve the group, qui skips the entire grouped action.
  • If groupId is set, there is no "trigger-only fallback".

Built-in group IDs:

  • cross_seed_content_path: Same Content Path (normalized)
  • cross_seed_content_save_path: Same Content Path + Save Path (normalized)
  • release_item: Same Content Type + Effective Name
  • tracker_release_item: Same Tracker + Content Type + Effective Name
  • hardlink_signature: Same physical file set signature (requires local filesystem access)

Custom groups (advanced)​

Rules can define custom groups via conditions.grouping.groups[] with:

  • id: string
  • keys: list of key names combined to form the group key

Supported keys:

  • contentPath, savePath, effectiveName, contentType, tracker
  • rlsSource, rlsResolution, rlsCodec, rlsHDR, rlsAudio, rlsChannels, rlsGroup
  • hardlinkSignature

For content-path-based grouping where Content Path == Save Path (ambiguous), you can set the policy below. The delete, category, and move actions apply it when they expand to the group. The Group Size and Is Grouped conditions ignore it.

  • ambiguousPolicy: "verify_overlap" (default for cross-seed groups) with minFileOverlapPercent (default 90)
  • ambiguousPolicy: "skip"

Actions​

You can combine actions, except Delete. Delete must be standalone. Each action supports an optional condition override.

Speed limits​

Set upload or download limits. Each field supports these modes:

ModeValueDescription
No change-Do not change this field
Unlimited0Remove speed limit (qBittorrent treats 0 as unlimited)
Custom>0Specific limit in KiB/s or MiB/s

qui applies limits in batches.

Share limits​

Set ratio limits or seeding time limits. Each field supports these modes:

ModeValueDescription
No change-Do not change this field
Use global-2Follow qBittorrent's global share settings
Unlimited-1No limit for this field
Custom>=0Specific value (ratio as decimal, time in minutes)

When a torrent reaches any enabled limit, it stops seeding.

Share limit action (Web API 2.15.1+)​

If the qBittorrent Web API is 2.15.1 or newer, the torrent share limit dialog and automation workflows show When limits are reached. When a torrent reaches its ratio, seeding time, or inactive seeding limit, this setting controls what happens. qui stores and sends the string enum names that qBittorrent expects for setShareLimits (Qt meta-object names, not numeric codes):

OptionValue (shareLimitAction)Description
Default (use global)omit or defaultFollow qBittorrent's global setting
Stop torrentStopPause the torrent
Remove torrentRemoveRemove from client, keep files
Remove with contentRemoveWithContentRemove from client and delete files
Enable super seedingEnableSuperSeedingSwitch to super seeding mode

Share limits matching mode (Web API 2.16.0+)​

Limits matching mode (match any limit or all limits) is a separate Web API capability and requires 2.16.0 or newer. If you run older 5.2 builds that expose only 2.15.1, qui shows the action above but hides this control until you upgrade qBittorrent. Values use string enum names for setShareLimits:

OptionValue (shareLimitsMode)Description
Default (use global)omit or defaultFollow qBittorrent's global setting
Match any limitMatchAnyTrigger when any single limit is reached
Match all limitsMatchAllTrigger only when all limits are reached

If the instance does not report the required Web API version, qui hides these options (see qBittorrent Version Compatibility). Ratio and seeding time limits above still apply on older instances. qui gates only the extra controls.

If the connected qBittorrent instance supports these fields, they appear in the torrent share limit dialog and the automation workflow editor. On older instances, qui hides the fields and sends only the classic ratio and seeding time limits.

Pause​

Pause matching torrents. qui pauses only torrents that are not already stopped.

If a resume action is also present, the last action wins.

Resume​

Resume matching torrents. qui resumes only torrents that are not already running.

If a pause action is also present, the last action wins.

Force recheck​

Force recheck matching torrents.

  • Triggers a qBittorrent recheck for matched torrents.
  • You can combine this action with other actions.
  • Supports an optional condition override, as other actions do.

Force reannounce​

Force reannounce matching torrents.

  • Triggers an immediate tracker reannounce for matched torrents.
  • You can combine this action with other actions.
  • Supports an optional condition override, as other actions do.

Delete​

Remove torrents from qBittorrent. Delete must be standalone. You cannot combine it with other actions.

ModeDescription
deleteRemove from client, keep files
deleteWithFilesRemove with files
deleteWithFilesPreserveCrossSeedsRemove files, but keep them if qui detects cross-seeds
deleteWithFilesIncludeCrossSeedsRemove files and also delete all cross-seeded torrents sharing the same files

Optional grouping (advanced):

Delete actions can specify a groupId to expand the deletion to all torrents in that group.

  • If you want "remove from client" to be cross-seed aware, use groupId for delete (keep files).
  • If you set groupId, a keep-files delete is strict all-or-none. If any group member does not satisfy the rule conditions, qui removes nothing in that group.

Include cross-seeds mode behavior:

When a torrent matches the rule, qui finds other torrents that point to the same downloaded files (cross-seeds and duplicates) and deletes them together. Use this mode to remove content and all its cross-seeded copies at once.

  • Safe expansion: If qui cannot determine that another torrent uses the same files, qui does not include it in the deletion.
  • File lists decide, not paths: qui includes a candidate only when at least 90% of the smaller torrent's bytes use the same file locations. A torrent that shares only the folder, such as a pack with a top folder named Season 2, keeps its files and stays in the client. If overlap is above zero but below 90%, qui skips the entire deletion group.
  • Safety-first: If the file check cannot complete for any reason, qui skips the entire group to prevent broken torrents.
  • Preview: The delete preview shows all torrents that qui deletes in simulation, with cross-seeds marked.

Include hardlinked copies:

If you enable "Include hardlinked copies" (available only with deleteWithFilesIncludeCrossSeeds mode), qui also deletes torrents that share the same physical files through hardlinks, even when their Content Paths differ.

  • Requires: You must enable Local Filesystem Access on the instance.
  • Safe scope: qui includes only hardlinks fully contained within qBittorrent's torrent set. qui never follows hardlinks to files outside qBittorrent (for example, your media library).
  • Preview: The preview marks hardlink-expanded torrents as "Cross-seed (hardlinked)".
  • Free Space projection: If you use Free Space conditions, qui deduplicates hardlink groups in the space projection. Torrents that share the same physical files count once.

If qBittorrent holds hardlinked copies of content in different locations and you want to remove all copies together, use this mode.

Tag​

Manage tags on torrents. You can add multiple Tag actions in one workflow.

ModeDescription
fullAdd to matches, remove from non-matches (smart toggle)
addOnly add to matches
removeOnly remove from matches
note

mode: remove removes tags from torrents that match the tag action condition. It does not remove from non-matches.

qui evaluates mode: full within the rule's scope for that run (enabled rule, tracker pattern match, and run eligibility). It is not a client-wide sweep by itself.

Options:

  • Managed / Replace in Client: Managed (default) applies per-torrent add/remove diffs only. Replace in client deletes managed tags from qBittorrent first, then reapplies them to current matches.
  • Use tracker name as tag: Derive the tag from the tracker domain.
  • Use display name: Use the tracker customization display name instead of the raw domain.

Behavior reference:

ConfigurationBehavior
mode: full + ManagedAdds/removes tag for torrents this rule evaluates. No client-wide reset.
mode: full + Replace in clientDeletes selected tag(s) client-wide first, then re-adds only current matches.

If you see repeated activity such as +tag=696 on every run, you likely enabled Replace in client for that tag action.

Quick troubleshooting:

  1. Look in the logs for automations: deleted managed tags from client before retagging.
  2. In the Automations UI, open enabled rules and look for "Replace in client" on any tag action.
  3. Make sure that the activity entry's rule list matches the expected rule.

Category​

Move torrents to a different category. Select Uncategorized to remove their category.

Options:

  • Include affected cross-seeds: Also move cross-seeds (torrents with matching ContentPath AND SavePath).
  • Group ID (advanced): Expand category changes to all torrents in the specified group (see Grouping). If set, this option takes precedence over "Include affected cross-seeds".
  • Strict grouped matching: If you set groupId, category expansion applies only when all group members satisfy the category rule checks.
  • Skip if cross-seed exists in categories: If another cross-seed is in a protected category, prevent the move.

Move​

Move torrents to a different path on disk. If AutoTMM is off, use this action to move content.

Options:

  • Group ID (advanced): Expand moves to all torrents in the specified group (see Grouping). qui resolves the move path for the matched torrent and applies it to the whole group.
  • Strict grouped matching: If you set groupId, move expansion is all-or-none. Every member must satisfy the move rule checks.
  • Skip if cross-seeds don't match the rule's conditions: If the torrent has cross-seeds that do not match the rule's conditions, skip the move. If Group ID is set, qui ignores this option.

Move path templates​

qui evaluates the move path as a Go template for each torrent. Use a fixed path (for example /data/archive) or template actions to build paths from torrent properties.

Available template variables:

VariableDescription
.NameTorrent display name
.HashInfo hash
.CategoryqBittorrent category
.IsolationFolderNameFilesystem-safe folder name (hash or sanitized name)
.TrackerTracker display name from Tracker Customizations, otherwise the tracker domain

Template function:

FunctionDescription
sanitizeMakes a string safe for use as a path segment (removes invalid characters). Use it for user-controlled values such as names, for example {{ sanitize .Name }}.

Examples:

  • Fixed path (no template actions): /data/archive
  • By category: /data/{{.Category}} → for example /data/movies
  • By name (safe for paths): /data/{{ sanitize .Name }}
  • By isolation folder: /data/{{.IsolationFolderName}}
  • By tracker: /data/{{.Tracker}}

Auto management​

Enable or disable qBittorrent's Automatic Torrent Management (AutoTMM) on matching torrents.

In JSON, enabled is the AutoTMM value that the action sets. true enables AutoTMM on matching torrents, and false disables it. The action runs when the autoManagement key is present, even when enabled is false.

{
"name": "Disable AutoTMM on cross-seeds",
"trackerPattern": "*",
"conditions": {
"schemaVersion": "1",
"autoManagement": {
"enabled": false,
"condition": { "field": "CATEGORY", "operator": "ENDS_WITH", "value": ".cross" }
}
}
}

When AutoTMM is on, qBittorrent moves torrents to the save path configured for their category. When AutoTMM is off, you control save paths manually.

If multiple rules match the same torrent with Auto Management actions, the last matching rule (by sort order) wins.

External Program​

When torrents match the automation rule, run a configured external program. This action uses the programs from Settings → External Programs.

FieldDescription
ProgramSelect from enabled external programs
Condition OverrideOptional condition specific to this action

Behavior:

  • The program runs asynchronously (fire-and-forget) and does not block automation processing.
  • You can combine this action with other actions (speed limits, share limits, pause, tag, category).
  • Only enabled programs appear in the dropdown.
  • qui logs activity with the rule name, torrent details, and success or failure status.
note

To appear in the automation dropdown, the program must be enabled in Settings → External Programs.

note

When multiple rules match the same torrent with External Program actions enabled, the last matching rule (by sort order) determines which program executes for that torrent. Only one program runs per torrent per automation cycle.

warning

The executable path of the program must be in the allowlist. Disabled programs and programs with forbidden paths do not run. qui rejects the execution attempt and logs the rejection in the activity log with the rule name and torrent details.

Use cases:

  • Run post-processing scripts when torrents complete.
  • When conditions match, notify external systems (webhooks, notifications).
  • Trigger media library scans after category changes.
  • Run cleanup scripts for old or stalled torrents.

Export to Instance​

Export a torrent's .torrent file from the current instance and add it to a different qBittorrent instance. Use this action to migrate torrents between instances, for example from a seedbox to a local instance for long-term seeding.

The action assumes the data already exists on the target (moved with rclone, Quickdrop for Deluge, or another tool) and uses skip_checking=true by default.

FieldDescription
Target instanceDestination qBittorrent instance (cannot be the same as source)
Save pathSave path on target instance (Go template supported, see below)
CategoryCategory to assign on target instance (dropdown from target's categories)
TagsTags to apply on target instance
Skip checkingSkip hash check on target (default: enabled)
PausedAdd torrent paused on target
Content layoutDefault, Original, Create subfolder, or Don't create subfolder. In JSON, contentLayout is Original, Subfolder, or NoSubfolder. With Default, the JSON has no contentLayout, and the target instance uses its own default layout.
Condition OverrideOptional condition specific to this action

Behavior:

  • The export runs asynchronously and does not block automation processing.
  • You cannot combine it with Delete. The API rejects rules that enable both export and delete.
  • Duplicate detection: Before the export, qui looks for the torrent on the target instance and skips the export if found.
  • After the add, qui verifies that the torrent appeared and is healthy. If that check fails, qui removes the torrent from the target so the next run can retry the transfer.
  • qui does not export cross-seed group members. To export a group, chain the action with Category/Tag actions that use group expansion.
  • qui logs activity with the rule name, torrent details, target instance, and success or failure status.
  • Dry-run shows what qui exports in simulation, without a transfer.
note

When multiple rules match the same torrent with Export to Instance actions, the last matching rule (by sort order) determines the export configuration for that torrent. Only one export runs per torrent per automation cycle.

Save path templates​

The save path field supports Go templates, the same as the Move action.

VariableDescription
.NameTorrent display name
.HashInfo hash
.CategoryqBittorrent category (on source instance)
.IsolationFolderNameFilesystem-safe folder name (hash or sanitized name)
.TrackerTracker display name from Tracker Customizations, otherwise the tracker domain
FunctionDescription
sanitizeMakes a string safe for use as a path segment (removes invalid characters).

Examples:

  • Fixed path: /data/torrents
  • By category: /data/{{.Category}}
  • By tracker: /data/{{.Tracker}}

If you set no save path but set a category, qui enables qBittorrent's Automatic Torrent Management so the target uses the category's configured path.

Cross-seed awareness​

Automations detect cross-seeded torrents (same content and files) and can handle them specially:

  • Detection: Cross-seed condition fields match on content path, exact name, and release metadata. Same-instance checks exclude the current torrent itself. Filter Cross-Seeds also pairs a retitled upload that has the same exact byte size. The condition fields do not pair retitled uploads, because a rule can delete torrents and a title is weaker evidence than a shared file.
  • Delete rules:
    • If cross-seeds exist, use deleteWithFilesPreserveCrossSeeds to keep files.
    • Use deleteWithFilesIncludeCrossSeeds to delete matching torrents and all their cross-seeds together.
  • Category rules: Enable "Include affected cross-seeds" to move related torrents together.
  • Blocking: If cross-seeds are in protected categories, prevent category moves.

The HARDLINK_SCOPE field lets automations tell apart torrents whose files are hardlinked into an external library (Sonarr, Radarr, and similar tools) and torrents that exist only within qBittorrent. This field serves as the foundation for safe "Remove Upgraded Torrents" automations.

How scope is determined​

When an automation references HARDLINK_SCOPE, qui validates and inspects every file of every torrent in qBittorrent. qui ignores a priority-0 (Do not download) file that does not exist on disk. qui scans an existing priority-0 file like any other regular file. To keep partially selected torrents out of a hardlink rule, add the condition Has Skipped Files is false. For each regular file, qui extracts:

  • The inode and device ID: These identify the file on disk.
  • The nlink count: The total number of hardlinks to that inode, as the filesystem reports it.

qui counts how many unique file paths across the qBittorrent torrent set point to each inode. qui compares these two numbers to set the scope for each torrent:

ScopeConditionMeaning
noneNo file has nlink > 1No hardlinks detected.
torrents_onlySome file is linked inside the torrent set, no file has outside linksHardlinks exist, but only between torrents in qBittorrent. No external library links.
outside_qbittorrentSome file has nlink > uniquePathCount, no file is linked inside the setSomething outside qBittorrent hardlinked the file, typically a Sonarr/Radarr library import.
bothSome file is linked inside the torrent set, some file also has outside linksLinked to other torrents and to an external location (for example, a cross-seeded library import).

In conditions, two additional predicate values are available on top of the exact scopes above:

  • inside_qbittorrent matches torrents linked to other torrents in the set, even when they are also linked outside (torrents_only or both).
  • outside_qbittorrent as a condition value keeps its historical meaning. It matches any torrent with outside links (outside_qbittorrent or both).

With AND/OR groups and the "is not" operator, you can express every combination of the inside and outside link states.

note

HARDLINK_SCOPE reflects only hardlink metadata. qui detects cross-seeds separately with ContentPath matching. A torrent can have HARDLINK_SCOPE = none and still be cross-seeded.

Unknown scope and safety behavior​

If path validation or file inspection fails for any remaining file, the torrent receives no scope entry. Causes include invalid paths, missing permissions, and inaccessible storage. All HARDLINK_SCOPE conditions evaluate to false for that torrent, regardless of the operator or value. This safety measure prevents unintended deletion of torrents that qui cannot fully inspect.

The NOT toggle cannot turn unknown data into a match, including through nested condition groups. This also applies to HARDLINK_SCOPE_CROSS and HAS_MISSING_FILES. Negation still inverts comparisons against known values.

Before deletion, qui reads the files again for rules that use hardlink data. If scope is unknown or changes, qui holds the deletion, even if another branch of an OR group matches.

To diagnose this issue, enable debug logging and check for the "hardlink index built" log message, which reports an inaccessible count.

How current the scope is​

qui keeps the hardlink data of each instance for up to 10 minutes. Rules, previews, and dry runs on that instance share it.

  • When a torrent is added, removed, or moved, qui reads that torrent and the torrents that share its files again at the next rule run.
  • A change only on disk, such as a library file that Sonarr or Radarr deletes after an upgrade, shows when qui reads all torrents again. That happens at the first rule run after the data is 10 minutes old. With the default interval of 15 minutes, every run reads all torrents again. Rules with shorter intervals, previews, and dry runs on the same instance can add up to 10 minutes.
  • A file list from qBittorrent can be up to 1 hour old. After a rename or a file priority change made outside qui, the scope of that torrent can stay unknown for up to 1 hour. The same changes made in qui refresh the file list at once, and the scope changes when qui reads all torrents again.

The check before deletion (see above) reads the files of the torrent again and holds any torrent whose scope changed. For HARDLINK_SCOPE_CROSS, it does not read the files of other instances again. A change on another instance shows when qui reads all torrents again.

Docker volume requirements​

For hardlink scope detection to work in Docker:

  1. Paths must match exactly. qui must read files at the exact paths qBittorrent reports. If qBittorrent reports a save path of /data/torrents/radarr/, qui must have access to /data/torrents/radarr/ inside its container.

  2. Same underlying storage. Both containers must share the same host mount so that inode numbers stay consistent. If qui and qBittorrent access the same files through different host mounts or different bind-mount configurations, inode numbers can differ.

  3. Single mount, not subdivided. Mount the common parent directory instead of individual subdirectories. For example, if your data lives under /mnt/media/data on the host:

services:
qui:
volumes:
- /home/user/docker/qui:/config
- /mnt/media/data:/data # single mount covering both torrents and library

Do not mount both /mnt/media/data/torrents:/data/torrents and /mnt/media/data:/data. Overlapping mounts cause inconsistent inode visibility. Use one mount at the common parent.

Filesystem limitations​

Hardlink scope detection depends on the kernel reporting accurate nlink values in stat results. Some filesystems do not report accurate values:

  • FUSE-based filesystems (sshfs, mergerfs, rclone mount) can report nlink = 1 for all files, regardless of the actual hardlink count.
  • Some NAS appliance filesystems and overlay filesystems (overlayfs) behave the same way.
  • Network filesystems (NFS, CIFS/SMB) usually report accurate nlink values, but behavior varies by server.

On affected filesystems, every torrent appears to have scope none because nlink is always 1. qui has no workaround for this kernel and filesystem limitation. If you suspect this issue, run stat on a file with hardlinks and read the "Links" count.

Hardlink scope does not detect reflinks (also called block clones). A reflink is a separate file with its own inode. Cloning does not raise its nlink count, even when the file shares its data with another file. A torrent whose files reach your library only through reflinks therefore gets scope none, and a "Remove Upgraded Torrents" rule can delete it. Tools such as cp --reflink, fclones dedupe, and ZFS block cloning make reflinks. Torrents that qui adds in reflink mode also get scope none. If your rules depend on HARDLINK_SCOPE, use hardlinks for the library link. For example, use fclones link instead of fclones dedupe.

Hardlinks cannot span different filesystems. If your torrent data and media library live on separate filesystems, or on Docker volumes with different host paths, Sonarr and Radarr copy files instead. Scope detection then finds nothing.

Example: Remove Upgraded Torrents​

This automation deletes torrents that Sonarr/Radarr replaced with an upgrade. It targets torrents whose library hardlink no longer exists (the arr removed or re-linked it during the upgrade). The rule also requires at least 7 days of seeding time and a category that matches your arr categories.

tip

Use HARDLINK_SCOPE with NOT_EQUAL to outside_qbittorrent rather than EQUAL to none. Torrents with scope torrents_only (cross-seeded but not in a library) then stay eligible for cleanup, and any torrent still linked into your media library stays protected.

{
"name": "Remove Upgraded Torrents",
"trackerPattern": "*",
"conditions": {
"schemaVersion": "1",
"delete": {
"enabled": true,
"mode": "deleteWithFilesPreserveCrossSeeds",
"condition": {
"operator": "AND",
"conditions": [
{
"operator": "OR",
"conditions": [
{ "field": "CATEGORY", "operator": "EQUAL", "value": "radarr" },
{
"field": "CATEGORY",
"operator": "EQUAL",
"value": "radarr.cross"
},
{
"field": "CATEGORY",
"operator": "EQUAL",
"value": "tv-sonarr"
},
{
"field": "CATEGORY",
"operator": "EQUAL",
"value": "tv-sonarr.cross"
}
]
},
{
"field": "HARDLINK_SCOPE",
"operator": "NOT_EQUAL",
"value": "outside_qbittorrent"
},
{
"field": "SEEDING_TIME",
"operator": "GREATER_THAN_OR_EQUAL",
"value": "604800"
}
]
}
}
}
}

When Sonarr or Radarr upgrades a release, it removes the old library hardlink. The old torrent's files then have nlink == 1 (scope none) or link only to other torrents (scope torrents_only). In both cases, the scope is not outside_qbittorrent. The automation matches and deletes the torrent once the torrent meets the seeding time requirement.

If the automation matches torrents that you expect to stay protected, make sure that:

  1. qui can access all torrent files at the paths qBittorrent reports (the debug log lists inaccessible files).
  2. Your filesystem reports accurate nlink values (stat <file> shows Links > 1 for hardlinked files).
  3. Your Docker volume mounts do not overlap or subdivide storage in a way that breaks inode consistency.

The HARDLINK_SCOPE_CROSS field extends hardlink detection across all configured qBittorrent instances. While HARDLINK_SCOPE considers only torrents within one instance, HARDLINK_SCOPE_CROSS accounts for hardlinks to files managed by any instance with local filesystem access enabled.

Use this field in multi-instance setups where cross-seeds are hardlinked across instances. Without cross-instance awareness, those hardlinks appear as outside_qbittorrent even though they point to files managed by another qBittorrent instance.

Scope values​

ScopeMeaning
noneNo hardlinks detected.
torrents_onlyAll hardlinks are accounted for across all qBittorrent instances.
outside_qbittorrentHardlinks exist to files outside all qBittorrent instances.
bothHardlinks exist to other torrents across instances and to files outside all instances.

The condition values inside_qbittorrent and outside_qbittorrent also match both, as they do for HARDLINK_SCOPE.

If you use both fields together, you can distinguish cross-instance hardlinks from truly external links:

CombinationInterpretation
HARDLINK_SCOPE = outside_qbittorrent AND HARDLINK_SCOPE_CROSS = torrents_onlyHardlinks point to other qBittorrent instances only (cross-seeds). No media library copy.
HARDLINK_SCOPE = outside_qbittorrent AND HARDLINK_SCOPE_CROSS = outside_qbittorrentHardlinks point outside all instances, typically a media library import.
HARDLINK_SCOPE = torrents_onlyAll hardlinks within this instance. HARDLINK_SCOPE_CROSS will also be torrents_only.

Prerequisites​

HARDLINK_SCOPE_CROSS requires:

  1. Local Filesystem Access enabled on all instances whose files you want considered. qui skips instances without this access. Their files are not scanned, and unresolved hardlinks show as outside_qbittorrent.
  2. Same filesystem across all instances. Hardlinks cannot cross filesystem boundaries.
  3. Matching paths in Docker: The same volume mount requirements as HARDLINK_SCOPE, applied to every instance.

Performance​

The cross-instance scan runs only when:

  • A rule uses HARDLINK_SCOPE_CROSS
  • The single-instance scan finds torrents with unresolved outside links

The scan uses cached torrent and file data from other instances without extra API calls. It calls Lstat() only on files that can resolve unaccounted hardlinks. The scan stops as soon as qui resolves all deficits.

A safety budget of 500,000 Lstat() calls limits the cross-instance scan. If the scan exhausts the budget before resolving all deficits, the remaining torrents report outside_qbittorrent. This limit restricts filesystem operations in large multi-instance setups. When the scan reaches the budget, qui logs a warning.

Example: noHL tagging in multi-instance setups​

If torrents have no media library hardlinks, this rule tags them with noHL, even when they have cross-instance hardlinks to other qBittorrent instances:

{
"name": "Tag noHL (multi-instance)",
"trackerPattern": "*",
"conditions": {
"schemaVersion": "1",
"tags": [
{
"enabled": true,
"mode": "add",
"tags": ["noHL"],
"condition": {
"operator": "AND",
"conditions": [
{
"field": "HARDLINK_SCOPE_CROSS",
"operator": "NOT_EQUAL",
"value": "outside_qbittorrent"
},
{
"field": "STATE",
"operator": "EQUAL",
"value": "uploading"
}
]
}
}
]
}
}

This configuration works because HARDLINK_SCOPE_CROSS != outside_qbittorrent matches both none (no hardlinks) and torrents_only (hardlinks only between qBittorrent instances). Torrents with a media library copy (outside_qbittorrent) do not receive the tag.

Season pack status​

The SEASON_PACK_STATUS field tells you whether a torrent is a season pack, an episode that a season pack in the client already covers, or an episode with no such pack. qui builds the set of season packs from the torrent names it already has in memory. It sends no extra requests to qBittorrent, and it builds the set only when a rule uses the field.

ValueMeaning
packThe name has one season and no episode, for example Show.S01.1080p.WEB-DL-GRP.
packedA single episode or an episode range such as S01E05E06, and a season pack of the same release is in the client.
unpackedA single episode or an episode range, and no season pack of the same release is in the client.
emptyThe name has no single season: movies, date-based releases, absolute-numbered anime, multi-season packs such as S01-S03, "Complete Series" names without a season token, and names the parser cannot read.

SEASON_PACK_STATUS looks at the torrent's own instance. SEASON_PACK_STATUS_ANY_INSTANCE looks at every active instance, so a pack on one instance covers an episode on another. Both fields support only is and is not.

"Same release" is strict on purpose, because packed is often paired with a delete action. A pack covers an episode only when these parsed fields match: title, season, cut, other markers (REPACK, PROPER, RERIP, HYBRiD, REMASTERED, Audio.Description), language markers (DUBBED, SUBBED), resolution, source, codec, audio, channels, HDR, and group. A 720p pack does not cover a 1080p episode, a pack from another group does not cover, and a plain pack does not cover a REPACK episode. An episode title in the name, such as S01E03.The.Long.Night, does not split the episode from its pack.

A partially downloaded pack still counts as a pack. Add a PROGRESS condition to the rule if you want more.

Example: tag packs, packed, and unpacked​

One rule per status. The rule editor keeps one condition per rule and applies it to every tag action in that rule, so three tag actions with three conditions cannot live in one rule. Mode full removes a tag again when the torrent stops matching, for example after you delete the pack. Import each rule on its own.

{
"name": "Season pack",
"trackerPattern": "*",
"conditions": {
"schemaVersion": "1",
"tags": [
{ "enabled": true, "mode": "full", "tags": ["season-pack"], "condition": { "field": "SEASON_PACK_STATUS", "operator": "EQUAL", "value": "pack" } }
]
}
}
{
"name": "Packed episode",
"trackerPattern": "*",
"conditions": {
"schemaVersion": "1",
"tags": [
{ "enabled": true, "mode": "full", "tags": ["packed"], "condition": { "field": "SEASON_PACK_STATUS", "operator": "EQUAL", "value": "packed" } }
]
}
}
{
"name": "Unpacked episode",
"trackerPattern": "*",
"conditions": {
"schemaVersion": "1",
"tags": [
{ "enabled": true, "mode": "full", "tags": ["unpacked"], "condition": { "field": "SEASON_PACK_STATUS", "operator": "EQUAL", "value": "unpacked" } }
]
}
}

Missing files detection​

The Has Missing Files field detects whether any file of a completed torrent is missing from disk.

  • qui checks completed torrents only.
  • If any file is missing from its expected path, this condition returns true.
note

Requires "Local filesystem access" enabled on the instance.

Important behavior​

Settings only set values​

Automations apply settings but do not revert them when you disable or delete a rule. If a rule sets the upload limit to 1000 KiB/s, affected torrents keep that limit until you change it or another rule applies a different value.

Efficient updates​

qui sends an API call only when the torrent's current setting differs from the target value. qui skips no-op updates.

Processing order​

  • First match wins for delete actions. A delete ends processing for that torrent, and qui evaluates no further rules.
  • Last rule wins for speed limits, share limits, category, external program, and export to instance actions.
  • Accumulative for tag actions. qui combines tags across matching rules.

Free Space condition behavior​

When a delete rule uses the Free Space condition, qui tracks freed space cumulatively:

  1. Configurable processing order: qui processes torrents according to the automation's Torrent Priority (Default, Simple, or Score). This lets you prioritize cleanups (for example, largest files first, or lowest score first).
  2. Cumulative space tracking: As qui marks each torrent for deletion, qui adds its size to the projected free space (only when the delete mode frees disk bytes).
  3. Stop when satisfied: Once Free Space + Space To Be Cleared exceeds your threshold, remaining torrents no longer match.
  4. Cross-seed aware: qui counts cross-seeded torrents that share the same files once to avoid overestimating freed space.

Preview views for Free Space rules

When you preview a delete rule with a Free Space condition, a toggle switches between two views:

ViewDescription
Needed to reach targetOnly the torrents qui removes now to reach your free-space target. This is the default view and reflects actual delete behavior.
All eligibleAll torrents this rule can remove while free space stays low. It shows the full scope of what the rule can delete (this can include cross-seeds that do not directly match filters).

The toggle appears only for delete rules that use the Free Space condition.

Preview features:

  • Path column: Shows the content path for each torrent, with copy-to-clipboard support.
  • Export CSV: Downloads the full preview list (all pages) as a CSV file for external analysis.

Cross-seed expansion in previews:

The preview expands and shows cross-seeds only in Remove with files (include cross-seeds) mode. In this mode, the preview shows all torrents that qui deletes together, with cross-seeds marked. Other delete modes do not expand cross-seeds in the preview because they either preserve cross-seeds or do not treat them specially.

Delete mode affects space projection:

Delete ModeSpace Added to Projection
Remove with filesFull torrent size
Preserve cross-seeds (no shared files)Full torrent size
Preserve cross-seeds (shared files)0 (files kept)

How preserve cross-seeds works:

  • Torrents become candidates when they share the same Content Path. qui then compares their resolved file paths and sizes.
  • qui does not treat torrents in the same directory that use different files as cross-seeds. qui removes their files.
  • If torrents share files or the file comparison cannot complete, qui keeps the files.
  • Only torrents whose files qui removes contribute to the free-space projection.

Example: If you have 400GB free and a rule "Delete if Free Space < 500GB" in Remove with files mode, qui deletes the oldest torrents. It stops when the cumulative freed space reaches 100GB. A 50GB torrent and its cross-seed (same files) count as 50GB freed, not 100GB.

note

The UI and API prevent the combination of Remove (keep files) mode with Free Space conditions. Keep-files does not free disk space, so such a rule can never reach the free space target and matches forever.

note

After qui removes files, it waits about 5 minutes before running Free Space deletes again, so qBittorrent can refresh its disk free space reading. The UI prevents 1 minute intervals for Free Space delete rules.

Free Space source​

By default, Free Space uses qBittorrent's reported free space, based on its default download location. If you want to manage a specific mount point, select "Path on server" and enter the path to that disk.

SourceDescription
Default (qBittorrent)Uses qBittorrent's reported free space
Path on serverReads free space from a specific filesystem path
note

Path on server requires "Local Filesystem Access" enabled on the instance.

If you want to manage multiple disks, create one workflow per disk and set a different Path on server for each workflow.

note

qui does not support Path on server on Windows. The UI disables the option and switches legacy workflows back to the default when you open them.

Batching​

qui groups torrents by action value and sends them to qBittorrent in batches of up to 50 hashes per API call.

Rules as JSON​

A rule can move as JSON. The rule menu has two entries, and the Import button sits above the rule list:

  • Export JSON copies the rule to the clipboard.
  • Edit as JSON opens the rule's JSON in an editor. Save updates the rule in place. The rule keeps its enabled state and its position in the list.
  • Import creates a new rule from pasted JSON. The new rule starts disabled and goes to the end of the list.

The JSON carries the name, the tracker fields, the conditions, the sorting config, the free space source, the interval, dry-run, and notify. It does not carry the id, the instance id, the enabled state, or the sort order. The export omits intervalSeconds at the default 15 minutes, dryRun when off, and notify when on; when you remove one of these keys, the rule goes back to that default.

The editor highlights the JSON and underlines syntax errors as you type. Save runs the same checks as Import. When qui rejects the JSON, the editor stays open with your text.

qui rejects a key that it does not know, at any level of the JSON. It also rejects a value of the wrong type, for example "intervalSeconds": "900". qui lists all problems at once, one line for each. Each line starts with the JSON path:

conditions.pasue: unknown key
intervalSeconds: expected a whole number, got a string

qui accepts and ignores the keys id, instanceId, createdAt, and updatedAt. You can paste a rule from an API response.

An export keeps externalProgram.programId and exportToInstance.targetInstanceId. These IDs belong to the qui that made the export. When an enabled action has an ID that does not exist on your qui, the import fails. When the ID exists but means a different program or instance, the import succeeds. Before you enable an imported rule, select the program or the target instance again. The instance ID is in the URL of the instance page, /instances/<id>.

qui also checks each condition. It rejects an unknown field, an unknown operator, and an operator that the field does not allow, for example GREATER_THAN on a yes/no field. It rejects a value that the field does not list, for example a misspelled torrent state, and an unknown exportToInstance.contentLayout. It rejects a groupId or defaultGroupId that names no built-in group and no group in conditions.grouping. The line names the operators or values that the field allows:

conditions.pause.condition.operator: PRIVATE does not allow GREATER_THAN; it allows EQUAL, NOT_EQUAL

If you edit a rule and do not change its conditions, qui does not run these condition checks. You can switch an older rule on or off and rename it, also when one of its conditions fails the check. qui treats the sorting the same way. It checks the score conditions of the sorting only when you change the sorting. When you change the groups in conditions.grouping, qui also checks the group IDs in the score conditions.

JSON reference​

This section lists every key of a rule as JSON, the condition fields and their operators. Legacy keys that qui still accepts in older rules are left out.

Rule​

KeyTypeValuesDescription
namestringRule name. Required.
trackerPatternstringTracker domains that the rule applies to, separated by commas. * matches all trackers. tracker.example.com matches one domain, *.example.com its subdomains, and .example.com the domain and its subdomains. A leading ! excludes a domain.
enabledbooleanWhether the rule runs. Import always sets it to false. Edit as JSON keeps the current value.
dryRunbooleanWhen true, the rule logs what it would do and changes nothing. Default false.
notifybooleanWhen true, qui sends a notification when the rule acts. Default true.
sortOrderintegerPosition of the rule in the list. Import puts the rule at the end. Edit as JSON keeps the current value.
intervalSecondsintegerHow often the rule runs, in seconds. At least 60. Default 900 (15 minutes).
conditionsobjectThe actions of the rule, each with its condition. Required. See conditions.
freeSpaceSourceobjectWhere the FREE_SPACE condition field reads free space. Default: the free space that qBittorrent reports. See freeSpaceSource.
sortingConfigobjectThe order in which the rule processes torrents. Default: oldest first. See sortingConfig.

conditions​

KeyTypeValuesDescription
schemaVersionstringMust be 1.
groupingobjectGroup definitions for group-aware actions and conditions. See conditions.grouping.
speedLimitsobjectSet upload and download speed limits. See conditions.speedLimits.
shareLimitsobjectSet ratio and seeding time limits. See conditions.shareLimits.
pauseobjectPause matching torrents. See conditions.pause.
resumeobjectResume matching torrents. See conditions.resume.
recheckobjectForce a recheck of matching torrents. See conditions.recheck.
reannounceobjectForce a reannounce of matching torrents. See conditions.reannounce.
deleteobjectDelete matching torrents. A rule with delete has no other action. See conditions.delete.
tagsarray of objectTag actions. Each entry manages its own set of tags. See conditions.tags[].
categoryobjectSet the category of matching torrents. See conditions.category.
moveobjectMove matching torrents to a different save path. See conditions.move.
externalProgramobjectRun an external program for each matching torrent. See conditions.externalProgram.
autoManagementobjectTurn automatic torrent management on or off. See conditions.autoManagement.
exportToInstanceobjectAdd matching torrents to a different qBittorrent instance. See conditions.exportToInstance.

conditions.grouping​

KeyTypeValuesDescription
defaultGroupIdstringcross_seed_content_path, cross_seed_content_save_path, release_item, tracker_release_item, hardlink_signatureThe group that GROUP_SIZE and IS_GROUPED use when the condition has no groupId. A built-in group ID or the id of a group in groups.
groupsarray of objectCustom group definitions. See conditions.grouping.groups[].

conditions.grouping.groups[]​

KeyTypeValuesDescription
idstringThe group ID. Conditions and actions refer to the group by this ID.
keysarray of stringcontentPath, savePath, effectiveName, contentType, tracker, rlsSource, rlsResolution, rlsCodec, rlsHDR, rlsAudio, rlsChannels, rlsGroup, hardlinkSignatureTorrents with equal values for all these keys are in the same group.
ambiguousPolicystringverify_overlap, skipWhat the delete, category, and move actions do when they expand to the group, contentPath is one of the keys, and a torrent content path equals its save path. verify_overlap compares the files. skip does not expand the action to the group. GROUP_SIZE and IS_GROUPED ignore this setting.
minFileOverlapPercentintegerWith verify_overlap: the percentage of files that must overlap. Default 90.

conditions.speedLimits​

KeyTypeValuesDescription
enabledbooleanWhether the action runs.
uploadKiBintegerUpload limit in KiB/s. 0 removes the limit. Leave it out to keep the current limit.
downloadKiBintegerDownload limit in KiB/s. 0 removes the limit. Leave it out to keep the current limit.
conditionconditionOptional. When set, the action applies only to torrents that also match this condition. See Condition object.

conditions.shareLimits​

KeyTypeValuesDescription
enabledbooleanWhether the action runs.
ratioLimitnumberRatio limit. -2 uses the global setting, -1 means no limit. Leave it out to keep the current limit.
seedingTimeMinutesintegerSeeding time limit in minutes. -2 uses the global setting, -1 means no limit. Leave it out to keep the current limit.
shareLimitActionstringStop, Remove, RemoveWithContent, EnableSuperSeedingWhat qBittorrent does when a limit is reached. Needs qBittorrent Web API 2.15.1+. Leave it out to use the global setting.
shareLimitsModestringMatchAny, MatchAllWhether any limit or all limits must be reached. Needs qBittorrent Web API 2.16.0+. Leave it out to use the global setting.
conditionconditionOptional. When set, the action applies only to torrents that also match this condition. See Condition object.

conditions.pause​

KeyTypeValuesDescription
enabledbooleanWhether the action runs.
conditionconditionOptional. When set, the action applies only to torrents that also match this condition. See Condition object.

conditions.resume​

KeyTypeValuesDescription
enabledbooleanWhether the action runs.
conditionconditionOptional. When set, the action applies only to torrents that also match this condition. See Condition object.

conditions.recheck​

KeyTypeValuesDescription
enabledbooleanWhether the action runs.
conditionconditionOptional. When set, the action applies only to torrents that also match this condition. See Condition object.

conditions.reannounce​

KeyTypeValuesDescription
enabledbooleanWhether the action runs.
conditionconditionOptional. When set, the action applies only to torrents that also match this condition. See Condition object.

conditions.delete​

KeyTypeValuesDescription
enabledbooleanWhether the action runs.
modestringdelete, deleteWithFiles, deleteWithFilesPreserveCrossSeeds, deleteWithFilesIncludeCrossSeedsWhat to delete. Default: delete. When condition uses FREE_SPACE, the mode must not be delete, because a delete that keeps the files frees no disk space.
includeHardlinksbooleanAlso delete torrents that share files through hardlinks. Only with mode deleteWithFilesIncludeCrossSeeds, and needs local filesystem access.
groupIdstringcross_seed_content_path, cross_seed_content_save_path, release_item, tracker_release_item, hardlink_signatureOnly with mode delete. Delete each matching torrent together with the other torrents in its group. A built-in group ID or the id of a group in conditions.grouping.
atomicstringallWith groupId: all deletes the group only when every torrent in it matches.
conditionconditionRequired when enabled is true. The action deletes only torrents that match this condition. See Condition object.

conditions.tags[]​

KeyTypeValuesDescription
enabledbooleanWhether the action runs.
tagsarray of stringThe tags that this action manages. With useTrackerAsTag, qui uses them when a torrent has no tracker domain.
modestringfull, add, removefull adds the tags to matching torrents and removes them from the others. add only adds. remove only removes them from matching torrents.
deleteFromClientbooleanDelete the managed tags from qBittorrent before the rule tags the matches. Needs explicit tags.
useTrackerAsTagbooleanUse the tracker domain of each torrent as its tag.
useDisplayNamebooleanWith useTrackerAsTag: use the tracker display name in place of the domain.
conditionconditionOptional. When set, the action applies only to torrents that also match this condition. See Condition object.

conditions.category​

KeyTypeValuesDescription
enabledbooleanWhether the action runs.
categorystringThe category to set. An empty string removes the category.
includeCrossSeedsbooleanAlso move the cross-seeds of each matching torrent to the category.
groupIdstringcross_seed_content_path, cross_seed_content_save_path, release_item, tracker_release_item, hardlink_signatureChange the category of each matching torrent together with the other torrents in its group. A built-in group ID or the id of a group in conditions.grouping.
blockIfCrossSeedInCategoriesarray of stringSkip a torrent when one of its cross-seeds is in one of these categories.
conditionconditionOptional. When set, the action applies only to torrents that also match this condition. See Condition object.

conditions.move​

KeyTypeValuesDescription
enabledbooleanWhether the action runs.
pathstringThe new save path.
blockIfCrossSeedbooleanSkip a torrent when one of its cross-seeds does not match condition. Not used when groupId is set.
groupIdstringcross_seed_content_path, cross_seed_content_save_path, release_item, tracker_release_item, hardlink_signatureMove each matching torrent together with the other torrents in its group. A built-in group ID or the id of a group in conditions.grouping.
atomicstringallWith groupId: all moves the group only when every torrent in it matches.
conditionconditionOptional. When set, the action applies only to torrents that also match this condition. See Condition object.

conditions.externalProgram​

KeyTypeValuesDescription
enabledbooleanWhether the action runs.
programIdintegerThe ID of the external program in this qui. An export keeps the ID of the qui that made it.
conditionconditionOptional. When set, the action applies only to torrents that also match this condition. See Condition object.

conditions.autoManagement​

KeyTypeValuesDescription
enabledbooleantrue turns automatic torrent management on, false turns it off.
conditionconditionOptional. When set, the action applies only to torrents that also match this condition. See Condition object.

conditions.exportToInstance​

KeyTypeValuesDescription
enabledbooleanWhether the action runs.
targetInstanceIdintegerThe ID of the target instance in this qui. The ID is in the URL of the instance page, /instances/ID.
savePathstringThe save path on the target instance. Supports Go templates.
categorystringThe category on the target instance.
tagsarray of stringThe tags on the target instance.
pausedbooleanAdd the torrent paused.
skipCheckingbooleanSkip the hash check on the target instance. Default true.
contentLayoutstringOriginal, Subfolder, NoSubfolderThe content layout on the target instance. Leave it out to use the default layout of the target instance.
conditionconditionOptional. When set, the action applies only to torrents that also match this condition. See Condition object.

freeSpaceSource​

KeyTypeValuesDescription
typestringqbittorrent, pathqbittorrent uses the free space that qBittorrent reports. path reads the free space at path.
pathstringWith type path: the path to read. Needs filesystem access on the instance.

sortingConfig​

KeyTypeValuesDescription
schemaVersionstringMust be 1.
typestringsimple, scoresimple sorts by one field. score sorts by the sum of scoreRules.
directionstringASC, DESCASC or DESC.
fieldcondition fieldADDED_ON, AMOUNT_LEFT, AVAILABILITY, CATEGORY, COMMENT, COMPLETION_ON, CONTENT_PATH, DL_SPEED, DOWNLOADED, FREE_SPACE, LAST_ACTIVITY, NAME, NUM_COMPLETE, NUM_INCOMPLETE, NUM_LEECHS, NUM_SEEDS, PROGRESS, RATIO, SAVE_PATH, SEEDING_TIME, SIZE, STATE, SYSTEM_DAY, SYSTEM_DAY_OF_WEEK, SYSTEM_HOUR, SYSTEM_MINUTE, SYSTEM_MONTH, SYSTEM_YEAR, TAGS, TIME_ACTIVE, TOTAL_SIZE, TRACKER, TRACKERS_COUNT, UPLOADED, UP_SPEEDWith type simple: the condition field to sort by. See Condition field names.
scoreRulesarray of objectWith type score: the rules that add up to the score of each torrent. See sortingConfig.scoreRules[].

sortingConfig.scoreRules[]​

KeyTypeValuesDescription
typestringfield_multiplier, conditionalThe kind of rule.
fieldMultiplierobjectWith type field_multiplier: the field and multiplier. See sortingConfig.scoreRules[].fieldMultiplier.
conditionalobjectWith type conditional: the condition and score. See sortingConfig.scoreRules[].conditional.

sortingConfig.scoreRules[].fieldMultiplier​

KeyTypeValuesDescription
fieldcondition fieldADDED_ON, AMOUNT_LEFT, AVAILABILITY, COMPLETION_ON, DL_SPEED, DOWNLOADED, FREE_SPACE, LAST_ACTIVITY, NUM_COMPLETE, NUM_INCOMPLETE, NUM_LEECHS, NUM_SEEDS, PROGRESS, RATIO, SEEDING_TIME, SIZE, SYSTEM_DAY, SYSTEM_DAY_OF_WEEK, SYSTEM_HOUR, SYSTEM_MINUTE, SYSTEM_MONTH, SYSTEM_YEAR, TIME_ACTIVE, TOTAL_SIZE, TRACKERS_COUNT, UPLOADED, UP_SPEEDThe condition field whose value is multiplied. See Condition field names.
multipliernumberThe number to multiply the field value by. The result is added to the score.

sortingConfig.scoreRules[].conditional​

KeyTypeValuesDescription
conditionconditionWhen the torrent matches this condition, score is added. See Condition object.
scorenumberThe score to add.

Condition object​

A condition is a test or an AND or OR group of conditions. The value of a test is always a JSON string. A number is written as a string, for example "1073741824", and a yes/no value as "true" or "false". BETWEEN uses minValue and maxValue in place of value.

KeyTypeValuesDescription
fieldcondition fieldThe condition field to test. Leave it out on an AND or OR group. See Condition field names.
operatoroperatorAn operator that the field allows, or AND or OR for a group. See Operator names.
groupIdstringcross_seed_content_path, cross_seed_content_save_path, release_item, tracker_release_item, hardlink_signatureFor GROUP_SIZE and IS_GROUPED: the group to use. A built-in group ID or the id of a group in conditions.grouping. Default: conditions.grouping.defaultGroupId.
valuestringThe value to compare, always as a JSON string, also for numbers and yes/no values. Not used with BETWEEN.
minValuenumberFor BETWEEN: the lower end of the range, as a JSON number.
maxValuenumberFor BETWEEN: the upper end of the range, as a JSON number. On SYSTEM_HOUR, SYSTEM_MINUTE, SYSTEM_DAY_OF_WEEK and SYSTEM_MONTH, a minValue above maxValue wraps past the end of the field.
regexbooleanWhen true, value is a regular expression. Applies to string fields. MATCHES always uses a regular expression.
negatebooleanWhen true, the condition matches when the test is false.
conditionsarray of conditionFor an AND or OR group: the child conditions. See Condition object.

Operator names​

OperatorMeaning
ANDGroup. Matches when every child condition matches.
ORGroup. Matches when at least one child condition matches.
EQUALEqual to value.
NOT_EQUALNot equal to value.
CONTAINSContains value.
NOT_CONTAINSDoes not contain value.
STARTS_WITHStarts with value.
ENDS_WITHEnds with value.
MATCHESMatches value as a regular expression, anywhere in the field.
GREATER_THANGreater than value.
GREATER_THAN_OR_EQUALGreater than or equal to value.
LESS_THANLess than value.
LESS_THAN_OR_EQUALLess than or equal to value.
BETWEENFrom minValue to maxValue, both included. A range that wraps on a clock field does not include maxValue.
EXISTS_INA torrent with exactly this name is in the category value.
CONTAINS_INA torrent with a similar name is in the category value. Case, accents, and the characters ., _ and - do not matter.

Condition field names​

Label is the name of the field in the rule builder. With EQUAL and NOT_EQUAL and no regular expression, a field with values accepts only those values.

FieldLabelTypeOperatorsValuesRequires
ADDED_ONAdded Ageinteger (seconds)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
AMOUNT_LEFTAmount Leftinteger (bytes)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
AUTO_MANAGEDAuto-managedbooleanEQUAL, NOT_EQUALtrue, false
AVAILABILITYAvailabilitynumberEQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
CATEGORYCategorystringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES
COMMENTCommentstringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES
COMPLETEDCompletedinteger (bytes)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
COMPLETION_ONCompleted Ageinteger (seconds)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
CONTENT_PATHContent PathstringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES
CONTENT_TYPEContent TypestringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHESmovie, tv, music, audiobook, book, comic, game, app, adult, unknown
CREATED_BYCreated BystringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES
CROSS_SEED_TAGSCross-seed TagsstringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES
DL_LIMITDownload Limitinteger (bytes per second)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
DL_SPEEDDownload Speedinteger (bytes per second)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
DOWNLOADEDDownloadedinteger (bytes)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
DOWNLOADED_SESSIONDownloaded (Session)integer (bytes)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
DOWNLOAD_PATHDownload PathstringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES
EFFECTIVE_NAMEEffective NamestringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES
ETAETAinteger (seconds)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
EXISTS_ON_OTHER_INSTANCEExists on Other InstancebooleanEQUAL, NOT_EQUALtrue, false
EXISTS_ON_SAME_INSTANCECross-seed Exists on Same InstancebooleanEQUAL, NOT_EQUALtrue, false
FIRST_LAST_PIECE_PRIOFirst/Last Piece PrioritybooleanEQUAL, NOT_EQUALtrue, false
FORCE_STARTForce StartbooleanEQUAL, NOT_EQUALtrue, false
FREE_SPACEFree Spaceinteger (bytes)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
GROUP_SIZEGroup SizeintegerEQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
HARDLINK_SCOPEHardlink scopeenumEQUAL, NOT_EQUALnone, torrents_only, inside_qbittorrent, outside_qbittorrent, bothlocal filesystem access
HARDLINK_SCOPE_CROSSHardlink scope (cross-instance)enumEQUAL, NOT_EQUALnone, torrents_only, inside_qbittorrent, outside_qbittorrent, bothlocal filesystem access
HASHHashstringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES
HAS_MISSING_FILESHas Missing FilesbooleanEQUAL, NOT_EQUALtrue, falselocal filesystem access
HAS_SKIPPED_FILESHas Skipped FilesbooleanEQUAL, NOT_EQUALtrue, false
INACTIVE_SEEDING_TIME_LIMITInactive Seeding Time Limitinteger (seconds)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
INFOHASH_V1Infohash v1stringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES
INFOHASH_V2Infohash v2stringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES
IS_GROUPEDIs GroupedbooleanEQUAL, NOT_EQUALtrue, false
IS_UNREGISTEREDUnregisteredbooleanEQUAL, NOT_EQUALtrue, falseqBittorrent 5.1+
LAST_ACTIVITYInactive Timeinteger (seconds)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
MAGNET_URIMagnet URIstringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES
MAX_INACTIVE_SEEDING_TIMEMax Inactive Seeding Timeinteger (seconds)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
MAX_RATIOMax RationumberEQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
MAX_SEEDING_TIMEMax Seeding Timeinteger (seconds)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
NAMENamestringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES, EXISTS_IN, CONTAINS_IN
NUM_COMPLETETotal SeedersintegerEQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
NUM_INCOMPLETETotal LeechersintegerEQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
NUM_LEECHSActive LeechersintegerEQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
NUM_SEEDSActive SeedersintegerEQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
POPULARITYPopularitynumberEQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
PRIORITYQueue PriorityintegerEQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
PRIVATEPrivatebooleanEQUAL, NOT_EQUALtrue, false
PROGRESSProgressnumber (0 to 1)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
RATIORationumberEQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
RATIO_LIMITRatio LimitnumberEQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
REANNOUNCEReannounce Ininteger (seconds)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
RLS_AUDIOAudio (RLS)stringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES
RLS_CHANNELSChannels (RLS)stringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES
RLS_CODECCodec (RLS)stringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES
RLS_GROUPGroup (RLS)stringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES
RLS_HDRHDR (RLS)stringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES
RLS_RESOLUTIONResolution (RLS)stringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES
RLS_SOURCESource (RLS)stringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES
RLS_YEARYear (RLS)integerEQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
SAVE_PATHSave PathstringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES
SEASON_PACK_STATUSSeason pack statusenumEQUAL, NOT_EQUALpack, packed, unpacked
SEASON_PACK_STATUS_ANY_INSTANCESeason pack status (any instance)enumEQUAL, NOT_EQUALpack, packed, unpacked
SEEDING_ON_OTHER_INSTANCESeeding on Other InstancebooleanEQUAL, NOT_EQUALtrue, false
SEEDING_ON_SAME_INSTANCECross-seed Seeding on Same InstancebooleanEQUAL, NOT_EQUALtrue, false
SEEDING_TIMESeeding Timeinteger (seconds)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
SEEDING_TIME_LIMITSeeding Time Limitinteger (seconds)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
SEEN_COMPLETESeen Complete Ageinteger (seconds)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
SEQUENTIAL_DOWNLOADSequential DownloadbooleanEQUAL, NOT_EQUALtrue, false
SIZESizeinteger (bytes)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
STATEStateenumEQUAL, NOT_EQUALdownloading, uploading, completed, stopped, active, inactive, running, stalled, stalled_uploading, stalled_downloading, errored, tracker_down, tracker_error, checking, checkingResumeData, moving, missingFiles
SUPER_SEEDINGSuper SeedingbooleanEQUAL, NOT_EQUALtrue, false
SYSTEM_DAYSystem DayintegerEQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
SYSTEM_DAY_OF_WEEKSystem Day of WeekintegerEQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
SYSTEM_HOURSystem HourintegerEQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
SYSTEM_MINUTESystem MinuteintegerEQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
SYSTEM_MONTHSystem MonthintegerEQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
SYSTEM_YEARSystem YearintegerEQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
TAGSTagsstringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES
TIME_ACTIVETime Activeinteger (seconds)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
TOTAL_SIZETotal Sizeinteger (bytes)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
TRACKERTrackerstringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHES
TRACKERS_COUNTTrackersintegerEQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
TRACKER_MESSAGETracker messagestringEQUAL, NOT_EQUAL, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, MATCHESqBittorrent 5.1+
TRACKER_STATUSTracker statusenumEQUAL, NOT_EQUALnot_contacted, working, updating, error, tracker_error, unreachableqBittorrent 5.1+
UPLOADEDUploadedinteger (bytes)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
UPLOADED_OVER_SIZEUploaded / SizenumberEQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
UPLOADED_SESSIONUploaded (Session)integer (bytes)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
UP_LIMITUpload Limitinteger (bytes per second)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN
UP_SPEEDUpload Speedinteger (bytes per second)EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, BETWEEN

Activity log​

qui logs every automation action with:

  • Torrent name and hash
  • Rule name and action type
  • Outcome (success/failed) with reasons
  • Action-specific details

qui keeps activity for 7 days. View the log in the Automations section for each instance.

Example rules​

Delete old completed torrents​

If disk space is low, remove torrents completed over 30 days ago:

  • Condition: Completed Age > 30 days AND State is completed AND Free Space < 500GB
  • Action: Remove with files

qui deletes matching torrents in the configured priority order (for example, oldest first) and stops once the projected free space exceeds 500GB.

Speed limit private trackers​

Limit upload on private trackers:

  • Tracker: *
  • Condition: Private is true
  • Action: Upload limit 10000 KiB/s

Tag stalled torrents​

Auto-tag torrents with no activity:

  • Tracker: *
  • Condition: Inactive Time > 7 days
  • Action: Tag "stalled" (mode: add)

Clean unregistered torrents​

Remove torrents the tracker no longer recognizes:

  • Tracker: *
  • Condition: Unregistered is true
  • Action: Delete (keep files)

Maintain minimum free space​

Keep at least 200GB free by removing oldest completed torrents:

  • Tracker: *
  • Condition: Free Space < 200GB AND State is completed
  • Action: Remove with files (preserve cross-seeds)

qui removes torrents from the client in the configured priority order until the projection frees enough space. Cross-seeded torrents keep their files on disk and do not contribute to the projection. If only cross-seeded torrents match, this rule can remove many torrents without freeing any disk space.

Clean up old content with cross-seeds​

Remove completed torrents and all their cross-seeded copies when they are old enough:

  • Tracker: *
  • Condition: Completed Age > 30 days AND State is completed
  • Action: Remove with files (include cross-seeds)

When a torrent matches, qui also deletes every other torrent that points to the same downloaded files. Use this rule when you no longer need any copy of the content.

Find duplicate releases of the same title​

List releases that share a parsed title but come from different release groups, such as Show.S01.1080p.WEB-DL-GROUP1 and Show.S01.1080p.WEB-DL-GROUP2:

  • Tracker: *
  • Condition: Is Grouped is true with groupId set to release_item (see Grouping)
  • Action: Tag "dupe" (mode: add)

The Live impact preview lists the matches while you edit, so the rule can stay disabled if you only want to look.

note

Cross-seeded copies of a release are also members of these groups, because the release_item key ignores the release group and the tracker.

Organize by tracker​

Move torrents to tracker-named categories:

  • Tracker: tracker.example.com
  • Action: Category "example" with "Include affected cross-seeds" enabled

Post-processing on completion​

When torrents finish downloading, run a script:

  • Tracker: *
  • Condition: State is completed AND Progress = 100
  • Action: External Program "post-process.sh"

Notify on stalled torrents​

When torrents stall, alert an external monitoring system:

  • Tracker: *
  • Condition: State is stalled AND Inactive Time > 24 hours
  • Action: External Program "send-alert" + Tag "stalled" (mode: add)