Building Monitoring Dashboards with Next.js
The @unblind/nextjs package provides a complete solution for building customer-facing monitoring dashboards in your Next.js application. It includes a secure server-side proxy, React hooks for data fetching, and pre-built chart components.
Installation
Install the Next.js package, which includes both client and server components:
npm install @unblind/nextjs
Setup
1. Configure proxy/middleware
Create or update your proxy.ts or middleware.ts file:
Starting with Next.js 16, Middleware is now called Proxy. Ref
Code
import { unblindProxy } from "@unblind/nextjs/server";
export default unblindProxy((req) => req.cookies.get("userId")?.value);
export const config = {
matcher: "/api/unblind/:path*",
};
2. Environment Variables
Set your Unblind API key in your .env:
.env
UNBLIND_API_KEY=your_api_key_here
2. Add Unblind styles
Add Unblind styles to your global tailwind file.
globals.css
@import "@unblind/nextjs/styles.css";
@import "tailwindcss";
/* ... */
4. Wrap Your App with UnblindProvider
The UnblindProvider provides configuration to all Unblind components and hooks.
app/layout.tsx
import { UnblindProvider } from '@unblind/nextjs'
export default function RootLayout({ children }) {
return (
<html>
<body>
<UnblindProvider>
{children}
</UnblindProvider>
</body>
</html>
)
}
Build Your Dashboard
Use the Timeseries component to display metrics:
app/dashboard/page.tsx
'use client'
import { Timeseries } from '@unblind/nextjs'
export default function Dashboard() {
return (
<div className="grid grid-cols-2 gap-4">
<div>
<h3>CPU Usage</h3>
<Timeseries
metrics={['system.cpu.utilization']}
type="area"
/>
</div>
<div>
<h3>Memory Usage</h3>
<Timeseries
metrics={['system.memory.usage']}
type="line"
/>
</div>
<div>
<h3>Request Duration</h3>
<Timeseries
metrics={['http.server.duration']}
groupBy={['http.route']}
operator="p95"
type="bar"
/>
</div>
<div>
<h3>Error Rate</h3>
<Timeseries
metrics={['http.server.request.count']}
attributes={{
'http.status_code': ['500', '503', '504']
}}
type="line"
/>
</div>
</div>
)
}
Advanced Features
Dynamic Time Ranges
Allow users to change the time range dynamically:
app/dashboard/page.tsx
'use client'
import { useState } from 'react'
import { Scope, Timeseries, TimeRange } from '@unblind/nextjs'
export default function Dashboard() {
return (
<div>
<Scope>
<TimeRange />
<div className="grid grid-cols-2 gap-4">
<Timeseries metrics={['system.cpu.utilization']} />
<Timeseries metrics={['system.memory.usage']} />
</div>
</Scope>
</div>
)
}
Using Hooks for Custom Components
For more control, use hooks directly:
'use client'
import { useTimeseries, useMetrics } from '@unblind/nextjs'
export function CustomMetricCard() {
// Get list of available metrics
const { list, isLoading: metricsLoading } = useMetrics()
// Fetch timeseries data
const { data, isLoading, hasError } = useTimeseries({
queries: [
{
metrics: ['system.cpu.utilization'],
operator: 'avg',
groupBy: ['host.name'],
}
],
timeRange: '1h',
})
if (isLoading || metricsLoading) return <div>Loading...</div>
if (hasError) return <div>Error loading data</div>
const { series, times, metadata } = data
return (
<div>
{series.map((serie) => (
<div key={serie.metric}>
<h4>{metric.name}</h4>
<p>Latest: {serie.values[serie.values.length - 1]}</p>
</div>
))}
</div>
)
}
Fetching Logs
Use the useLogs hook for log data with infinite scroll:
'use client'
import { useLogs } from '@unblind/nextjs'
export function LogViewer() {
const { logs, isLoading, hasNextPage, fetchNextPage } = useLogs({
timeRange: '1h',
filters: [
{ name: 'severity', value: 'ERROR' },
{ name: 'service.name', value: 'api' }
]
})
return (
<div>
{logs.map((log, i) => (
<div key={i}>
<span>{new Date(log.timestamp).toISOString()}</span>
<span>{log.severity_text}</span>
<span>{log.body}</span>
</div>
))}
{hasNextPage && (
<button onClick={() => fetchNextPage()}>
Load More
</button>
)}
</div>
)
}
Usage Analytics
Track and display usage metrics:
'use client'
import { useUsage } from '@unblind/nextjs'
export function UsageChart() {
const { usage, isLoading } = useUsage({
timeRange: '30d'
})
if (isLoading) return <div>Loading...</div>
return (
<div>
{usage.map((day) => (
<div key={day.date}>
<span>{day.date}</span>
<span>Metrics: {day.metrics.units}</span>
<span>Logs: {day.logs.units} ({day.logs.bytes} bytes)</span>
</div>
))}
</div>
)
}
Refresh Data
Use the useRefresh hook to manually refresh all queries:
'use client'
import { useRefresh } from '@unblind/nextjs'
export function RefreshButton() {
const refresh = useRefresh()
return (
<button onClick={refresh}>
Refresh Dashboard
</button>
)
}
Next Steps
- React Package Guide - Use Unblind with other React frameworks
- API Reference - Explore all available endpoints
- Metrics Guide - Learn about supported metric types