@tapemetric/analytics
v0.1.0
Published
Video analytics SDK — web, mobile webviews, smart-TV apps.
Maintainers
Readme
@tapemetric/analytics
Lightweight video analytics SDK for web, mobile webviews, and smart-TV apps. Under 6 kB gzipped, zero dependencies.
Install
npm install @tapemetric/analyticsOr via CDN:
<script src="https://cdn.tapemetric.com/v1/tapemetric.min.js"></script>Quick start
Grab an API key from the admin panel under Workspace → API keys. The key is shown once at creation — save it into your build-time env.
import Tapemetric from '@tapemetric/analytics';
const rd = Tapemetric.init({
apiKey: process.env.NEXT_PUBLIC_TAPEMETRIC_KEY!,
debug: process.env.NODE_ENV !== 'production',
});
rd.trackPageView();That single call gets you page views, device detection, geo enrichment (via server-side IP lookup), and session tracking. Everything below is optional playback instrumentation.
Identify logged-in users
Call identify once the user logs in. The SDK links pre-login anonymous activity to the now-known user id.
rd.identify('user_12345', { plan: 'svod', joined_at: '2026-01-14' });Call rd.reset() on logout to start a fresh anonymous session.
Playback instrumentation
Wire these four methods into your player's events and you get the full QoS picture — concurrency, watch time, rebuffer rate, completion, bitrate ladder health.
// Start
player.on('play', () => {
rd.trackPlayStart(
{
contentId: 'aashiqana_s04e12',
contentType: 'series',
contentTitle: 'Aashiqana · S4 E12',
season: 4,
episode: 12,
durationSec: 2640,
},
{ positionSec: player.currentTime, bitrateKbps: player.currentBitrate },
);
});
// Buffer
let bufferStart = 0;
player.on('waiting', () => (bufferStart = Date.now()));
player.on('playing', () => {
if (bufferStart) {
rd.trackBuffer(Date.now() - bufferStart, {
positionSec: player.currentTime,
bitrateKbps: player.currentBitrate,
});
bufferStart = 0;
}
});
// Bitrate change (HLS / DASH ladder step)
player.on('levelswitched', (level) => rd.trackBitrateChange(level.bitrate / 1000));
// Completion
player.on('ended', () =>
rd.trackComplete({ positionSec: player.duration, durationSec: player.duration }),
);The SDK emits a heartbeat every 30 seconds while content is playing, which powers concurrent-viewer counts and watch-hour totals.
Revenue tracking
// One-off rental
rd.trackPurchase('mumbai_junction', 149, 'tvod');
// Subscription activation — call identify with plan
rd.identify('user_12345', { plan: 'svod' });Custom events
rd.track({
eventType: 'search',
properties: { query: 'thriller', result_count: 24 },
});Framework notes
React / Next.js
Initialize once in a top-level client component:
'use client';
import { useEffect } from 'react';
import Tapemetric from '@tapemetric/analytics';
export function AnalyticsProvider({ children }: { children: React.ReactNode }) {
useEffect(() => {
const rd = Tapemetric.init({ apiKey: process.env.NEXT_PUBLIC_TAPEMETRIC_KEY! });
rd.trackPageView();
}, []);
return <>{children}</>;
}For route changes, call rd.trackPageView(pathname) from a usePathname effect.
React Native / mobile webviews
Use the SDK inside a WebView bridge or call the ingest REST API directly — see /docs/api/ingest in the admin panel. A native iOS/Android SDK is on the roadmap.
Smart TV (Tizen, webOS, HbbTV, Android TV)
Smart TVs run Chromium-based webviews, so the web SDK works as-is. Detect device via UA:
Tapemetric.init({ apiKey: '...', debug: false });
// 'tv' device_type is auto-detected from Tizen / webOS / Bravia / HbbTV user agentsPrivacy & DPDP compliance
- No cookies. Anonymous id persists in
localStorageonly. - User IDs are never sent until you call
identify. - Call
rd.reset()on logout or user request to wipe the anonymous id. - The API's IP enrichment is done server-side and the raw IP is never stored.
- Data residency: events land in
ap-south-1 (Mumbai)by default for Indian tenants. Enterprise tenants can request EU or US residency.
Config reference
| Option | Default | Description |
|---|---|---|
| apiKey | (required) | Tenant API key from the admin panel |
| apiUrl | https://ingest.tapemetric.com | Override for self-hosted ingest |
| flushIntervalMs | 10000 | How often batched events are sent |
| maxBatchSize | 50 | Flush immediately if queue reaches this size |
| debug | false | Log events to console |
| disableAutoFlush | false | Disable timer-based flushing (you call rd.flush() yourself) |
Bundle size
The ESM build is budgeted under 6 kB gzipped and enforced via size-limit on every PR.
License
MIT — see LICENSE.
