Usage
API usage metrics and limits view component for DeveloperApp
Usage
The Usage view provides comprehensive API usage analytics, rate limiting information, quota tracking, and billing insights. Monitor API consumption patterns and optimize usage across endpoints and time periods.
Type Signature
interface UsageViewProps {
/** Page title */
title?: string
/** Page description */
description?: string
/** View layout mode */
layout?: 'single' | 'column' | 'canvas' | 'vibe'
/** Usage metrics */
metrics?: {
requests: number // Total requests
quota?: number // Usage quota limit
bandwidth?: number // Bandwidth used (bytes)
errors?: number // Error count
}
/** Usage over time */
timeseries?: Array<{
timestamp: string
requests: number
errors?: number
}>
/** Rate limit info */
rateLimit?: {
limit: number
remaining: number
reset: string // Reset timestamp
}
/** Group by */
groupBy?: 'total' | 'endpoint' | 'key' | 'status'
/** Page-level action buttons */
actions?: Array<{
id: string
label: string
icon?: string
onClick?: () => void
variant?: 'default' | 'primary' | 'destructive'
}>
/** Child content */
children?: React.ReactNode
}Usage
<App name="Developer Portal">
<Shell>
<UsageView
title="API Usage"
description="Monitor API consumption and rate limits"
groupBy="endpoint"
/>
</Shell>
</App>Props
title
The page title displayed in the header. Defaults to "Usage".
<UsageView title="API Usage">description
Optional page description or subtitle.
<UsageView
title="API Usage"
description="Track your API consumption, quotas, and rate limits"
>layout
Layout mode for the view content. Defaults to 'single'.
// Single column layout (default)
<UsageView layout="single">
// Multi-column layout
<UsageView layout="column">metrics
Current usage statistics and totals.
<UsageView
metrics={{
requests: 1245678,
quota: 2000000,
bandwidth: 45231987654, // bytes
errors: 234
}}
>timeseries
Usage data over time for charts and trends.
<UsageView
timeseries={[
{
timestamp: '2024-12-19T00:00:00Z',
requests: 12450,
errors: 23
},
{
timestamp: '2024-12-19T01:00:00Z',
requests: 11230,
errors: 15
}
// ... more data points
]}
>rateLimit
Current rate limit status.
<UsageView
rateLimit={{
limit: 1000,
remaining: 847,
reset: '2024-12-19T09:00:00Z'
}}
>groupBy
How to group and display usage data. Defaults to 'total'.
// Total usage (default)
<UsageView groupBy="total">
// By API endpoint
<UsageView groupBy="endpoint">
// By API key
<UsageView groupBy="key">
// By HTTP status code
<UsageView groupBy="status">actions
Page-level action buttons displayed in the header.
<UsageView
actions={[
{
id: 'export',
label: 'Export Data',
icon: 'Download',
onClick: () => exportUsageData()
},
{
id: 'upgrade',
label: 'Upgrade Plan',
icon: 'Zap',
variant: 'primary',
onClick: () => navigateToUpgrade()
}
]}
>Usage Metrics
Overview Metrics
Display key usage statistics:
<UsageView
metrics={{
requests: 1245678,
quota: 2000000,
bandwidth: 45231987654,
errors: 234
}}
>
<div className="grid grid-cols-4 gap-4">
<MetricCard
title="Requests"
value={formatNumber(metrics.requests)}
description={`${percentage(metrics.requests, metrics.quota)}% of quota`}
trend="up"
/>
<MetricCard
title="Quota"
value={`${formatNumber(metrics.requests)} / ${formatNumber(metrics.quota)}`}
description="Monthly limit"
/>
<MetricCard
title="Bandwidth"
value={formatBytes(metrics.bandwidth)}
description="Data transferred"
/>
<MetricCard
title="Error Rate"
value={`${percentage(metrics.errors, metrics.requests)}%`}
description={`${formatNumber(metrics.errors)} errors`}
trend="down"
/>
</div>
</UsageView>Rate Limit Status
Show current rate limit information:
<UsageView rateLimit={rateLimit}>
<Card>
<CardHeader>
<CardTitle>Rate Limit</CardTitle>
<CardDescription>
Resets {formatRelativeTime(rateLimit.reset)}
</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span>Used</span>
<span>{rateLimit.limit - rateLimit.remaining} / {rateLimit.limit}</span>
</div>
<Progress
value={(rateLimit.limit - rateLimit.remaining) / rateLimit.limit * 100}
/>
<div className="text-sm text-muted-foreground">
{rateLimit.remaining} requests remaining
</div>
</div>
</CardContent>
</Card>
</UsageView>Time Series Charts
Visualize usage over time:
<UsageView timeseries={timeseries}>
<Card>
<CardHeader>
<CardTitle>Requests Over Time</CardTitle>
<CardDescription>Last 24 hours</CardDescription>
</CardHeader>
<CardContent>
<LineChart
data={timeseries}
xAxis={{ dataKey: 'timestamp', tickFormatter: formatTime }}
yAxis={{ tickFormatter: formatNumber }}
lines={[
{ dataKey: 'requests', stroke: '#3b82f6', name: 'Requests' },
{ dataKey: 'errors', stroke: '#ef4444', name: 'Errors' }
]}
/>
</CardContent>
</Card>
</UsageView>Breakdown Views
By Endpoint
Show usage grouped by API endpoint:
<UsageView groupBy="endpoint">
<Table>
<TableHeader>
<TableRow>
<TableHead>Endpoint</TableHead>
<TableHead>Requests</TableHead>
<TableHead>Avg Response Time</TableHead>
<TableHead>Error Rate</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{endpointUsage.map(endpoint => (
<TableRow key={endpoint.path}>
<TableCell>
<Code>{endpoint.method} {endpoint.path}</Code>
</TableCell>
<TableCell>{formatNumber(endpoint.requests)}</TableCell>
<TableCell>{endpoint.avgResponseTime}ms</TableCell>
<TableCell>
<Badge variant={endpoint.errorRate > 5 ? 'destructive' : 'secondary'}>
{endpoint.errorRate}%
</Badge>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</UsageView>By API Key
Track usage per API key:
<UsageView groupBy="key">
<div className="space-y-4">
{keyUsage.map(key => (
<Card key={key.id}>
<CardHeader>
<CardTitle>{key.name}</CardTitle>
<CardDescription>{key.key}</CardDescription>
</CardHeader>
<CardContent>
<div className="grid grid-cols-3 gap-4">
<div>
<div className="text-sm text-muted-foreground">Requests</div>
<div className="text-2xl font-bold">{formatNumber(key.requests)}</div>
</div>
<div>
<div className="text-sm text-muted-foreground">Bandwidth</div>
<div className="text-2xl font-bold">{formatBytes(key.bandwidth)}</div>
</div>
<div>
<div className="text-sm text-muted-foreground">Error Rate</div>
<div className="text-2xl font-bold">{key.errorRate}%</div>
</div>
</div>
</CardContent>
</Card>
))}
</div>
</UsageView>By Status Code
Analyze HTTP status code distribution:
<UsageView groupBy="status">
<div className="grid grid-cols-2 gap-4">
<Card>
<CardHeader>
<CardTitle>Status Code Distribution</CardTitle>
</CardHeader>
<CardContent>
<PieChart
data={[
{ name: '2xx Success', value: statusCodes['2xx'], fill: '#10b981' },
{ name: '4xx Client Error', value: statusCodes['4xx'], fill: '#f59e0b' },
{ name: '5xx Server Error', value: statusCodes['5xx'], fill: '#ef4444' }
]}
/>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Status Breakdown</CardTitle>
</CardHeader>
<CardContent>
<Table>
<TableBody>
{Object.entries(statusCodes).map(([code, count]) => (
<TableRow key={code}>
<TableCell>{code}</TableCell>
<TableCell>{formatNumber(count)}</TableCell>
<TableCell>{percentage(count, totalRequests)}%</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
</div>
</UsageView>Time Period Filters
Filter usage by time period:
const [period, setPeriod] = useState<TimePeriod>('24h')
<UsageView
actions={[
{
id: 'period',
label: period,
onClick: () => showPeriodMenu()
}
]}
>
<Select value={period} onValueChange={setPeriod}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="1h">Last hour</SelectItem>
<SelectItem value="24h">Last 24 hours</SelectItem>
<SelectItem value="7d">Last 7 days</SelectItem>
<SelectItem value="30d">Last 30 days</SelectItem>
<SelectItem value="custom">Custom range</SelectItem>
</SelectContent>
</Select>
<UsageChart period={period} />
</UsageView>Quota Management
Display quota usage and upgrade options:
<UsageView>
<Card>
<CardHeader>
<CardTitle>Usage Quota</CardTitle>
<CardDescription>Monthly API request limit</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div>
<div className="flex justify-between mb-2">
<span>{formatNumber(used)} used</span>
<span>{formatNumber(quota)} limit</span>
</div>
<Progress value={usedPercentage} />
</div>
{usedPercentage > 80 && (
<Alert variant="warning">
<AlertTitle>Approaching quota limit</AlertTitle>
<AlertDescription>
You've used {usedPercentage}% of your monthly quota.
Consider upgrading to a higher plan.
</AlertDescription>
</Alert>
)}
<Button onClick={() => navigateToUpgrade()}>
Upgrade Plan
</Button>
</div>
</CardContent>
</Card>
</UsageView>Export Functionality
Allow users to export usage data:
const handleExport = async (format: 'csv' | 'json') => {
const data = await exportUsageData({ format, period })
downloadFile(data, `usage-${period}.${format}`)
toast.success(`Usage data exported as ${format.toUpperCase()}`)
}
<UsageView
actions={[
{
id: 'export',
label: 'Export',
icon: 'Download',
onClick: () => showExportDialog()
}
]}
>
<ExportDialog
formats={['csv', 'json']}
onExport={handleExport}
/>
</UsageView>Real-Time Updates
Show live usage metrics:
<UsageView>
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<CardTitle>Live Requests</CardTitle>
<Badge variant="success">
<span className="animate-pulse">ā</span> Live
</Badge>
</div>
</CardHeader>
<CardContent>
<RealtimeChart
data={realtimeData}
interval={1000} // Update every second
/>
</CardContent>
</Card>
</UsageView>Billing Integration
Link usage to billing information:
<UsageView>
<Card>
<CardHeader>
<CardTitle>Usage & Billing</CardTitle>
<CardDescription>Current billing period</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div className="flex justify-between">
<span>Base plan</span>
<span>$49/month</span>
</div>
<div className="flex justify-between">
<span>Additional requests</span>
<span>${calculateOverage(usage)} ({formatNumber(overage)} requests)</span>
</div>
<Separator />
<div className="flex justify-between font-bold">
<span>Total</span>
<span>${calculateTotal(usage)}</span>
</div>
</div>
</CardContent>
<CardFooter>
<Button onClick={() => navigateToBilling()}>
View Billing
</Button>
</CardFooter>
</Card>
</UsageView>Empty State
Handle cases with no usage data:
<UsageView>
{totalRequests === 0 ? (
<EmptyState
icon="BarChart"
title="No usage data yet"
description="Start making API requests to see usage metrics and analytics"
action={{
label: 'View API Docs',
onClick: () => navigateToDocs()
}}
/>
) : (
<UsageCharts data={usageData} />
)}
</UsageView>Integration with Payload CMS
Auto-wire to Payload usage collection:
// Auto-fetches from Payload 'usage' collection
<UsageView collection="usage">
{/* Usage data loaded automatically */}
</UsageView>DeveloperApp Integration
Part of the DeveloperApp component suite:
<DeveloperDashboard
config={{
showAPIKeys: true,
showWebhooks: true,
showUsage: true,
showLogs: true
}}
>
<APIKeysView />
<WebhooksView />
<UsageView />
<LogsView />
</DeveloperDashboard>Responsive Behavior
The view adapts to screen size:
Desktop (ā„1024px)
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Usage [Export] ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā āāāāāāā āāāāāāā āāāāāāā āāāāāāā ā
ā ā1.2M ā ā62.4%ā ā45GB ā ā0.02%ā ā
ā āāāāāāā āāāāāāā āāāāāāā āāāāāāā ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā [Usage Chart] ā ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
ā ā Endpoint Breakdown Table ā ā
ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Metrics + charts + breakdownMobile (under 768px)
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Usage [Export] ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā āāāāāāāāāāāāāāāāāāāāāā ā
ā ā 1.2M Requests ā ā
ā ā 62.4% of quota ā ā
ā āāāāāāāāāāāāāāāāāāāāāā ā
ā āāāāāāāāāāāāāāāāāāāāāā ā
ā ā [Chart] ā ā
ā āāāāāāāāāāāāāāāāāāāāāā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Stacked metrics and chartAccessibility
The Usage view implements accessibility features:
- Keyboard navigation - Tab through filters and actions
- Screen reader labels - Descriptive labels for metrics
- Chart accessibility - Data tables for screen readers
- Status announcements - Announce quota warnings
<UsageView aria-label="API usage metrics and analytics">
<MetricCard
aria-label={`${formatNumber(requests)} API requests, ${percentage(requests, quota)}% of quota`}
/>
<Chart
aria-label="API requests over time"
aria-describedby="chart-description"
>
<span id="chart-description" className="sr-only">
Line chart showing API request volume over the last 24 hours
</span>
</Chart>
</UsageView>