Some checks failed
Build and Deploy / build (push) Has been cancelled
- Add Rybbit server-side tracking to analytics-server.ts for order completion and revenue - Add trackNewsletterSignup to analytics.ts and wire up NewsletterSection - Add cart tracking to CartDrawer (cart view, remove from cart) - All ecommerce events now track to both OpenPanel and Rybbit
151 lines
4.1 KiB
TypeScript
151 lines
4.1 KiB
TypeScript
"use server";
|
|
|
|
import { OpenPanel } from "@openpanel/nextjs";
|
|
|
|
// Server-side OpenPanel instance
|
|
const op = new OpenPanel({
|
|
clientId: process.env.NEXT_PUBLIC_OPENPANEL_CLIENT_ID || "",
|
|
clientSecret: process.env.OPENPANEL_CLIENT_SECRET || "",
|
|
apiUrl: process.env.OPENPANEL_API_URL || "https://op.nodecrew.me/api",
|
|
});
|
|
|
|
// Rybbit server-side tracking
|
|
const RYBBIT_HOST = process.env.NEXT_PUBLIC_RYBBIT_HOST || "https://rybbit.nodecrew.me";
|
|
const RYBBIT_API_KEY = process.env.RYBBIT_API_KEY;
|
|
const RYBBIT_SITE_ID = process.env.NEXT_PUBLIC_RYBBIT_SITE_ID || "1";
|
|
|
|
export interface ServerOrderData {
|
|
orderId: string;
|
|
orderNumber: string;
|
|
total: number;
|
|
currency: string;
|
|
itemCount: number;
|
|
customerEmail?: string;
|
|
paymentMethod?: string;
|
|
shippingCost?: number;
|
|
couponCode?: string;
|
|
}
|
|
|
|
export interface ServerEventData {
|
|
event: string;
|
|
properties?: Record<string, any>;
|
|
}
|
|
|
|
async function trackRybbitServer(eventName: string, properties?: Record<string, any>) {
|
|
try {
|
|
const headers: Record<string, string> = {
|
|
"Content-Type": "application/json",
|
|
};
|
|
if (RYBBIT_API_KEY) {
|
|
headers["Authorization"] = `Bearer ${RYBBIT_API_KEY}`;
|
|
}
|
|
|
|
const response = await fetch(`${RYBBIT_HOST}/api/track`, {
|
|
method: "POST",
|
|
headers,
|
|
body: JSON.stringify({
|
|
site_id: RYBBIT_SITE_ID,
|
|
type: "custom_event",
|
|
event_name: eventName,
|
|
properties: JSON.stringify(properties || {}),
|
|
}),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
console.warn("[Rybbit Server] Track failed:", await response.text());
|
|
}
|
|
} catch (error) {
|
|
console.warn("[Rybbit Server] Track error:", error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Server-side analytics tracking
|
|
* Called from API routes or Server Components
|
|
*/
|
|
export async function trackOrderCompletedServer(data: ServerOrderData) {
|
|
try {
|
|
console.log("[Server Analytics] Tracking order:", data.orderNumber, "Total:", data.total);
|
|
|
|
// Track order event with OpenPanel
|
|
await op.track("order_completed", {
|
|
order_id: data.orderId,
|
|
order_number: data.orderNumber,
|
|
total: data.total,
|
|
currency: data.currency,
|
|
item_count: data.itemCount,
|
|
customer_email: data.customerEmail,
|
|
payment_method: data.paymentMethod,
|
|
shipping_cost: data.shippingCost,
|
|
coupon_code: data.couponCode,
|
|
source: "server",
|
|
});
|
|
|
|
// Track revenue with OpenPanel
|
|
await op.revenue(data.total, {
|
|
currency: data.currency,
|
|
transaction_id: data.orderNumber,
|
|
order_id: data.orderId,
|
|
source: "server",
|
|
});
|
|
|
|
// Track conversion/revenue with Rybbit
|
|
await trackRybbitServer("order_completed", {
|
|
order_id: data.orderId,
|
|
order_number: data.orderNumber,
|
|
total: data.total,
|
|
currency: data.currency,
|
|
item_count: data.itemCount,
|
|
customer_email: data.customerEmail,
|
|
payment_method: data.paymentMethod,
|
|
shipping_cost: data.shippingCost,
|
|
coupon_code: data.couponCode,
|
|
revenue: data.total,
|
|
source: "server",
|
|
});
|
|
|
|
console.log("[Server Analytics] Order tracked successfully");
|
|
return { success: true };
|
|
} catch (error) {
|
|
console.error("[Server Analytics] Failed to track order:", error);
|
|
// Don't throw - analytics shouldn't break the app
|
|
return { success: false, error: String(error) };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Track any server-side event
|
|
*/
|
|
export async function trackServerEvent(data: ServerEventData) {
|
|
try {
|
|
await op.track(data.event, {
|
|
...data.properties,
|
|
source: "server",
|
|
});
|
|
|
|
// Also track to Rybbit
|
|
await trackRybbitServer(data.event, data.properties);
|
|
|
|
return { success: true };
|
|
} catch (error) {
|
|
console.error("[Server Analytics] Event tracking failed:", error);
|
|
return { success: false, error: String(error) };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Identify user server-side
|
|
*/
|
|
export async function identifyUserServer(profileId: string, properties?: Record<string, any>) {
|
|
try {
|
|
await op.identify({
|
|
profileId,
|
|
...properties,
|
|
});
|
|
return { success: true };
|
|
} catch (error) {
|
|
console.error("[Server Analytics] Identify failed:", error);
|
|
return { success: false, error: String(error) };
|
|
}
|
|
}
|