Thisbefine
API Reference

Analytics API

Every method on the Analytics instance (yes, all of them)

Analytics API

The full reference for the Analytics class. Everything the SDK can do is listed here.

Getting an Instance

Three ways to get started. Pick your favorite.

createAnalytics(config)

Create a new instance. You manage its lifecycle.

import { createAnalytics } from '@thisbefine/analytics';

const analytics = createAnalytics({
  apiKey: 'tif_your_api_key',
});

Parameters: config: AnalyticsConfig

Returns: Analytics


initAnalytics(config)

Initialize the global singleton. Use this if you want to access the same instance from anywhere.

import { initAnalytics } from '@thisbefine/analytics';

initAnalytics({
  apiKey: 'tif_your_api_key',
});

Parameters: config: AnalyticsConfig

Returns: Analytics


getAnalytics()

Get the global singleton (if you initialized it).

import { getAnalytics } from '@thisbefine/analytics';

const analytics = getAnalytics();
if (analytics) {
  analytics.track('event_name');
}

Returns: Analytics | null (null if you forgot to call initAnalytics)


Event Tracking

The fun part. Actually tracking things.

track(event, properties?)

Track something happening. A click, a purchase, a signup—whatever you care about.

analytics.track('button_clicked', {
  buttonId: 'cta-hero',
  variant: 'primary',
});

Prop

Type

Returns: void


page(name?, properties?)

Track a pageview. Essential for understanding where users spend their time.

// Basic - captures URL, referrer, title automatically
analytics.page();

// Named
analytics.page('Dashboard');

// With extra context
analytics.page('Product Page', {
  productId: 'prod_123',
  category: 'electronics',
});

Prop

Type

Returns: void

Automatically captured:

  • url - Full URL
  • path - Just the path
  • referrer - Where they came from
  • title - Page title

Lifecycle Events

Built-in methods for common SaaS events. See the Lifecycle Events Guide for full documentation.

User Lifecycle

analytics.signup({ method: 'google', plan: 'free' });
analytics.login({ method: 'passkey' });
analytics.logout({ reason: 'manual' });
analytics.accountDeleted({ reason: 'not_using', tenure: 180 });

Subscription Lifecycle

analytics.subscriptionStarted({ plan: 'pro', mrr: 29 });
analytics.subscriptionCancelled({ plan: 'pro', reason: 'too_expensive' });
analytics.subscriptionRenewed({ plan: 'pro', renewalCount: 3 });
analytics.planUpgraded({ fromPlan: 'free', toPlan: 'pro' });
analytics.planDowngraded({ fromPlan: 'pro', toPlan: 'free' });
analytics.trialStarted({ plan: 'pro', trialDays: 14 });
analytics.trialEnded({ plan: 'pro', converted: true });

Engagement

analytics.inviteSent({ inviteEmail: 'team@example.com', role: 'member' });
analytics.inviteAccepted({ invitedBy: 'user_123' });
analytics.featureActivated({ feature: 'api_keys', isFirstTime: true });

These methods are type-safe and trigger automatic insights (churn alerts, subscriber notifications).


User Identification

Turn anonymous visitors into real people.

identify(userId, traits?)

"This is user_123 and here's what we know about them."

analytics.identify('user_123', {
  email: 'jane@example.com',
  name: 'Jane Doe',
  plan: 'pro',
  createdAt: '2025-01-15',
});

Prop

Type

Returns: void


group(accountId, traits?)

"This user belongs to workspace_456." Essential for B2B apps.

analytics.group('workspace_456', {
  name: 'Acme Corp',
  plan: 'enterprise',
  mrr: 5000,
  industry: 'Technology',
});

Prop

Type

Returns: void


reset()

Clear everything and start fresh. Call this on logout.

await logout();
analytics.reset();

Returns: void

What it does:

  1. Flushes any pending events
  2. Clears userId and user traits
  3. Clears accountId and account traits
  4. Generates a new anonymousId
  5. Starts a new session

Basically: "New phone, who dis?"


getUser()

Peek at the current user state.

const user = analytics.getUser();
console.log(user.anonymousId);  // Always there
console.log(user.userId);       // After identify()
console.log(user.traits);       // User info

Returns: UserState

interface UserState {
  anonymousId: string;
  userId?: string;
  traits?: UserTraits;
  accountId?: string;
  accountTraits?: AccountTraits;
}

Error Tracking

When things go wrong (and they will).

captureException(error, context?)

Catch an error and send it to us.

try {
  await riskyOperation();
} catch (error) {
  analytics.captureException(error as Error, {
    operation: 'riskyOperation',
    userId: user.id,
  });
}

Prop

Type

Returns: void


captureMessage(message, level?, context?)

Report an error without an Error object. For when you detect something fishy.

analytics.captureMessage(
  'Payment processing timeout',
  'error',
  { orderId: 'ord_123' }
);

Prop

Type

Returns: void


addBreadcrumb(breadcrumb)

Leave a trail of crumbs leading to the error. Like Hansel and Gretel, but for debugging.

analytics.addBreadcrumb({
  type: 'custom',
  message: 'User started checkout',
  data: { cartItems: 3, total: 149.97 },
});

Prop

Type

Returns: void


Logging

Structured logs. Better than console.log('here 3').

log(message, level, metadata?)

Send a log entry.

analytics.log('User exported data', 'info', {
  format: 'csv',
  rowCount: 1000,
  duration: 234,
});

Prop

Type

Returns: void


Privacy & Control

Respect your users. They'll appreciate it.

optOut()

Stop tracking this user. Completely.

analytics.optOut();

Returns: void

What happens:

  • No events are tracked
  • Nothing is sent to the server
  • Choice persists in localStorage

optIn()

Resume tracking (after they opted out).

analytics.optIn();

Returns: void


isOptedOut()

Check if the user opted out.

if (!analytics.isOptedOut()) {
  analytics.track('some_event');
}

Returns: boolean


Event Queue

Under the hood, events are batched for efficiency.

flush()

Force-send all pending events right now. Don't wait for the batch.

// Before navigating away
await analytics.flush();
window.location.href = '/external-page';

Returns: Promise<void>

Use this before:

  • Navigating to an external page
  • Closing a modal where timing matters
  • Any action where you need immediate delivery

Otherwise, let the SDK batch events automatically. It's more efficient.

On this page