This project won the first prize 🥇 at Telegram Lightweight Client Contest and now is an official Telegram client available to anyone at web.telegram.org/a.
According to the original contest rules, it has nearly zero dependencies and is fully based on its own Teact framework (which re-implements React paradigm). It also uses a custom version of GramJS as an MTProto implementation.
The project incorporates lots of technologically advanced features, modern Web APIs and techniques: WebSockets, Web Workers and WebAssembly, multi-level caching and PWA, voice recording and media streaming, cryptography and raw binary data operations, optimistic and progressive interfaces, complicated CSS/Canvas/SVG animations, reactive data streams, and so much more.
Feel free to explore, provide feedback and contribute.
mv .env.example .env
npm iObtain API ID and API hash on my.telegram.org and populate the .env file.
npm run devThis fork is deployed as HSgram Web A. Deployment must keep the runtime MTProto configuration, static files, and browser cache behavior aligned; otherwise the app may load but fail at login, country selection, WebSocket auth, or account switching.
npm ci
npm run check:ts
npm run build:production
git diff --check- Use the package manager from the committed lockfile. This repo currently uses
package-lock.json, so deployment builds should usenpm ci. - Do not upload
node_modules. - Do not change Android/iOS packaging or signing files as part of a Web deploy.
- Build-time CSP must include the HSgram MTProto endpoints. For production
builds, set
HSGRAM_WS_URL,HSGRAM_HTTP_URL, orHSGRAM_HOSTbefore building when the WebSocket is not same-origin.
Example for the current test gateway:
HSGRAM_WS_URL=ws://43.134.228.34:8801/apiws \
HSGRAM_HTTP_URL=http://43.134.228.34:8801/api \
npm run build:productionpublic/web-config.json is copied into dist/web-config.json by
deploy/copy_to_dist.sh. It must be present on the server beside
index.html.
Check these fields before every deploy:
modemust behsgram.apiIdandapiHashmust match the HSgram server expectation.dcOptions[].wssmust point to the HSgram MTProto WebSocket endpoint, for examplews://43.134.228.34:8801/apiwsin the test environment.dcOptions[].httpsmust point to the HSgram HTTP MTProto endpoint if HTTP fallback is enabled.serverPublicKeys[].fingerprintmust match the HSgram server RSA key.- Feature flags must reflect real server support. Do not enable a feature just to show UI if the RPC, storage, and updates are not implemented.
public/hsgram-countries.json is also required for the login country/region
selector. If this file is missing or stale, the login page can lose the selected
country after typing a phone number.
- Deploy the full
dist/directory to the Web static root. Do not deploy onlymain.*.js. - If serving under
/web/, the static server must route/web/*to the deployed files and should fall back unknown SPA routes to/web/index.html. - Serve
web-config.json,hsgram-countries.json,index.html, andversion.txtwithno-storeor a very short cache lifetime. - Hashed assets such as
main.<hash>.js,BundleMain.<hash>.css, wasm files, and emoji image assets can use long immutable cache headers. - If the static root is bind-mounted, restart or reload the static server after
replacing
dist/. A stale mount/inode can keep serving the previous bundle.
Use a cache-busting URL after every deploy:
http://43.134.228.34/web/?v=<deploy-id>
Verify:
index.htmlreferences the newly builtmain.<hash>.js.web-config.jsonreturns the expected HSgram gateway values.- The Network panel has no
telegram.org,web.telegram.org, orapi.telegram.orgrequests. - The browser opens
ws://43.134.228.34:8801/apiwsand receives WebSocket101 Switching Protocols. - Phone login reaches
auth.sendCode, accepts the verification code, and shows dialogs. - Country/region stays selected after typing the phone number and the Next button is enabled.
- Account switching does not mix sessions, cached avatars, dialogs, settings, updates, or default reactions between accounts.
- Group privacy checks still match the server state, especially hidden members and "disable private chat from group member context".
If Safari or mobile browsers keep showing old behavior, clear the site data or
open the cache-busting URL above. Seeing "clearing cache" on startup usually
means the app is migrating local cache; wait for it once, then reload with a new
v= value if the old bundle is still visible.
Start your dev server and locate GramJS worker in the console context.
All constructors and functions available in global GramJs variable.
Run npm run gramjs:tl full to get access to all available Telegram methods.
Example usage:
await invoke(new GramJs.help.GetAppConfig())- GramJS (MIT License)
- fflate (MIT License)
- cryptography (Apache License 2.0)
- emoji-data (MIT License)
- twemoji-parser (MIT License)
- rlottie (MIT License)
- opus-recorder (Various Licenses)
- qr-code-styling (MIT License)
- music-metadata (MIT License)
- lowlight (MIT License)
- idb-keyval (Apache License 2.0)
- fasttextweb
- fastblur
If you find an issue with this app, let Telegram know using the Suggestions Platform.