npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

top-analyze-sdk

v1.2.2

Published

SDK for TOP analytics

Readme

Top Analyze SDK

Automatic analytics for TG Mini Apps with minimal integration.

Quick Start

npm install top-analyze-sdk
import { TopAnalyzeSDK } from 'top-analyze-sdk';

// Initialize with required apiToken
const analytics = new TopAnalyzeSDK({
  appName: 'MyTonApp',
  apiToken: 'your-api-token',
});
analytics.start();

The core SDK is enough for sessions, clicks, wallet, Telegram WebApp events, and custom events. Optional modules (e.g. backend request tracking) are documented at the end — see Optional modules.

What's Collected Automatically

Sessions

  • Start/end session
  • Duration, idle timeouts
  • Page URL, referrer, User-Agent

Clicks and Taps

  • Coordinates (page/client)
  • DOM snapshot of target (tag, id, classes, attributes)
  • Safe CSS selector and XPath
  • Truncated text (with PII masking)

Telegram WebApp

Inside a Telegram Mini App, the SDK subscribes to Telegram.WebApp.onEvent and sends analytics events automatically — no extra setup.

Native Telegram UI buttons are tracked as separate events (not as regular DOM clicks):

| Event | Telegram UI | |-------|-------------| | backButtonClicked | Back button (←) in the header | | settingsButtonClicked | Menu button (⋮) in the header | | mainButtonClicked | Main bottom button | | secondaryButtonClicked | Secondary bottom button |

Other WebApp events (popups, invoices, fullscreen, clipboard, etc.) are tracked too. Each event includes the original Telegram payload in telegram_event_data.

TON Connect

  • Wallet connection request
  • Connect/disconnect
  • Wallet info (name, address)

Transactions

  • transaction_sent_for_signature
  • transaction_signed
  • transaction_signing_failed
  • Amount, recipient, transaction ID

Configuration

const analytics = new TopAnalyzeSDK({
  appName: 'MyTonApp',
  apiToken: 'your-api-token', // Required
  debug: true, // Detailed logs
  onlyImportantClicks: false, // Track only important clicks (buttons, links, etc.)
});

TON Connect Integration

To track TON Connect events, you need to attach your TON Connect instance using the attachTonConnect method.

With @tonconnect/ui-react

import { useEffect } from 'react';
import { useTonConnectUI } from '@tonconnect/ui-react';
import { TopAnalyzeSDK } from 'top-analyze-sdk';

// Initialize analytics
const analytics = new TopAnalyzeSDK({
  appName: 'MyTonApp',
  apiToken: 'your-api-token',
});

// Hook for TON Connect integration
export const useTonConnectAnalytics = () => {
  const [tonConnectUI] = useTonConnectUI();

  useEffect(() => {
    if (!analytics || !tonConnectUI) return;

    // Attach TON Connect to analytics
    analytics.attachTonConnect(tonConnectUI);
  }, [tonConnectUI]);
};

With custom adapter

import { TopAnalyzeSDK } from 'top-analyze-sdk';

const analytics = new TopAnalyzeSDK({
  appName: 'MyTonApp',
  apiToken: 'your-api-token',
});

// Create adapter for compatibility
const tonConnectAdapter = {
  sendTransaction: async (transaction) => {
    return await tonConnectUI.sendTransaction(transaction);
  },
  connect: async () => {
    return tonConnectUI.connect();
  },
  disconnect: async () => {
    await tonConnectUI.disconnect();
  },
  onStatusChange: (callback) => {
    tonConnectUI.onStatusChange(callback);
  },
  wallet: tonConnectUI.wallet,
};

// Attach TON Connect to analytics
analytics.attachTonConnect(tonConnectAdapter);

Custom Events

// Game events
analytics.track('game_start', { level: 1, mode: 'normal' });
analytics.track('game_score', { score: 1500, level: 3 });
analytics.track('game_end', { score: 1500, duration: 120 });

// Business events
analytics.track('purchase_intent', { item: 'premium', price: '0.1' });
analytics.track('feature_used', { feature: 'dark_mode' });

Getting Information

// Session info
const sessionInfo = analytics.getSessionInfo();
console.log(sessionInfo.sessionId, sessionInfo.duration);

// Wallet info
const walletInfo = analytics.getTonWalletInfo();
console.log(walletInfo?.address, walletInfo?.name);

// SDK status
const status = analytics.getStatus();
console.log(status.isStarted, status.isTonConnectAttached);

Lifecycle Management

const analytics = new TopAnalyzeSDK({
  appName: 'MyTonApp',
  apiToken: 'your-api-token',
});

analytics.start(); // Start tracking
analytics.stop(); // Stop (with sending remaining events)

Event Structure

All events have a unified structure:

interface AnalyticsEvent {
  type: EventType; // Event type
  timestamp: number; // Unix timestamp
  sessionId: string; // Session ID
  appName: string; // App name
  data: EventData; // Specific data
}

Optional modules

Everything above is the core SDK — sessions, clicks, Telegram WebApp events, TON Connect, custom events. It works on its own; no extra packages or subpath imports required.

Optional modules extend the SDK with additional behaviour. Each module:

  • is imported from a separate subpath (e.g. top-analyze-sdk/request-interceptor);
  • is not enabled by default — you opt in explicitly;
  • connects via analytics.useModule(create…Module(config));
  • returns detach() — call it on SPA unmount to restore patched globals;
  • sends events through the same batch queue as core analytics (when analytics.start() is active).
import { TopAnalyzeSDK } from 'top-analyze-sdk';
// Optional — only if you need this module:
import { createRequestInterceptorModule } from 'top-analyze-sdk/request-interceptor';

const analytics = new TopAnalyzeSDK({ appName: 'MyTonApp', apiToken: '…' });

const detach = analytics.useModule(createRequestInterceptorModule({ /* config */ }));

analytics.start();

// on unmount:
detach();

Modules can be attached before or after start(). Patching (fetch, XMLHttpRequest, …) happens on useModule(); events are queued only while the SDK is started.

Request Interceptor Module

Package: top-analyze-sdk/request-interceptor

Tracks product backend requests (REST/GraphQL) inside TMA activity: endpoint, method, request params, response time, HTTP status. Static assets, CDN, telemetry, and SDK analytics traffic are not tracked.

Quick start

import { createRequestInterceptorModule } from 'top-analyze-sdk/request-interceptor';

analytics.useModule(
  createRequestInterceptorModule({
    apiBaseUrl: import.meta.env.VITE_API_URL,
  })
);

createRequestInterceptorModule(config)

| Option | Type | Required | Description | |--------|------|----------|-------------| | apiBaseUrl | string | No* | Sugar: adds includeOrigins: [new URL(apiBaseUrl).origin]. Handy when API lives on a dedicated domain. | | includeOrigins | string[] | No* | Whitelist of backend origins, e.g. ['https://api.myapp.com']. All paths on these origins are candidates for tracking. | | includePathPrefixes | string[] | No* | Whitelist of path prefixes on the current page origin, e.g. ['/api/', '/graphql']. Use for same-origin BFF. | | excludePathPrefixes | string[] | No | Extra path prefixes to skip (applied after built-in static excludes). | | excludeOrigins | string[] | No | Extra origins to skip. | | shouldTrack | (url, method) => boolean | No | Final per-request filter — see below. |

* Deny-by-default: at least one of apiBaseUrl, includeOrigins, or includePathPrefixes must be set. Otherwise the module attaches but tracks nothing (warning in debug mode).

Options can be combined, e.g. apiBaseUrl + includePathPrefixes for API on a separate domain and GraphQL on the app origin.

How request filtering works

A request is tracked only if all checks pass (in order):

  1. Hard exclude (built-in, not configurable) — always skipped:
    • SDK analytics endpoint (analyze.playdeck.io);
    • static extensions (.js, .css, .map, images, fonts, video, …);
    • common static paths (/_next/, /static/, /assets/, …).
  2. Whitelist — URL must match includeOrigins or includePathPrefixes.
  3. Config exclude — not in excludeOrigins / excludePathPrefixes.
  4. shouldTrack(url, method) — if provided, must return true.

shouldTrack runs last, only for requests that already passed whitelist and excludes. Use it for edge cases that are awkward to express with path/origin lists:

createRequestInterceptorModule({
  includePathPrefixes: ['/api/', '/graphql'],

  // Skip GraphQL introspection and healthchecks
  shouldTrack: (url, method) => {
    if (url.pathname.startsWith('/graphql/introspection')) return false;
    if (url.pathname === '/api/health') return false;
    return true;
  },
});

If shouldTrack is omitted, every whitelisted non-excluded request is tracked.

Configuration examples

// API on a separate domain (most common)
createRequestInterceptorModule({
  apiBaseUrl: import.meta.env.VITE_API_URL,
});

// Same-origin BFF
createRequestInterceptorModule({
  includePathPrefixes: ['/api/', '/graphql'],
});

// Full control
createRequestInterceptorModule({
  includeOrigins: ['https://api.myapp.com'],
  includePathPrefixes: ['/graphql'],
  excludePathPrefixes: ['/graphql/introspection'],
  shouldTrack: (url) => !url.pathname.includes('/internal/'),
});

intercepted_request event

Each tracked fetch / XMLHttpRequest call emits one intercepted_request event (category NETWORK).

| Field | Description | |-------|-------------| | method | HTTP method | | endpoint | URL pathname only, e.g. /graphql | | request_params | POST JSON body or GET query params as-is; null for non-JSON body | | page_path | Page URL at request time | | duration_ms | Round-trip ms (performance.now() before/after the call) | | status_code | HTTP status or null on network error | | is_success | true if status 2xx/3xx | | error_code | Status string, network_error, or aborted |

GraphQL operationName is available inside request_params when the client sends it.

Contact

Telegram: @Ektomorphine