Skip to content

Next.js

5-minute integration for Next.js 14+. App Router is the recommended path; Pages Router is covered after.

Terminal window
bun add @goliapkg/sentori-next
# or
pnpm add @goliapkg/sentori-next

.env.local:

Terminal window
NEXT_PUBLIC_SENTORI_TOKEN=st_pk_...
NEXT_PUBLIC_SENTORI_RELEASE=myapp@1.2.3
NEXT_PUBLIC_SENTORI_ENVIRONMENT=prod

NEXT_PUBLIC_* is required so the SDK can read them on the browser side. Optional server-only overrides (SENTORI_TOKEN, etc.) let you differentiate server traffic on the dashboard.

// instrumentation.ts (project root)
export { register, onRequestError } from '@goliapkg/sentori-next/instrumentation'

That’s the entire server wiring. register() boots the SDK on Node start; onRequestError captures every server-side request error with route + method tags. The edge runtime is skipped automatically.

app/layout.tsx
'use client'
import { clientInit, SentoriProvider } from '@goliapkg/sentori-next/client'
clientInit() // reads NEXT_PUBLIC_SENTORI_*
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<SentoriProvider config={configFromEnv()}>{children}</SentoriProvider>
</body>
</html>
)
}
function configFromEnv() {
return {
token: process.env.NEXT_PUBLIC_SENTORI_TOKEN!,
release: process.env.NEXT_PUBLIC_SENTORI_RELEASE!,
environment: process.env.NEXT_PUBLIC_SENTORI_ENVIRONMENT ?? 'prod',
}
}
app/error.tsx
'use client'
import { useReportNextError } from '@goliapkg/sentori-next/app-router'
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
useReportNextError(error)
return (
<div>
<h2>Something went wrong</h2>
<button onClick={reset} type="button">Try again</button>
</div>
)
}

For a global catch-all that wraps the root layout too, drop the same component into app/global-error.tsx.

// app/Shell.tsx — thin client wrapper used by app/layout.tsx
'use client'
import { useNextRouter } from '@goliapkg/sentori-next/app-router'
export function Shell({ children }: { children: React.ReactNode }) {
useNextRouter()
return <>{children}</>
}
import { clientInit, SentoriProvider } from '@goliapkg/sentori-next/client'
clientInit()
export default function MyApp({ Component, pageProps }) {
return (
<SentoriProvider config={configFromEnv()}>
<Component {...pageProps} />
</SentoriProvider>
)
}
import { useCaptureError } from '@goliapkg/sentori-next/client'
import { useEffect } from 'react'
export default function ErrorPage({ statusCode }: { statusCode: number }) {
const capture = useCaptureError()
useEffect(() => {
capture(new Error(`Pages Router ${statusCode}`), {
tags: { source: 'next.pages._error' },
})
}, [capture, statusCode])
return <p>Sorry — something broke ({statusCode}).</p>
}

instrumentation.ts from §3a covers Pages API routes too — Next forwards both Pages and App Router errors through the same onRequestError hook.

next.config.js:

module.exports = {
productionBrowserSourceMaps: true,
}

Server-side maps are generated by default. After next build, the maps live in .next/static/chunks/*.map (browser) and .next/server/**/*.map (server).

sentori-cli upload sourcemap takes a release name + a file or directory and walks it for .js / .js.map pairs.

Terminal window
sentori-cli upload sourcemap \
--release "myapp@$(git rev-parse --short HEAD)" \
--token "$SENTORI_TOKEN" \
--ingest-url "$SENTORI_INGEST_URL" \
.next/static/chunks/

.github/workflows/deploy.yml:

name: Deploy
on:
push:
branches: [main]
jobs:
build-and-upload:
runs-on: ubuntu-latest
env:
SENTORI_TOKEN: ${{ secrets.SENTORI_TOKEN }}
SENTORI_INGEST_URL: https://ingest.sentori.golia.jp
NEXT_PUBLIC_SENTORI_TOKEN: ${{ secrets.SENTORI_TOKEN }}
NEXT_PUBLIC_SENTORI_RELEASE: myapp@${{ github.sha }}
NEXT_PUBLIC_SENTORI_ENVIRONMENT: prod
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install --frozen-lockfile
- run: bun run build
- name: Install sentori-cli
run: |
curl -fsSL https://cdn.sentori.golia.jp/install-cli.sh | bash
echo "$HOME/.sentori/bin" >> "$GITHUB_PATH"
- name: Upload sourcemaps
run: |
sentori-cli upload sourcemap \
--release "myapp@${{ github.sha }}" \
.next/static/chunks/
# ... your deploy step (Vercel CLI, AWS, Cloudflare Pages, ...)
SurfaceCaught by
Server Components / RSC throwsinstrumentation.ts:onRequestError
Route handlers (app/api/*/route.ts)instrumentation.ts:onRequestError
Pages Router API (pages/api/*)instrumentation.ts:onRequestError
Client component rendersapp/error.tsxuseReportNextError
Unhandled browser errors / promisesJS SDK global hooks (clientInit)