Skip to main content
The TGAuth Web SDK gives you one-tap Telegram authentication in any JavaScript environment — whether you load it from a CDN or import it as an npm module. You create a TGAuth instance with your project ID, call signIn() or mount(), and the SDK handles the complete authentication flow — from opening Telegram to delivering a verified user object — for you.

Loading the SDK

Choose the installation method that fits your project.
Install the package from npm:
npm install @bondify/web
Then import it in your module:
import TGAuth from '@bondify/web';

Constructor

Instantiate a TGAuth client by passing a configuration object. Only projectId is required.
const client = new TGAuth({
  projectId: 'proj_xxxxxxxx',           // required
  apiBase: 'https://tgauth-backend.onrender.com', // optional — default shown
  pollInterval: 2000,                   // optional — ms between status polls
  sessionTimeout: 600000,              // optional — ms until session times out
});
projectId
string
required
Your Bondify project ID. Find this in the dashboard under Projects.
apiBase
string
Override the API base URL. Defaults to https://tgauth-backend.onrender.com. You only need this if you are self-hosting Bondify on the Business plan.
pollInterval
number
Milliseconds between each status poll while waiting for the user to confirm in Telegram. Defaults to 2000 (2 seconds).
sessionTimeout
number
Milliseconds before the client-side polling loop gives up and throws a TIMEOUT error. Defaults to 600000 (10 minutes).

Methods

client.signIn()Promise<User>

Runs the complete authentication flow: creates a session on the server, opens Telegram via a deeplink, then polls for confirmation. Returns a Promise that resolves to the authenticated user object.
try {
  const user = await client.signIn();

  // user.telegramId    — string  — the user's Telegram ID
  // user.name          — string  — the user's display name
  // user.username      — string | null — @handle, or null if not set
  // user.proof         — string  — verify this on your server!
  // user.sessionToken  — string  — the session identifier

  sendProofToYourServer(user.proof);
} catch (err) {
  if (err.code === 'CANCELLED') console.log('User cancelled the login');
  if (err.code === 'EXPIRED')   console.log('Session expired before confirmation');
  if (err.code === 'TIMEOUT')   console.log('Client polling timed out');
}
Always call signIn() from within a user gesture — a button click handler. If you call it from useEffect, a timer, or any context outside a direct user interaction, most browsers will block the Telegram popup.

client.mount(target, options)unmount()

Injects a fully styled, interactive Telegram auth button into a DOM element. Handles loading states, status messages, and error display automatically. Returns an unmount function you can call to remove the button.
const unmount = client.mount('#login-container', {
  theme: 'dark',
  text: 'Continue with Telegram',
  onSuccess: (user) => {
    sendProofToYourServer(user.proof);
  },
  onError: (err) => {
    console.error('Auth failed:', err.message);
  },
});

// Later — remove the button and clean up event listeners:
unmount();
target
string | Element
required
A CSS selector string (e.g. '#login-container') or a DOM Element to inject the button into.
options.theme
string
Button colour scheme. Pass "light" for a white button with a blue border, or "dark" for a dark navy background. Defaults to the standard Telegram blue.
options.text
string
Custom button label. Defaults to "Sign in with Telegram".
options.onSuccess
function
Called with the resolved User object after successful authentication. Receives the same user shape as signIn().
options.onError
function
Called with a TGAuthError if the flow fails or is cancelled. Check err.code for the reason.

Static helpers

For simple use cases, you can skip instantiation entirely and use the static one-liner methods.
// One-liner: start the full auth flow
const user = await TGAuth.signIn({ projectId: 'proj_xxxxxxxx' });

// One-liner: render a button into a container
const unmount = TGAuth.renderButton('#container', {
  projectId: 'proj_xxxxxxxx',
  theme: 'dark',
  onSuccess: (user) => console.log('Logged in as', user.name),
});
Both static methods construct a TGAuth instance internally using the options you provide and then call the appropriate instance method. Two additional static properties are available on the TGAuth constructor:
TGAuth.Error
class
The TGAuthError class. Use this to instanceof-check caught errors: if (err instanceof TGAuth.Error).
TGAuth.version
string
The SDK version string, e.g. '1.0.0'. Useful for debugging and support.

Error codes

Every error thrown by the SDK is a TGAuthError instance with a code property. Use it to branch your error-handling logic.
CodeWhen it occurs
CANCELLEDThe user tapped ❌ Cancel in the Telegram bot message
EXPIREDThe session was not confirmed within the sessionTimeout window (default: 10 min)
TIMEOUTThe client-side polling loop reached the sessionTimeout deadline without a terminal status
Differentiate CANCELLED from EXPIRED in your UI. A cancelled flow means the user actively declined — show a neutral prompt. An expired flow likely means the user never opened Telegram — prompt them to try again.

Widget embed (no-build)

For pages where you cannot run JavaScript build steps — landing pages, CMS templates, plain HTML files — the TGAuth Widget script auto-mounts authentication buttons from HTML data attributes. Drop a single <script> tag on the page and annotate your container element; no JavaScript is required to wire it up.
<!-- 1. Load the widget script once, anywhere on the page -->
<script src="https://tgauth-backend.onrender.com/cdn/v1/widget.js" async defer></script>

<!-- 2. Drop a button container wherever you need it -->
<div class="tgauth-button"
     data-project-id="proj_xxxxxxxx"
     data-theme="dark"
     data-text="Continue with Telegram"
     data-callback="onTelegramLogin">
</div>

<script>
  function onTelegramLogin(user) {
    // user.telegramId, user.name, user.username, user.proof, user.sessionToken
    fetch('/api/auth', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ proof: user.proof }),
    });
  }
</script>

Widget data attributes

data-project-id
string
required
Your Bondify project ID. Required — the widget logs a warning and skips mounting if this attribute is absent.
data-api-base
string
Override the API base URL (mirrors the apiBase constructor option). Omit for the default.
data-theme
string
Button colour scheme: "light" or "dark". Omit for the default Telegram blue.
data-text
string
Custom button label. Defaults to "Sign in with Telegram".
data-callback
string
Name of a global function to call on success. Receives the user object as its only argument. If omitted, the widget dispatches a tgauth:success Custom Event instead.
data-on-error
string
Name of a global function to call on error. Receives the TGAuthError as its only argument. If omitted, the widget dispatches a tgauth:error Custom Event instead.
data-submit-to
string
URL to POST the user object to on success. The widget sends Content-Type: application/json.
data-redirect-to
string
URL to navigate to after a successful data-submit-to POST. Only used in combination with data-submit-to.

Widget Custom Events

Both events bubble up the DOM (bubbles: true) and carry the payload on event.detail.
Eventevent.detailWhen fired
tgauth:successUser object (telegramId, name, username, proof, sessionToken)Authentication succeeded
tgauth:errorTGAuthError instanceAuthentication failed or was cancelled
The widget uses a MutationObserver to watch for buttons added dynamically to the DOM after page load, so you can insert widget markup at any time. You can also call window.TGAuthWidget.mountAll() to trigger mounting manually.

Complete example

The following example shows a minimal integration using the CDN build.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Bondify Login</title>
  <script src="https://tgauth-backend.onrender.com/cdn/v1/tgauth.min.js"></script>
</head>
<body>
  <div id="login-container"></div>

  <script>
    const client = new TGAuth({ projectId: 'proj_xxxxxxxx' });

    client.mount('#login-container', {
      theme: 'dark',
      text: 'Continue with Telegram',
      onSuccess: async (user) => {
        // Send the proof to your backend for verification
        const res = await fetch('/api/auth', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ proof: user.proof }),
        });
        if (res.ok) window.location.href = '/dashboard';
      },
      onError: (err) => {
        if (err.code !== 'CANCELLED') {
          alert('Sign-in failed: ' + err.message);
        }
      },
    });
  </script>
</body>
</html>