Next.js Integration
Capture errors from Next.js App Router and Pages Router applications.
Installation
npm install @statly/observeApp Router Setup
Initialize SDK
Create a provider component:
// app/providers.tsx
'use client';
import { useEffect } from 'react';
import { init } from '@statly/observe';
export function StatlyProvider({ children }: { children: React.ReactNode }) {
useEffect(() => {
init({
dsn: process.env.NEXT_PUBLIC_STATLY_DSN!,
environment: process.env.NODE_ENV,
});
}, []);
return <>{children}</>;
}Add to your layout:
// app/layout.tsx
import { StatlyProvider } from './providers';
export default function RootLayout({ children }) {
return (
<html>
<body>
<StatlyProvider>{children}</StatlyProvider>
</body>
</html>
);
}Error Boundary
Capture React errors:
// app/error.tsx
'use client';
import { useEffect } from 'react';
import { captureException } from '@statly/observe';
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
captureException(error, {
digest: error.digest,
source: 'error-boundary',
});
}, [error]);
return (
<div>
<h2>Something went wrong!</h2>
<button onClick={() => reset()}>Try again</button>
</div>
);
}Server Actions
Wrap server actions:
// app/actions.ts
'use server';
import { withStatlyServerAction } from '@statly/observe/nextjs';
async function createUserAction(data: FormData) {
// Your logic here
const user = await db.users.create({
name: data.get('name'),
});
return user;
}
export const createUser = withStatlyServerAction(
createUserAction,
'createUser'
);Route Handlers
Wrap App Router route handlers:
// app/api/users/route.ts
import { NextResponse } from 'next/server';
import { withStatly } from '@statly/observe/nextjs';
export const GET = withStatly(async (request) => {
const users = await db.users.findMany();
return NextResponse.json(users);
});
export const POST = withStatly(async (request) => {
const data = await request.json();
const user = await db.users.create(data);
return NextResponse.json(user, { status: 201 });
});Pages Router Setup
Initialize SDK
// pages/_app.tsx
import { useEffect } from 'react';
import { init } from '@statly/observe';
import type { AppProps } from 'next/app';
export default function App({ Component, pageProps }: AppProps) {
useEffect(() => {
init({
dsn: process.env.NEXT_PUBLIC_STATLY_DSN!,
environment: process.env.NODE_ENV,
});
}, []);
return <Component {...pageProps} />;
}API Routes
Wrap Pages Router API handlers:
// pages/api/users.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import { withStatlyPagesApi } from '@statly/observe/nextjs';
async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === 'GET') {
const users = await db.users.findMany();
res.json(users);
}
}
export default withStatlyPagesApi(handler);getServerSideProps
Wrap data fetching:
// pages/users/[id].tsx
import { withStatlyGetServerSideProps } from '@statly/observe/nextjs';
export const getServerSideProps = withStatlyGetServerSideProps(
async (context) => {
const user = await db.users.findUnique({
where: { id: context.params.id },
});
return { props: { user } };
}
);Exported Functions
withStatly(handler)
Wrap App Router route handlers:
import { withStatly } from '@statly/observe/nextjs';
export const GET = withStatly(async (request) => {
// Handler code
});withStatlyPagesApi(handler)
Wrap Pages Router API routes:
import { withStatlyPagesApi } from '@statly/observe/nextjs';
export default withStatlyPagesApi(async (req, res) => {
// Handler code
});withStatlyServerAction(action, name?)
Wrap server actions:
import { withStatlyServerAction } from '@statly/observe/nextjs';
export const myAction = withStatlyServerAction(
async (data) => { /* ... */ },
'myAction' // Optional name for tracking
);withStatlyGetServerSideProps(handler)
Wrap getServerSideProps:
import { withStatlyGetServerSideProps } from '@statly/observe/nextjs';
export const getServerSideProps = withStatlyGetServerSideProps(
async (context) => {
return { props: {} };
}
);withStatlyGetStaticProps(handler)
Wrap getStaticProps:
import { withStatlyGetStaticProps } from '@statly/observe/nextjs';
export const getStaticProps = withStatlyGetStaticProps(
async (context) => {
return { props: {} };
}
);captureNextJsError(error, context?)
Capture Next.js specific errors:
import { captureNextJsError } from '@statly/observe/nextjs';
// In error boundary
captureNextJsError(error, { page: '/users' });Automatically extracts Next.js error digest and adds source metadata.