# How to Monitor Usage Analytics and Request Logs in FreeLLMAPI

> Track FreeLLMAPI usage and request logs with built in analytics. Access aggregated metrics via authenticated REST endpoints for detailed insights.

- Repository: [Tashfeen/freellmapi](https://github.com/tashfeenahmed/freellmapi)
- Tags: how-to-guide
- Published: 2026-06-24

---

**FreeLLMAPI captures every proxy request in an internal SQLite database and exposes aggregated metrics through authenticated REST endpoints under `/api/analytics`.**

FreeLLMAPI provides built-in observability through comprehensive request logging and analytics. The system automatically records every proxy interaction—including token usage, latency, model selection, and error details—to a local SQLite database. This article explains how to access and configure these monitoring capabilities using the platform's analytics API and retention settings.

## Understanding the Logging Architecture

### The Core Logging Function

Every request passing through the FreeLLMAPI proxy triggers the **`logRequest`** function in [`server/src/lib/request-log.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/request-log.ts). This utility inserts a detailed row into the **`requests`** table, capturing success status, failure reasons, token consumption, latency metrics, and whether the client explicitly pinned a specific model or accepted an auto-selection.

### Data Retention Management

To prevent unbounded database growth, FreeLLMAPI implements automatic pruning via [`server/src/services/request-retention.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/request-retention.ts). The helper **`getRequestAnalyticsRetentionConfig`** reads two environment variables that control the lifecycle of logged data:

- **`REQUEST_ANALYTICS_RETENTION_DAYS`**: Maximum age of rows before deletion (default: `90`)
- **`REQUEST_ANALYTICS_MAX_ROWS`**: Hard cap on total rows retained (default: `100000`)

The pruning logic executes on every log write or on a timed interval to enforce these limits, ensuring the SQLite table remains performant.

## Available Analytics Endpoints

All analytics are exposed through a dedicated router in [`server/src/routes/analytics.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/routes/analytics.ts) mounted under the prefix `/api/analytics`. These read-only endpoints require authentication via the **`requireAuth`** middleware attached in [`server/src/app.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/app.ts).

### High-Level Summary Statistics

The **`GET /api/analytics/summary`** endpoint provides rolling aggregates including total requests, success rates, token totals, average latency, estimated cost savings, and counts of pinned versus auto-selected models. The underlying SQL joins the `requests` table with model pricing data to calculate savings estimates.

### Model and Platform Breakdowns

For granular cost and performance analysis:

- **`GET /api/analytics/by-model`**: Groups statistics by `platform` and `model_id`, returning request counts, success percentages, average latency, token totals, and pinned counts per model
- **`GET /api/analytics/by-platform`**: Aggregates metrics by provider (e.g., OpenAI, Anthropic) to compare platform-level performance and costs

### Timeline and Error Analysis

Time-series monitoring is available through **`GET /api/analytics/timeline`**, which uses SQLite's `strftime` function to bucket request volume, success counts, and failure counts into hourly or daily intervals.

For debugging, two specialized endpoints expose error data:

- **`GET /api/analytics/error-distribution`**: Categorizes errors by type (rate-limit, authentication, timeout) using `CASE WHEN` logic on the error message strings
- **`GET /api/analytics/errors`**: Returns raw recent error rows with full request details for deep investigation

## Querying Analytics via API

All endpoints accept authentication headers and optional range parameters. Below are practical examples for common monitoring tasks.

Fetch a summary of the last 7 days (default range):

```bash
curl -H "Authorization: Bearer <YOUR_API_KEY>" \
     https://<your-host>/api/analytics/summary

```

Get model-level stats for the past 24 hours:

```bash
curl -H "Authorization: Bearer <YOUR_API_KEY>" \
     "https://<your-host>/api/analytics/by-model?range=24h"

```

Show hourly timeline for the last day:

```bash
curl -H "Authorization: Bearer <YOUR_API_KEY>" \
     "https://<your-host>/api/analytics/timeline?range=24h&interval=hour"

```

Inspect recent errors:

```bash
curl -H "Authorization: Bearer <YOUR_API_KEY>" \
     "https://<your-host>/api/analytics/errors?range=7d"

```

## Configuring Data Retention

Adjust retention policies by setting environment variables before starting the service. Create or modify your `.env` file:

```dotenv
REQUEST_ANALYTICS_RETENTION_DAYS=30
REQUEST_ANALYTICS_MAX_ROWS=50000

```

After restarting the service, the next `logRequest` invocation will trigger the new retention policy defined in [`server/src/services/request-retention.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/request-retention.ts).

## Direct Database Access

Because analytics data persists in a local SQLite file within the runtime data directory, you can bypass the API for custom reporting. Connect directly to the database using standard SQLite tools to run ad-hoc queries against the `requests` table, join with custom tables, or export data to external business intelligence systems.

## Summary

- **Request logging** is handled by `logRequest` in [`server/src/lib/request-log.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/request-log.ts), which writes every proxy interaction to the SQLite `requests` table
- **Data retention** is controlled via `REQUEST_ANALYTICS_RETENTION_DAYS` and `REQUEST_ANALYTICS_MAX_ROWS`, enforced by [`server/src/services/request-retention.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/request-retention.ts)
- **Analytics endpoints** under `/api/analytics` provide summary, model-specific, platform-specific, timeline, and error-distribution views
- **Authentication is mandatory** for all analytics routes via the `requireAuth` middleware in [`server/src/app.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/app.ts)
- **Direct SQL access** is possible for operators requiring custom analysis beyond the built-in JSON endpoints

## Frequently Asked Questions

### How long does FreeLLMAPI retain request logs by default?

By default, FreeLLMAPI retains request logs for **90 days** and maintains a maximum of **100,000 rows** in the `requests` table. These defaults are defined in [`server/src/services/request-retention.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/request-retention.ts) and can be overridden using the `REQUEST_ANALYTICS_RETENTION_DAYS` and `REQUEST_ANALYTICS_MAX_ROWS` environment variables.

### What authentication is required to access analytics endpoints?

All analytics endpoints require **Bearer token authentication** via the `Authorization` header. The `requireAuth` middleware in [`server/src/app.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/app.ts) guards these routes, ensuring only authenticated users can view sensitive usage data and error logs.

### Can I export FreeLLMAPI analytics data to external systems?

Yes. Since FreeLLMAPI stores data in a local SQLite file, you can connect external tools directly to the database or build automated scripts that query the `/api/analytics` endpoints. The JSON responses from endpoints like `/api/analytics/timeline` and `/api/analytics/by-model` are designed for easy integration with monitoring platforms and data warehouses.

### How does the retention service handle reaching the maximum row limit?

When the row count exceeds `REQUEST_ANALYTICS_MAX_ROWS`, the retention service prunes the oldest entries based on timestamp. This cleanup occurs either on every write operation or on a timed interval, ensuring the database never grows beyond the configured hard cap while preserving the most recent analytics data.