# How the Self-Destruct Messaging Feature Works in Telegram Desktop: A Technical Deep Dive

> Explore the technical workings of Telegram Desktop's self-destruct messaging and its TTL implementation across API, HistoryServiceSelfDestruct, and Session timer components.

- Repository: [Telegram Desktop/tdesktop](https://github.com/telegramdesktop/tdesktop)
- Tags: deep-dive
- Published: 2026-04-05

---

**The self-destruct messaging feature in Telegram Desktop implements Time-To-Live (TTL) through three coordinated subsystems: an API layer for server configuration, a `HistoryServiceSelfDestruct` component attached to individual messages, and a central `Session::_selfDestructTimer` that monitors expiration and triggers removal when `getSelfDestructIn()` returns zero.**

Telegram Desktop's self-destruct messaging feature enables users to send photos and videos that automatically disappear after a specified duration. According to the `telegramdesktop/tdesktop` source code, this TTL system relies on a tight integration between the MTProto API layer, message-level components, and session-wide timers to ensure synchronized expiration across clients.

## Configuring TTL via the API Layer

User-facing configuration begins in the settings dialogs. The **Settings UI** ([`settings/sections/settings_privacy_security.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/settings/sections/settings_privacy_security.cpp) and [`settings/sections/settings_global_ttl.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/settings/sections/settings_global_ttl.cpp)) provides interfaces for selecting default message TTL and account self-destruction intervals.

When a user modifies these values, the application invokes the API wrapper defined in [`api/api_self_destruct.h`](https://github.com/telegramdesktop/tdesktop/blob/main/api/api_self_destruct.h):

```cpp
session->api().selfDestruct().updateDefaultHistoryTTL(ttl);   // settings_global_ttl.cpp
session->api().selfDestruct().updateAccountTTL(days);        // settings_privacy_security.cpp

```

The implementation in [`api/api_self_destruct.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/api/api_self_destruct.cpp) transmits the corresponding MTProto requests (`messages_SetDefaultHistoryTTL` and `account_SetAccountTTL`) and stores the server response in reactive variables (`_defaultHistoryTTL.period` and `_accountTTL.days`). This ensures the client maintains the authoritative TTL values for subsequent message operations.

## Attaching Self-Destruct Components to Messages

When composing a self-destructing media message, the client attaches a specialized component to the `HistoryItem`. The method `HistoryItem::setSelfDestruct()` in [`history/history_item.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/history/history_item.cpp) (lines 7296–7307) initializes this data:

```cpp
void HistoryItem::setSelfDestruct(
        HistorySelfDestructType type,
        MTPint mtpTTLvalue) {
    UpdateComponents(HistoryServiceSelfDestruct::Bit());
    const auto selfdestruct = Get<HistoryServiceSelfDestruct>();
    if (mtpTTLvalue.v == TimeId(0x7FFFFFFF)) {
        selfdestruct->timeToLive = TimeToLiveSingleView();   // “forever”
    } else {
        selfdestruct->timeToLive = mtpTTLvalue.v * crl::time(1000);
    }
    selfdestruct->type = type;
}

```

The component structure is defined in [`history/history_item_components.h`](https://github.com/telegramdesktop/tdesktop/blob/main/history/history_item_components.h) (lines 28–35):

```cpp
struct HistoryServiceSelfDestruct
    : RuntimeComponent<HistoryServiceSelfDestruct, HistoryItem> {
    using Type = HistorySelfDestructType;
    Type type = Type::Photo;
    std::variant<crl::time, TimeToLiveSingleView> timeToLive = crl::time();
    std::variant<crl::time, TimeToLiveSingleView> destructAt = crl::time();
};

```

This component stores both the `timeToLive` duration and the calculated `destructAt` timestamp. When the server echoes the message to recipients, they receive the same `destructAt` value, ensuring consistent expiration across all clients.

## The Session Timer and Expiration Tracking

All pending self-destruct messages are tracked centrally by the `Session` class in [`data/data_session.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/data/data_session.cpp). The system maintains a vector `Session::_selfDestructItems` containing `FullMsgId` identifiers and a single `base::Timer` instance called `_selfDestructTimer`.

When a new self-destructing message is created, the system registers it via `Session::selfDestructIn()` (lines 3201–3206):

```cpp
void Session::selfDestructIn(not_null<HistoryItem*> item, crl::time delay) {
    _selfDestructItems.push_back(item->fullId());
    if (!_selfDestructTimer.isActive()
        || _selfDestructTimer.remainingTime() > delay) {
        _selfDestructTimer.callOnce(delay);
    }
}

```

The timer callback `Session::checkSelfDestructItems()` (lines 3210–3229) processes the queue:

```cpp
void Session::checkSelfDestructItems() {
    const auto now = crl::now();
    crl::time nextDestructIn = 0;
    for (auto i = _selfDestructItems.begin(); i != _selfDestructItems.cend();) {
        if (const auto item = message(*i)) {
            if (const auto destructIn = item->getSelfDestructIn(now)) {
                if (nextDestructIn > 0) {
                    accumulate_min(nextDestructIn, destructIn);
                } else {
                    nextDestructIn = destructIn;
                }
                ++i;
            } else {
                i = _selfDestructItems.erase(i);
            }
        } else {
            i = _selfDestructItems.erase(i);
        }
    }
    if (nextDestructIn > 0) {
        _selfDestructTimer.callOnce(nextDestructIn);
    }
}

```

This implementation efficiently batches expiration checks by rescheduling the timer only for the nearest future expiry, minimizing CPU wakeups.

## Computing Message Lifetime

Individual messages calculate their remaining lifespan through `HistoryItem::getSelfDestructIn()` in [`history/history_item.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/history/history_item.cpp) (lines 7830–7850):

```cpp
crl::time HistoryItem::getSelfDestructIn(crl::time now) {
    if (const auto selfdestruct = Get<HistoryServiceSelfDestruct>()) {
        const auto at = std::get_if<crl::time>(&selfdestruct->destructAt);
        if (at && (*at) > 0) {
            const auto destruct = *at;
            if (destruct <= now) {
                // Message already expired – replace service text with “expired”
                setServiceText({ TextWithEntities{ .text = expiredMessage() } });
                return 0;
            }
            return destruct - now;               // ms remaining
        }
    }
    return 0;
}

```

When this method returns zero, the calling code in `checkSelfDestructItems()` removes the message from the tracking vector. Simultaneously, the UI updates the message bubble to display a localized "photo expired" or "video expired" string via `setServiceText()`.

## UI Implementation and Countdown Display

The visual countdown is rendered using components in [`ui/effects/ttl_icon.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/ui/effects/ttl_icon.cpp), which draws the timer badge next to the message bubble. Human-readable time formatting is handled by `Ui::FormatTTL()` in [`ui/text/format_values.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/ui/text/format_values.cpp) (lines 438–470), converting millisecond deltas into strings like "5 min" or "30 sec".

The TTL selection dialog ([`boxes/self_destruction_box.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/boxes/self_destruction_box.cpp), lines 148–173) provides the interface for choosing expiration intervals, invoking the same `Api::SelfDestruct` methods used in the settings panels.

## Key Source Files

| Component | File Path | Purpose |
|-----------|-----------|---------|
| **API Interface** | [`api/api_self_destruct.h`](https://github.com/telegramdesktop/tdesktop/blob/main/api/api_self_destruct.h) | Declares `SelfDestruct` class with `updateDefaultHistoryTTL` |
| **API Implementation** | [`api/api_self_destruct.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/api/api_self_destruct.cpp) | MTProto request construction and reactive state storage |
| **Session Timer** | [`data/data_session.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/data/data_session.cpp) | `selfDestructIn` and `checkSelfDestructItems` logic |
| **Message Component** | [`history/history_item_components.h`](https://github.com/telegramdesktop/tdesktop/blob/main/history/history_item_components.h) | `HistoryServiceSelfDestruct` struct definition |
| **TTL Logic** | [`history/history_item.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/history/history_item.cpp) | `setSelfDestruct` and `getSelfDestructIn` implementations |
| **Settings UI** | [`settings/sections/settings_global_ttl.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/settings/sections/settings_global_ttl.cpp) | Default TTL configuration interface |
| **Formatting** | [`ui/text/format_values.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/ui/text/format_values.cpp) | `FormatTTL` helper for countdown strings |
| **Visual Effects** | [`ui/effects/ttl_icon.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/ui/effects/ttl_icon.cpp) | Timer icon rendering |

## Summary

- **Configuration**: The `Api::SelfDestruct` class manages server communication for both default message TTL and account self-destruction settings.
- **Message Tagging**: The `HistoryServiceSelfDestruct` component attaches expiration metadata to `HistoryItem` objects, storing both `timeToLive` duration and absolute `destructAt` timestamps.
- **Centralized Tracking**: `Session::_selfDestructTimer` monitors all pending expirations through the `_selfDestructItems` vector, using efficient batch processing to minimize resource usage.
- **Expiration Logic**: `HistoryItem::getSelfDestructIn()` calculates remaining milliseconds and triggers UI updates when deadlines pass.
- **Visual Feedback**: The UI layer combines [`ttl_icon.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/ttl_icon.cpp) for graphics and [`format_values.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/format_values.cpp) for human-readable countdown text.

## Frequently Asked Questions

### What triggers a self-destruct message to disappear in Telegram Desktop?

The disappearance is triggered by `Session::checkSelfDestructItems()` when it detects that `HistoryItem::getSelfDestructIn()` returns zero, indicating the current time has exceeded the `destructAt` timestamp. At this point, the message is removed from the tracking list and its service text is replaced with an expiration notice.

### How does Telegram Desktop handle "View Once" or infinite TTL settings?

When the server specifies a TTL value of `0x7FFFFFFF`, the client stores a `TimeToLiveSingleView()` variant instead of a numeric timestamp in the `HistoryServiceSelfDestruct` component. This special value indicates the content should remain until manually viewed once, rather than expiring after a fixed duration.

### What is the difference between default history TTL and account TTL?

**Default history TTL** (`updateDefaultHistoryTTL`) sets the automatic expiration timer for new messages sent in chats, while **account TTL** (`updateAccountTTL`) specifies how long the account itself should remain inactive before Telegram automatically deletes it. Both are managed through the `api_self_destruct` module but control distinct server-side behaviors.

### Which source files contain the core logic for message expiration?

The expiration engine spans [`history/history_item.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/history/history_item.cpp) (message-level TTL calculations), [`data/data_session.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/data/data_session.cpp) (centralized timer and tracking), and [`history/history_item_components.h`](https://github.com/telegramdesktop/tdesktop/blob/main/history/history_item_components.h) (data structures). UI components reside in [`ui/effects/ttl_icon.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/ui/effects/ttl_icon.cpp) and [`ui/text/format_values.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/ui/text/format_values.cpp).