Next.js Integration
Set up Apperio with Next.js App Router and Pages Router.
App Router Setup
With Next.js App Router, the SDK should be initialized client-side since it relies on browser APIs. Create a provider component marked with "use client":
npm install apperioclass="syntax-string">"use client";
import { useEffect, useRef } from class="syntax-string">"react";
import Apperio from class="syntax-string">"apperio";
export function ApperioProvider({ children }: { children: React.ReactNode }) {
const initialized = useRef(false);
useEffect(() => {
if (!initialized.current) {
Apperio.init({
projectId: process.env.NEXT_PUBLIC_APPERIO_PROJECT_ID!,
apiKey: process.env.NEXT_PUBLIC_APPERIO_API_KEY!,
environment: process.env.NODE_ENV,
autoCapture: {
errors: true,
performance: true,
network: true,
pageviews: true,
},
});
initialized.current = true;
}
return () => {
Apperio.flush();
};
}, []);
return <>{children}</>;
}Add the provider to your root layout:
import { ApperioProvider } from class="syntax-string">"./providers/ApperioProvider";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang=class="syntax-string">"en">
<body>
<ApperioProvider>
{children}
</ApperioProvider>
</body>
</html>
);
}Info
window, PerformanceObserver, and XMLHttpRequest. It must be initialized in a client component, not a server component.Client-Side Initialization
For pages that need logging before the provider mounts, you can also initialize in a client component directly:
class="syntax-string">"use client";
import { useEffect, useRef } from class="syntax-string">"react";
import Apperio from class="syntax-string">"apperio";
export function ApperioInit() {
const initialized = useRef(false);
useEffect(() => {
if (!initialized.current) {
Apperio.init({
projectId: process.env.NEXT_PUBLIC_APPERIO_PROJECT_ID!,
apiKey: process.env.NEXT_PUBLIC_APPERIO_API_KEY!,
});
initialized.current = true;
}
}, []);
return null; class="syntax-comment">// Renders nothing
}
class="syntax-comment">// Usage in a server component layout:
class="syntax-comment">// <ApperioInit />
class="syntax-comment">// <DashboardContent />Server-Side Logging
For server-side logging in Server Components, Server Actions, or Route Handlers, you can send logs directly to the Apperio API:
const API_BASE = process.env.APPERIO_API_URL
|| class="syntax-string">"https:class="syntax-comment">//apperioserver.onrender.com/api/v1";
const PROJECT_ID = process.env.APPERIO_PROJECT_ID;
const API_KEY = process.env.APPERIO_API_KEY;
interface ServerLogOptions {
level: class="syntax-string">"trace" | class="syntax-string">"debug" | class="syntax-string">"info" | class="syntax-string">"warn" | class="syntax-string">"error" | class="syntax-string">"fatal";
message: string;
data?: Record<string, any>;
service?: string;
}
export async function serverLog(options: ServerLogOptions) {
try {
await fetch(API_BASE + class="syntax-string">"/" + PROJECT_ID + class="syntax-string">"/logs", {
method: class="syntax-string">"POST",
headers: {
class="syntax-string">"Content-Type": class="syntax-string">"application/json",
class="syntax-string">"X-API-Key": API_KEY!,
},
body: JSON.stringify({
timestamp: new Date().toISOString(),
level: options.level,
message: options.message,
data: options.data,
service: options.service || class="syntax-string">"nextjs-server",
environment: process.env.NODE_ENV,
}),
});
} catch (err) {
console.error(class="syntax-string">"Failed to send server log:", err);
}
}
class="syntax-comment">// Usage in a Server Component or Server Action:
class="syntax-comment">// await serverLog({
class="syntax-comment">// level: class="syntax-string">"info",
class="syntax-comment">// message: class="syntax-string">"Page rendered",
class="syntax-comment">// data: { page: class="syntax-string">"/dashboard" },
class="syntax-comment">// });Warning
NEXT_PUBLIC_ prefix) are only available in server-side code. Use separate env vars for server and client.Middleware Integration
Log requests passing through Next.js middleware for observability into routing decisions:
import { NextResponse } from class="syntax-string">"next/server";
import type { NextRequest } from class="syntax-string">"next/server";
export async function middleware(request: NextRequest) {
const start = Date.now();
const response = NextResponse.next();
class="syntax-comment">// Log to Apperio(fire-and-forget)
const logData = {
timestamp: new Date().toISOString(),
level: class="syntax-string">"info",
message: class="syntax-string">"Middleware: " + request.method + class="syntax-string">" " + request.nextUrl.pathname,
service: class="syntax-string">"nextjs-middleware",
data: {
method: request.method,
path: request.nextUrl.pathname,
userAgent: request.headers.get(class="syntax-string">"user-agent"),
duration: Date.now() - start,
},
};
class="syntax-comment">// Non-blocking log send
fetch(process.env.APPERIO_API_URL + class="syntax-string">"/" + process.env.APPERIO_PROJECT_ID + class="syntax-string">"/logs", {
method: class="syntax-string">"POST",
headers: {
class="syntax-string">"Content-Type": class="syntax-string">"application/json",
class="syntax-string">"X-API-Key": process.env.APPERIO_API_KEY!,
},
body: JSON.stringify(logData),
}).catch(() => {
class="syntax-comment">// Silently fail - don't block the request
});
return response;
}Error Handling
Use Next.js error files with Apperio for comprehensive error reporting:
Global Error Handler
class="syntax-string">"use client";
import { useEffect } from class="syntax-string">"react";
import Apperio from class="syntax-string">"apperio";
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
Apperio.error(class="syntax-string">"Next.js page error", {
error: {
name: error.name,
message: error.message,
stack: error.stack,
digest: error.digest,
},
});
}, [error]);
return (
<div>
<h2>Something went wrong</h2>
<button onClick={reset}>Try again</button>
</div>
);
}Not Found Handler
import Apperio from class="syntax-string">"apperio";
export default function NotFound() {
class="syntax-comment">// Note: This is a server component, so use serverLog
class="syntax-comment">// or handle client-side
return (
<div>
<h2>Page Not Found</h2>
<NotFoundLogger />
</div>
);
}
class="syntax-comment">// Client component for logging
class="syntax-string">"use client";
function NotFoundLogger() {
useEffect(() => {
Apperio.warn(class="syntax-string">"class="syntax-number">404 - Page not found", {
url: window.location.href,
referrer: document.referrer,
});
}, []);
return null;
}Route Handler Logging
Log API route handler activity for server-side observability:
import { NextResponse } from class="syntax-string">"next/server";
import { serverLog } from class="syntax-string">"@/lib/server-logger";
export async function GET(request: Request) {
const start = Date.now();
try {
const users = await fetchUsers();
await serverLog({
level: class="syntax-string">"info",
message: class="syntax-string">"GET /api/users",
data: {
status: class="syntax-number">200,
count: users.length,
duration: Date.now() - start,
},
});
return NextResponse.json({ users });
} catch (err) {
await serverLog({
level: class="syntax-string">"error",
message: class="syntax-string">"GET /api/users failed",
data: {
error: err instanceof Error ? err.message : class="syntax-string">"Unknown error",
duration: Date.now() - start,
},
});
return NextResponse.json(
{ error: class="syntax-string">"Internal server error" },
{ status: class="syntax-number">500 }
);
}
}Environment Variables
Configure your .env.local with both client-side and server-side variables:
# Client-side(exposed to browser)
NEXT_PUBLIC_APPERIO_PROJECT_ID=your_project_id
NEXT_PUBLIC_APPERIO_API_KEY=your_api_key
# Server-side only(not exposed to browser)
APPERIO_PROJECT_ID=your_project_id
APPERIO_API_KEY=your_api_key
APPERIO_API_URL=https://apperioserver.onrender.com/api/v1| Variable | Scope | Used By |
|---|---|---|
NEXT_PUBLIC_APPERIO_PROJECT_ID | Client | SDK initialization in browser |
NEXT_PUBLIC_APPERIO_API_KEY | Client | SDK API authentication |
APPERIO_PROJECT_ID | Server | Server-side logging, middleware |
APPERIO_API_KEY | Server | Server-side API authentication |
APPERIO_API_URL | Server | API base URL for server logging |
Pages Router (Legacy)
If you are using the Pages Router, initialize Apperio in _app.tsx:
import { useEffect, useRef } from class="syntax-string">"react";
import Apperio from class="syntax-string">"apperio";
import type { AppProps } from class="syntax-string">"next/app";
export default function App({ Component, pageProps }: AppProps) {
const initialized = useRef(false);
useEffect(() => {
if (!initialized.current) {
Apperio.init({
projectId: process.env.NEXT_PUBLIC_APPERIO_PROJECT_ID!,
apiKey: process.env.NEXT_PUBLIC_APPERIO_API_KEY!,
environment: process.env.NODE_ENV,
});
initialized.current = true;
}
}, []);
return <Component {...pageProps} />;
}Tip