qBittorrent Ratio Limits and Seeding Goals: Complete Technical Guide
qBittorrent enforces share limits through a ShareLimits structure that evaluates ratio thresholds, total seeding time, and inactive seeding time to trigger automated actions like stopping, removing, or super-seeding torrents.
The qbittorrent/qBittorrent repository implements a sophisticated torrent management system centered around share ratio enforcement and seeding goals. This architecture allows both global defaults and per-torrent overrides to automate seeding behavior through the ShareLimits data structure and the effectiveShareLimits() resolution chain.
How Share Limits Work in qBittorrent
The Three Limit Metrics
Every torrent can be configured with three independent limit metrics defined in src/base/bittorrent/sharelimits.h:
- Ratio limit (
share_ratio/ratioLimit): The desired upload-to-download ratio (e.g., 2.0 for 2:1) - Seeding time limit (
seedingTimeLimit): Maximum total seeding time in minutes after completion - Inactive seeding time limit (
inactiveSeedingTimeLimit): Maximum idle time in minutes since last activity
All limits use sentinel values: -2 means "use default", -1 means "no limit", and any positive value sets a specific threshold.
Evaluation Modes and Actions
When limits are evaluated in SessionImpl::processTorrentShareLimits, the system checks conditions based on the selected mode:
- MatchAny: Any single satisfied condition triggers the action
- MatchAll: All configured conditions must be satisfied before triggering
The configured action executed when limits are reached includes:
Stop: Callstorrent->stop()Remove: CallsremoveTorrent(..., KeepContent)RemoveWithContent: CallsremoveTorrent(..., RemoveContent)EnableSuperSeeding: Callstorrent->setSuperSeeding(true)
Core Implementation Architecture
Data Structures in sharelimits.h
The central ShareLimits struct stores limits, evaluation mode, and action:
struct ShareLimits
{
qreal ratioLimit = DEFAULT_RATIO_LIMIT; // –2 = default, –1 = no limit
int seedingTimeLimit = DEFAULT_SEEDING_TIME_LIMIT; // –2 = default, –1 = no limit
int inactiveSeedingTimeLimit = DEFAULT_SEEDING_TIME_LIMIT;
ShareLimitsMode mode = ShareLimitsMode::Default; // MatchAny / MatchAll
ShareLimitAction action = ShareLimitAction::Default; // Stop / Remove / …
};
Per-torrent limits are stored in TorrentImpl::m_shareLimits within src/base/bittorrent/torrentimpl.cpp, while global defaults reside in SessionImpl (e.g., m_globalMaxRatio) and category options use CategoryOptions::shareLimits.
Effective Limit Resolution
The effectiveShareLimits() method in torrentimpl.cpp (lines 74-88) implements a fallback hierarchy from torrent-specific to category to global settings:
ShareLimits TorrentImpl::effectiveShareLimits() const
{
const ShareLimits categoryShareLimits = m_session->categoryShareLimits(category());
return {
.ratioLimit = (m_shareLimits.ratioLimit == DEFAULT_RATIO_LIMIT)
? categoryShareLimits.ratioLimit : m_shareLimits.ratioLimit,
.seedingTimeLimit = (m_shareLimits.seedingTimeLimit == DEFAULT_SEEDING_TIME_LIMIT)
? categoryShareLimits.seedingTimeLimit : m_shareLimits.seedingTimeLimit,
.inactiveSeedingTimeLimit = (m_shareLimits.inactiveSeedingTimeLimit == DEFAULT_SEEDING_TIME_LIMIT)
? categoryShareLimits.inactiveSeedingTimeLimit : m_shareLimits.inactiveSeedingTimeLimit,
.mode = (m_shareLimits.mode == ShareLimitsMode::Default)
? categoryShareLimits.mode : m_shareLimits.mode,
.action = (m_shareLimits.action == ShareLimitAction::Default)
? categoryShareLimits.action : m_shareLimits.action
};
}
Processing Logic in sessionimpl.cpp
Limit evaluation occurs in SessionImpl::processTorrentShareLimits every time a torrent finishes downloading or when periodic timers fire. This method retrieves effective limits, checks them against the selected mode (MatchAny or MatchAll), and executes the configured action when conditions are satisfied.
Persistence and API Integration
Resume Data Storage
Share limits persist across application restarts through the resume data storage system in src/base/bittorrent/dbresumedatastorage.cpp:
query.bindValue(DB_COLUMN_RATIO_LIMIT.placeholder,
static_cast<int>(m_resumeData.shareLimits.ratioLimit * 1000));
When torrents are re-added, stored limits are restored from the database, preserving user configuration.
Web API Endpoints
The REST API exposes share limit control through POST /api/v2/torrents/setShareLimits implemented in src/webui/api/torrentscontroller.cpp (lines 1089-1095):
| Parameter | Description |
|---|---|
hashes |
"all" or comma-separated torrent hashes |
ratioLimit |
Desired ratio (-2 for default, -1 for unlimited) |
seedingTimeLimit |
Minutes of total seeding time (-2 for default) |
inactiveSeedingTimeLimit |
Minutes of idle time (-2 for default) |
shareLimitAction |
"stop", "remove", "removeWithContent", or "enableSuperSeeding" |
shareLimitsMode |
"matchAny" or "matchAll" |
UI components including TorrentShareLimitsWidget (src/gui/torrentsharelimitswidget.cpp) and the Options dialog (src/gui/optionsdialog.cpp) provide graphical interfaces to these same parameters.
Practical Configuration Examples
Via Web API (Python)
Configure global ratio limits programmatically using the qBittorrent Web API:
import requests
URL = "http://localhost:8080/api/v2/torrents/setShareLimits"
payload = {
"hashes": "all", # apply to every torrent
"ratioLimit": 2.0, # stop after 2:1 share ratio
"seedingTimeLimit": 1440, # 24 hours total seeding time
"inactiveSeedingTimeLimit": 180, # 3 hours idle time
"shareLimitAction": "remove", # remove torrent, keep files
"shareLimitsMode": "matchAny" # any condition triggers action
}
resp = requests.post(URL, data=payload, auth=('admin', 'password'))
resp.raise_for_status()
Programmatic Configuration (C++)
Set limits directly on a torrent instance:
BitTorrent::ShareLimits limits;
limits.ratioLimit = 1.5; // 150%
limits.seedingTimeLimit = 720; // 12 hours
limits.inactiveSeedingTimeLimit = 60; // 1 hour
limits.mode = BitTorrent::ShareLimitsMode::MatchAll;
limits.action = BitTorrent::ShareLimitAction::Stop;
torrent->setShareLimits(limits); // torrent is a BitTorrent::Torrent*
Reading Effective Limits
Retrieve the resolved limits for display or logic:
const BitTorrent::ShareLimits eff = torrent->effectiveShareLimits();
qDebug() << "Effective ratio limit:" << eff.ratioLimit;
qDebug() << "Effective seeding limit (min):" << eff.seedingTimeLimit;
Summary
- ShareLimits encapsulates ratio, seeding time, and inactive seeding time thresholds with evaluation modes and actions
- Effective limits resolve through a hierarchy: torrent-specific → category defaults → global defaults via
effectiveShareLimits() - Limits are evaluated in
processTorrentShareLimitsusing either MatchAny (OR logic) or MatchAll (AND logic) modes - Supported actions include stopping, removing (with or without content), and enabling super-seeding
- Configuration persists in resume data (
dbresumedatastorage.cpp) and is accessible via the C++ API, GUI widgets, and Web API endpoint/api/v2/torrents/setShareLimits
Frequently Asked Questions
How do ratio limits work in qBittorrent?
Ratio limits define the upload-to-download ratio (share ratio) that a torrent must reach before triggering an automated action. When set to -1, the limit is disabled; when set to -2, the torrent uses the category or global default. The limit is evaluated against actual upload and download statistics stored in each torrent's resume data.
What is the difference between MatchAny and MatchAll modes?
MatchAny triggers the configured action when any single limit condition is satisfied (e.g., ratio reached OR seeding time exceeded), while MatchAll requires all configured limits to be satisfied simultaneously (e.g., ratio reached AND seeding time exceeded). These modes are defined in the ShareLimitsMode enum and evaluated in SessionImpl::processTorrentShareLimits.
Where are share limits stored in qBittorrent?
Per-torrent share limits persist in the SQLite resume data database through src/base/bittorrent/dbresumedatastorage.cpp, specifically binding to DB_COLUMN_RATIO_LIMIT and related columns. Global defaults are managed in SessionImpl and serialized through appcontroller.cpp for the Web UI.
Can I set different ratio limits for different categories?
Yes. qBittorrent supports category-specific defaults through CategoryOptions::shareLimits. When a torrent's individual limit is set to -2 (default), the system falls back first to the category's share limits, then to global session limits. This hierarchy is resolved in TorrentImpl::effectiveShareLimits() within torrentimpl.cpp.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →