sanjayacloud/ai-model-usage-tracker

Accurately track AI model usage, tokens, and cost in Laravel with automatic instrumentation, reporting, and an Inertia dashboard.

Maintainers

Package info

github.com/sanjayacloud/ai-model-usage-tracker

pkg:composer/sanjayacloud/ai-model-usage-tracker

Transparency log

Fund package maintenance!

sanjayacloud

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-08-14 14:41 UTC

This package is auto-updated.

Last update: 2026-08-14 14:48:30 UTC


README

AI Model Usage Tracker

Packagist PHP from Packagist GitHub Workflow Status (main) Total Downloads

Accurately track AI model usage in your Laravel app: token counts, computed cost, latency, success/failure, per-user attribution, and per-conversation attribution. Capture usage automatically from the first-party laravel/ai SDK (plus Prism and raw HTTP clients), or record it manually with a fluent API. Includes a headless reporting layer, budget alerts, and an optional Inertia/Vue dashboard.

Features

  • Automatic capture for the laravel/ai SDK — no code changes required.
  • Computed cost from a configurable per-model pricing table (input, output, cache read/write, reasoning).
  • Per-request, per-user, and per-conversation attribution.
  • Reporting API — totals, breakdowns by model/provider/operation, daily trends, top consumers.
  • Budgets with threshold events, retention pruning, and an optional Inertia/Vue dashboard.
  • Sync or queued persistence.

Requirements

  • PHP 8.3+
  • Laravel 12 or 13
  • (Optional) laravel/ai for automatic instrumentation
  • (Optional) Inertia + Vue for the bundled dashboard

How it works

Every AI request becomes one row in the ai_usage_records table, written through a single pipeline regardless of how it was captured:

manual API ─┐
laravel/ai ─┤
Prism      ─┼─▶ UsageTracker ─▶ CostCalculator ─▶ (sync | queue) ─▶ ai_usage_records
raw HTTP   ─┘

Getting started

Step 1 — Install

composer require sanjayacloud/ai-model-usage-tracker

The service provider and AiModelUsageTracker facade are auto-discovered.

Step 2 — Publish and run the migration

php artisan vendor:publish --tag="ai-model-usage-tracker-migrations"
php artisan migrate

This creates the ai_usage_records table.

Step 3 — Publish the config (recommended)

php artisan vendor:publish --tag="ai-model-usage-tracker-config"

This writes config/ai-model-usage-tracker.php, where you control pricing, recording mode, instrumentation, budgets, retention, and the dashboard.

Step 4 — Capture your first usage

If you use laravel/ai, you're already done — the next agent prompt or embedding call is recorded automatically (see Automatic capture).

To record manually from anywhere:

use AiModelUsageTracker\AiModelUsageTracker\Facades\AiModelUsageTracker;

AiModelUsageTracker::track()
    ->provider('openai')
    ->model('gpt-4o')
    ->tokens(prompt: 1200, completion: 350)
    ->record();

Step 5 — Read it back

use AiModelUsageTracker\AiModelUsageTracker\Reporting\UsageReporter;

app(UsageReporter::class)->totals(); // ['records' => 1, 'total_tokens' => 1550, 'total_cost' => 0.0065, ...]

That's the full loop: capture → cost → report.

Capturing usage

Automatic capture (laravel/ai)

Enabled by default. The package listens to the SDK's events (AgentPrompted, AgentStreamed, EmbeddingsGenerated, ImageGenerated, AudioGenerated, TranscriptionGenerated, ProviderFailedOver) and records tokens, model, provider, latency, failures — and the conversation id when the call is part of a laravel/ai conversation.

Toggle it in config:

'instrumentation' => [
    'laravel-ai' => true,
    'prism' => false,
    'http' => false,
],

Manual API (fluent builder)

use AiModelUsageTracker\AiModelUsageTracker\Facades\AiModelUsageTracker;
use AiModelUsageTracker\AiModelUsageTracker\Enums\Operation;

AiModelUsageTracker::for($user) // attribute to any Eloquent model
    ->provider('openai')
    ->model('gpt-4o')
    ->operation(Operation::Chat)
    ->tokens(prompt: 1200, completion: 350, cacheRead: 800, reasoning: 120)
    ->conversation($conversationId) // optional, for per-conversation reporting
    ->latency(840)
    ->meta(['feature' => 'support-bot'])
    ->record();

Available builder methods: provider(), model(), operation(), tokens(), latency(), status(), failed(), streamed(), for(), conversation(), invocation(), meta(), startedAt(), endedAt(), record().

Prism

$response = Prism::text()->using('openai', 'gpt-4o')->withPrompt('...')->generate();

AiModelUsageTracker::capturePrism($response, $user);

Enable it in config (instrumentation.prism => true).

Raw HTTP clients

Set instrumentation.http => true to parse OpenAI/Anthropic-style usage blocks from outgoing HTTP responses automatically.

Attribution

Per-user (or any model)

Use for() on the manual builder, or set a global resolver so every recorded row is attributed automatically (great for auto-instrumentation):

use AiModelUsageTracker\AiModelUsageTracker\Facades\AiModelUsageTracker;

// e.g. in a service provider or middleware
AiModelUsageTracker::resolveTrackableUsing(fn () => auth()->user());

Per-conversation

When you use laravel/ai conversations, the conversation id is captured automatically on each recorded row (conversation_id). You can then aggregate usage for a single conversation:

use AiModelUsageTracker\AiModelUsageTracker\Reporting\UsageReporter;

$summary = app(UsageReporter::class)->forConversation($conversationId);

$summary['totals'];   // ['records' => 5, 'total_tokens' => 8120, 'total_cost' => 0.0123, ...]
$summary['by_model']; // per-model breakdown for that conversation

For manual records, pass the id explicitly with ->conversation($conversationId).

Per-request usage in your responses

Each request is recorded individually, so you can surface its cost inline:

use AiModelUsageTracker\AiModelUsageTracker\Facades\AiModelUsageTracker;
use AiModelUsageTracker\AiModelUsageTracker\Http\Resources\UsageResource;

$record = AiModelUsageTracker::forInvocation($invocationId); // or ::latest()

return response()->json([
    'answer' => $answer,
    'usage' => $record ? (new UsageResource($record))->toArray($request) : null,
]);

$record->toUsageArray() returns a compact block of tokens, cost, currency, and latency.

Cost accuracy

Costs are computed from a configurable pricing table in config/ai-model-usage-tracker.php, with bundled rates for common OpenAI, Anthropic, and Gemini models, expressed per 1,000,000 tokens. Cached read/write and reasoning tokens are priced separately when rates are provided.

Requests for models not in the table are recorded with a zero cost and a pricing_missing flag in metadata, so gaps are auditable rather than silently wrong.

Adding pricing for a model

If a model shows $0 cost, add its rates.

  1. Publish the config (Step 3 above) if you haven't.
  2. Add the model under its provider in pricing.models. Rates are per 1M tokens:
'pricing' => [
    'currency' => 'USD',
    'models' => [
        'gemini' => [
            'gemini-3.1-flash-lite' => ['input' => 0.25, 'output' => 1.50, 'cache_read' => 0.025],
        ],
    ],
],
  1. Clear the config cache so the new rate is picked up:
php artisan config:clear

New records for that model will now be priced. Existing zero-cost rows are left untouched (recompute them yourself if you need a backfill).

Supported rate keys: input, output, cache_write, cache_read, reasoning. Missing cache_write/cache_read fall back to input; missing reasoning falls back to output.

Reporting

use AiModelUsageTracker\AiModelUsageTracker\Reporting\UsageReporter;

$reporter = app(UsageReporter::class);

$reporter->totals();                 // records, tokens, cost, failures
$reporter->forConversation($id);     // totals + per-model breakdown for one conversation
$reporter->byModel();                // grouped by model
$reporter->byProvider();             // grouped by provider
$reporter->byOperation();            // grouped by operation
$reporter->dailyTrend();             // cost/tokens per day
$reporter->topConsumers();           // biggest spenders (attributed models)

Every method except forConversation() accepts optional $from/$to DateTimeInterface bounds.

CLI summary:

php artisan ai-usage:report --days=30

Budgets

Define spending caps in config; a BudgetThresholdReached event fires the moment a threshold is crossed:

'budgets' => [
    'monthly' => ['period' => 'month', 'limit' => 500.0, 'thresholds' => [0.8, 1.0]],
],

Listen for the event to send alerts:

use AiModelUsageTracker\AiModelUsageTracker\Events\BudgetThresholdReached;

Event::listen(BudgetThresholdReached::class, function (BudgetThresholdReached $event) {
    // notify your team
});

Recording mode

Set recording.mode to sync (default, always exact) or queue to offload writes to a job for high-throughput apps:

'recording' => [
    'mode' => 'queue',
    'queue' => ['connection' => null, 'queue' => null],
],

Retention

php artisan ai-usage:prune --days=90

Set retention_days in config and schedule the command in routes/console.php (or app/Console/Kernel.php):

use Illuminate\Support\Facades\Schedule;

Schedule::command('ai-usage:prune')->daily();

Dashboard (Inertia/Vue)

Requires a host app using Inertia + Vue.

Step 1 — Publish the page component

php artisan vendor:publish --tag="ai-model-usage-tracker-assets"

Step 2 — Build assets

npm run build

Step 3 — Define the access gate

The dashboard is served at the configured dashboard.path (default /ai-usage) and is protected by the viewAiUsageDashboard gate:

use Illuminate\Support\Facades\Gate;

Gate::define('viewAiUsageDashboard', fn ($user) => $user->isAdmin());

Adjust dashboard.path and dashboard.middleware in config as needed.

Testing

composer test

This runs static analysis (PHPStan/Larastan), code style (Pint), 100% type coverage, and the Pest test suite.

Changelog

Please see CHANGELOG for more information on what has changed recently.

License

AI Model Usage Tracker is open-sourced software licensed under the MIT license.