Skip to main content
The @bondify/react package gives you idiomatic React primitives for Telegram authentication — a context provider, a drop-in button component, and a hook that exposes auth state and actions anywhere in your component tree. You wrap your app in <PulseProvider>, drop in <PulseButton> where you want the login UI, and access the resulting user session via usePulse().

Installation

npm install @bondify/react

<PulseProvider>

PulseProvider is the context provider that supplies your Bondify project configuration to every component and hook below it in the tree. Place it near the root of your app — or around just the pages that require authentication.
import { PulseProvider } from '@bondify/react';

export default function App({ Component, pageProps }) {
  return (
    <PulseProvider projectId="proj_xxxxxxxx">
      <Component {...pageProps} />
    </PulseProvider>
  );
}

Props

projectId
string
required
Your Bondify project ID from the dashboard. All SDK calls inside this provider use this ID to identify your project.
Every <PulseButton> and every usePulse() call must be rendered inside a <PulseProvider>. Rendering either outside the provider will throw a runtime error.

<PulseButton>

PulseButton is a pre-styled, self-contained authentication button. It handles the full auth flow internally — loading state, Telegram deeplink, status confirmation, and callbacks — so you only need to handle the result.
import { PulseButton } from '@bondify/react';

function LoginPage() {
  return (
    <PulseButton
      onSuccess={(user) => {
        // Send the proof to your server before trusting the login
        sendProofToServer(user.proof);
      }}
      onError={(err) => {
        if (err.code !== 'CANCELLED') {
          console.error('Auth error:', err.message);
        }
      }}
      text="Continue with Telegram"
      theme="dark"
    />
  );
}

Props

onSuccess
function
Called with the resolved User object when authentication succeeds. The user object contains:
  • telegramId — the user’s Telegram ID
  • name — the user’s display name
  • username — the user’s @handle, or null if not set
  • proof — the signed session proof (verify this on your server)
  • channel — the authentication channel, e.g. "telegram"
onError
function
Called with a TGAuthError on failure. Inspect err.code — possible values are CANCELLED, EXPIRED, and TIMEOUT.
text
string
Custom label for the button. Defaults to "Sign in with Telegram".
theme
string
Visual theme for the button. Accepts "light" (white background, blue border) or "dark" (dark navy background). Defaults to the standard Telegram blue.
Always send user.proof to your backend and call verifyProof() before creating a session, cookie, or JWT. Never trust the client-side isAuthenticated state alone.

usePulse() hook

The usePulse() hook gives you access to the current auth state and the signIn / signOut actions from any component inside <PulseProvider>. Use it to build custom auth UI, protect routes, or personalise content.
import { usePulse } from '@bondify/react';

function ProfileButton() {
  const { user, isAuthenticated, signIn, signOut } = usePulse();

  if (isAuthenticated) {
    return (
      <button onClick={signOut}>
        Sign out ({user.name})
      </button>
    );
  }

  return (
    <button onClick={signIn}>
      Sign in with Telegram
    </button>
  );
}

Return value

user
User | null
The authenticated user object, or null when no user is logged in. When present, the object has the following shape:
{
  telegramId: string;
  name:       string;
  username:   string | null;
  proof:      string;
  channel:    string;
}
isAuthenticated
boolean
true when a user is currently authenticated, false otherwise. Use this for conditional rendering of protected content.
signIn
function
Triggers the Telegram authentication flow programmatically — identical to calling client.signIn() on the Web SDK. Call this only from a user gesture (e.g. a button’s onClick).
signOut
function
Clears the authenticated user from context state. You are responsible for invalidating any session cookie or JWT on your server in parallel.

Full integration example

The following example shows how all three pieces — PulseProvider, PulseButton, and usePulse — work together in a Next.js app.
1

Wrap your app with PulseProvider

In pages/_app.tsx (Pages Router) or app/layout.tsx (App Router), add the provider:
import { PulseProvider } from '@bondify/react';

export default function RootLayout({ children }) {
  return (
    <PulseProvider projectId={process.env.NEXT_PUBLIC_BONDIFY_PROJECT_ID}>
      {children}
    </PulseProvider>
  );
}
2

Add PulseButton to your login page

import { PulseButton } from '@bondify/react';
import { useRouter } from 'next/navigation';

export default function LoginPage() {
  const router = useRouter();

  const handleSuccess = async (user) => {
    const res = await fetch('/api/auth/verify', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ proof: user.proof }),
    });
    if (res.ok) router.push('/dashboard');
  };

  return (
    <main>
      <h1>Sign in to MyApp</h1>
      <PulseButton
        onSuccess={handleSuccess}
        onError={(err) => console.error(err)}
        theme="dark"
      />
    </main>
  );
}
3

Verify the proof on your server

In your API route (/api/auth/verify), use @bondify/server to validate the proof before issuing a session:
import { verifyProof } from '@bondify/server';

export async function POST(req) {
  const { proof } = await req.json();
  const user = await verifyProof(proof, process.env.BONDIFY_SECRET_KEY);
  // Create a session, set a cookie, etc.
  return Response.json({ ok: true, userId: user.telegramId });
}
4

Access auth state anywhere

Use usePulse() to personalise UI or protect routes:
'use client';
import { usePulse } from '@bondify/react';
import { redirect } from 'next/navigation';

export default function Dashboard() {
  const { user, isAuthenticated, signOut } = usePulse();

  if (!isAuthenticated) redirect('/login');

  return (
    <div>
      <p>Welcome, {user.name}!</p>
      <button onClick={signOut}>Sign out</button>
    </div>
  );
}