Add comprehensive OpenPanel analytics tracking: - Install @openpanel/nextjs SDK - Add OpenPanelComponent to root layout for automatic page views - Create useAnalytics hook for tracking custom events - Track checkout funnel: started, shipping step, order completed - Track product views and add-to-cart events - Identify users on order completion - Add NEXT_PUBLIC_OPENPANEL_CLIENT_ID to environment
155 lines
3.5 KiB
TypeScript
155 lines
3.5 KiB
TypeScript
"use client";
|
|
|
|
import { useOpenPanel } from "@openpanel/nextjs";
|
|
import { useCallback } from "react";
|
|
|
|
export function useAnalytics() {
|
|
const op = useOpenPanel();
|
|
|
|
// Page views are tracked automatically by OpenPanelComponent
|
|
// but we can track specific events manually
|
|
|
|
const trackProductView = useCallback((product: {
|
|
id: string;
|
|
name: string;
|
|
price: number;
|
|
currency: string;
|
|
category?: string;
|
|
}) => {
|
|
op.track("product_viewed", {
|
|
product_id: product.id,
|
|
product_name: product.name,
|
|
price: product.price,
|
|
currency: product.currency,
|
|
category: product.category,
|
|
});
|
|
}, [op]);
|
|
|
|
const trackAddToCart = useCallback((product: {
|
|
id: string;
|
|
name: string;
|
|
price: number;
|
|
currency: string;
|
|
quantity: number;
|
|
variant?: string;
|
|
}) => {
|
|
op.track("add_to_cart", {
|
|
product_id: product.id,
|
|
product_name: product.name,
|
|
price: product.price,
|
|
currency: product.currency,
|
|
quantity: product.quantity,
|
|
variant: product.variant,
|
|
});
|
|
}, [op]);
|
|
|
|
const trackRemoveFromCart = useCallback((product: {
|
|
id: string;
|
|
name: string;
|
|
quantity: number;
|
|
}) => {
|
|
op.track("remove_from_cart", {
|
|
product_id: product.id,
|
|
product_name: product.name,
|
|
quantity: product.quantity,
|
|
});
|
|
}, [op]);
|
|
|
|
const trackCheckoutStarted = useCallback((cart: {
|
|
total: number;
|
|
currency: string;
|
|
item_count: number;
|
|
items: Array<{
|
|
id: string;
|
|
name: string;
|
|
quantity: number;
|
|
price: number;
|
|
}>;
|
|
}) => {
|
|
op.track("checkout_started", {
|
|
cart_total: cart.total,
|
|
currency: cart.currency,
|
|
item_count: cart.item_count,
|
|
items: cart.items,
|
|
});
|
|
}, [op]);
|
|
|
|
const trackCheckoutStep = useCallback((step: string, data?: Record<string, unknown>) => {
|
|
op.track("checkout_step", {
|
|
step,
|
|
...data,
|
|
});
|
|
}, [op]);
|
|
|
|
const trackOrderCompleted = useCallback((order: {
|
|
order_id: string;
|
|
order_number: string;
|
|
total: number;
|
|
currency: string;
|
|
item_count: number;
|
|
shipping_cost?: number;
|
|
customer_email?: string;
|
|
}) => {
|
|
op.track("order_completed", {
|
|
order_id: order.order_id,
|
|
order_number: order.order_number,
|
|
total: order.total,
|
|
currency: order.currency,
|
|
item_count: order.item_count,
|
|
shipping_cost: order.shipping_cost,
|
|
customer_email: order.customer_email,
|
|
});
|
|
|
|
// Also track revenue for analytics
|
|
op.track("purchase", {
|
|
transaction_id: order.order_number,
|
|
value: order.total,
|
|
currency: order.currency,
|
|
});
|
|
}, [op]);
|
|
|
|
const trackSearch = useCallback((query: string, results_count: number) => {
|
|
op.track("search", {
|
|
query,
|
|
results_count,
|
|
});
|
|
}, [op]);
|
|
|
|
const trackExternalLink = useCallback((url: string, label?: string) => {
|
|
op.track("external_link_click", {
|
|
url,
|
|
label,
|
|
});
|
|
}, [op]);
|
|
|
|
const identifyUser = useCallback((user: {
|
|
profileId: string;
|
|
email?: string;
|
|
firstName?: string;
|
|
lastName?: string;
|
|
properties?: Record<string, unknown>;
|
|
}) => {
|
|
op.identify({
|
|
profileId: user.profileId,
|
|
firstName: user.firstName,
|
|
lastName: user.lastName,
|
|
email: user.email,
|
|
properties: user.properties,
|
|
});
|
|
}, [op]);
|
|
|
|
return {
|
|
trackProductView,
|
|
trackAddToCart,
|
|
trackRemoveFromCart,
|
|
trackCheckoutStarted,
|
|
trackCheckoutStep,
|
|
trackOrderCompleted,
|
|
trackSearch,
|
|
trackExternalLink,
|
|
identifyUser,
|
|
};
|
|
}
|
|
|
|
export default useAnalytics;
|