mirror of https://github.com/kortix-ai/suna.git
Integrate PostHog analytics and tracking
- Added PostHog client initialization in instrumentation-client.ts. - Configured Next.js rewrites for PostHog ingestion endpoints in next.config.ts. - Implemented user identification and event tracking in various components, including pricing-section.tsx, sidebar-left.tsx, chat-input.tsx, and api.ts. - Introduced PostHogIdentify component to handle user session changes. - Updated package.json and package-lock.json to include PostHog dependencies.
This commit is contained in:
parent
2975772806
commit
921925ac45
|
@ -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',
|
||||
});
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -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;
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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' });
|
||||
|
|
Loading…
Reference in New Issue