# How Telegram Desktop Implements Push Notifications and Update Mechanisms

> Explore how Telegram Desktop implements push notifications and updates. Discover its layered architecture, notification queuing, and secure binary update processes for a seamless user experience.

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

---

**Telegram Desktop delivers native push notifications and automatic updates through a layered architecture that separates platform-specific services from cross-platform scheduling logic, using `Window::Notifications::System` for notification queuing and `Core::UpdateChecker` for secure binary updates.**

Telegram Desktop orchestrates real-time push notifications and seamless automatic updates through a sophisticated C++ architecture that abstracts platform differences behind unified manager interfaces. In the `telegramdesktop/tdesktop` repository, the implementation cleanly separates policy decisions—such as when to display alerts or download new binaries—from the mechanics of native OS integration. This analysis examines the specific source files, class hierarchies, and data flows that enable notifications across Windows, macOS, and Linux, alongside the cryptographic update verification pipeline.

## Push Notification Architecture

The notification system relies on a four-layer stack. The **Platform layer** invokes native APIs like Windows Runtime toasts, macOS `NSUserNotification`, or Linux DBus. The **Cross-platform manager** provides a unified interface through `Window::Notifications::System` that handles queuing, deduplication, and grouping. The **Core scheduler** determines timing and visibility rules, while the **UI rendering** layer either draws custom toasts or delegates to the OS.

The client supports three **manager types**—`Dummy`, `Default`, and `Native`—defined in `Window::Notifications::ManagerType` within [`Telegram/SourceFiles/window/notifications_manager.h`](https://github.com/telegramdesktop/tdesktop/blob/main/Telegram/SourceFiles/window/notifications_manager.h). The `Default` manager renders custom notification widgets in Qt, whereas the `Native` manager forwards calls to platform-specific implementations.

### Notification Flow: From MTProto to Toast

When the MTProto layer receives a new message or reaction, it constructs a `Data::ItemNotification` object and invokes `Window::Notifications::System::schedule()`. This method first calls `skipNotification()` (lines 92–115 in [`notifications_manager.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/notifications_manager.cpp)) to enforce mute settings and rate limits. If the notification passes filters, `countTiming()` (lines 58–71) calculates display delays based on `kMinimalDelay` constants.

The scheduler stores the notification in `_waitTimer` or `_waitForAllGroupedTimer`. Upon firing, `showNext()` or `showGrouped()` assembles a `NotificationFields` object and dispatches it. For native mode, this calls `Platform::Notifications::Create()`; for default mode, it instantiates a `Notification` widget in [`notifications_manager_default.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/notifications_manager_default.cpp) (lines 355–380).

Platform-specific implementations reside in:

- **Windows**: [`Telegram/SourceFiles/platform/win/notifications_manager_win.h`](https://github.com/telegramdesktop/tdesktop/blob/main/Telegram/SourceFiles/platform/win/notifications_manager_win.h) and `.cpp` (WinRT toast)
- **macOS**: [`Telegram/SourceFiles/platform/mac/notifications_manager_mac.h`](https://github.com/telegramdesktop/tdesktop/blob/main/Telegram/SourceFiles/platform/mac/notifications_manager_mac.h) and `.cpp` (`NSUserNotification`)
- **Linux**: [`Telegram/SourceFiles/platform/linux/notifications_manager_linux.h`](https://github.com/telegramdesktop/tdesktop/blob/main/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h) and `.cpp` (DBus `org.freedesktop.Notifications`)

### Custom vs. Native Notifications

Users can force the **default** manager even when native support exists by enabling `kOptionCustomNotification` (defined in [`notifications_manager.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/notifications_manager.cpp), lines 36–46). Conversely, the platform can mandate native notifications via `Platform::Notifications::Enforced()`, implemented per-OS in the platform-specific files listed above. This dual-mode approach ensures consistent behavior across diverse desktop environments while respecting OS conventions when requested.

## Automatic Update Mechanisms

The update system centers on `Core::UpdateChecker`, instantiated globally within `Core::Application`. The public entry point `Core::UpdateApplication()` (defined in [`Telegram/SourceFiles/core/update_checker.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/Telegram/SourceFiles/core/update_checker.cpp), line 1634) triggers the entire workflow, whether invoked by automated timers or user interaction.

### Update Checker Components

The architecture consists of an **Updater core** handling verification and restart, a **Network layer** with `HttpChecker` and `MtpChecker` subclasses, and **UI triggers** in settings and intro screens. The system uses reactive streams (`rpl::producer`) to broadcast states like `checking()`, `progress()`, `failed()`, and `ready()` to interface elements.

### The Update Sequence: Download to Restart

When invoked, `UpdateApplication()` creates a `Core::Updater` instance (line 1650). The checker selection logic inspects `cAlphaVersion()`: if non-zero, it uses `MtpChecker` for MTProto-based downloads; otherwise, `HttpChecker` performs an HTTP GET to the update server via `start()` (line 132).

After `HttpChecker::parseResponse()` extracts the download URL (lines 44–66), `HttpLoader` (lines 58–71) spawns a thread to fetch the binary. The downloaded payload undergoes RSA signature verification using OpenSSL (lines 37–42). Upon validation, `Updater::unpackDone()` (line 1070) extracts the archive, and the application launches the new binary via `Core::Launcher` before exiting the old process.

## Implementation Examples

### Scheduling a Message Notification

The following pattern from [`notifications_manager.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/notifications_manager.cpp) demonstrates how incoming MTProto events enter the notification pipeline:

```cpp
// Called from the MTProto update handler when a new message arrives.
void Window::Notifications::System::schedule(Data::ItemNotification notification) {
    if (skipNotification(notification).value == SkipState::Value::Skip) {
        return; // Respect mute / settings.
    }
    const auto when = countTiming(notification.thread, kMinimalDelay);
    _waitTimer.callOnce(when);
    // The timer will invoke showNext() which builds NotificationFields.
}

```

### Triggering Manual Update Checks

UI elements initiate checks by calling the global update function. The Settings screen uses this pattern from [`settings_privacy_security.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/settings_privacy_security.cpp):

```cpp
// Settings screen button handler (settings_privacy_security.cpp, line 439)
void SettingsPrivacySecurity::checkForUpdates() {
    Core::UpdateApplication(); // Starts the whole update flow.
}

```

### Monitoring Download Progress

The updater exposes reactive streams that UI components can observe to display progress bars:

```cpp
auto updater = Core::UpdateChecker::instance();
updater->checking() | rpl::start_with_next([=] {
    ui->statusLabel->setText(tr::lng_update_checking(tr::now));
});

updater->progress() | rpl::start_with_next([=](Core::UpdateChecker::Progress p) {
    ui->progressBar->setValue(p.percentage);
});

updater->ready() | rpl::start_with_next([=] {
    QMessageBox::information(this, tr::lng_update_ready(tr::now),
                             tr::lng_update_success(tr::now));
    Core::UpdateApplication(); // Restart to apply.
});

```

## Summary

- **Notification routing** flows from MTProto through `Window::Notifications::System`, which applies rate-limiting via `skipNotification()` and timing logic via `countTiming()` before delegating to platform-specific backends.
- **Platform abstraction** uses `Platform::Notifications` with dedicated implementations for Windows (WinRT), macOS (`NSUserNotification`), and Linux (DBus) to render native toasts.
- **Update orchestration** relies on `Core::UpdateChecker`, which selects between `HttpChecker` and `MtpChecker` based on alpha build status, then verifies RSA signatures before unpacking.
- **Security integration** ensures that only cryptographically signed binaries pass verification (lines 37–42 in [`update_checker.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/update_checker.cpp)) prior to the restart sequence triggered by `unpackDone()`.

## Frequently Asked Questions

### How does Telegram Desktop choose between native and custom notifications?

The platform reports capabilities via `Platform::Notifications::Supported()` and enforcement status via `Enforced()`. Users can override this with `kOptionCustomNotification` (defined in [`notifications_manager.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/notifications_manager.cpp), lines 36–46) to force the `Default` manager, which renders custom Qt-based toasts instead of native OS notifications.

### What initiates an automatic update check in Telegram Desktop?

`Core::UpdateApplication()` serves as the universal entry point, triggered by UI elements such as the Settings button in [`settings_privacy_security.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/settings_privacy_security.cpp) (line 439) or the QR intro screen in [`intro_qr.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/intro_qr.cpp) (line 486). The method instantiates `Core::UpdateChecker` to begin the network verification sequence.

### How does the client suppress notifications for muted chats?

The scheduler calls `skipNotification()` (lines 92–115 in [`notifications_manager.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/notifications_manager.cpp)) to check mute status and notification settings. For sounds specifically, `MaybeSoundFor()` (lines 17–31) returns a `std::optional<DocumentId>` only for unmuted threads, preventing audio playback when appropriate.

### What security measures protect Telegram Desktop updates?

Telegram Desktop verifies downloaded binaries using RSA signatures through OpenSSL calls (lines 37–42 in [`update_checker.cpp`](https://github.com/telegramdesktop/tdesktop/blob/main/update_checker.cpp)) before extraction. The update only proceeds to `unpackDone()` and subsequent restart if cryptographic validation succeeds, preventing execution of tampered binaries.