Merge pull request #1236 from mykonos-ibiza/feat-product-analytics

feat: analytics on various events
This commit is contained in:
Bobbie 2025-08-08 17:39:26 +05:30 committed by GitHub
commit b504d7bee9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 115 additions and 2 deletions

View File

@ -0,0 +1,11 @@
import posthog from 'posthog-js';
if (process.env.NEXT_PUBLIC_POSTHOG_KEY) {
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY, {
api_host: '/ingest',
ui_host: 'https://eu.posthog.com',
defaults: '2025-05-24',
capture_exceptions: true, // This enables capturing exceptions using Error Tracking, set to false if you don't want this
debug: process.env.NODE_ENV === 'development',
});
}

View File

@ -2,6 +2,23 @@ import type { NextConfig } from 'next';
const nextConfig = (): NextConfig => ({
output: (process.env.NEXT_OUTPUT as 'standalone') || undefined,
async rewrites() {
return [
{
source: '/ingest/static/:path*',
destination: 'https://eu-assets.i.posthog.com/static/:path*',
},
{
source: '/ingest/:path*',
destination: 'https://eu.i.posthog.com/:path*',
},
{
source: '/ingest/flags',
destination: 'https://eu.i.posthog.com/flags',
},
];
},
skipTrailingSlashRedirect: true,
});
export default nextConfig;

View File

@ -86,6 +86,8 @@
"papaparse": "^5.5.2",
"pdfjs-dist": "4.8.69",
"postcss": "8.4.33",
"posthog-js": "^1.258.6",
"posthog-node": "^5.6.0",
"react": "^18",
"react-day-picker": "^8.10.1",
"react-diff-viewer-continued": "^3.4.0",
@ -7473,7 +7475,6 @@
"integrity": "sha512-Sz4PP4ZA+Rq4II21qkNqOEDTDrCvcANId3xpIgB34NDkWc3UduWj2dqEtN9yZIq8Dk3HyPI33x9sqqU5C8sr0g==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/core-js"
@ -12488,6 +12489,45 @@
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
"license": "MIT"
},
"node_modules/posthog-js": {
"version": "1.258.6",
"resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.258.6.tgz",
"integrity": "sha512-vL5AGG+rOoRg3LGquMfBPO55jD4bGl0CiV44SHdHAoBnOVDDAqxczRGDqMdxor+VLx3/ofTFOJ2FNprfAHp70Q==",
"license": "SEE LICENSE IN LICENSE",
"dependencies": {
"core-js": "^3.38.1",
"fflate": "^0.4.8",
"preact": "^10.19.3",
"web-vitals": "^4.2.4"
},
"peerDependencies": {
"@rrweb/types": "2.0.0-alpha.17",
"rrweb-snapshot": "2.0.0-alpha.17"
},
"peerDependenciesMeta": {
"@rrweb/types": {
"optional": true
},
"rrweb-snapshot": {
"optional": true
}
}
},
"node_modules/posthog-js/node_modules/fflate": {
"version": "0.4.8",
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz",
"integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==",
"license": "MIT"
},
"node_modules/posthog-node": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-5.6.0.tgz",
"integrity": "sha512-MVXxKmqAYp2cPBrN1YMhnhYsJYIu6yc6wumbHz1dbo67wZBf2WtMm67Uh+4VCrp07049qierWlxQqz1W5zGDeg==",
"license": "MIT",
"engines": {
"node": ">=20"
}
},
"node_modules/preact": {
"version": "10.26.8",
"resolved": "https://registry.npmjs.org/preact/-/preact-10.26.8.tgz",
@ -14915,6 +14955,12 @@
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/web-vitals": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz",
"integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==",
"license": "Apache-2.0"
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",

View File

@ -89,6 +89,8 @@
"papaparse": "^5.5.2",
"pdfjs-dist": "4.8.69",
"postcss": "8.4.33",
"posthog-js": "^1.258.6",
"posthog-node": "^5.6.0",
"react": "^18",
"react-day-picker": "^8.10.1",
"react-diff-viewer-continued": "^3.4.0",

View File

@ -9,6 +9,7 @@ import { Analytics } from '@vercel/analytics/react';
import { GoogleAnalytics } from '@next/third-parties/google';
import { SpeedInsights } from '@vercel/speed-insights/next';
import Script from 'next/script';
import { PostHogIdentify } from '@/components/posthog-identify';
const geistSans = Geist({
variable: '--font-geist-sans',
@ -152,6 +153,7 @@ export default function RootLayout({
<Analytics />
<GoogleAnalytics gaId="G-6ETJFB3PT3" />
<SpeedInsights />
<PostHogIdentify />
</ThemeProvider>
</body>
</html>

View File

@ -16,6 +16,7 @@ import {
import { toast } from 'sonner';
import { isLocalMode, isYearlyCommitmentDowngrade, isPlanChangeAllowed, getPlanInfo } from '@/lib/config';
import { useSubscription, useSubscriptionCommitment } from '@/hooks/react-query';
import posthog from 'posthog-js';
// Constants
export const SUBSCRIPTION_PLANS = {
@ -241,6 +242,7 @@ function PricingTier({
case 'checkout_created':
case 'commitment_created':
if (response.url) {
posthog.capture('plan_purchase_attempted');
window.location.href = response.url;
} else {
console.error(
@ -255,6 +257,7 @@ function PricingTier({
? `Subscription upgraded from $${response.details.current_price} to $${response.details.new_price}`
: 'Subscription updated successfully';
toast.success(upgradeMessage);
posthog.capture('plan_upgraded');
if (onSubscriptionUpdate) onSubscriptionUpdate();
break;
case 'commitment_blocks_downgrade':
@ -276,6 +279,7 @@ function PricingTier({
</p>
</div>,
);
posthog.capture('plan_downgraded');
if (onSubscriptionUpdate) onSubscriptionUpdate();
break;
case 'no_change':

View File

@ -0,0 +1,24 @@
'use client';
import posthog from 'posthog-js';
import { useEffect } from 'react';
import { createClient } from '@/lib/supabase/client';
export const PostHogIdentify = () => {
useEffect(() => {
const supabase = createClient();
const listener = supabase.auth.onAuthStateChange((_, session) => {
if (session) {
posthog.identify(session.user.id, { email: session.user.email });
} else {
posthog.reset();
}
});
return () => {
listener.data.subscription.unsubscribe();
};
}, []);
return null;
};

View File

@ -41,6 +41,7 @@ import { useIsMobile } from '@/hooks/use-mobile';
import { cn } from '@/lib/utils';
import { usePathname, useSearchParams } from 'next/navigation';
import { useFeatureFlags } from '@/lib/feature-flags';
import posthog from 'posthog-js';
export function SidebarLeft({
...props
@ -150,7 +151,7 @@ export function SidebarLeft({
<Link href="/dashboard">
<SidebarMenuButton className={cn({
'bg-accent text-accent-foreground font-medium': pathname === '/dashboard',
})}>
})} onClick={() => posthog.capture('new_task_clicked')}>
<Plus className="h-4 w-4 mr-1" />
<span className="flex items-center justify-between w-full">
New Task

View File

@ -28,6 +28,7 @@ import { useSubscriptionWithStreaming } from '@/hooks/react-query/subscriptions/
import { isLocalMode } from '@/lib/config';
import { BillingModal } from '@/components/billing/billing-modal';
import { useRouter } from 'next/navigation';
import posthog from 'posthog-js';
export interface ChatInputHandles {
getPendingFiles: () => File[];
@ -282,6 +283,8 @@ export const ChatInput = forwardRef<ChatInputHandles, ChatInputProps>(
thinkingEnabled = true;
}
posthog.capture("task_prompt_submitted", { message });
onSubmit(message, {
model_name: baseModelName,
enable_thinking: thinkingEnabled,

View File

@ -1,5 +1,6 @@
import { createClient } from '@/lib/supabase/client';
import { handleApiError } from './error-handler';
import posthog from 'posthog-js';
// Get backend URL from environment variables
const API_URL = process.env.NEXT_PUBLIC_BACKEND_URL || '';
@ -838,6 +839,8 @@ export const stopAgent = async (agentRunId: string): Promise<void> => {
cache: 'no-store',
});
posthog.capture('task_abandoned', { agentRunId });
if (!response.ok) {
const stopError = new Error(`Error stopping agent: ${response.statusText}`);
handleApiError(stopError, { operation: 'stop agent', resource: 'AI assistant' });