DEV Community

Cover image for Nuances of Developing a Business App on Telegram Mini Apps: What I Learned About the Platform
Vibe Seeker
Vibe Seeker

Posted on • Edited on

Nuances of Developing a Business App on Telegram Mini Apps: What I Learned About the Platform

The code examples in this series are written in C#/.NET 10 (since that's what our production uses), but this article is about Telegram mechanics, not the language. The exact same architecture can be built on Node.js, Python, or Go without changes. That easily transferable mechanic is exactly why this article was written.

What is this article about? We used "vibe-coding" to build a bridge from Telegram to Google Meet, Zoom, and other video conferencing services. Along the way, we stepped on every possible rake you can hit when developing a business application as a Telegram Mini App. This article contains four practical hacks that you will absolutely need when writing any business app on this platform. Here are some of them:

  • a ready-to-use block of rules for your agent's memory — Telegram web engine constraints plus catalog requirements (copy as is into CLAUDE.md);
  • a "where am I?" function — platform and mode detection, without which every page turns into a guessing game;
  • a tunnel from day one — a trick that turns deploy-for-every-tiny-change into lightning-fast iterations;
  • how to manage state between bot calls, miniapp, and an external browser;
  • a bot that "rings" like a phone;
  • and more;

The Full Series Outline:

  • Part 1 (You are here) — The product's story and an honest verdict on Telegram as a platform for business apps: what's cheap, what's painful, and what you must tell your AI agent before writing the first line of code.
  • Part 2 — The session mechanism: how to pass parameters from an inline bot to a Mini App and read them in an external browser; authentication, feedback loops, and how to avoid bans when editing messages.
  • Part 3 — UX hacks: a bot that "rings" like a real phone, building an onboarding funnel in a single JSON file, and why you must pre-calculate URLs before the user clicks.

How It All Started

Calls in Telegram work great — but strictly as calls: voice, video, hang up. Meetings are a completely different genre, and it's practically non-existent in Telegram. Meanwhile, ecosystems have grown around Google Meet and Zoom: AI summaries, transcriptions, recordings, calendar integrations, and CRM syncs. When a conversation turns to business, you usually want a proper meeting with all these tools.

But the text conversation itself lives in Telegram: that's where your team group is, or the client who finds it "more convenient." Every time a chat matures to a "let's jump on a call" stage, a ritual begins: open Google Meet or Zoom, create a meeting, copy the link, return to the chat, paste it, and explain where to click.

Our idea was brazenly simple: let the bot create the link. Right in the chat, with a single button, using the service available to both me and my counterpart. That's how GoosleeBot was born — a bridge from Telegram to the world of video meetings: Google Meet, Zoom, Microsoft Teams, Jitsi, FaceTime, and others.

What followed was pure vibe-coding: AI agents, prompts, and iterations. The numbers speak for themselves: the first MVP (Google Meet, Zoom, and Jitsi) was ready in two days and proved the idea worked. Then came four weeks of polishing. Here is the crucial part: the main time sink wasn't writing code — AI writes code fast. The time was eaten up by the sheer volume of scenarios we had to cover and manually test: two participants vs. a group, the first call vs. the hundredth, whether the creator has a specific provider connected, iOS vs. Desktop, a private chat vs. an external group. Every combination had to be clicked through in the real Telegram app.

That's why this article isn't a "look how great we are" showcase. It's a list of things I would hardcode into my AI agent's memory before writing the first line of code. Because the main lesson is this: Telegram is an excellent platform for productivity apps, but its web engine is not a standard browser, and the Bot API is not a standard REST backend. If your agent doesn't know this, it will confidently generate beautiful code that simply won't work.

How It Looks to the User

the call starts right in the conversation

provider selection

meeting created, live statuses

the bot is calling

Scenario: in any chat, you trigger the bot and press a button — the bot creates a room with an available provider and places a "Join" button in the chat. If the other person doesn't respond, the bot can "call" them: sending repeated call messages, mimicking a real incoming call (how this is implemented is covered in part three of the series — it's a simple, clever trick).

Neither participant installs anything new. That's the whole premise: distribution through chat is a Telegram feature that no "traditional" platform offers.

Rules to Put in Your Agent's Memory Before Starting

This is the core section of the article. If you vibe-code for Telegram, copy this section directly into your agent's CLAUDE.md or system prompt as is. Every single rule was paid for with hours of debugging "why does this behave differently on iPhone."

Block A. Telegram's Web Engine Is Not a Browser

  1. Never use 100vh. Use only viewportStableHeight / the CSS variable var(--tg-viewport-height) and subscribe to the viewportChanged event. What breaks: on iOS, the bottom of the page slides under the bottom panel; on Android, the keyboard compresses the viewport and breaks the layout.
  2. No window.open or target="\_blank". Use Telegram.WebApp.openLink() for external links and openTelegramLink() for internal ones. What breaks: on some clients, clicking simply does nothing without any error.
  3. No alert, confirm, or prompt. Use only showAlert, showConfirm, or showPopup. What breaks: the same silent failure instead of a modal dialog, happening unpredictably for certain users, which is even harder to debug.
  4. Don't rely on cookies for authentication in miniapps. The Webview loses them unpredictably. Authenticate using an explicitly passed token (in headers or query parameters). What breaks: the user gets logged out between sessions, leaving you searching for a non-existent server bug for a week.
  5. localStorage is a cache, not a database. Store everything important on the server (or in CloudStorage). What breaks: user state suddenly disappears, and you won't even realize it happened.
  6. "Back" navigation must go through Telegram's BackButton, not the browser history. What breaks: the system back button on Android closes the entire miniapp instead of going back one step.
  7. The first thing on every page — figure out where you are: platform and mode (miniapp or standard browser). CSS and logic branch from here. Function provided below.
  8. Everything the user can click must be ready before the click. The standard web flow "click → server processes → builds URL → redirect" doesn't work in Telegram: there are no redirects. The target URL must already be inside the button when it renders — so all redirect logic must be pre-calculated (detailed breakdown in Part 3).
  9. Test on at least three platforms: iOS, Android, Desktop. These are three distinct webviews with different rendering and behavior. "It works on my desktop" counts as zero out of three.

Block B. Catalog Requirements — From Day One, Not "We'll Polish Later"

App catalogs (both Telegram's official directory and third-party miniapp showcases) have strict requirements. Adapting a finished app for them later is the most expensive work in a project. So configure your agent's memory strictly from the start:

  1. Multi-language support from the very first screen. Not a single hardcoded string in the markup — route everything through locale files. The user's language code comes automatically via initDataUnsafe.user.language\_code. Adding a second language to a codebase with hardcoded UI text means rewriting the application.
  2. Theming only via themeParams. All colors must come from --tg-theme-\* CSS variables. Dark and light themes are mandatory, along with subscribing to themeChanged. Never hardcode colors. What breaks: white text on a white background for half your users — and rejection from catalogs.
  3. Catalogs test languages, both themes, and all platforms. These are mandatory release requirements, not optional polish. The agent must consider them part of the Definition of Done for every page.

The "Where Am I?" Function — An Essential First Building Block

In our app, the exact same page opens on iOS, Android, desktop — and sometimes in a regular browser when a user copies a link. CSS and behavior differ in all four cases, so this helper was the very first piece of code we wrote:

function whereAmI() {
  const tg = window.Telegram?.WebApp;
  const inMiniApp = !!tg \&\& tg.initData !== '';   // empty initData = regular browser
  const platform = tg?.platform ?? 'browser';     // ios | android | tdesktop | macos | weba | ...
  const isMobile = platform === 'ios' || platform === 'android';
  return { inMiniApp, platform, isMobile };
}

// then — add class to body and branch behavior
document.body.classList.add(`plt-${platform}`, inMiniApp ? 'in-tg' : 'in-browser');
Enter fullscreen mode Exit fullscreen mode

Where this matters in practice:

  • CSS. Header/footer spacing, iOS safe areas, keyboard behavior on Android — everything attaches to plt-\* CSS classes.
  • Redirects. After Google OAuth authentication, a mobile user should return to Telegram via a tg:// deep link, while a desktop user receives a standard https redirect. Get this wrong, and you end up with either a frozen browser or a user kicked out of the miniapp.
  • Fallback for non-Telegram environments. If initData is empty, it's not a miniapp — so instead of the app, we show an "open via bot" landing page.

A small detail? Sure. But without it, every page turns into a guessing game.

Practical Tip: A Tunnel From Day One

Telegram doesn't work with "localhost": both the bot's webhook and the miniapp URL must be public HTTPS endpoints. That's why your first tool on a project — before the database, before CI — should be a tunneling service: ngrok, cloudflared, Visual Studio dev tunnels, or anything that exposes your local machine to a persistent public URL.

This creates a smooth dev workflow: the bot and miniapp point to the tunnel URL, you edit code locally with hot reload, and test changes immediately in real Telegram on a physical phone. Without a tunnel, every iteration requires a full deployment; with a tunnel, it takes seconds. Remember the endless scenarios that took four weeks? Without a tunnel, that would have taken months.

Verdict: Telegram as a Platform for Productivity Apps

What is cheap — absurdly cheap:

  • Distribution. The product spreads simply by sharing a button in a chat. Zero installations, zero landing pages to launch: the other person sees the button — and instantly becomes a user.
  • Out-of-the-box authentication. Telegram cryptographically signs user data and hands it to the miniapp. No sign-ups, no passwords, no "Log in with Google" needed — you only need to verify the signature correctly (which is covered in detail in Part 2).
  • Inline mechanics. The bot works in any chat, even where it isn't added as a member. That's the essence of the "bridge": the product lives directly inside existing conversations instead of waiting for users to visit a separate app.
  • Real-time features work — and you should use them. We were skeptical whether SignalR (WebSockets) would run smoothly inside Telegram's webview. It did: a full real-time hub with groups runs reliably in production across all platforms. Call status updates land in the miniapp instantly without page reloads. We keep polling fallback as insurance, not as the primary channel. If your agent suggests "let's just poll every second," don't fall for it — WebSocket connections work fine.

What is painful:

  • Client fragmentation. iOS, Android, Desktop, web — four separate Telegram implementations with different webviews. Hence Rule #9 and the "where am I?" function.
  • A web engine with quirks. Everything in Block A above paints its full picture.
  • Catalog guidelines. Multi-language support and themes aren't optional. Anyone who discovers this at the end of development ends up rewriting their UI layout.
  • On a minor note: receiving updates from Telegram toggles with a flag between webhook and polling in our code — super handy for debugging, and that's pretty much all you need to know about that.

Bottom line: if your product is about communication, coordination, or "getting things done without leaving the chat," Telegram gives you a massive head start over traditional platforms. The cost is webview discipline. And that discipline can easily be delegated: just hand your agent the rules from this article.

What's Next in the Series

Part 2 — the subtle mechanics. An inline chat button is shared by all participants and simply opens a URL. How do you pass specific call parameters into the miniapp? How do you verify who clicked it without getting spoofed? How do you send responses back from the miniapp into the chat? Plus a sneaky trap: part of the workflow inevitably leads to an external browser (e.g. Google OAuth) — where miniapp variables don't exist at all, leaving only what you explicitly passed in the URL. I'll share our session mechanism that solves all of this at once — it's not just a parameter-passing hack, but a true server-side session abstraction: a typed key-value store powering the entire call logic. Bonus: how to edit chat messages via an async queue without getting rate-limited by the Bot API.

Part 3 — the tricks. How to make a bot "call" — complete with repeated ring notifications like a real incoming call (spoiler: we delete and re-send the message). Why links must be prepared ahead of time — and this isn't just about pre-generating URLs: in standard web, you click, the server processes the request, generates a link, and redirects — in Telegram, this flow physically doesn't work since there are no redirects, so all redirect workload must be pre-calculated before the click. How to onboard users using a simple JSON file instead of a complex onboarding library: a scripted chat that types, shows slides, and sends funnel metrics to analytics.

---

Try the bridge yourself: @GoosleeBot · gooslibot.com

Top comments (0)