Telegram Mini Apps (TMA), Fullscreen & initData Validation

Raw MD
Launch full-screen Web Apps, validate initData cryptographically with HMAC-SHA256 in PHP 8.2, and dispatch prepared inline messages.

Telegram Mini Apps (TMA) Architecture

Telegram Mini Apps allow you to embed modern HTML5/JavaScript web applications directly inside Telegram. Mini Apps support full-screen mode, native dark/light theme synchronization, haptic feedback, cloud storage, biometric authentication, and Telegram Stars checkout.

1. Launching Mini Apps from Buttons

Mini Apps can be opened from Inline Keyboards, Reply Keyboards, or the persistent Chat Menu Button:

PHP — Mini App Button Launchers
<?php
// ── Botlify Cloud .env — auto-injected, never hardcode secrets ──
$BOT_TOKEN     = getenv('BOT_TOKEN');     // Telegram bot token from @BotFather
$ADMIN_CHAT_ID = getenv('ADMIN_CHAT_ID'); // Your numeric admin Telegram user ID
$BOT_USERNAME  = getenv('BOT_USERNAME');  // Bot username without @

declare(strict_types=1);

// 1. Inline Keyboard Mini App Button (with Telegram 8.0 style)
$inlineMarkup = [
    'inline_keyboard' => [
        [
            [
                'text'    => '🚀 Launch Web3 Game',
                'web_app' => ['url' => 'https://tma.botlify.cloud/game'],
                'style'   => 'primary'
            ]
        ]
    ]
];

// 2. Persistent Menu Button (Bottom-Left Chat Input)
bot('setChatMenuButton', [
    'menu_button' => [
        'type'    => 'web_app',
        'text'    => 'Open App',
        'web_app' => ['url' => 'https://tma.botlify.cloud']
    ]
]);

2. Cryptographic initData Validation in Pure PHP 8.2

When a user opens your Mini App, Telegram injects a secure string called initData containing the user's ID, name, username, and a cryptographic hash. To prevent attackers from spoofing identities, you MUST validate this hash on your PHP backend using your BOT_TOKEN:

PHP — Native HMAC-SHA256 initData Validator
<?php
// ── Botlify Cloud .env — auto-injected, never hardcode secrets ──
$BOT_TOKEN     = getenv('BOT_TOKEN');     // Telegram bot token from @BotFather
$ADMIN_CHAT_ID = getenv('ADMIN_CHAT_ID'); // Your numeric admin Telegram user ID
$BOT_USERNAME  = getenv('BOT_USERNAME');  // Bot username without @

declare(strict_types=1);

/**
 * Validates Telegram Mini App initData signature using pure native PHP
 * Returns parsed user array if valid; false if spoofed or expired
 */
function validate_telegram_init_data(string $initData, string $botToken, int $maxAgeSeconds = 86400): array|false {
    if (empty($initData) || empty($botToken)) {
        return false;
    }

    // 1. Parse URL query string into key-value pairs
    parse_str($initData, $params);
    if (!isset($params['hash'])) {
        return false;
    }

    $receivedHash = $params['hash'];
    unset($params['hash']);

    // 2. Sort parameters alphabetically by key
    ksort($params);

    // 3. Build data-check-string (key=value\n...)
    $dataCheckParts = [];
    foreach ($params as $k => $v) {
        $dataCheckParts[] = "{$k}={$v}";
    }
    $dataCheckString = implode("\n", $dataCheckParts);

    // 4. Derive Secret Key: HMAC-SHA256(botToken, "WebAppData")
    $secretKey = hash_hmac('sha256', $botToken, 'WebAppData', true);

    // 5. Compute Calculated Hash: HMAC-SHA256(dataCheckString, secretKey)
    $calculatedHash = hash_hmac('sha256', $dataCheckString, $secretKey);

    // 6. Timing-Safe Hash Verification
    if (!hash_equals($calculatedHash, $receivedHash)) {
        return false; // Signature mismatch! Data was tampered with!
    }

    // 7. Check Timestamp to Prevent Replay Attacks
    if (isset($params['auth_date']) && (time() - (int)$params['auth_date']) > $maxAgeSeconds) {
        return false; // Authentication data expired
    }

    // Return parsed user object
    if (isset($params['user'])) {
        $params['user'] = json_decode($params['user'], true);
    }

    return $params;
}

// ─────────────────────────────────────────────────────────────────────────────
// Example API Endpoint Usage:
// ─────────────────────────────────────────────────────────────────────────────
$rawInitData = $_SERVER['HTTP_X_TELEGRAM_INIT_DATA'] ?? ($_POST['initData'] ?? '');
$validated = validate_telegram_init_data($rawInitData, BOT_TOKEN);

if ($validated === false) {
    http_response_code(403);
    echo json_encode(['ok' => false, 'error' => 'Unauthorized Telegram Session']);
    exit;
}

$user = $validated['user'];
$telegramUserId = $user['id'];
$telegramName   = $user['first_name'];

echo json_encode([
    'ok'      => true,
    'message' => "Welcome, {$telegramName}!",
    'user_id' => $telegramUserId
]);

3. Full-Screen Mode & Orientation Locks (API 8.0)

Inside your Mini App's front-end JavaScript, you can request full-screen mode and lock screen orientation:

JavaScript — Telegram 8.0 Fullscreen & Orientation
// Check if Telegram WebApp SDK is available
if (window.Telegram?.WebApp) {
    const tg = window.Telegram.WebApp;
    tg.ready();

    // 1. Expand to maximum height
    tg.expand();

    // 2. Request True Full-Screen Mode (Telegram 8.0+)
    if (tg.requestFullscreen) {
        tg.requestFullscreen();
    }

    // 3. Lock Orientation to Landscape (Great for Web3 games)
    if (tg.lockOrientation) {
        tg.lockOrientation('landscape');
    }

    // 4. Disable Vertical Swipes (Prevents accidental sheet closing)
    if (tg.disableVerticalSwipes) {
        tg.disableVerticalSwipes();
    }
}

4. Prepared Inline Messages (savePreparedInlineMessage)

Mini Apps can pre-package rich interactive messages on the server so users can share them into any Telegram chat with one tap:

PHP — savePreparedInlineMessage Implementation
<?php
// ── Botlify Cloud .env — auto-injected, never hardcode secrets ──
$BOT_TOKEN     = getenv('BOT_TOKEN');     // Telegram bot token from @BotFather
$ADMIN_CHAT_ID = getenv('ADMIN_CHAT_ID'); // Your numeric admin Telegram user ID
$BOT_USERNAME  = getenv('BOT_USERNAME');  // Bot username without @

declare(strict_types=1);

function prepare_game_share_card(int $userId, int $score): string {
    $res = bot('savePreparedInlineMessage', [
        'user_id' => $userId,
        'result'  => [
            'type'        => 'article',
            'id'          => 'score_card_' . time(),
            'title'       => "🏆 I scored {$score} points in Botlify Cloud Runner!",
            'description' => 'Can you beat my high score? Tap to play!',
            'input_message_content' => [
                'message_text' => "🎮 I just scored {$score} points!\n\nThink you can beat me? Play now on Botlify Cloud:",
                'parse_mode'   => 'HTML'
            ],
            'reply_markup' => [
                'inline_keyboard' => [
                    [
                        [
                            'text'    => '🕹️ Play Now',
                            'web_app' => ['url' => 'https://tma.botlify.cloud/game'],
                            'style'   => 'success'
                        ]
                    ]
                ]
            ]
        ]
    ]);

    // Returns prepared_message_id to pass to Mini App frontend
    return $res['result']['id'] ?? '';
}
Botlify Cloud Runtime
Credentials are auto-injected in .env — always load them with getenv(): BOT_TOKEN, ADMIN_CHAT_ID, BOT_USERNAME. Main database: database.db (SQLite, WAL mode). Runtime errors: error.log. Quick test: send to $ADMIN_CHAT_ID. Full details: Runtime Reference.