Skip to content

Commit 6752851

Browse files
committed
feat(site): show unique viewers, completions, and breakdowns in analytics
1 parent 1189d10 commit 6752851

1 file changed

Lines changed: 43 additions & 2 deletions

File tree

apps/site/components/AnalyticsClient.tsx

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,13 @@ function formatBucket(value: string) {
9090
}).format(date);
9191
}
9292

93+
function formatDimension(value: string) {
94+
return value
95+
.split("_")
96+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
97+
.join(" ");
98+
}
99+
93100
function maxSeriesValue(points: AnalyticsTimeSeriesPoint[]) {
94101
return Math.max(1, ...points.map((point) => Math.max(point.views, point.request_count)));
95102
}
@@ -198,16 +205,18 @@ export default function AnalyticsClient({
198205
{analytics ? (
199206
<div className="flex flex-col gap-5">
200207
<StatGrid>
201-
<Stat label="Views" value={formatNumber(analytics.views)} hint="Sessions with first frame" icon={Eye} />
208+
<Stat label="Views" value={formatNumber(analytics.views)} hint="Playback sessions with first frame" icon={Eye} />
209+
<Stat label="Unique viewers" value={formatNumber(analytics.unique_viewers)} hint="Pseudonymous viewer hashes" icon={Eye} />
202210
<Stat label="Watch time" value={formatWatchTime(analytics.watch_time_ms)} hint="Player heartbeat estimate" icon={Clock} />
203211
<Stat label="Startup" value={formatPercent(analytics.startup_success_rate)} hint={`p95 ${formatMs(analytics.startup_p95_ms)}`} icon={Gauge} />
204212
<Stat label="Rebuffer" value={formatPercent(analytics.rebuffer_ratio)} hint={`${formatNumber(analytics.stalled_sessions)} stalled sessions`} icon={Activity} />
205213
</StatGrid>
206214

207215
<StatGrid>
208-
<Stat label="Requests" value={formatCompact(analytics.request_count)} hint={`${formatBytes(analytics.bytes_served)} served`} icon={Database} />
216+
<Stat label="Requests" value={formatCompact(analytics.request_count)} hint="Edge artifact requests" icon={Database} />
209217
<Stat label="Cache hit" value={formatPercent(analytics.cache_hit_rate)} hint="Edge request rollup" icon={Signal} />
210218
<Stat label="Errors" value={formatPercent(analytics.error_rate)} hint={`${formatNumber(analytics.playback_failures)} player failures`} icon={Activity} />
219+
<Stat label="Completions" value={formatNumber(analytics.completions)} hint={`${formatNumber(analytics.exits_before_start)} exits before start`} icon={Activity} />
211220
<Stat label="Edge latency" value={formatMs(analytics.request_p95_ms)} hint={`p50 ${formatMs(analytics.request_p50_ms)}`} icon={Gauge} />
212221
</StatGrid>
213222

@@ -277,6 +286,38 @@ export default function AnalyticsClient({
277286
</Table>
278287
)}
279288
</Panel>
289+
290+
<Panel title="Breakdowns" flush={analytics.breakdowns.length > 0}>
291+
{analytics.breakdowns.length === 0 ? (
292+
<p className="text-[13.5px] text-muted">No breakdowns available yet.</p>
293+
) : (
294+
<div className="grid gap-4 lg:grid-cols-2">
295+
{analytics.breakdowns.map((breakdown) => (
296+
<div key={breakdown.dimension} className="min-w-0">
297+
<p className="px-4 pb-2 pt-3 text-[12px] font-medium text-faint">
298+
{formatDimension(breakdown.dimension)}
299+
</p>
300+
<Table>
301+
<TBody>
302+
{breakdown.rows.map((row) => (
303+
<TR key={`${breakdown.dimension}:${row.value}`}>
304+
<TD className="max-w-[220px] truncate text-[12.5px] text-ink-soft">
305+
{row.value}
306+
</TD>
307+
<TD className="text-right font-mono text-[12px] tabular-nums text-muted">
308+
{row.request_count > 0
309+
? formatNumber(row.request_count)
310+
: formatNumber(row.views)}
311+
</TD>
312+
</TR>
313+
))}
314+
</TBody>
315+
</Table>
316+
</div>
317+
))}
318+
</div>
319+
)}
320+
</Panel>
280321
</div>
281322
) : null}
282323
</DashboardContent>

0 commit comments

Comments
 (0)