diff --git a/allstarr/wwwroot/index.html b/allstarr/wwwroot/index.html
index f2e2716..3946dc9 100644
--- a/allstarr/wwwroot/index.html
+++ b/allstarr/wwwroot/index.html
@@ -539,6 +539,7 @@
+
+
+ API Endpoint Usage
+
+ Refresh
+ Clear Data
+
+
+
+ Track which Jellyfin API endpoints are being called most frequently. Useful for debugging and understanding client behavior.
+
+
+
+
+
+ Show Top
+
+ Top 25
+ Top 50
+ Top 100
+ Top 500
+
+
+
+
+
+
+
+ #
+ Endpoint
+ Requests
+ % of Total
+
+
+
+
+
+ Loading endpoint usage data...
+
+
+
+
+
+
+
+
+
About Endpoint Tracking
+
+ Allstarr logs every Jellyfin API endpoint call to help you understand how clients interact with your server.
+ This data is stored in /app/cache/endpoint-usage/endpoints.csv
+ and persists across restarts.
+
+ Common Endpoints:
+
+ /Users/{userId}/Items - Browse library items
+ /Items/{itemId} - Get item details
+ /Audio/{itemId}/stream - Stream audio
+ /Sessions/Playing - Report playback status
+ /Search/Hints - Search functionality
+
+
+
+
@@ -2864,6 +2944,7 @@
fetchJellyfinUsers();
fetchJellyfinPlaylists();
fetchConfig();
+ fetchEndpointUsage();
// Auto-refresh every 30 seconds
setInterval(() => {
@@ -2872,7 +2953,102 @@
fetchTrackMappings();
fetchMissingTracks();
fetchDownloads();
+
+ // Refresh endpoint usage if on that tab
+ const endpointsTab = document.getElementById('tab-endpoints');
+ if (endpointsTab && endpointsTab.classList.contains('active')) {
+ fetchEndpointUsage();
+ }
}, 30000);
+
+ // Endpoint Usage Functions
+ async function fetchEndpointUsage() {
+ try {
+ const topSelect = document.getElementById('endpoints-top-select');
+ const top = topSelect ? topSelect.value : 50;
+
+ const res = await fetch(`/api/admin/debug/endpoint-usage?top=${top}`);
+ const data = await res.json();
+
+ // Update summary stats
+ document.getElementById('endpoints-total-requests').textContent = data.totalRequests?.toLocaleString() || '0';
+ document.getElementById('endpoints-unique-count').textContent = data.totalEndpoints?.toLocaleString() || '0';
+
+ const mostCalled = data.endpoints && data.endpoints.length > 0
+ ? data.endpoints[0].endpoint
+ : '-';
+ document.getElementById('endpoints-most-called').textContent = mostCalled;
+
+ // Update table
+ const tbody = document.getElementById('endpoints-table-body');
+
+ if (!data.endpoints || data.endpoints.length === 0) {
+ tbody.innerHTML = '