# How to Monitor FreeLLM API Performance: REST Endpoints and Desktop Analytics

> Monitor FreeLLM API performance with REST endpoints and desktop analytics. Track latency, token usage, success rates, and cost savings easily.

- Repository: [Tashfeen/freellmapi](https://github.com/tashfeenahmed/freellmapi)
- Tags: performance
- Published: 2026-07-02

---

**FreeLLM API tracks every request in a local SQLite database and exposes real-time performance metrics through REST endpoints and an Electron-based desktop dashboard, enabling you to monitor latency, token usage, success rates, and cost savings.**

The tashfeenahmed/freellmapi repository provides a self-hosted LLM API server with built-in performance monitoring capabilities. Understanding how to monitor FreeLLM API performance is essential for optimizing costs, debugging failures, and ensuring service reliability. The system utilizes a dual-layer architecture where raw request data is stored in SQLite while aggregated hourly statistics power both the desktop UI and REST API.

## Monitoring Architecture Overview

FreeLLM API implements a two-tier data collection system that balances detail with query performance. As implemented in tashfeenahmed/freellmapi, the [`server/src/lib/request-log.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/request-log.ts) middleware captures every request in a `requests` table while simultaneously updating the `request_hourly` aggregate table. This design ensures that analytics queries remain fast even after the raw table is pruned, while the `request_hourly` buckets provide durable historical metrics.

The data flows from [`server/src/services/media.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/media.ts) through the logging middleware into SQLite, then surfaces via [`server/src/routes/analytics.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/routes/analytics.ts) for HTTP clients or [`desktop/src/stats.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/desktop/src/stats.ts) for the local Electron interface.

## REST API Analytics Endpoints

The server exposes a comprehensive analytics API under `/api/analytics` that returns JSON performance data. These endpoints accept a `range` parameter (`24h`, `7d`, or `30d`) to filter time windows.

### Summary Metrics

The `/summary` endpoint provides high-level performance indicators including total requests, success rate, token totals, average latency, estimated cost savings, and pinned-request statistics. It also returns the timestamp of the first recorded request.

```bash
curl http://localhost:3000/api/analytics/summary

```

### Detailed Breakdown Endpoints

For deeper analysis, query these specialized endpoints:

- **`/by-model`** – Returns metrics grouped by LLM model (e.g., GPT-4, Claude)
- **`/by-platform`** – Breaks down usage by provider platform
- **`/timeline`** – Provides time-series data for charting hourly trends
- **`/error-distribution`** – Categorizes failures by error type
- **`/errors`** – Lists recent error logs with details

```bash

# Model performance for the last 24 hours

curl "http://localhost:3000/api/analytics/by-model?range=24h"

# Hourly timeline data

curl "http://localhost:3000/api/analytics/timeline?range=24h&interval=hour"

```

## Desktop Dashboard and Tray Interface

The Electron-based desktop application provides immediate visual feedback through system tray pop-overs and a dedicated dashboard window opened by [`desktop/src/window.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/desktop/src/window.ts).

### Tray Pop-over Statistics

The tray interface utilizes helper functions from [`desktop/src/stats.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/desktop/src/stats.ts) to query the local SQLite database directly. Key functions include:

- **`todayStats()`** – Returns today's request count, token usage, and last model used
- **`hourlyRequests()`** – Generates a histogram of requests per hour
- **`successRateToday()`** – Calculates the percentage of successful requests for the current day

These functions bypass the HTTP layer and call `getDb()` from [`server/src/db/index.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/db/index.ts) directly, ensuring instant access to local metrics.

### Programmatic Access to Desktop Stats

You can reuse the desktop statistics helpers in custom scripts by importing from the desktop source:

```typescript
import { todayStats, hourlyRequests, formatTokens, successRateToday } from '../desktop/src/stats.js';

const stats = todayStats();
console.log(`Requests today: ${stats.requests}`);
console.log(`Tokens today: ${formatTokens(stats.tokens)}`);
console.log(`Success rate: ${await successRateToday()}%`);
console.log('Hourly histogram:', hourlyRequests());

```

## Database Schema and Aggregation Strategy

The monitoring system relies on SQLite for lightweight, in-process storage. The `requests` table captures individual request details including model name, token counts, latency milliseconds, and success status. However, analytics queries primarily target the `request_hourly` aggregate table, which the logging middleware updates transactionally alongside each request insert.

This aggregation strategy prevents full-table scans during analytics queries. When you request data via the REST API or desktop helpers, the system queries the pre-aggregated hourly buckets for historical data, falling back to raw rows only for recent unaggregated entries.

## Extending Analytics with Custom Metrics

The modular architecture in [`server/src/routes/analytics.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/routes/analytics.ts) supports custom metric endpoints. For example, to expose requests-per-minute (RPM) calculations:

```typescript
// Add to server/src/routes/analytics.ts
analyticsRouter.get('/rpm', (req, res) => {
  const range = (req.query.range as string) ?? '7d';
  const since = getSinceTimestamp(range);
  const rows = getDb().prepare(`
    SELECT strftime('%Y-%m-%dT%H:%M:00', hour) AS minute,
           SUM(total_requests) / 60.0 AS rpm
    FROM request_hourly
    WHERE hour >= ?
    GROUP BY minute
    ORDER BY minute ASC
  `).all(since);
  res.json(rows);
});

```

After restarting the server, `GET /api/analytics/rpm` returns per-minute request rates derived from the hourly aggregate data.

## Summary

- **FreeLLM API** stores all request metadata in a local SQLite database managed through [`server/src/db/index.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/db/index.ts)
- **Hourly aggregation** via the `request_hourly` table ensures fast analytics queries even with large datasets
- **REST endpoints** under `/api/analytics` provide JSON data for external monitoring tools, supporting ranges of 24 hours, 7 days, or 30 days
- **Desktop interface** uses [`desktop/src/stats.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/desktop/src/stats.ts) helpers to read the database directly for instant tray pop-over statistics
- **Key files** include [`server/src/lib/request-log.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/request-log.ts) for data collection, [`server/src/routes/analytics.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/routes/analytics.ts) for API routes, and [`server/src/services/media.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/media.ts) for request insertion

## Frequently Asked Questions

### How does FreeLLM API store performance data?

FreeLLM API uses a lightweight SQLite database that runs in-process with the server. Every request passes through the logging middleware in [`server/src/lib/request-log.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/request-log.ts), which inserts a row into the `requests` table and updates the `request_hourly` aggregate within the same transaction. This dual-write approach ensures data consistency while optimizing query performance for analytics.

### What is the difference between the requests table and request_hourly?

The `requests` table contains granular data for individual API calls, including model names, token counts, and latency measurements. The `request_hourly` table stores pre-aggregated buckets grouped by hour, containing summed totals and averages. Analytics queries prefer the hourly table to avoid expensive full-table scans, while the raw table supports detailed debugging and can be pruned independently.

### Can I access analytics without using the desktop UI?

Yes. The REST API exposed in [`server/src/routes/analytics.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/routes/analytics.ts) provides full access to performance metrics without requiring the Electron desktop application. You can query endpoints like `/api/analytics/summary` or `/api/analytics/by-model` using standard HTTP clients such as `curl`, Python's `requests` library, or monitoring tools like Grafana.

### How do I calculate custom metrics like requests per minute?

Create new routes in [`server/src/routes/analytics.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/routes/analytics.ts) that query the `request_hourly` table. Since hourly aggregates contain `total_requests` per hour, you can derive per-minute estimates by dividing by 60.0 and grouping by minute using SQLite's `strftime` function. Register the new route with the analytics router and restart the server to expose the endpoint.