Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/lib/analytic/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Analytics events
*
* Uses the `category:object_action` naming convention to ensure consistent and descriptive event naming.
* - **category**: The context or domain where the event occurred (e.g., `auth`, `account_settings`, `signup_flow`)
* - **object**: The component, feature, or location involved (e.g., `signup_button`, `pricing_page`)
* - **action**: The user action or system event that occurred (e.g., `click`, `submit`, `view`, `cancel`)
*
* @examples
* - `account_settings:forgot_password_button_click`
* - `signup_flow:pricing_page_view`
* - `registration:sign_up_button_click`
* - `registration_v2:sign_up_button_click` - version your events
*
* @see {@link https://posthog.com/docs/product-analytics/best-practices#2-implement-a-naming-convention}
*/
export enum AnalyticEvent {}
58 changes: 58 additions & 0 deletions src/lib/analytic/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { usePostHog } from '@posthog/react';
import type { CaptureOptions } from 'posthog-js';

import { AnalyticEvent } from '~/lib/analytic/events';
import type { AnalyticProperty } from '~/lib/analytic/properties';
import type { AnalyticEventMessage } from '~/lib/analytic/types';
import { createPosthogClient } from '~/lib/posthog/server';

/**
* Hook for capturing analytics events using PostHog.
*
* Provides a typed interface for tracking analytics events with associated properties.
* This hook wraps the PostHog client to ensure type-safe event capturing.
*/
export function useAnalytic() {
const posthog = usePostHog();

function capture<TEvent extends AnalyticEvent & keyof AnalyticProperty>(
event: TEvent,
properties: AnalyticProperty[TEvent],
options?: CaptureOptions,
) {
return posthog.capture(event, properties, options);
}

return { ...posthog, capture };
}

/**
* Creates a server-side analytics client using PostHog.
*
* This function initializes a PostHog client for server-side analytics tracking,
* providing a type-safe interface for capturing analytics events immediately.
* Useful for tracking events that occur during server-side operations.
*/
export function createAnalyticClient() {
const posthog = createPosthogClient();

function captureImmediate<
TEvent extends AnalyticEvent & keyof AnalyticProperty,
>(props: AnalyticEventMessage<TEvent>) {
return posthog.captureImmediate({
event: props.event,
properties: props.properties || undefined,
});
}

function capture<TEvent extends AnalyticEvent & keyof AnalyticProperty>(
props: AnalyticEventMessage<TEvent>,
) {
return posthog.capture({
event: props.event,
properties: props.properties || undefined,
});
}

return { ...posthog, capture, captureImmediate };
}
20 changes: 20 additions & 0 deletions src/lib/analytic/properties.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Analytics properties - contextual data attached to events
*
* Uses naming conventions to ensure consistent and descriptive property naming.
* - **object_adjective pattern**: Use descriptive property names (e.g., `user_id`, `item_price`, `member_count`)
* - **boolean prefixes**: Use `is_` or `has_` for boolean properties (e.g., `is_subscribed`, `has_seen_upsell`)
* - **temporal suffixes**: For dates/timestamps, include `_date` or `_timestamp` (e.g., `user_creation_date`, `last_login_timestamp`)
*
* @examples
* - `user_id`
* - `item_price`
* - `member_count`
* - `is_subscribed`
* - `has_seen_upsell`
* - `last_login_timestamp`
* - `user_creation_date`
*
* @see {@link https://posthog.com/docs/product-analytics/best-practices#2-implement-a-naming-convention}
*/
export interface AnalyticProperty {}
11 changes: 11 additions & 0 deletions src/lib/analytic/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { EventMessage } from 'posthog-node';

import type { AnalyticEvent } from '~/lib/analytic/events';
import type { AnalyticProperty } from '~/lib/analytic/properties';

export type AnalyticEventMessage<
TEvent extends AnalyticEvent & keyof AnalyticProperty,
> = {
event: TEvent;
properties: AnalyticProperty[TEvent];
} & Omit<EventMessage, 'event' | 'properties'>;