FreeLLMAPI Desktop App Features: Native Menu-Bar Client with Live Analytics

The FreeLLMAPI desktop app is a native Electron menu-bar application that bundles the full API router and React dashboard, offering live 24-hour analytics, one-click dashboard access, and multi-language support through a lightweight tray interface.

The FreeLLMAPI desktop application, available in the tashfeenahmed/freellmapi repository, transforms the web-based LLM router into a standalone native experience. Built with Electron, this client runs the complete FreeLLMAPI stack locally on your machine, providing persistent SQLite-based analytics and instant API management through an elegant menu-bar interface that requires no external dependencies.

System Tray and Glass-Style Popover Interface

The application centers on a platform-native tray icon implemented in desktop/src/tray.ts. The buildTray() function creates a Tray instance using a template PNG that automatically tints for light or dark macOS themes.

Left-clicking the tray icon toggles a glass-style popover window, while right-click reveals a native context menu with quick actions. This menu provides instant access to open the full dashboard, copy the unified API key to the clipboard, or quit the application. The implementation uses Electron's nativeImage and Menu APIs to ensure the tray feels like a first-class system citizen.

import { Tray, Menu, nativeImage } from 'electron';
import { openDashboard } from './window.js';
import { dt, type NativeLocale } from './i18n.js';

export function buildTray(port: number, token: string, getLocale: () => NativeLocale): Tray {
  const icon = nativeImage.createFromPath('assets/trayTemplate.png');
  icon.setTemplateImage(true);
  const tray = new Tray(icon);
  tray.setToolTip(dt(getLocale(), 'tooltip'));

  tray.on('click', () => togglePopover(tray));
  tray.on('right-click', () => {
    const locale = getLocale();
    tray.popUpContextMenu(Menu.buildFromTemplate([
      { label: dt(locale, 'runningOn', { addr: `127.0.0.1:${port}` }), enabled: false },
      { label: dt(locale, 'openDashboard'), click: () => openDashboard(port, token) },
      { type: 'separator' },
      { label: dt(locale, 'quitApp'), click: () => app.quit() },
    ]));
  });
  return tray;
}

(Full source: tray.ts)

Live Analytics and Statistical Tracking

The popover interface displays real-time metrics powered by desktop/src/stats.ts, which queries the local SQLite database for request history.

24-Hour Request Charting

The hourlyRequests() function aggregates the last 24 hours of request data into hourly buckets. It reads from the requests table in the local database and returns an array of 24 integers representing hourly activity, enabling the UI to render trend charts without network calls.

Daily Health Metrics

The todayStats() function calculates the current day's total request count, token usage, and most recent model ID. It uses SQL aggregation with datetime('now','localtime','start of day') filters to ensure accurate daily boundaries based on the user's local timezone.

export function todayStats(): TodayStats {
  const db = getDb();
  const row = db
    .prepare(`
      SELECT COUNT(*) AS requests,
             COALESCE(SUM(COALESCE(input_tokens,0)+COALESCE(output_tokens,0)),0) AS tokens
      FROM requests
      WHERE datetime(created_at,'localtime') >= datetime('now','localtime','start of day')
    `)
    .get() as { requests: number; tokens: number };

  const last = db.prepare('SELECT model_id FROM requests ORDER BY id DESC LIMIT 1')
                .get() as { model_id?: string } | undefined;

  return { requests: row.requests, tokens: row.tokens, lastModel: last?.model_id ?? '—' };
}

(Full source: stats.ts)

Success Rate Monitoring

The successRateToday() function in desktop/src/stats.ts computes the percentage of successful requests for the current day, providing a health indicator in the popover. This metric helps users monitor provider reliability without opening the full dashboard.

Full-Feature Dashboard Window

When users need advanced configuration, the openDashboard() function in desktop/src/window.ts creates a dedicated BrowserWindow instance. The window measures 1200×800 pixels and implements platform-specific styling that varies by operating system.

On macOS, the window uses titleBarStyle: 'hiddenInset' and vibrancy: 'sidebar' to create a glass effect matching the Finder aesthetic, combined with a transparent background color. Windows and Linux versions default to a dark background (#09090b). The window loads the local React dashboard served from http://127.0.0.1:<port> and passes the authentication token via additionalArguments in the web preferences.

export function openDashboard(port: number, token: string): void {
  if (dashboardWindow && !dashboardWindow.isDestroyed()) {
    dashboardWindow.show();
    dashboardWindow.focus();
    return;
  }

  dashboardWindow = new BrowserWindow({
    width: 1200,
    height: 800,
    title: 'FreeLLMAPI',
    ...(process.platform === 'darwin'
      ? { titleBarStyle: 'hiddenInset', vibrancy: 'sidebar', backgroundColor: '#00000000' }
      : { backgroundColor: '#09090b' }),
    webPreferences: {
      preload: path.join(__dirname, 'preload.cjs'),
      contextIsolation: true,
      nodeIntegration: false,
      additionalArguments: [`--freeapi-token=${token}`],
    },
  });

  dashboardWindow.loadURL(`http://127.0.0.1:${port}`);
  dashboardWindow.on('closed', () => (dashboardWindow = null));
}

(Full source: window.ts)

The implementation ensures single-instance behavior—if the dashboard is already open, the existing window receives focus rather than spawning duplicates.

Multi-Language Interface Support

The desktop application supports six languages through the internationalization module in desktop/src/i18n.ts. Available locales include English, Chinese, French, Spanish, Portuguese (Brazilian), and Italian.

The system automatically detects the host operating system's language on first launch. Users can manually switch languages through the tray menu's settings, with all UI strings externalized in JSON files located in client/src/i18n/locales/.

Local Data Persistence and Security

All request analytics persist to a local SQLite database stored in the OS-specific application support directory. On macOS, this resolves to ~/Library/Application Support/FreeLLMAPI/; on Windows, to %APPDATA%\FreeLLMAPI\. This ensures that request history, token usage statistics, and provider performance metrics survive application restarts and system reboots.

The bundled server binds exclusively to the loopback address (127.0.0.1), preventing external network access to the local API. If the default port 31415 is occupied, the application automatically scans for the next available port and persists this selection for future launches.

Zero-Install Build System

The FreeLLMAPI desktop app ships as a standalone distributable containing the bundled Node.js server, React client UI, and native SQLite driver. Build commands vary by platform:

  • macOS: npm run desktop:dist produces a DMG file
  • Windows: npm run desktop:dist:win generates an installer

These commands, documented in desktop/README.md, compile the entire stack into platform-native packages that require no runtime dependencies, Node.js installation, or external configuration.

Summary

  • Menu-bar native integration: The buildTray() function in desktop/src/tray.ts provides template-based icons with automatic dark mode support and context menu actions.
  • Real-time SQLite analytics: Functions like hourlyRequests(), todayStats(), and successRateToday() in desktop/src/stats.ts deliver live metrics without network latency.
  • Glass-effect dashboard: The openDashboard() implementation uses macOS vibrancy APIs and hidden title bars for native aesthetic integration.
  • Multi-language support: Six locales available via desktop/src/i18n.ts with automatic OS language detection.
  • Secure local binding: Server runs on 127.0.0.1 with automatic port discovery starting at 31415.
  • Standalone distribution: Single-command builds produce zero-dependency installers for macOS and Windows.

Frequently Asked Questions

What platforms does the FreeLLMAPI desktop app support?

The application supports macOS and Windows through platform-specific Electron builds. The macOS version utilizes native vibrancy effects and hidden inset title bars, while the Windows build defaults to a dark-themed interface. Both versions store their SQLite databases in OS-standard application support directories.

How does the desktop app store my API request history?

Request data persists to a local SQLite database located at ~/Library/Application Support/FreeLLMAPI/ on macOS or %APPDATA%\FreeLLMAPI\ on Windows. The todayStats() and hourlyRequests() functions query this local database to populate the tray popover with analytics, ensuring your data remains on your machine and survives application restarts.

Can I access the dashboard without using the tray menu?

Yes. While the tray icon provides the primary interface, the dashboard remains accessible via any web browser at http://127.0.0.1:<port> where the port defaults to 31415 or the next available port if that address is occupied. The desktop app simply provides a convenient native wrapper that automatically copies your API key and launches the correct local URL.

How do I change the interface language in the desktop app?

The application automatically detects your operating system language on first launch from among six supported locales: English, Chinese, French, Spanish, Portuguese (Brazilian), and Italian. You can manually change the language through the tray menu settings, which updates the UI strings exported from desktop/src/i18n.ts without requiring an application restart.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →