From a Button to Production: How We Build Telegram Mini Apps
Hi! We’re Dima and Ilya, developers on the TMA team at Doubletapp, and in this tutorial, we’ll show you how to build a Telegram Mini App using a React + Python stack.
Telegram Mini Apps are a powerful tool for creating interactive web applications that run directly inside the messenger. They’re perfect for games, marketplaces, booking services, and much more.
In this tutorial, we’ll walk through the process of building a Mini App:
- setting up the project
- building the frontend in React with Telegram SDK integration
- implementing the backend with Python (Django)
- connecting all components and deploying the application.
Who is this guide for?
This guide is aimed at experienced developers who want to build a production-ready Mini App using the React + Python stack. We won’t cover basic concepts like deploying a standard web app on this stack — instead, we’ll focus on building a fully functional, optimized, and secure solution.
Purpose of the article
Our goal is not just to walk through the theory, but to guide you through the entire development process — from setting up the environment to deploying a working application. This guide will help you avoid common pitfalls and significantly speed up your development.
Key concepts and terminology
In this section, we’ll explain what Telegram Mini Apps are, what capabilities they offer to developers and users, and how they differ from traditional Telegram bots. Understanding these distinctions will help you decide when Mini Apps are a better solution for your project.
What are Telegram Mini Apps?
Telegram Mini Apps (TMAs) are web applications that run inside Telegram, allowing users to interact with services without installing separate mobile apps. They work within Telegram’s built-in browser and provide seamless authorization, a smooth user experience, and deep integration with the messenger. TMAs are supported across all major platforms: Android, iOS, Windows, macOS, and Linux.
Mini Apps use standard web technologies such as HTML, CSS, and JavaScript, and communicate with Telegram through the Web Apps API. This enables developers to build flexible interfaces, access user data (e.g., name and contact information), and interact via bots.
In short, Mini Apps are a powerful way to create interactive services that run directly in Telegram, simplifying user interactions with digital products.
How are Mini Apps different from regular bots?
While both Telegram Mini Apps and bots operate within the messenger, they have different interaction models and use cases.
1. Interface and user experience
Telegram bots interact with users through text commands and inline buttons. Their interface is limited by the capabilities of the messenger.
Mini Apps, on the other hand, offer a full graphical interface, enabling rich and interactive web applications directly inside Telegram.
2. Technical implementation
Bots operate through the Telegram Bot API, which manages messages, commands, and buttons.
Mini Apps use the Web Apps API, which allows launching web applications that communicate with Telegram via JavaScript.
3. Use cases
Bots are typically used for task automation, sending broadcasts, customer support, and basic chatbot workflows.
Mini Apps are better suited for more complex services such as e-commerce and delivery platforms, fintech and payment applications, games and entertainment services, CRMs, and business tools.
In essence, Mini Apps extend the functionality of bots, providing a more flexible and user-friendly experience within Telegram.
Preparing for development
Before building a Telegram Mini App, it’s important to properly set up your environment and define the project’s architectural foundation. In this section, we’ll walk through each preparation step:
- configure a local environment for isolated and convenient development
- organize the project as a monorepo to manage frontend and backend in a single repository
- create a Telegram bot that will be used to launch the Mini App
- initialize a frontend application using Vite + React
- set up Docker to unify the development and production environments
- use proxy tools for seamless Mini App testing
- configure Nginx
- implement user authentication via Init Data
- connect the Telegram Web Apps SDK (@telegram-apps/sdk-react)
Setting up the local environment
The first step is to prepare a complete local environment that runs both the frontend and the backend simultaneously. This is critical not only for testing application logic, but also for ensuring proper authentication through Telegram.
To isolate the environment and streamline the launch of all components, we’ll use Docker — this allows you to standardize the setup on both local machines and production servers, eliminating the need for manual configuration.
One key aspect of Mini Apps is that user authentication is handled via Init Data validation using a specific Telegram bot token. This means the backend must verify the Init Data signature against the token of the bot used to launch the Mini App.
As a result, each developer needs to create their own Telegram bot and use its token during local development. Even frontend developers must run a local backend to enable full authentication and test app behavior in production-like conditions.
We also use a monorepo approach for our projects: both frontend and backend live in the same repository but are split into separate folders (/frontend, /backend). This structure significantly simplifies:
- collaborative development
- CI/CD configuration
- API version synchronization
- making coordinated changes
- centralized dependency and config management
This approach is particularly effective for Mini Apps, where the frontend and backend are tightly coupled.
Creating a bot
A Telegram Mini App is launched via a Telegram bot. The bot acts as an entry point that allows users to open a web application inside the messenger. Therefore, having a properly configured bot is a prerequisite for running a Mini App.
If you don’t have a bot yet, you can create one using @BotFather. We won’t go into detail here, as the process is standard and well-documented in the official Telegram documentation.
Here’s what you need to do:
- Obtain the bot token.
- Set the Mini App URL.
In a conversation with @BotFather, navigate to:
Bot Settings → Configure Mini App → Edit Mini App URL - Configure the Mini App launch button.
For better usability, you can add a button that opens the Mini App directly. Do this via @BotFather:
Bot Settings → Edit Menu Button
Creating a user on first interaction
In a Mini App, it’s essential that a user is created in your database on any interaction with the bot — not just when the /start command is triggered. Telegram includes the from object (representing the user) in nearly all update types, which makes it possible to handle user creation in a centralized way.
We’ll implement middleware that:
- extracts Telegram user data from any incoming update
- creates a user in the database if they’re not already registered
- stores the user in the request context, making them easily accessible in the rest of the logic.
import typing
import structlog
from dependency_injector.wiring import Provide
from dependency_injector.wiring import inject
from telegram import Update
from telegram.ext import CallbackContext
from project.containers import Container
if typing.TYPE_CHECKING:
from users.services import UserService
logger = structlog.get_logger(__name__)
@inject
def update_or_create_user(
update: Update,
context: CallbackContext,
user_service: 'UserService' = Provide[Container.user_service],
) -> None:
if update.message is None:
return
tg_user = update.message.from_user
if not tg_user:
logger.debug('No Telegram user found in the update message')
return
user, created = user_service.update_or_create(tg_user)
structlog.contextvars.bind_contextvars(
user_id=user.id,
messenger_user_id=update.message.from_user.id,
)
if created:
logger.info('New user created')
context.user_data['user'] = userDone! Now, in every handler, we’ll have access to the current user.
Once the bot is configured, we can move on to the next step — creating the frontend application that will run inside Telegram.
Initializing the React application
We’ve previously described how to set up a standard React app. In this article, we’ll focus on the specifics of building a TMA project. The configuration of a Telegram Mini App project includes a dedicated initialization function.
import { retrieveLaunchParams } from '@telegram-apps/sdk-react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import 'config/i18n/i18n.ts'
import { init } from './utils/init.ts'
const root = ReactDOM.createRoot(document.getElementById('root')!)
try {
// Configure all application dependencies.
init(retrieveLaunchParams().startParam === 'debug' || import.meta.env.DEV)
root.render(<App />)
} catch (e) {
console.error(e)The Mini App initialization takes place before rendering the React application.
import {
backButton,
viewport,
themeParams,
miniApp,
initData,
$debug,
init as initSDK
} from '@telegram-apps/sdk-react'
export function init(debug: boolean): void {
$debug.set(debug)
initSDK()
if (!backButton.isSupported() || !miniApp.isSupported()) {
throw new Error('ERR_NOT_SUPPORTED')
}
backButton.mount()
miniApp.mount()
themeParams.mount()
initData.restore()
void viewport
.mount()
.catch(e => {
console.error('Something went wrong mounting the viewport', e)
})
.then(() => {
viewport.bindCssVars()
})
miniApp.bindCssVars()
themeParams.bindCssVars()
}In this project, we used version 2 of the @telegram-apps/sdk-react package. The SDK is not initialized by default — all of its components remain unmounted. To start using the SDK and access its components (such as the back button, mini app object, theme parameters, viewport, and others), we need to call the init function first. Only after that can we safely use its features throughout the application.
Docker setup
Since our project follows a monorepo structure, we use a dedicated Docker configuration for local development. This setup supports hot reload, which is essential for frontend development.
For the development environment, we added a special docker-compose.local.yml configuration. It includes:
- an additional Vite service running the frontend in development mode
- a modified Nginx config that proxies requests to the Vite service
services:
...
vite:
build:
context: .
dockerfile: ./docker/vite/Dockerfile
args:
API_BASE_URL: ${API_BASE_URL}
volumes:
- ./frontend:/app
- /app/node_modules
restart: always
ports:
- "5173:5173"
nginx:
image: "${IMAGE_NGINX}"
build:
context: .
dockerfile: docker/nginx-local/Dockerfile
...Docker-compose.local.yml
http {
...
server {
...
location / {
proxy_pass http://vite:5173;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
}nginx.conf
The Vite application is launched in development mode as follows:
FROM node:21-alpine as build
ARG API_BASE_URL
ENV VITE_API_BASE_URL=$API_BASE_URL
WORKDIR /app
COPY frontend/package*.json ./
RUN npm install
COPY ./frontend .
EXPOSE 5173
CMD ["npm", "run", "start", "--", "--host", "0.0.0.0"]Frontend proxy tools
During development, Telegram Mini Apps require a valid public URL to render and test the app inside the Telegram client. Localhost URLs are incompatible with BotFather’s Mini App settings due to Telegram’s strict requirement for HTTPS.
To bridge this gap, developers typically use services that expose local applications to the internet via secure tunnels.
We’ve tried a few tools in our work:
- ngrok — works only with a VPN in some regions. It offers a free plan with limitations, including one static domain, 20,000 HTTP requests per month, and 1 GB of outbound traffic. When limits are reached, you can create a new account.
- localtunnel — a completely free alternative to ngrok, providing similar functionality. Easily installable via npm (npm install -g localtunnel). In our experience, it sometimes required frequent restarts, which also meant constantly updating the Mini App URL in BotFather and in environment variables.
- Tuna — a paid solution available in Russia. It allows you to generate multiple domains and has proven to be stable in our usage.
User authentication via Init Data
One of the key aspects of Telegram Mini App development is user authentication. Telegram provides a mechanism for securely passing user data through Init Data, which can be used to identify and verify users. However, it’s important for developers to validate this data correctly and to consider third-party integrations when necessary.
Verifying Init Data from TMA
When a Mini App is launched, the client stores Init Data in the browser’s Telegram.WebApp.initData object. (If the app is launched via a keyboard button or inline mode, the object may be empty.)
Init Data is passed as a string containing parameters such as user info (user), a hash (hash), authentication timestamp (auth_date), and others. You can find a full description of this object in the official documentation.
The Init Data should be sent in the HTTP headers of each request. The backend is then responsible for validating the authenticity of the data and implementing the authentication/authorization mechanism. The verification process includes the following steps:
- Extract parameters: Parse the Init Data string to obtain the individual key-value pairs.
- Compute the verification signature:
- Exclude the hash field.
- Sort the remaining parameters alphabetically and concatenate them in the form key=value.
- Compute an HMAC-SHA256 hash using a secret key derived from the bot token.
3. Compare signatures:
- If the computed hash matches the provided hash, the data is considered valid.
4. Validate auth_date:
- If the timestamp is too old (e.g., older than a few hours), the data should be considered expired.
You can find a detailed explanation of this algorithm in the Telegram docs.
To simplify working with Init Data in TMAs, we developed a small internal library at our company. It helps implement the authentication and authorization mechanism on the backend with minimal effort.
Django example
Let’s take a look at an example implementation in Django. We’ll create middleware for user authentication that will:
- validate the Init Data signature
- extract user information (ID, name, username, etc.)
- and — most importantly — create a new user in the database if they don’t already exist
This step is essential because a Mini App can be opened not only via the /start command in the bot, but also directly via a link. In such cases, the user lands straight in the frontend, bypassing any initial setup logic on the bot’s side.
We’ll start by defining the necessary variables in settings.py
from telegram_webapp_auth.auth import generate_secret_key
# other settings…
TELEGRAM_BOT_TOKEN = env.str('TELEGRAM_BOT_TOKEN')
TELEGRAM_SECRET_KEY = generate_secret_key(TELEGRAM_BOT_TOKEN)Implementing the Middleware:
from django.conf import settings
from django.http import HttpRequest
from django.http import HttpResponse
from telegram_webapp_auth.auth import TelegramAuthenticator
from telegram_webapp_auth.errors import InvalidInitDataError
from users.services import UserService
class TMAAuthorizationMiddleware:
def __init__(self, get_response) -> None:
self.get_response = get_response
self._telegram_authenticator = TelegramAuthenticator(settings.TELEGRAM_SECRET_KEY)
self._user_service = UserService()
def __call__(self, request: HttpRequest) -> HttpResponse:
auth_cred = request.headers.get('Authorization')
try:
init_data = self._telegram_authenticator.validate(auth_cred)
except InvalidInitDataError:
# TODO: handle exception ExpiredInitDataError
# TODO: handle case if Init Data is invalid
pass
if not init_data.user:
# TODO: handle case if Init Data does not contain user information
pass
current_user = self._user_service.update_or_create(init_data.user)
request.user = current_user # add user to request object
response = self.get_response(request)
return response
Add the created middleware to the MIDDLEWARE settings in settings.py:
MIDDLEWARE = [
# other middlewares
'path.to.TMAAuthorizationMiddleware',
]Done! We can now authenticate our user from the TMA.
Verifying Third-Party Data
Telegram also introduced a feature for validating Init Data from a third-party bot. To do this, you only need the ID of the desired bot. This is useful when you want to integrate between the backends of different bots.
The integrity of the data can be verified using the signature parameter, which is a base64url-encoded Ed25519 signature. The verification is done using the public key provided by Telegram.
This algorithm is also implemented in our internal library.
Exchanging Init Data for a JWT
Some developers prefer to exchange Init Data for a JWT token after the initial initialization. The process looks like this:
- The frontend sends Init Data to the backend.
- The backend validates it and generates a JWT.
- The JWT is returned to the client and stored (e.g., in localStorage).
- All subsequent frontend requests use this token.
Pros:
- Allows flexible session expiration management
- Versatile — you can pass custom data inside the token
- Cross-domain — suitable for microservices
Cons:
- localStorage may not persist in Telegram Mini Apps: On certain platforms (iOS, Linux Desktop), Telegram WebView is sandboxed. Restarting the Mini App can clear the cache and storage. Unfortunately, there’s no workaround for this.
- Losing the token means re-authentication, leading to extra requests
Because Telegram apps don’t always persist localStorage, we prefer using Init Data-based authentication for simpler projects. It’s secure, straightforward, and doesn’t rely on WebView behavior.
Integrating the Telegram React SDK
The @telegram-apps/sdk-react package provides a set of components and methods that allow developers to interact seamlessly with Telegram’s native UI elements and platform features.
SDK Capabilities Overview
A few examples:
BackButton — probably the most commonly used component, manages the “Back” button in the Mini App’s header. Its main purpose is to aid app navigation, but note: the click event must be handled manually, as it doesn’t trigger any default actions. We created a custom hook to simplify using this button:
import { backButton } from '@telegram-apps/sdk-react'
import { useEffect } from 'react'
export const useAppBackButton = (handler: () => void) => {
useEffect(() => {
backButton.onClick(handler)
return () => {
backButton.offClick(handler)
}
}, [backButton])
return {
isVisible: backButton.isVisible,
showButton: backButton.show.bind(backButton),
hideButton: backButton.hide.bind(backButton)
}
}Viewport gives access to the Mini App’s display state within the Telegram client. It provides useful properties like width, height, isStable (whether a resize is expected), isExpanded, and fullscreen mode status. You can programmatically expand the app using:
if (viewport.expand.isAvailable()) {
viewport.expand()
}or request fullscreen mode:
if (viewport.requestFullscreen.isAvailable()) {
await viewport.requestFullscreen();
}which is particularly useful for games or media apps. The viewport also exposes some CSS variables:
if (viewport.bindCssVars.isAvailable()) {
viewport.bindCssVars();
// Creates CSS variables:
// --tg-viewport-height: 675px
// --tg-viewport-width: 320px
// --tg-viewport-stable-height: 675px
}ThemeParams enables the app to adapt its styles to the user’s current Telegram theme. Calling bindCssVars() makes CSS variables available:
if (themeParams.bindCssVars.isAvailable()) {
themeParams.bindCssVars();
// Creates CSS variables:
// --tg-theme-button-color: #aabbcc
// --tg-theme-accent-text-color: #aabbcc
// --tg-theme-bg-color: #aabbcc
// ...
}This helps the Mini App feel more native and integrated with the platform.
The miniApp object allows setting the Mini App’s header and background colors:
if (
miniApp.setHeaderColor.isAvailable()
&& miniApp.setHeaderColor.supports('rgb')
) {
miniApp.setHeaderColor('#aabbcc');
miniApp.headerColor(); // '#aabbcc'
}if (miniApp.setBackgroundColor.isAvailable()) {
miniApp.setBackgroundColor('#ffffff');
miniApp.backgroundColor(); // '#ffffff'
}It also has close() and ready() methods — the former closes the app, while the latter notifies Telegram that your web app is initialized and ready to be displayed.
Telegram provides a hapticFeedback API for device vibration. The impactOccurred() method supports various styles like light, medium, heavy, rigid, and soft. This can significantly improve the app’s UX:
if (hapticFeedback.impactOccurred.isAvailable()) {
hapticFeedback.impactOccurred('medium');
}The swipeBehavior object lets you control whether the Mini App can be dismissed via swipe gesture. If your app uses vertical scrolling, it’s better to disable this gesture:
if (swipeBehavior.disableVertical.isAvailable()) {
swipeBehavior.disableVertical()
}There are also other native components available in the SDK — such as popup, mainButton, settingsButton, qrScanner, and more — that help deliver a native-like experience in your Mini App.
Key SDK Features and Init Data Authorization
Client-side request authorization in our app is performed using the initDataRaw object from the retrieveLaunchParams method:
const { initDataRaw } = retrieveLaunchParams()
export const http = axios.create({
baseURL: appConfig.api.baseUrl,
headers: {
Authorization: initDataRaw,
'Content-Type': 'application/json'
}
})Testing and Debugging
Before launching your Mini App to production, it’s essential to ensure stable and predictable behavior across all layers — from backend logic to the Telegram UI. Since Mini Apps operate in an environment where frontend and backend are tightly coupled — and behavior can vary across platforms (Android, iOS, Desktop, Web) — debugging requires a specific approach.
In this section, we’ll cover:
- how to effectively debug the backend, even when Init Data isn’t available yet
- how to test the Mini App across various devices to ensure SDK functionality, responsive design, and behavioral consistency
Backend Debugging
Debugging the API effectively is crucial when developing a Telegram Mini App. Telegram passes a special Init Data parameter to the Mini App, which is used to authenticate the user on the server. However, during development, using this directly is inconvenient:
- Init Data can only be retrieved from a running frontend within Telegram
- You have to manually copy it each time — which slows down development and debugging
To speed up local API development, it’s helpful to implement an alternate dev-only authorization mode where you can pass user_id directly, bypassing Init Data.
How to implement it:
- In your middleware, check if development mode is enabled (e.g., via settings.DEBUG)
- If the X-Dev-User-ID header is present in the request — use that instead of Init Data
- Find or create the user by this ID and assign them to request.user
Example middleware:
from django.conf import settings
from django.http import HttpRequest
from django.http import HttpResponse
from users.services import UserService
class DevAuthMiddleware:
def __init__(self, get_response) -> None:
self.get_response = get_response
self._user_service = UserService()
def __call__(self, request: HttpRequest) -> HttpResponse:
auth_cred = request.headers.get('X-Dev-User-ID')
if settings.DEBUG and auth_cred:
user, _ = user_service.get_or_create(user_id=auth_cred)
request.user = user
return self.get_response(request)Now you can use Postman, cURL, or Swagger UI to send requests by simply providing the user ID.
Cross-Device Testing
For Android, the main debugging interface is Chrome DevTools, which can be accessed via chrome://inspect/#devices in a Chrome browser on a connected machine. This tool lets you inspect DOM elements, monitor network activity, view console logs, and more.
For the iOS Telegram client, Safari’s Web Inspector on macOS provides similar debugging capabilities. After connecting your iOS device to a Mac, you can use the “Develop” menu in Safari to inspect the app’s WebView with functionality similar to Chrome DevTools.
In situations where platform-specific debugging tools aren’t available — especially for iOS devices without access to a Mac — the eruda npm package offers a lightweight in-app debugging alternative. Eruda is a simple web console you can embed directly into your Mini App. After adding the library to your project, initialize it using eruda.init(). Once deployed, the app UI will display an Eruda icon. Clicking it opens the console, enabling basic debugging tools like logging, DOM inspection, and network monitoring.
Production Deployment
Once development is complete, it’s time to deploy the Mini App to production. In this section, we’ll cover core best practices for deployment, security, performance, and ensuring your Telegram Mini App runs reliably in production — most of which also apply to general web development.
General Production Recommendations
- Isolate environments: Local dev, staging, and production should be completely separated to avoid unintended interactions.
- Monitor logs and errors using tools like Sentry, Prometheus + Grafana + Loki, or similar observability stacks.
- Use Webhook mode for your Telegram bot in production:
◦ It’s more efficient
◦ It has lower latency (updates arrive instantly)
◦ It scales more easily
Security Recommendations
- Limit the lifetime of Init Data — never issue long-lived tokens
- Restrict access to admin interfaces — via IP allowlists, VPN, or secure authentication
- Limit CORS and CSP sources — to Telegram WebView, your domain, and required APIs
- Keep dependencies up-to-date and monitor for CVE vulnerabilities
- Protect against DDoS attacks — bad actors never sleep
- Set rate limits on all API endpoints — don’t let clients overload your server
Static Asset Caching and Compression
- Minify and hash JS/CSS — saves bandwidth and improves load times
- Enable Gzip or Brotli compression — further reduces asset size
Backend API Caching
To improve response times and reduce backend load:
- Cache public and frequently repeated GET requests — and ensure they are idempotent
- Use Redis or Memcached to cache the requests
- Enable Cache-Control headers and leverage browser caching
Case Studies
Here are a few real-world projects we’ve delivered using Telegram Mini Apps — from games to e-commerce and service platforms:
- Doubletapalka — We designed the mechanics, built the economy model, and handled everything from UI/UX to backend logic. The result: a fast-paced game with monetization potential.
- Merch Store — A fully functional e-commerce experience inside Telegram, complete with native payments via credit cards and cryptocurrency. We handled the design, frontend, and backend.
- Car Rental Service — We created a clean, UX-focused interface for booking vehicles directly within a Mini App. Emphasis was on intuitive booking flow and visual clarity.
- CryptoFlow — A card-based decision game in the style of Reigns. Includes swipe mechanics, story saving, achievements, collectible cards, and in-app purchases using Telegram Stars. We built both the frontend and backend.
Conclusion
Telegram Mini Apps are a powerful tool for building fully functional web applications inside the messenger. In this guide, we walked through the key steps needed to create a production-ready solution.
Quick Recap
- We explored what Mini Apps are and how they differ from traditional bots
- Set up the development environment using Docker, Nginx, and a monorepo
- Created and configured a bot to work with a Mini App
- Implemented authorization via Init Data and user registration
- Configured the frontend with Vite and the backend with Django
- Covered debugging, testing, and production deployment best practices
If you’ve made it this far — you now have everything you need to launch your own Telegram Mini App.
Good luck in production! 🚀
Want to integrate a Telegram Mini App into your business?
If you see the potential in TMAs and want to use them strategically, we’re here to help. Our team builds solutions that drive results — from intuitive interfaces to deep integration with your business processes.
Let’s talk — email us at hi@doubletapp.ai or reach out via our Telegram bot.
It all starts with a short conversation. We’ll take care of the rest.
Additional Resources
Read our other stories:
- How to Remember and Not Forget: Implementing and Automating the Spaced Repetition System
- Frontend Application Architecture in React (No FSD Needed)
- Has AI already taken over the world?
- Doubletapp Meeting Notes
- How to communicate with a knowledge base in natural language: using LLM to create such a system and evaluating its performance
- University International Sports Festival: Website for the festival
- Mobile Application for Exams (NDA)
- IT-Regatta Identity
- Branding for the Data Science Kazakhstan Community
- Agency Growth Day: Event Website for Alto
- How We Implement JWT Authentication
- MOBILE APP TESTING — PROCESS DETAILS
- DNS for beginners: what is it, how does it work, and what is it for?
- Cross-platform Mobile App Development — Pros and Cons
- Stages of Design Process
- Storing Resources Wisely: How to Organize Resources in a Multi-Module Project
- They Will Make You Hate It: Getting to Know VAST and VPAID, or How to Integrate Ads into a Web Video Player
- The Role of QA in Product Security Testing
- Overview of Monitoring System with Prometheus and Grafana
- “External” navigation in a multi-module project in Kotlin
- Parsing responses to BLE commands in Swift using the example of GoPro
- What Is Happening With The Mobile App Market
- Yandex Travel
- Case Ural Music Night
- Player’s Health Protect
- DJU Drone Club
- Case Alibra School
- Case Praktika
- Case Watchmen
- Case Adventure Aide
- Neural Network Optimization: Ocean in a Drop
- Case Elixir Gallery
- Forgive us, John Connor, or How We Taught a Neural Network to Accurately Recognize Gunshots
- Case Bus Factor
- CI/CD for iOS-projects: device or cloud? What’s better, Doubletapp’s take
- How to set up Gitlab CI/CD with Fastlane for iOS-project on a Mac mini
- The story about the contest from telegram
- What should be done before starting the site? Checklist from Doubletapp
- How to Generate PDF Documents in Python
- How to manage Gradle dependencies in an Android project properly
- The History of the Doubletapp Company
