# qBittorrent Ratio Limits and Seeding Goals: Complete Technical Guide

> Master qBittorrent ratio limits and seeding goals. This technical guide explains how to automate torrent management and optimize your sharing with precise control.

- Repository: [qBittorrent project/qBittorrent](https://github.com/qbittorrent/qBittorrent)
- Tags: complete-technical-guide
- Published: 2026-05-05

---

**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`](https://github.com/qbittorrent/qBittorrent/blob/main/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`: Calls `torrent->stop()`
- `Remove`: Calls `removeTorrent(..., KeepContent)`
- `RemoveWithContent`: Calls `removeTorrent(..., RemoveContent)`  
- `EnableSuperSeeding`: Calls `torrent->setSuperSeeding(true)`

## Core Implementation Architecture

### Data Structures in sharelimits.h

The central `ShareLimits` struct stores limits, evaluation mode, and action:

```cpp
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`](https://github.com/qbittorrent/qBittorrent/blob/main/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`](https://github.com/qbittorrent/qBittorrent/blob/main/torrentimpl.cpp) (lines 74-88) implements a fallback hierarchy from torrent-specific to category to global settings:

```cpp
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`](https://github.com/qbittorrent/qBittorrent/blob/main/src/base/bittorrent/dbresumedatastorage.cpp):

```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`](https://github.com/qbittorrent/qBittorrent/blob/main/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`](https://github.com/qbittorrent/qBittorrent/blob/main/src/gui/torrentsharelimitswidget.cpp)) and the Options dialog ([`src/gui/optionsdialog.cpp`](https://github.com/qbittorrent/qBittorrent/blob/main/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:

```python
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:

```cpp
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:

```cpp
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 `processTorrentShareLimits` using 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`](https://github.com/qbittorrent/qBittorrent/blob/main/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`](https://github.com/qbittorrent/qBittorrent/blob/main/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`](https://github.com/qbittorrent/qBittorrent/blob/main/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`](https://github.com/qbittorrent/qBittorrent/blob/main/torrentimpl.cpp).