| name | clerk-observability |
| description | Implement monitoring, logging, and observability for Clerk authentication.
Use when setting up monitoring, debugging auth issues in production,
or implementing audit logging.
Trigger with phrases like "clerk monitoring", "clerk logging",
"clerk observability", "clerk metrics", "clerk audit log".
|
| allowed-tools | Read, Write, Edit, Bash(npm:*), Grep |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
Clerk Observability
Overview
Implement comprehensive monitoring, logging, and observability for Clerk authentication.
Prerequisites
- Clerk integration working
- Monitoring platform (DataDog, New Relic, Sentry, etc.)
- Logging infrastructure
Instructions
Step 1: Authentication Event Logging
import { auth, currentUser } from '@clerk/nextjs/server'
interface AuthEvent {
type: string
userId: string | null
timestamp: string
metadata: Record<string, any>
}
class AuthLogger {
private events: AuthEvent[] = []
log(type: string, metadata: Record<string, any> = {}) {
const event: AuthEvent = {
type,
userId: null,
timestamp: new Date().toISOString(),
metadata
}
this.events.push(event)
console.log('[Auth Event]', JSON.stringify(event))
this.sendToMonitoring(event)
}
async logWithAuth(type: string, metadata: Record<string, any> = {}) {
const { userId, sessionId } = await auth()
const event: AuthEvent = {
type,
userId,
timestamp: new Date().toISOString(),
metadata: {
...metadata,
sessionId,
hasUser: !!userId
}
}
this.events.push(event)
console.log('[Auth Event]', JSON.stringify(event))
this.sendToMonitoring(event)
}
private sendToMonitoring(event: AuthEvent) {
if (process.env.DD_API_KEY) {
fetch('https://http-intake.logs.datadoghq.com/v1/input', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'DD-API-KEY': process.env.DD_API_KEY
},
body: JSON.stringify({
ddsource: 'clerk',
ddtags: 'env:production',
message: event
})
}).catch(console.error)
}
}
}
export const authLogger = new AuthLogger()
Step 2: Middleware Monitoring
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'
import { NextResponse } from 'next/server'
const isPublicRoute = createRouteMatcher(['/', '/sign-in(.*)', '/sign-up(.*)'])
export default clerkMiddleware(async (auth, request) => {
const start = performance.now()
const { userId, sessionId } = await auth()
const authDuration = performance.now() - start
const response = NextResponse.next()
response.headers.set('x-auth-duration', String(authDuration.toFixed(2)))
response.headers.set('x-auth-user', userId || 'anonymous')
if (authDuration > 100) {
console.warn('[Clerk Perf] Slow auth check:', {
duration: authDuration,
path: request.nextUrl.,
userId
})
}
(, authDuration)
(, userId ? : )
response
})
() {
.()
}
Step 3: Session Analytics
import { clerkClient } from '@clerk/nextjs/server'
interface SessionMetrics {
totalSessions: number
activeSessions: number
averageSessionDuration: number
sessionsByDevice: Record<string, number>
}
export async function getSessionMetrics(userId: string): Promise<SessionMetrics> {
const client = await clerkClient()
const sessions = await client.sessions.getSessionList({
userId,
status: 'active'
})
const sessionsByDevice: Record<string, number> = {}
let totalDuration = 0
for (const session of sessions.data) {
const device = parseDeviceType(session.userAgent || '')
sessionsByDevice[device] = (sessionsByDevice[device] || ) +
duration = .() - (session.).()
totalDuration += duration
}
{
: sessions.,
: sessions..,
: totalDuration / sessions.. || ,
sessionsByDevice
}
}
(): {
(.(userAgent))
(.(userAgent))
}
Step 4: Webhook Event Tracking
import { Webhook } from 'svix'
import { headers } from 'next/headers'
import { WebhookEvent } from '@clerk/nextjs/server'
const webhookMetrics = {
received: 0,
processed: 0,
failed: 0,
byType: {} as Record<string, number>
}
export async function POST(req: Request) {
webhookMetrics.received++
const start = performance.now()
const headerPayload = await headers()
const svix_id = headerPayload.get('svix-id')!
try {
const evt = wh.verify(body, headers) as WebhookEvent
const eventType = evt.type
webhookMetrics.byType[eventType] = (webhookMetrics.byType[eventType] || ) +
(evt)
webhookMetrics.++
.(, {
: eventType,
: svix_id,
: performance.() - start,
:
})
.({ : })
} (error) {
webhookMetrics.++
.(, {
: svix_id,
: error.,
: performance.() - start
})
.({ : }, { : })
}
}
() {
.(webhookMetrics)
}
Step 5: Error Tracking with Sentry
import * as Sentry from '@sentry/nextjs'
import { auth, currentUser } from '@clerk/nextjs/server'
export async function initSentryWithClerk() {
const { userId, orgId } = await auth()
if (userId) {
Sentry.setUser({
id: userId,
})
Sentry.setContext('clerk', {
userId,
orgId,
hasOrg: !!orgId
})
}
}
export async function withAuthErrorTracking<T>(
operation: () => Promise<T>,
context: string
): Promise<T> {
try {
return await operation()
} catch (error) {
Sentry.captureException(error, {
tags: {
component: 'clerk',
operation: context
}
})
throw error
}
}
user = (
(),
)
Step 6: Health Check Endpoint
import { auth, clerkClient } from '@clerk/nextjs/server'
interface HealthStatus {
status: 'healthy' | 'degraded' | 'unhealthy'
checks: {
auth: { status: string; latency: number }
api: { status: string; latency: number }
webhooks: { status: string; lastReceived: string | null }
}
timestamp: string
}
export async function GET() {
const health: HealthStatus = {
status: 'healthy',
checks: {
auth: { status: 'unknown', latency: 0 },
api: { status: 'unknown', latency: 0 },
webhooks: { status: 'unknown', lastReceived: null }
},
: ().()
}
authStart = performance.()
{
()
health.. = {
: ,
: performance.() - authStart
}
} {
health.. = {
: ,
: performance.() - authStart
}
health. =
}
apiStart = performance.()
{
client = ()
client..({ : })
health.. = {
: ,
: performance.() - apiStart
}
} {
health.. = {
: ,
: performance.() - apiStart
}
health. =
}
.(health)
}
Dashboard Metrics
Track these key metrics:
- Authentication success/failure rate
- Auth latency (p50, p95, p99)
- Active sessions over time
- Webhook processing time
- Error rate by type
Output
- Authentication event logging
- Performance monitoring
- Error tracking integration
- Health check endpoints
Error Handling
| Issue | Monitoring Action |
|---|
| High auth latency | Alert on p95 > 200ms |
| Failed webhooks | Alert on failure rate > 1% |
| Session anomalies | Track unusual session patterns |
| API errors | Capture with Sentry context |
Resources
Next Steps
Proceed to clerk-incident-runbook for incident response procedures.