Skip to content

JavaScript / TypeScript SDK

The Hintway JS/TS SDK is a lightweight, isomorphic library for sending analytics events to the Hintway platform from any JavaScript runtime: Node.js, modern browsers, and edge runtimes. It is a faithful port of the Go SDK, sharing the same wire format, endpoints, and behavior.

npm: @hintway/sdk
GitHub: hintwayapp/Javascript-SDK

Supported features:

  • Immediate and batched event tracking
  • Automatic retry when the server becomes available
  • Persistent device and session identification (file-based in Node, localStorage in browsers)
  • Verbose logging for debugging
  • Full TypeScript types out of the box
  • Zero runtime dependencies

Terminal window
npm install @hintway/sdk
# or
pnpm add @hintway/sdk
# or
yarn add @hintway/sdk

Requirements: Node.js 18+ (for native fetch). All modern browsers and edge runtimes are supported.


Call init() once in your application’s entry point before sending any events.

import { Hintway } from '@hintway/sdk';
// Get the singleton instance
const hintway = Hintway.instance();
// Optional: see network requests in the console
hintway.setVerbose(true);
hintway.init({
tenantId: '481b9cfb-4b48-4d99-a310-d383c6cc5d3b',
serverUrl: 'https://in.hintway.app',
platform: 'my_backend_service',
appVersion: '1.0.0',
autoBatching: true, // queue events and flush periodically
flushIntervalSec: 2, // flush every 2 seconds
});
// Give background tenant validation a moment to complete
await new Promise((r) => setTimeout(r, 1000));
// ... your app logic ...
await hintway.shutdown();
ParameterTypeDefaultDescription
tenantIdstringRequired. Your project identifier from the Hintway dashboard
serverUrlstringhttps://in.hintway.appServer endpoint
platformstringRequired. Free-form platform identifier, e.g. web_app, node_backend
appVersionstring1.0.0Your application version
autoBatchingbooleanRequired. Queue events and flush on an interval instead of sending immediately
flushIntervalSecnumber10Flush interval in seconds (only used when autoBatching is true)
  1. Loads or generates a persistent device identifier
    • Node: stored in analytics.id next to process.cwd()
    • Browser: stored in localStorage under hintway.analytics.id
    • Edge runtimes: in-memory only (regenerated on cold start unless you provide a custom storage adapter)
  2. Creates a new session ID
  3. Starts a background task to validate the tenant and check server health
  4. Enables or disables analytics based on server availability

If the server is unreachable, events are safely queued until connectivity is restored.


hintway.trackEvent('app_started');
hintway.trackEvent('user_logged_in', 'admin_user');
hintway.trackEvent('order_completed', {
order_id: 12345,
total_amount: 99.99,
currency: 'USD',
items_count: 3,
});

Use manual batching when you want explicit control over when events are sent (e.g. at the end of a transaction or an API request).

// Queue events
hintway.batchedTrackEvent('transaction_started', 'checkout');
hintway.batchedTrackEvent('payment_processed', {
amount: 49.99,
method: 'credit_card',
status: 'success',
});
// Send all queued events in a single HTTP request
hintway.flushManualBatch();

Enable autoBatching: true during init():

  • trackEvent calls are queued automatically
  • The queue flushes every flushIntervalSec seconds
  • If the server is unreachable, events stay queued until connectivity is restored

Attach persistent metadata to every event the SDK sends — useful for user context, environment details, or any session-level information.

// Set custom data — included in all subsequent events
hintway.setCustomData({
user_id: 'user_123',
subscription: 'premium',
environment: 'production',
region: 'us-east-1',
});
hintway.trackEvent('feature_used', 'dark_mode_toggle');
// Remove custom data
hintway.clearCustomData();
// Or:
hintway.setCustomData(null);
  • Custom data persists across event calls until explicitly cleared or replaced
  • Empty / null custom data is not included in request payloads
  • Non-serializable values are silently dropped (mirrors the Go SDK)

Always call shutdown() before your application exits. It cancels background timers, drains any remaining queued events into a final batch, appends an app_exit event, and best-effort-flushes the result with a 2-second hard timeout.

import { Hintway } from '@hintway/sdk';
async function main() {
const hintway = Hintway.instance();
hintway.init({
tenantId: 'tenant-id',
serverUrl: 'https://in.hintway.app',
platform: 'cli_app',
appVersion: '1.0.0',
autoBatching: true,
flushIntervalSec: 5,
});
hintway.trackEvent('app_started');
// ... application logic ...
hintway.trackEvent('app_completed');
await hintway.shutdown();
}
main();
import express from 'express';
import { Hintway } from '@hintway/sdk';
const hintway = Hintway.instance();
hintway.init({
tenantId: 'tenant-id',
platform: 'web_service',
appVersion: '1.0.0',
autoBatching: true,
flushIntervalSec: 10,
});
const app = express();
app.use((req, _res, next) => {
hintway.trackEvent('api_request', { path: req.path, method: req.method });
next();
});
// Flush on graceful shutdown
async function gracefulShutdown() {
await hintway.shutdown();
process.exit(0);
}
process.on('SIGTERM', gracefulShutdown);
process.on('SIGINT', gracefulShutdown);
import { Hintway } from '@hintway/sdk';
const hintway = Hintway.instance();
hintway.init({
tenantId: 'tenant-id',
platform: 'web_app',
appVersion: '1.0.0',
autoBatching: true,
flushIntervalSec: 5,
});
hintway.trackEvent('page_view', { path: window.location.pathname });
// Flush whatever is queued before the user leaves
window.addEventListener('beforeunload', () => {
hintway.flushManualBatch();
});

Edge runtime (Cloudflare Workers / Vercel Edge)

Section titled “Edge runtime (Cloudflare Workers / Vercel Edge)”
import { Hintway } from '@hintway/sdk';
export default {
async fetch(request: Request): Promise<Response> {
const hintway = Hintway.instance();
hintway.init({
tenantId: 'tenant-id',
platform: 'edge_worker',
autoBatching: false, // requests are short — send immediately
});
hintway.trackEvent('edge_request', { path: new URL(request.url).pathname });
// shutdown() ensures the final flush happens before the request ends
await hintway.shutdown();
return new Response('ok');
},
};