Grafana Dashboard Integration
This guide explains how to integrate Grafana dashboards into the OpportunityDAO admin panel.
Overview
The integration allows you to embed Grafana dashboards directly into the Reserves page, providing real-time monitoring of:
- Reserve account balances
- Transaction history
- Performance metrics
- Custom analytics
Architecture
The integration uses a proxy pattern for security:
- Frontend requests dashboard content
- Backend proxies requests to Grafana with service token
- Service token never exposed to client
- Only authenticated founders can access
┌─────────┐ ┌──────────┐ ┌─────────┐
│ Browser │ ───> │ Next.js │ ───> │ Grafana │
│ │ <─── │ Backend │ <─── │ │
└─────────┘ └──────────┘ └─────────┘
(with token)
Setup Instructions
1. Create Grafana Service Account
- Log into your Grafana instance as an admin
- Navigate to Administration → Service accounts
- Click Add service account
- Configure the account:
- Name: OpportunityDAO Embed
- Role: Viewer (or Editor if needed)
- Description: Service account for embedding dashboards
- Click Create
- Click Add service account token
- Set token name (e.g., "Production") and expiration
- Click Generate token
- Copy the token immediately - it won't be shown again!
2. Find Your Dashboard UID
- Open the dashboard you want to embed
- Click the Settings gear icon (⚙️) in the top right
- Look at the URL:
/d/{UID}/dashboard-name - Or find the UID in the General section
- Copy the UID (e.g.,
abc123def456)
3. Configure Environment Variables
Add these variables to your .env file:
# Enable Grafana integration
NEXT_PUBLIC_GRAFANA_ENABLED=true
# Your Grafana instance URL (without trailing slash)
NEXT_PUBLIC_GRAFANA_URL=https://grafana.yourdomain.com
# Dashboard UID from step 2
NEXT_PUBLIC_GRAFANA_DASHBOARD_UID=abc123def456
# Server-side configuration (DO NOT prefix with NEXT_PUBLIC_)
GRAFANA_URL=https://grafana.yourdomain.com
GRAFANA_SERVICE_TOKEN=glsa_xxxxxxxxxxxxxxxxxxxxx
4. Configure Grafana Embedding Settings
In your Grafana instance:
-
Go to Configuration → Settings
-
Find the
[security]section -
Enable anonymous access for embedding (optional):
[auth.anonymous]
enabled = true
org_role = Viewer -
Or configure CORS if needed:
[security]
allow_embedding = true
cookie_samesite = none
cookie_secure = true
5. Restart Your Application
npm run dev # Development
# or
npm run build && npm start # Production
Usage
Basic Dashboard Embed
The dashboard will automatically appear on the Reserves page (/admin/reserves) when configured.
Custom Dashboard Usage
You can embed dashboards in other pages using the GrafanaDashboard component:
import GrafanaDashboard from '@/components/GrafanaDashboard';
export default function MyPage() {
return (
<div>
<h1>Custom Dashboard</h1>
<GrafanaDashboard
dashboardUid="abc123def456"
theme="light"
height="800px"
refreshInterval={30000}
from="now-24h"
to="now"
/>
</div>
);
}
Component Props
| Prop | Type | Default | Description |
|---|---|---|---|
dashboardUid | string | required | Dashboard UID from Grafana |
panelId | number | undefined | Specific panel ID to show (omit for full dashboard) |
theme | 'light' | 'dark' | 'light' | Dashboard theme |
height | string | '600px' | Height of dashboard iframe |
refreshInterval | number | undefined | Auto-refresh interval in milliseconds |
from | string | 'now-6h' | Time range start (Grafana format) |
to | string | 'now' | Time range end (Grafana format) |
Embed Single Panel
To embed just one panel instead of the full dashboard:
<GrafanaDashboard
dashboardUid="abc123def456"
panelId={2} // Panel ID from Grafana
height="400px"
/>
Finding Panel ID:
- Open dashboard in Grafana
- Click panel title → Edit
- Look at URL:
?editPanel={panelId}
API Endpoints
Grafana Proxy API
The backend provides a proxy API for secure Grafana requests:
GET /api/admin/grafana/proxy?path={grafana-path}
- Proxies GET requests to Grafana
- Adds service token authentication
- Requires founder authentication
POST /api/admin/grafana/proxy?path={grafana-path}
- Proxies POST requests to Grafana
- Adds service token authentication
- Requires founder authentication
Security Considerations
-
Service Token Storage
- Service token stored server-side only
- Never exposed to client
- Use environment variables, not code
-
Access Control
- Only founders can access Grafana proxy
- Authentication checked on every request
- Audit log all access (future enhancement)
-
Token Permissions
- Use minimum required permissions (Viewer)
- Set token expiration
- Rotate tokens regularly
-
CORS & Embedding
- Configure Grafana embedding settings
- Use HTTPS in production
- Set appropriate cookie settings
Troubleshooting
Dashboard Not Showing
-
Check environment variables:
echo $NEXT_PUBLIC_GRAFANA_ENABLED
echo $NEXT_PUBLIC_GRAFANA_URL
echo $NEXT_PUBLIC_GRAFANA_DASHBOARD_UID -
Verify service token:
curl -H "Authorization: Bearer $GRAFANA_SERVICE_TOKEN" \
$GRAFANA_URL/api/dashboards/uid/$DASHBOARD_UID -
Check browser console for errors
CORS Errors
If you see CORS errors in the console:
- Configure Grafana
allow_embedding = true - Set
cookie_samesite = noneandcookie_secure = true - Ensure Grafana URL uses HTTPS
Authentication Issues
If you get 401 errors:
- Verify service token is valid
- Check token hasn't expired
- Ensure service account has Viewer role
- Verify dashboard is accessible with the token
iframe Not Loading
If the iframe appears but doesn't load:
- Check Grafana embedding settings
- Verify dashboard UID is correct
- Look for X-Frame-Options errors
- Check browser console for security errors
Example Dashboards
Reserves Monitoring Dashboard
Create a Grafana dashboard with these panels:
-
Total Reserves Balance (Stat panel)
- Shows current total balance across all accounts
- Color-coded thresholds
-
Balance by Account (Bar chart)
- Breakdown by broker/wallet
- Sortable
-
24h Balance Changes (Time series)
- Balance trends over time
- Multiple series per account
-
Recent Transactions (Table)
- Latest deposits/withdrawals
- Transaction details
-
Reserve Ratio (Gauge)
- Reserves vs. deployed capital
- Warning thresholds
Advanced Usage
Multiple Dashboards
You can embed multiple dashboards on the same page:
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<GrafanaDashboard
dashboardUid="overview-uid"
height="400px"
/>
<GrafanaDashboard
dashboardUid="details-uid"
height="400px"
/>
</div>
Dynamic Time Ranges
Control time range programmatically:
const [timeRange, setTimeRange] = useState({ from: 'now-6h', to: 'now' });
<GrafanaDashboard
dashboardUid="abc123def456"
from={timeRange.from}
to={timeRange.to}
/>
Custom Refresh Intervals
Different refresh rates for different dashboards:
// Real-time (10 seconds)
<GrafanaDashboard dashboardUid="realtime-uid" refreshInterval={10000} />
// Standard (30 seconds)
<GrafanaDashboard dashboardUid="standard-uid" refreshInterval={30000} />
// Slow (5 minutes)
<GrafanaDashboard dashboardUid="historical-uid" refreshInterval={300000} />
Production Deployment
Environment Variables Checklist
-
NEXT_PUBLIC_GRAFANA_ENABLEDset totrue -
NEXT_PUBLIC_GRAFANA_URLpoints to production Grafana -
NEXT_PUBLIC_GRAFANA_DASHBOARD_UIDis correct -
GRAFANA_URLmatches public URL -
GRAFANA_SERVICE_TOKENis production token - All URLs use HTTPS
- Service token has appropriate permissions
- Token expiration is set
Monitoring
Monitor Grafana integration health:
- Track iframe load times
- Monitor proxy API response times
- Alert on authentication failures
- Log dashboard access for audit
Support
For issues with:
- Grafana setup: See Grafana Documentation
- Integration bugs: Open issue in repository
- Security concerns: Contact security team