Fingerprints & Consistency
When connecting to Telegram’s servers via the initConnection method, every client sends a set of parameters that identify the device and application. These parameters form the session’s fingerprint:
| Parameter | Description | Example |
|---|---|---|
api_id | Application identifier | 2496 |
api_hash | Application secret | "8da85b0d5bfe62527e5b244c209159c3" |
device_model | Device or User-Agent string | "Samsung Galaxy S24 Ultra" |
system_version | OS version | "SDK 35" |
app_version | Client version | "12.3.0" |
system_lang_code | OS locale | "en-US" |
lang_code | Client language | "en" |
lang_pack | Language pack identifier | "android" |
Telegram uses these values to identify sessions. If the parameters look inconsistent (e.g. an Android lang_pack with an iOS device_model), the account may be flagged.
opentele2 provides tools to keep fingerprints realistic and internally consistent.
Why Fingerprints Matter
According to Telegram TOS , all accounts that sign up or log in using unofficial Telegram API clients are automatically put under observation. opentele2 uses official api_id/api_hash values and the lang_pack parameter (which is restricted to official apps) so that sessions are indistinguishable from real official clients.
However, using an official api_id alone is not enough. The remaining fingerprint fields must also be realistic:
device_modelshould match real devices for mobile APIs, or a valid User-Agent for web APIs.system_versionshould correspond to OS versions that the device actually ships with.app_versionshould match a version the official client has released.lang_packmust match the platform ("android","ios","tdesktop","macos", or""for web).
Generating Realistic Fingerprints
Every API template in opentele2 supports Generate() to create randomized but realistic device info.
Mobile & Desktop
from opentele2.api import API
# Android — random real device model + SDK version
api = API.TelegramAndroid.Generate()
# e.g. device_model="Samsung SM-A750FN", system_version="SDK 24"
# iOS — random iPhone model + iOS version
api = API.TelegramIOS.Generate()
# e.g. device_model="iPhone 16 Pro Max", system_version="18.2"
# Desktop — random desktop hardware + OS version
api = API.TelegramDesktop.Generate()
# e.g. device_model="ASUS All Series", system_version="Windows 11"
# macOS — random Mac model + macOS version
api = API.TelegramMacOS.Generate()
# e.g. device_model="MacBook Pro", system_version="macOS 15.2"Web Clients (Browser Fingerprints)
Web APIs (TelegramWeb_A, TelegramWeb_K, Webogram) now support fingerprint generation using the browserforge library. This generates realistic browser User-Agent strings as the device_model.
Note Browser fingerprint generation requires the
browserforgepackage.pip install browserforgeOr install opentele2 with the web extra:
pip install opentele2[web]
from opentele2.api import API
# Web A — same behavior as Web Z
api = API.TelegramWeb_A.Generate()
# e.g. device_model="Mozilla/5.0 (Macintosh; ...) Chrome/144.0.0.0 Safari/537.36"
# system_version="macOS"
# Web K — random User-Agent + navigator.platform as system_version
api = API.TelegramWeb_K.Generate()
# e.g. device_model="Mozilla/5.0 (Windows NT 10.0; ...) Chrome/144.0.0.0 Safari/537.36 Edg/144.0.0.0"
# system_version="Win32"
# Webogram (legacy) — same style as Web K
api = API.Webogram.Generate()How Web Fingerprints Work
The web client fingerprint system:
- Fetches the latest stable Chrome version from Google’s official API to keep browser version ranges current.
- Generates diverse User-Agent strings for Chrome, Edge, and Firefox on Windows and macOS using browserforge.
- Derives
system_versionfrom the User-Agent:- Web Z / Web A: Uses the OS name (e.g.
"Windows","macOS","Linux") — matching how telegram-tt sends it. - Web K / Webogram: Uses
navigator.platform(e.g."Win32","MacIntel") — matching how tweb sends it.
- Web Z / Web A: Uses the OS name (e.g.
Web Z vs Web A vs Web K
| Client | system_version style | app_version | lang_pack |
|---|---|---|---|
| Web A | OS name ("macOS") | "5.0.0 A" | "" |
| Web K | navigator.platform ("Win32") | "1.4.2 K" | "macos" |
| Webogram | navigator.platform ("Win32") | "0.7.0" | "" |
Deterministic Generation with unique_id
All Generate() calls accept an optional unique_id parameter. When provided, the same unique_id always produces the same device data:
# Always produces the same fingerprint for this session
api = API.TelegramWeb_A.Generate(unique_id="my_session_1")
# Different unique_id = different fingerprint
api2 = API.TelegramWeb_A.Generate(unique_id="my_session_2")
# No unique_id = random each time
api3 = API.TelegramWeb_A.Generate()This is useful when you need consistent device info across restarts for the same session.
Fingerprint Validation
opentele2 includes a validation system that checks initConnection parameters for consistency issues. This is provided by the FingerprintConfig class.
from opentele2.fingerprint import FingerprintConfig, StrictMode, validate_init_connection_paramsManual Validation
You can validate parameters directly:
from opentele2.fingerprint import validate_init_connection_params
issues = validate_init_connection_params(
api_id=2496,
device_model="Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...",
system_version="Windows",
app_version="5.0.0 Z",
system_lang_code="en-US",
lang_pack="",
lang_code="en",
)
if issues:
for issue in issues:
print(f" - {issue}")
else:
print("All checks passed")The validator checks:
lang_packis a known official value ("android","ios","tdesktop","macos", or"")lang_codeis a valid language tagsystem_lang_codeincludes a region for mobile clients (e.g."en-US"not"en")- No empty strings in
device_model,system_version, orapp_version
With strict=True, additional checks are performed:
api_idmatches the expected value for thelang_packapp_versionmajor version matches the latest known official release
Strict Mode Configuration
from opentele2.fingerprint import FingerprintConfig, StrictMode
# Warn on issues (default)
config = FingerprintConfig(strict_mode=StrictMode.WARN)
# Raise exceptions on any inconsistency
config = FingerprintConfig(strict_mode=StrictMode.STRICT)
# Disable all checks
config = FingerprintConfig(strict_mode=StrictMode.OFF)| Mode | Behavior |
|---|---|
StrictMode.OFF | No checks |
StrictMode.WARN | Emit warnings for issues (default) |
StrictMode.STRICT | Raise ValueError for any inconsistency |
TL Layer Tracking
opentele2 tracks the current official Telegram schema layer and compares it with the layer used by the installed Telethon version. If they diverge too far, a warning is emitted.
from opentele2.fingerprint import get_recommended_layer, LAYER
# The latest official schema layer
print(LAYER) # e.g. 214
# The layer that will be used (from Telethon)
print(get_recommended_layer())If the difference between the Telethon layer and the official schema layer exceeds 15, a warning is emitted suggesting an update.
Post-Login Consistency Checks
After connecting and authenticating, official Telegram clients make several API calls that the server expects. Skipping them can look suspicious. The ConsistencyChecker class mimics this behavior.
from opentele2.tl import TelegramClient
from opentele2.api import API
from opentele2.consistency import ConsistencyChecker
api = API.TelegramWeb_A.Generate()
client = TelegramClient("session.session", api=api)
await client.connect()
checker = ConsistencyChecker(client)
report = await checker.run_all()
print(report.summary)
# Consistency: 6/6 checks passed
# [OK] get_config: Config OK (DC 2)
# [OK] current_session: api_id=2496, official=True, ...
# [OK] layer_match: Telethon layer=198, official schema layer=214, diff=16
# [OK] lang_pack: lang_pack is empty (web client mode)
# [OK] app_update: No update available (app_version accepted)
# [OK] terms_of_service: ToS check OKWhat Gets Checked
| Check | What it does |
|---|---|
get_config | Calls help.getConfig — every official client does this on connect |
current_session | Verifies the session is seen as an official app via account.getAuthorizations |
layer_match | Checks if the Telethon TL layer is close to the official schema layer |
lang_pack | Calls langpack.getLanguages to verify the lang_pack value is accepted |
app_update | Calls help.getAppUpdate — official clients do this periodically |
terms_of_service | Calls help.getTermsOfServiceUpdate — official clients check this |
All checks are read-only and safe to call. They are the same requests that official clients make routinely.
Auto-Warning
By default, ConsistencyChecker emits a warning if any check fails:
# Disable auto-warning
checker = ConsistencyChecker(client, auto_warn=False)
report = await checker.run_all()
if not report.all_passed:
# Handle manually
for check in report.checks:
if not check.passed:
print(f"FAILED: {check.name} - {check.detail}")Transport Recommendations
Official Telegram clients use obfuscated transport by default. opentele2 provides helpers to use the recommended transport:
from opentele2.fingerprint import TransportRecommendation
# Get the recommended connection class
ConnectionClass = TransportRecommendation.get_connection_class()
# Use it with TelegramClient
from opentele2.tl import TelegramClient
from opentele2.api import API
api = API.TelegramWeb_A.Generate()
client = TelegramClient("session.session", api=api, connection=ConnectionClass)Using plain ConnectionTcpFull without obfuscation is increasingly distinguishable from official clients.
Platform Version Constants
opentele2 tracks the latest known versions of all official Telegram clients:
from opentele2.fingerprint import get_platform_versions
pv = get_platform_versions()
print(pv.android_app_version) # "12.3.0"
print(pv.ios_app_version) # "12.3"
print(pv.desktop_app_version) # "5.12.3"
print(pv.macos_app_version) # "12.3"
print(pv.web_z_version) # "5.0.0 Z"
print(pv.web_a_version) # "5.0.0 A"
print(pv.web_k_version) # "1.4.2 K"
print(pv.chrome_version) # "144.0.0.0"These constants are used by the strict validator and should be updated when Telegram releases new client versions.