Token导航 LogoToken导航

Agent Skill · 开发

telegram-mini-app-skill(Telegram mini 应用技能)

telegram-mini-app-skill 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

telegram-mini-app-skill 是开发类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为需要联网;许可证信息还不明确,第三方扫描有提醒项,按安装量在开发类的 21,746 个 Skill 里排第 19,065。

总安装 294周安装 12GitHub Stars 3下载 94核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:telegram-mini-app-skill(Telegram mini 应用技能)
来源仓库:https://github.com/rithprohos/telegram-mini-app-skills
仓库路径:skills/telegram-mini-app-skill
安装命令:
npx skills add https://github.com/rithprohos/telegram-mini-app-skills --skill telegram-mini-app-skill
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/rithprohos/telegram-mini-app-skills --skill telegram-mini-app-skill

这个 Skill 是做什么的

开发类 Skill 面向写代码、改代码和排查问题,一般会读写仓库文件,部分还会执行构建或测试命令。

telegram-mini-app-skill 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息。适合在 Codex、Claude、Cursor、Gemini CLI 中围绕仓库状态、代码变更或协作事项进行整理。

通过 npx skills add 命令从指定 GitHub 仓库安装并使用。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。可结合来源仓库和原始 README 进一步核验具体用法。

来源仓库内路径:skills/telegram-mini-app-skill

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/rithprohos/telegram-mini-app-skills --skill te…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要需要联网,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

telegram-mini-app-skill 怎么安装?

在终端执行 npx skills add https://github.com/rithprohos/telegram-mini-app-skills --skill telegram-min…。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

telegram-mini-app-skill 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

telegram-mini-app-skill 需要什么权限?

权限级别是需要联网。该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

telegram-mini-app-skill 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

telegram-mini-app-skill 用的人多吗?

公开数据是累计安装 294 次,近一周安装 12 次,下载 94 次,GitHub 3 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

telegram-mini-app-skill 安全吗?

第三方扫描有提醒项,说明存在需要人工确认的行为。安装前请打开源码看清它读了什么、联网到哪里。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。

先想清楚的地方

  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方扫描存在提醒项或未通过项,需要人工逐条确认。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理开发类任务、又不想每次都手写提示词的人。

不太适合

  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

开发类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
skill-vetter

技能审查员 · OpenClaw

8,779,018986操作浏览器MIT-0通过
ontology

本体论 · OpenClaw

6,636,960576只读MIT-0通过
entra-app-registration

内部应用程序注册 · Codex、Claude

6,631,872764接触敏感数据未明确通过
entra-app-registration

内部应用程序注册 · Codex、Claude

3,757,680201接触敏感数据未明确通过
nano-banana-pro

纳米香蕉专业版 · OpenClaw

3,526,898364接触敏感数据MIT-0有提醒
telegram-mini-app-skill

Telegram mini 应用技能 · 本页

2943需要联网未明确有提醒

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

Telegram Mini App Development Guide

Official Reference: core.telegram.org/bots/webapps

This skill is a framework-agnostic guide for building Telegram Mini Apps. Whether you use React, Vue, Svelte, Angular, Solid, or vanilla HTML/JS — this guide covers the universal SDK concepts, theming system, and best practices.


Table of Contents

  1. What is a Telegram Mini App?
  2. Loading the SDK
  3. The WebApp Object
  4. Initialization Lifecycle
  5. Theming & CSS Variables
  6. Navigation Components
  7. Bottom Buttons (MainButton & SecondaryButton)
  8. Haptic Feedback
  9. Popups & Alerts
  10. Data Validation & Security
  11. Storage APIs
  12. Full-Screen Mode
  13. Safe Areas
  14. Available Events
  15. Framework Integration Recipes
  16. Design Guidelines
  17. Testing & Debugging
  18. Common Pitfalls

1. What is a Telegram Mini App?

Telegram Mini Apps are web applications (HTML, CSS, JavaScript) that run inside the Telegram messenger. They can be launched from:

  • Bot menus — via BotFather's menu button configuration
  • Inline buttons — web_app type in bot messages
  • Attachment menu — bot added to the attachment menu
  • Direct links — t.me/botname/appname
  • Keyboard buttons — web_app type keyboard buttons
  • Home screen shortcuts — users can add Mini Apps to their home screen

Key characteristics:

  • Must be served over HTTPS
  • Run in a WebView on all platforms (iOS, Android, Desktop, Web)
  • Can access Telegram user data, theme, and native UI components
  • Associated with a bot created via @BotFather

2. Loading the SDK

Option A: Script Tag (All Frameworks)

Place this in your <head> before any other scripts:

<script src="https://telegram.org/js/telegram-web-app.js"></script>

This creates the window.Telegram.WebApp object and automatically injects CSS variables for theming.

Option B: npm Packages

For modern JavaScript projects with bundlers:

# Official community SDK (TypeScript-first, tree-shakeable)
npm install @telegram-apps/sdk

# Alternative lightweight wrapper
npm install @twa-dev/sdk

Framework-Specific Loading

FrameworkHow to Load
Vanilla HTML<script> tag in <head>
React / Next.js<Script src="..." strategy="beforeInteractive" /> via next/script, or <script> in index.html
Vue / Nuxt<script> in index.html, or Nuxt plugin with useHead()
Svelte / SvelteKit<svelte:head> tag or app.html
AngularAdd to angular.json scripts array or index.html

3. The WebApp Object

Once the SDK is loaded, the main API is available at:

const tg = window.Telegram.WebApp;

Key Properties

PropertyTypeDescription
initDatastringRaw init data string for backend validation
initDataUnsafeobjectParsed init data (user, chat, etc.) — not validated, do not trust client-side
versionstringSDK version (e.g., "8.0")
platformstringPlatform identifier ("android", "ios", "tdesktop", "web", "unknown")
colorSchemestring"light" or "dark"
themeParamsobjectCurrent theme colors as key-value pairs
isExpandedbooleanWhether the Mini App is expanded to full height
viewportHeightnumberCurrent viewport height in pixels
viewportStableHeightnumberStable viewport height (doesn't change with keyboard)
headerColorstringCurrent header color (#RRGGBB)
backgroundColorstringCurrent background color (#RRGGBB)
bottomBarColorstringCurrent bottom bar color (#RRGGBB)
isFullscreenbooleanWhether full-screen mode is active

Key Sub-Objects

Sub-ObjectDescription
BackButtonControls the back button in the header
MainButtonControls the primary bottom button
SecondaryButtonControls the secondary bottom button
SettingsButtonControls the settings item in the context menu
HapticFeedbackControls haptic/vibration feedback
CloudStorageCloud key-value storage (up to 1024 items, synced across devices)
DeviceStoragePersistent local storage (up to 5 MB, device-only)
SecureStorageEncrypted storage using OS keychain/keystore (up to 10 items)
BiometricManagerBiometric authentication
AccelerometerAccelerometer sensor data
GyroscopeGyroscope sensor data
DeviceOrientationDevice orientation data
LocationManagerLocation access

4. Initialization Lifecycle

Every Mini App must call tg.ready() to signal to Telegram that the app is ready to be displayed.

Universal Pattern (Any Framework)

// 1. Get the WebApp instance
const tg = window.Telegram.WebApp;

// 2. Signal ready
tg.ready();

// 3. Expand to full height (recommended)
tg.expand();

// 4. Access user data
const user = tg.initDataUnsafe?.user;
console.log(user?.first_name, user?.username);

Why ready() Matters

  • Telegram shows a loading placeholder until ready() is called
  • Call it as early as possible after your app's initial UI has rendered
  • Don't call it before your app has something meaningful to display

5. Theming & CSS Variables

The Golden Rule

NEVER hardcode colors. Use the CSS variables that Telegram's SDK injects automatically. This ensures your app looks native in Light mode, Dark mode, and across all platforms.

Available CSS Variables

The SDK automatically sets these CSS variables on the <html> element:

CSS VariableJS Property (themeParams.X)Description
--tg-theme-bg-colorbg_colorMain background
--tg-theme-text-colortext_colorPrimary text
--tg-theme-hint-colorhint_colorSecondary/hint text
--tg-theme-link-colorlink_colorLinks
--tg-theme-button-colorbutton_colorPrimary button background
--tg-theme-button-text-colorbutton_text_colorButton text
--tg-theme-secondary-bg-colorsecondary_bg_colorSecondary background (cards, sections)
--tg-theme-header-bg-colorheader_bg_colorHeader background
--tg-theme-bottom-bar-bg-colorbottom_bar_bg_colorBottom bar background
--tg-theme-accent-text-coloraccent_text_colorAccent text
--tg-theme-section-bg-colorsection_bg_colorSection/card background
--tg-theme-section-header-text-colorsection_header_text_colorSection header text
--tg-theme-section-separator-colorsection_separator_colorSeparator lines
--tg-theme-subtitle-text-colorsubtitle_text_colorSubtitle text
--tg-theme-destructive-text-colordestructive_text_colorDestructive/danger text

Additional CSS Variables

CSS VariableDescription
--tg-color-scheme"light" or "dark"
--tg-viewport-heightCurrent viewport height
--tg-viewport-stable-heightStable viewport height
--tg-safe-area-inset-topSystem safe area (top)
--tg-safe-area-inset-bottomSystem safe area (bottom)
--tg-safe-area-inset-leftSystem safe area (left)
--tg-safe-area-inset-rightSystem safe area (right)
--tg-content-safe-area-inset-topTelegram UI safe area (top)
--tg-content-safe-area-inset-bottomTelegram UI safe area (bottom)
--tg-content-safe-area-inset-leftTelegram UI safe area (left)
--tg-content-safe-area-inset-rightTelegram UI safe area (right)

Usage Examples

✅ CORRECT — Using CSS Variables
/* CSS */
body {
  background-color: var(--tg-theme-bg-color, #ffffff);
  color: var(--tg-theme-text-color, #000000);
}

.card {
  background-color: var(--tg-theme-section-bg-color, #f5f5f5);
  border: 1px solid var(--tg-theme-section-separator-color, #e0e0e0);
}

.button-primary {
  background-color: var(--tg-theme-button-color, #3b82f6);
  color: var(--tg-theme-button-text-color, #ffffff);
}

.hint-text {
  color: var(--tg-theme-hint-color, #999999);
}
Always provide fallback values (the second argument in var()) so your app works outside of Telegram during development.
❌ WRONG — Hardcoded Colors
/* NEVER do this */
body {
  background-color: #ffffff;
  color: #000000;
}
.dark body {
  background-color: #1a1a1a;
  color: #ffffff;
}

Creating a Shorthand Variable System (Recommended)

For convenience, map Telegram's verbose variables to shorter names in your global CSS:

:root {
  --bg: var(--tg-theme-bg-color, #ffffff);
  --fg: var(--tg-theme-text-color, #171717);
  --btn: var(--tg-theme-button-color, #3b82f6);
  --btn-text: var(--tg-theme-button-text-color, #ffffff);
  --hint: var(--tg-theme-hint-color, #a1a1aa);
  --link: var(--tg-theme-link-color, #007aff);
  --secondary-bg: var(--tg-theme-secondary-bg-color, #efeff4);
  --section-bg: var(--tg-theme-section-bg-color, #ffffff);
  --section-header: var(--tg-theme-section-header-text-color, #6d6d72);
  --subtitle: var(--tg-theme-subtitle-text-color, #8e8e93);
  --destructive: var(--tg-theme-destructive-text-color, #ff3b30);
  --accent: var(--tg-theme-accent-text-color, #007aff);
  --separator: var(--tg-theme-section-separator-color, #c8c7cc);
}

Listening to Theme Changes

tg.onEvent("themeChanged", () => {
  // Theme params have been updated
  // CSS variables are auto-updated by the SDK
  // If using JS theming, re-read tg.themeParams
  console.log("New color scheme:", tg.colorScheme);
});

6. Navigation Components

BackButton

Controls the native back button in the Telegram header. Use this instead of building your own back button.

// Show the back button
tg.BackButton.show();

// Handle clicks
tg.BackButton.onClick(() => {
  // Navigate back in your app's routing
  history.back(); // or your router's back method
});

// Hide when no longer needed
tg.BackButton.hide();

// Remove a specific handler
tg.BackButton.offClick(handler);

SettingsButton

Adds a "Settings" option to the Mini App's context menu (three-dot menu).

tg.SettingsButton.show();
tg.SettingsButton.onClick(() => {
  // Navigate to settings page
});

7. Bottom Buttons

Telegram provides two bottom buttons: MainButton (primary) and SecondaryButton (secondary). They appear fixed at the bottom of the Mini App.

MainButton

const btn = tg.MainButton;

// Configure and show
btn.setText("SUBMIT ORDER");
btn.show();

// Or use setParams for multiple properties at once
btn.setParams({
  text: "SUBMIT ORDER",
  color: tg.themeParams.button_color,
  text_color: tg.themeParams.button_text_color,
  is_active: true,
  is_visible: true,
  has_shine_effect: false,
});

// Handle click
btn.onClick(() => {
  // Perform the action
});

// Show loading state
btn.showProgress(true); // true = leave button active
btn.disable(); // prevent double-clicks

// Reset after completion
btn.hideProgress();
btn.enable();
btn.hide();

SecondaryButton

Works identically to MainButton:

tg.SecondaryButton.setParams({
  text: "CANCEL",
  is_visible: true,
});

tg.SecondaryButton.onClick(() => {
  // Handle secondary action
});

BottomButton Properties

Property / MethodDescription
.textButton text
.colorBackground color
.textColorText color
.isVisibleWhether the button is shown
.isActiveWhether the button is clickable
.isProgressVisibleWhether the loading spinner is shown
.setText(text)Update button text
.show() / .hide()Toggle visibility
.enable() / .disable()Toggle clickability
.showProgress(leaveActive)Show spinner
.hideProgress()Hide spinner
.setParams(params)Set multiple properties at once
.onClick(cb)Register click handler
.offClick(cb)Remove click handler

Important: Handler Cleanup

Always remove click handlers when they're no longer relevant (e.g., on component unmount or page navigation). Failure to do so can cause ghost handlers.


8. Haptic Feedback

Trigger native haptic vibrations for tactile feedback:

const haptic = tg.HapticFeedback;

// Impact feedback — for button presses, interactions
haptic.impactOccurred("light"); // light tap
haptic.impactOccurred("medium"); // medium tap
haptic.impactOccurred("heavy"); // strong tap
haptic.impactOccurred("rigid"); // rigid tap
haptic.impactOccurred("soft"); // soft tap

// Notification feedback — for results/outcomes
haptic.notificationOccurred("success"); // operation succeeded
haptic.notificationOccurred("error"); // operation failed
haptic.notificationOccurred("warning"); // caution

// Selection feedback — for selection changes
haptic.selectionChanged(); // e.g., picker/slider changes

When to Use

ScenarioType
Button tapimpactOccurred("light")
Form submit successnotificationOccurred("success")
Error responsenotificationOccurred("error")
Toggling a switchimpactOccurred("medium")
Slider/picker value changeselectionChanged()
Deleting an itemimpactOccurred("heavy")
Clear/reset actionimpactOccurred("light")

9. Popups & Alerts

Use native Telegram dialogs instead of browser alert() / confirm():

// Simple alert
tg.showAlert("File saved successfully!", () => {
  // Callback after user dismisses
});

// Confirmation dialog
tg.showConfirm("Are you sure you want to delete this?", (confirmed) => {
  if (confirmed) {
    // User tapped "OK"
  }
});

// Custom popup with buttons
tg.showPopup(
  {
    title: "Choose an option", // optional
    message: "What would you like to do?",
    buttons: [
      { id: "save", type: "default", text: "Save" },
      { id: "delete", type: "destructive", text: "Delete" },
      { id: "cancel", type: "cancel" }, // text is auto-set
    ],
  },
  (buttonId) => {
    switch (buttonId) {
      case "save":
        /* ... */ break;
      case "delete":
        /* ... */ break;
      case "cancel":
        /* ... */ break;
    }
  },
);

Popup Button Types

TypeBehavior
"default"Regular button
"ok""OK" text, closes popup
"close""Close" text, closes popup
"cancel""Cancel" text, closes popup
"destructive"Red/destructive styled button

10. Data Validation & Security

Client-Side Data

tg.initDataUnsafe gives you parsed user data, but it can be spoofed. Always validate on your backend.

// Client: send initData to your backend
const response = await fetch("/api/your-endpoint", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Telegram-Init-Data": tg.initData, // raw string for validation
  },
  body: JSON.stringify({
    /* your payload */
  }),
});

Server-Side Validation (HMAC-SHA256)

The backend must validate initData using the bot's token:

1. Parse initData as query string
2. Extract `hash` parameter, keep remaining fields
3. Sort remaining fields alphabetically
4. Create data_check_string = sorted fields joined with '\n' in "key=value" format
5. secret_key = HMAC_SHA256(bot_token, "WebAppData")
6. Compare: HMAC_SHA256(data_check_string, secret_key) == hash
7. Check auth_date for freshness

Pseudocode:

data_check_string = "auth_date=<auth_date>\nquery_id=<query_id>\nuser=<user>"
secret_key = HMAC_SHA256(<bot_token>, "WebAppData")
if hex(HMAC_SHA256(data_check_string, secret_key)) == hash:
    # Data is genuine and from Telegram

Third-Party Validation (Ed25519 Signatures)

For sharing data with third parties (who don't have your bot token), use the signature field with Telegram's public keys:

  • Production: e7bf03a2fa4602af4580703d88dda5bb59f32ed8b02a56c187fe7d34caed242d
  • Test env: 40055058a4ee38156a06562e52eece92a771bcd8346a8c4615cb7376eddf72ec

11. Storage APIs

CloudStorage (Synced Across Devices)

Up to 1024 key-value pairs, 4096 bytes per value, synced via Telegram's servers:

tg.CloudStorage.setItem("theme_pref", "dark", (err, success) => {});
tg.CloudStorage.getItem("theme_pref", (err, value) => {});
tg.CloudStorage.getItems(["key1", "key2"], (err, values) => {});
tg.CloudStorage.removeItem("theme_pref", (err, success) => {});
tg.CloudStorage.getKeys((err, keys) => {});

DeviceStorage (Local Only, Bot API 9.0+)

Up to 5 MB, persists on device, similar to localStorage:

tg.DeviceStorage.setItem("draft", longText);
tg.DeviceStorage.getItem("draft");

SecureStorage (Encrypted, Bot API 9.0+)

Up to 10 items, uses OS Keychain (iOS) / Keystore (Android):

tg.SecureStorage.setItem("auth_token", token);
tg.SecureStorage.getItem("auth_token");

12. Full-Screen Mode

Available since Bot API 8.0 (November 2024). Allows the Mini App to use the entire screen:

// Enter full-screen
tg.requestFullscreen();

// Exit full-screen
tg.exitFullscreen();

// Check status
console.log(tg.isFullscreen);

// Listen for changes
tg.onEvent("fullscreenChanged", () => {
  console.log("Fullscreen:", tg.isFullscreen);
});

tg.onEvent("fullscreenFailed", (event) => {
  console.log("Fullscreen failed:", event.error);
});
Important: When in full-screen mode, you must handle safe areas to avoid content overlapping with system UI elements (notch, status bar, etc.).

13. Safe Areas

Two types of safe areas to handle, especially critical in full-screen mode:

System Safe Area (notch, status bar, home indicator)

.content {
  padding-top: var(--tg-safe-area-inset-top, 0px);
  padding-bottom: var(--tg-safe-area-inset-bottom, 0px);
  padding-left: var(--tg-safe-area-inset-left, 0px);
  padding-right: var(--tg-safe-area-inset-right, 0px);
}

Content Safe Area (Telegram's own header, bottom bar)

It is highly recommended in frameworks like React/Next.js to avoid applying these to the raw document body, as Telegram's Webview injection can cause 100vw or scaling constraints to clip or shrink off-screen horizontally.

Instead, the most bulletproof approach across all Webview versions involves a hybrid Javascript-to-CSS fallback. Combining contentSafeAreaInset.top (Telegram UI) and safeAreaInset.top (Mobile Device Notches) prevents overlap completely:

1. Calculate and combine the padding natively in your Telegram Initialization loop:

// Add base safeArea (device notches) + contentSafe (Telegram header ui) together
// Apply a hard fallback (e.g., 48px) just in case Telegram fails to inject variables entirely
const top = Math.max(
  48,
  (tg.contentSafeAreaInset?.top || 0) + (tg.safeAreaInset?.top || 0),
);
const bottom = Math.max(
  32,
  (tg.contentSafeAreaInset?.bottom || 0) + (tg.safeAreaInset?.bottom || 0),
);

// Explicitly inject safe bounds into your root HTML variables
document.documentElement.style.setProperty("--safe-top", `${top}px`);
document.documentElement.style.setProperty("--safe-bottom", `${bottom}px`);

2. In your CSS (like globals.css or Tailwind config), reference the injected variables:

:root {
  /* You can optionally add env() fallbacks here if you want native browser backup */
  --safe-top: env(safe-area-inset-top, 48px);
  --safe-bottom: env(safe-area-inset-bottom, 32px);
}

3. Finally, in your React individual Page wrappers padding:

<main
  style={{
    // Add your desired extra padding (e.g., 1rem) to the base safe area boundary mathematically
    paddingTop: "calc(1rem + var(--safe-top))",
    paddingBottom: "calc(2rem + var(--safe-bottom))",
  }}
>
  {/* Content goes here safely below the Close/Settings notch */}
</main>

Listening for Safe Area Changes

tg.onEvent("safeAreaChanged", () => {
  // System safe area changed (e.g., orientation change)
});

tg.onEvent("contentSafeAreaChanged", () => {
  // Telegram UI safe area changed
});

14. Available Events

Register handlers with tg.onEvent(eventType, handler) and remove with tg.offEvent(eventType, handler):

EventTrigger
activatedMini App becomes active/visible
deactivatedMini App becomes inactive/hidden
themeChangedUser changed Telegram theme
viewportChangedViewport height changed (keyboard, expand)
safeAreaChangedSystem safe area insets changed
contentSafeAreaChangedTelegram content safe area changed
mainButtonClickedMain button was pressed
secondaryButtonClickedSecondary button was pressed
backButtonClickedBack button was pressed
settingsButtonClickedSettings button was pressed
invoiceClosedPayment invoice was closed
popupClosedPopup was closed
qrTextReceivedQR code was scanned
clipboardTextReceivedClipboard text was received
writeAccessRequestedWrite access permission result
contactRequestedContact sharing result
fullscreenChangedFull-screen state changed
fullscreenFailedFull-screen request failed
homeScreenAddedApp was added to home screen
homeScreenCheckedHome screen status checked
biometricManagerUpdatedBiometric manager state changed
biometricAuthRequestedBiometric auth result
shareMessageSentShare message was sent
shareMessageFailedShare message failed
emojiStatusSetEmoji status was set
emojiStatusFailedEmoji status setting failed
fileDownloadRequestedFile download request result

15. Framework Integration Recipes

Vanilla JavaScript

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script src="https://telegram.org/js/telegram-web-app.js"></script>
    <style>
      body {
        margin: 0;
        font-family: -apple-system, BlinkMacSystemFont, sans-serif;
        background: var(--tg-theme-bg-color, #fff);
        color: var(--tg-theme-text-color, #000);
      }
      .card {
        background: var(--tg-theme-section-bg-color, #f5f5f5);
        border-radius: 14px;
        padding: 16px;
        margin: 16px;
      }
      .hint {
        color: var(--tg-theme-hint-color, #999);
        font-size: 13px;
      }
    </style>
  </head>
  <body>
    <div class="card">
      <h1>Hello, <span id="username">User</span>!</h1>
      <p class="hint">Welcome to the Mini App</p>
    </div>
    <script>
      const tg = window.Telegram.WebApp;
      tg.ready();
      tg.expand();

      const user = tg.initDataUnsafe?.user;
      if (user) {
        document.getElementById("username").textContent = user.first_name;
      }

      tg.MainButton.setText("DONE");
      tg.MainButton.show();
      tg.MainButton.onClick(() => {
        tg.HapticFeedback.notificationOccurred("success");
        tg.close();
      });
    </script>
  </body>
</html>

React / Next.js

// hooks/useTelegram.ts — Reusable hook
import { useEffect, useState, useCallback } from "react";

export function useTelegram() {
  const [tg, setTg] = useState<TelegramWebApp | null>(null);
  const [user, setUser] = useState<TelegramUser | null>(null);

  useEffect(() => {
    if (typeof window !== "undefined" && window.Telegram?.WebApp) {
      const webapp = window.Telegram.WebApp;
      webapp.ready();
      webapp.expand();
      setTg(webapp);
      setUser(webapp.initDataUnsafe?.user || null);
    }
  }, []);

  const showMainButton = useCallback(
    (text: string, onClick: () => void) => {
      if (!tg) return;
      tg.MainButton.setText(text);
      tg.MainButton.show();
      tg.MainButton.onClick(onClick);
      return () => tg.MainButton.offClick(onClick);
    },
    [tg],
  );

  const showBackButton = useCallback(
    (onClick: () => void) => {
      if (!tg) return;
      tg.BackButton.show();
      tg.BackButton.onClick(onClick);
      return () => {
        tg.BackButton.offClick(onClick);
        tg.BackButton.hide();
      };
    },
    [tg],
  );

  return { tg, user, showMainButton, showBackButton };
}
// pages/MyPage.tsx
"use client";
import { useEffect } from "react";
import { useTelegram } from "@/hooks/useTelegram";

export default function MyPage() {
  const { tg, user, showBackButton } = useTelegram();

  useEffect(() => {
    return showBackButton?.(() => window.history.back());
  }, [showBackButton]);

  return (
    <main style={{ background: "var(--tg-theme-secondary-bg-color)" }}>
      <h1 style={{ color: "var(--tg-theme-text-color)" }}>
        Hello, {user?.first_name}!
      </h1>
    </main>
  );
}
Next.js Layout Setup
// app/layout.tsx
import Script from "next/script";

export default function RootLayout({ children }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <Script
          src="https://telegram.org/js/telegram-web-app.js"
          strategy="beforeInteractive"
        />
        {children}
      </body>
    </html>
  );
}
suppressHydrationWarning is required because Telegram's script injects style attributes into the DOM during SSR/hydration.

Vue 3 / Nuxt

<!-- composables/useTelegram.ts -->
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from "vue";

const tg = ref<any>(null);
const user = ref<any>(null);

export function useTelegram() {
  onMounted(() => {
    if (window.Telegram?.WebApp) {
      tg.value = window.Telegram.WebApp;
      tg.value.ready();
      tg.value.expand();
      user.value = tg.value.initDataUnsafe?.user || null;
    }
  });

  function showBackButton(onClick: () => void) {
    tg.value?.BackButton.show();
    tg.value?.BackButton.onClick(onClick);
    onUnmounted(() => {
      tg.value?.BackButton.offClick(onClick);
      tg.value?.BackButton.hide();
    });
  }

  return { tg, user, showBackButton };
}
</script>
<!-- pages/MyPage.vue -->
<template>
  <main :style="{ background: 'var(--tg-theme-secondary-bg-color)' }">
    <h1 :style="{ color: 'var(--tg-theme-text-color)' }">
      Hello, {{ user?.first_name }}!
    </h1>
  </main>
</template>

<script setup lang="ts">
import { useTelegram } from "@/composables/useTelegram";
import { useRouter } from "vue-router";

const { user, showBackButton } = useTelegram();
const router = useRouter();

showBackButton(() => router.back());
</script>

Svelte / SvelteKit

<!-- lib/telegram.ts -->
<script context="module" lang="ts">
  export function getTelegram() {
    if (typeof window !== 'undefined' && window.Telegram?.WebApp) {
      return window.Telegram.WebApp;
    }
    return null;
  }
</script>
<!-- routes/+page.svelte -->
<script lang="ts">
  import { onMount, onDestroy } from 'svelte';
  import { getTelegram } from '$lib/telegram';

  let user: any = null;

  onMount(() => {
    const tg = getTelegram();
    if (tg) {
      tg.ready();
      tg.expand();
      user = tg.initDataUnsafe?.user;

      tg.BackButton.show();
      tg.BackButton.onClick(() => history.back());
    }
  });

  onDestroy(() => {
    const tg = getTelegram();
    tg?.BackButton.hide();
  });
</script>

<main style="background: var(--tg-theme-secondary-bg-color); color: var(--tg-theme-text-color);">
  <h1>Hello, {user?.first_name ?? 'User'}!</h1>
</main>
SvelteKit Layout
<!-- src/app.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://telegram.org/js/telegram-web-app.js"></script>
    %sveltekit.head%
  </head>
  <body>
    %sveltekit.body%
  </body>
</html>

16. Design Guidelines

Telegram's official design principles for Mini Apps:

Core Principles

  1. Mobile-First: All elements must be responsive and optimized for mobile viewports
  2. Native Feel: Mimic the style and behavior of existing Telegram UI components
  3. Smooth Animations: Target 60fps for all animations
  4. Accessibility: All inputs and images should have labels
  5. Theme Adaptive: Use Telegram CSS variables for all colors
  6. Safe Area Aware: Respect safe areas, especially in full-screen mode
  7. Performance Conscious: On Android, check User-Agent for device performance class and reduce animations on low-end devices

Recommended UI Patterns

ElementRecommended Style
Page backgroundvar(--tg-theme-secondary-bg-color)
Cards / Sectionsvar(--tg-theme-section-bg-color) with border-radius: 14px
Section labelsUppercase, small font, var(--tg-theme-section-header-text-color)
Hint textSmaller font, var(--tg-theme-hint-color)
Separators1px line with var(--tg-theme-section-separator-color)
Input font size≥ 16px (prevents iOS auto-zoom on focus)
ButtonUse MainButton for primary actions, or custom with var(--tg-theme-button-color)
Destructive actionsvar(--tg-theme-destructive-text-color)
Bottom paddingAdd enough padding to avoid overlap with MainButton (~80px)

17. Testing & Debugging

Development Environment

  1. Run your dev server on localhost
  2. Expose via HTTPS tunnel: ngrok http 3000 (or Cloudflare Tunnel, localtunnel, etc.)
  3. Configure BotFather:

- Create/select your bot - Set the Web App URL via /setmenubutton or /newapp

  1. Open in Telegram and test

Debugging Tips

PlatformMethod
AndroidEnable WebView debugging in Android Developer Settings → chrome://inspect
iOSSafari → Develop → your device → your WebView
DesktopRight-click inside Mini App → "Inspect Element" (on some builds)
Telegram WebRegular browser DevTools

Testing Outside Telegram

Wrap all tg calls with a safety check. Provide fallback UI for development:

const tg = window.Telegram?.WebApp;
const isInTelegram = !!tg?.initData;

if (isInTelegram) {
  tg.ready();
  tg.MainButton.show();
} else {
  // Show a regular HTML button instead for local testing
  console.log("Running outside Telegram — showing fallback UI");
}

18. Common Pitfalls

PitfallSolution
Colors look wrong in TelegramUse --tg-theme-* CSS variables, never hardcode
App stuck on loading spinnerCall tg.ready() after initial render
MainButton not respondingAlways offClick(handler) before registering new handler
iOS zooms in on input focusSet input font-size to ≥ 16px
SSR hydration errors (Next.js, Nuxt)Add suppressHydrationWarning to <html> tag
initData is emptyApp was launched via keyboard button (expected) — handle gracefully
API calls return 403Validate initData correctly on server; check auth_date freshness
Stale state in button handlersUse refs (React) or reactive getters (Vue) — handlers capture closure variables
Content hidden behind MainButtonAdd bottom padding (~80–100px) to main content
Safe area content overlap in fullscreenUse --tg-safe-area-inset-* and --tg-content-safe-area-inset-* CSS variables
window.Telegram is undefinedSDK script not loaded yet — ensure it loads before your app code
Double-click on MainButtonDisable button and show progress immediately on click
Theme not updating dynamicallyListen to themeChanged event; CSS variables update automatically
Clipboard API not workingUse tg.readTextFromClipboard(), not the browser Clipboard API
File download not working on webInclude Content-Disposition and Access-Control-Allow-Origin: https://web.telegram.org response headers

Quick Reference: Useful Methods

const tg = window.Telegram.WebApp;

// Basics
tg.ready(); // Signal app is ready
tg.expand(); // Expand to full height
tg.close(); // Close the Mini App

// User data
tg.initData; // Raw string for server validation
tg.initDataUnsafe.user; // User object (not validated!)

// Navigation
tg.openLink(url); // Open URL in browser
tg.openLink(url, { try_instant_view: true }); // Try Instant View
tg.openTelegramLink(url); // Open telegram link (resolves inside Telegram)

// Sharing
tg.switchInlineQuery(query, ["users", "groups"]); // Switch to inline mode
tg.shareToStory(mediaUrl, params); // Share to Stories

// Clipboard
tg.readTextFromClipboard((text) => {}); // Read clipboard

// QR Code
tg.showScanQrPopup({ text: "Scan QR" }, (data) => {
  // Handle QR data
  return true; // return true to close popup
});
tg.closeScanQrPopup();

// Payments
tg.openInvoice(invoiceUrl, (status) => {
  // status: "paid", "cancelled", "failed", "pending"
});

// Colors
tg.setHeaderColor("#RRGGBB"); // Custom header color
tg.setBackgroundColor("#RRGGBB"); // Custom background color
tg.setBottomBarColor("#RRGGBB"); // Custom bottom bar color

// Permissions
tg.requestWriteAccess((granted) => {}); // Request PM write access
tg.requestContact((shared) => {}); // Request phone contact

// Home screen
tg.addToHomeScreen(); // Prompt add to home screen
tg.checkHomeScreenStatus((status) => {}); // 'added', 'missed', etc.

// Fullscreen
tg.requestFullscreen();
tg.exitFullscreen();

// Closing confirmation
tg.enableClosingConfirmation(); // Warn user before closing
tg.disableClosingConfirmation();

// Send data to bot (limited to 4096 bytes)
tg.sendData(JSON.stringify({ action: "submit" }));

平台分布

Codex

34.84%
按下载量换算33

Claude

29.74%
按下载量换算28

Cursor

16.94%
按下载量换算16

Gemini CLI

10.4%
按下载量换算10

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

可疑

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在提醒或未通过项,安装前请自行复核。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills