Some checks failed
Build and Deploy / build (push) Has been cancelled
- Add Next.js rewrites to proxy /api/script.js and /api/track through self-hosted Rybbit - This bypasses ad blockers that would block rybbit.nodecrew.me directly - Add NEXT_PUBLIC_RYBBIT_HOST and NEXT_PUBLIC_RYBBIT_SITE_ID env vars to K8s deployment
210 lines
4.6 KiB
TypeScript
210 lines
4.6 KiB
TypeScript
"use client";
|
|
|
|
// Rybbit Analytics Service
|
|
// Self-hosted instance at rybbit.nodecrew.me
|
|
|
|
declare global {
|
|
interface Window {
|
|
rybbit?: {
|
|
event: (eventName: string, eventData?: Record<string, any>) => void;
|
|
pageview: () => void;
|
|
};
|
|
}
|
|
}
|
|
|
|
export const RYBBIT_HOST = process.env.NEXT_PUBLIC_RYBBIT_HOST || "https://rybbit.nodecrew.me";
|
|
export const RYBBIT_SITE_ID = process.env.NEXT_PUBLIC_RYBBIT_SITE_ID || "1";
|
|
|
|
/**
|
|
* Check if Rybbit is loaded and available
|
|
*/
|
|
export function isRybbitAvailable(): boolean {
|
|
return typeof window !== "undefined" &&
|
|
!!window.rybbit &&
|
|
typeof window.rybbit.event === "function";
|
|
}
|
|
|
|
/**
|
|
* Track a custom event with Rybbit
|
|
*/
|
|
export function trackRybbitEvent(
|
|
eventName: string,
|
|
eventData?: Record<string, any>
|
|
): void {
|
|
if (isRybbitAvailable()) {
|
|
try {
|
|
window.rybbit!.event(eventName, eventData);
|
|
} catch (e) {
|
|
console.warn("[Rybbit] Event tracking error:", e);
|
|
}
|
|
} else {
|
|
console.warn("[Rybbit] Not available for event:", eventName);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Track page view manually (usually auto-tracked by Rybbit script)
|
|
*/
|
|
export function trackRybbitPageview(): void {
|
|
if (isRybbitAvailable()) {
|
|
try {
|
|
window.rybbit!.pageview();
|
|
} catch (e) {
|
|
console.warn("[Rybbit] Pageview error:", e);
|
|
}
|
|
}
|
|
}
|
|
|
|
// E-commerce Event Tracking Functions
|
|
|
|
export function trackRybbitProductView(product: {
|
|
id: string;
|
|
name: string;
|
|
price: number;
|
|
currency: string;
|
|
category?: string;
|
|
variant?: string;
|
|
}): void {
|
|
trackRybbitEvent("product_view", {
|
|
product_id: product.id,
|
|
product_name: product.name,
|
|
price: product.price,
|
|
currency: product.currency,
|
|
category: product.category,
|
|
variant: product.variant,
|
|
});
|
|
}
|
|
|
|
export function trackRybbitAddToCart(product: {
|
|
id: string;
|
|
name: string;
|
|
price: number;
|
|
currency: string;
|
|
quantity: number;
|
|
variant?: string;
|
|
}): void {
|
|
trackRybbitEvent("add_to_cart", {
|
|
product_id: product.id,
|
|
product_name: product.name,
|
|
price: product.price,
|
|
currency: product.currency,
|
|
quantity: product.quantity,
|
|
variant: product.variant,
|
|
});
|
|
}
|
|
|
|
export function trackRybbitRemoveFromCart(product: {
|
|
id: string;
|
|
name: string;
|
|
quantity: number;
|
|
}): void {
|
|
trackRybbitEvent("remove_from_cart", {
|
|
product_id: product.id,
|
|
product_name: product.name,
|
|
quantity: product.quantity,
|
|
});
|
|
}
|
|
|
|
export function trackRybbitCartView(cart: {
|
|
total: number;
|
|
currency: string;
|
|
item_count: number;
|
|
}): void {
|
|
trackRybbitEvent("cart_view", {
|
|
cart_total: cart.total,
|
|
currency: cart.currency,
|
|
item_count: cart.item_count,
|
|
});
|
|
}
|
|
|
|
export function trackRybbitCheckoutStarted(cart: {
|
|
total: number;
|
|
currency: string;
|
|
item_count: number;
|
|
items: Array<{
|
|
id: string;
|
|
name: string;
|
|
quantity: number;
|
|
price: number;
|
|
}>;
|
|
}): void {
|
|
trackRybbitEvent("checkout_started", {
|
|
cart_total: cart.total,
|
|
currency: cart.currency,
|
|
item_count: cart.item_count,
|
|
items: cart.items,
|
|
});
|
|
}
|
|
|
|
export function trackRybbitCheckoutStep(step: string, data?: Record<string, unknown>): void {
|
|
trackRybbitEvent("checkout_step", {
|
|
step,
|
|
...data,
|
|
});
|
|
}
|
|
|
|
export function trackRybbitOrderCompleted(order: {
|
|
order_id: string;
|
|
order_number: string;
|
|
total: number;
|
|
currency: string;
|
|
item_count: number;
|
|
shipping_cost?: number;
|
|
customer_email?: string;
|
|
payment_method?: string;
|
|
}): void {
|
|
trackRybbitEvent("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,
|
|
payment_method: order.payment_method,
|
|
});
|
|
}
|
|
|
|
export function trackRybbitSearch(query: string, results_count: number): void {
|
|
trackRybbitEvent("search", {
|
|
query,
|
|
results_count,
|
|
});
|
|
}
|
|
|
|
export function trackRybbitExternalLink(url: string, label?: string): void {
|
|
trackRybbitEvent("external_link_click", {
|
|
url,
|
|
label,
|
|
});
|
|
}
|
|
|
|
export function trackRybbitNewsletterSignup(email: string, source: string): void {
|
|
trackRybbitEvent("newsletter_signup", {
|
|
email,
|
|
source,
|
|
});
|
|
}
|
|
|
|
export function trackRybbitWishlistAdd(product: {
|
|
id: string;
|
|
name: string;
|
|
}): void {
|
|
trackRybbitEvent("wishlist_add", {
|
|
product_id: product.id,
|
|
product_name: product.name,
|
|
});
|
|
}
|
|
|
|
export function trackRybbitUserLogin(method: string): void {
|
|
trackRybbitEvent("user_login", {
|
|
method,
|
|
});
|
|
}
|
|
|
|
export function trackRybbitUserRegister(method: string): void {
|
|
trackRybbitEvent("user_register", {
|
|
method,
|
|
});
|
|
}
|