Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions apps/next-js/15-app-router-todo/components/todos/todo-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { useState, useEffect } from 'react';
import Link from 'next/link';
import posthog from 'posthog-js';
import { Todo } from '@/lib/data';
import { TodoForm } from './todo-form';
import { TodoItem } from './todo-item';
Expand All @@ -24,6 +25,9 @@ export function TodoList() {
}
} catch (error) {
console.error('Failed to fetch todos:', error);
posthog.capture('todo_fetch_error', {
error: error instanceof Error ? error.message : 'Unknown error',
});
} finally {
setLoading(false);
}
Expand All @@ -42,9 +46,16 @@ export function TodoList() {
if (response.ok) {
const newTodo = await response.json();
setTodos([...todos, newTodo]);
posthog.capture('todo_created', {
todo_id: newTodo.id,
has_description: !!description,
});
}
} catch (error) {
console.error('Failed to add todo:', error);
posthog.capture('todo_create_error', {
error: error instanceof Error ? error.message : 'Unknown error',
});
}
};

Expand All @@ -61,9 +72,22 @@ export function TodoList() {
if (response.ok) {
const updatedTodo = await response.json();
setTodos(todos.map((todo) => (todo.id === id ? updatedTodo : todo)));
if (completed) {
posthog.capture('todo_completed', {
todo_id: id,
});
} else {
posthog.capture('todo_uncompleted', {
todo_id: id,
});
}
}
} catch (error) {
console.error('Failed to update todo:', error);
posthog.capture('todo_update_error', {
todo_id: id,
error: error instanceof Error ? error.message : 'Unknown error',
});
}
};

Expand All @@ -75,9 +99,16 @@ export function TodoList() {

if (response.ok) {
setTodos(todos.filter((todo) => todo.id !== id));
posthog.capture('todo_deleted', {
todo_id: id,
});
}
} catch (error) {
console.error('Failed to delete todo:', error);
posthog.capture('todo_delete_error', {
todo_id: id,
error: error instanceof Error ? error.message : 'Unknown error',
});
}
};

Expand Down
14 changes: 14 additions & 0 deletions apps/next-js/15-app-router-todo/instrumentation-client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import posthog from "posthog-js"

posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
api_host: "/ingest",
ui_host: "https://us.posthog.com",
// Include the defaults option as required by PostHog
defaults: '2025-05-24',
// Enables capturing unhandled exceptions via Error Tracking
capture_exceptions: true,
// Turn on debug in development mode
debug: process.env.NODE_ENV === "development",
});

//IMPORTANT: Never combine this approach with other client-side PostHog initialization approaches, especially components like a PostHogProvider. instrumentation-client.ts is the correct solution for initializating client-side PostHog in Next.js 15.3+ apps.
14 changes: 14 additions & 0 deletions apps/next-js/15-app-router-todo/next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@ import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
// Configuration for stable Next.js 15
async rewrites() {
return [
{
source: "/ingest/static/:path*",
destination: "https://us-assets.i.posthog.com/static/:path*",
},
{
source: "/ingest/:path*",
destination: "https://us.i.posthog.com/:path*",
},
];
},
// This is required to support PostHog trailing slash API requests
skipTrailingSlashRedirect: true,
};

export default nextConfig;
2 changes: 2 additions & 0 deletions apps/next-js/15-app-router-todo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
"lucide-react": "^0.511.0",
"next": "15.5.7",
"postcss": "^8.5.3",
"posthog-js": "^1.321.2",
"posthog-node": "^5.21.0",
"radix-ui": "^1.4.2",
"react": "19.1.2",
"react-dom": "19.1.2",
Expand Down
Loading