diff --git a/src/lib/analytic/events.ts b/src/lib/analytic/events.ts new file mode 100644 index 0000000..e70c780 --- /dev/null +++ b/src/lib/analytic/events.ts @@ -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 {} diff --git a/src/lib/analytic/index.ts b/src/lib/analytic/index.ts new file mode 100644 index 0000000..8cad68a --- /dev/null +++ b/src/lib/analytic/index.ts @@ -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( + 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) { + return posthog.captureImmediate({ + event: props.event, + properties: props.properties || undefined, + }); + } + + function capture( + props: AnalyticEventMessage, + ) { + return posthog.capture({ + event: props.event, + properties: props.properties || undefined, + }); + } + + return { ...posthog, capture, captureImmediate }; +} diff --git a/src/lib/analytic/properties.ts b/src/lib/analytic/properties.ts new file mode 100644 index 0000000..940abd9 --- /dev/null +++ b/src/lib/analytic/properties.ts @@ -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 {} diff --git a/src/lib/analytic/types.ts b/src/lib/analytic/types.ts new file mode 100644 index 0000000..ec0996e --- /dev/null +++ b/src/lib/analytic/types.ts @@ -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;