Track and log AI usage (tokens, cost, duration) for any Laravel application, with optional auto-discovery for laravel/ai SDK.
backtik-ch/laravel-ai-usage is a Laravel package for track and log ai usage (tokens, cost, duration) for any laravel application, with optional auto-discovery for laravel/ai sdk..
It currently has 0 GitHub stars and 598 downloads on Packagist (latest version v1.0.7).
Install it with composer require backtik-ch/laravel-ai-usage.
Discover more Laravel packages by backtik-ch
or browse all Laravel packages to compare alternatives.
Last updated
Track and log AI usage (tokens, cost, duration) for any Laravel application, with optional auto-discovery for the laravel/ai SDK and an optional Filament panel integration.
composer require backtik-ch/laravel-ai-usage
Publish the config file and run the migrations:
php artisan vendor:publish --tag=ai-usage-config
php artisan migrate
This package hooks into the laravel/ai SDK lifecycle via two events:
PromptingAgent — fired when an agent starts. The package creates a pending record with the agent class, label, and an invocation ID.AgentPrompted — fired when the agent completes. The package locates the pending record, fills in token counts, duration, model/driver info, and snapshots the token prices from your config.The result is a complete, immutable log of every AI call — no manual code required if you use laravel/ai.
If you're not using laravel/ai, you can log calls manually via the fluent AiUsage facade (see Manual logging).
The config file (config/ai-usage.php) exposes the following options:
| Key | Default | Description |
|---|---|---|
| table | ai_usage | Database table name |
| queue_logs | false | Dispatch log writes as queued jobs |
| log_system_prompt | false | Store system prompts in the log |
| log_response_text | true | Store AI response bodies |
| max_text_length | 10_000 | Truncate prompt/response text (chars); null disables |
| stale_timeout_minutes | 60 | Minutes before a processing record is considered stale |
| auto_discover | true | Auto-listen to laravel/ai events |
| attach_authenticated_user | false | Associate auto-discovered logs with the authenticated user |
| show_costs | true | Show estimated costs and pricing details in the Filament UI |
| prices | (see below) | Token prices (USD / 1 M tokens) per driver & model |
Prices are snapshotted into each log row at write time so historical cost estimates remain accurate after you update the config.
// config/ai-usage.php
'prices' => [
'openai' => [
'gpt-4o' => ['prompt' => 2.50, 'completion' => 10.00],
'gpt-4o-mini' => ['prompt' => 0.15, 'completion' => 0.60],
// ...
],
'anthropic' => [
'claude-sonnet-4-5' => [
'prompt' => 3.00, 'completion' => 15.00,
'cache_read' => 0.30, 'cache_write' => 3.75,
],
// ...
],
'gemini' => [
'gemini-2.0-flash' => ['prompt' => 0.10, 'completion' => 0.40],
// ...
],
],
Supported price keys: prompt, completion, cache_read, cache_write, reasoning.
The package ships with indicative prices for common OpenAI, Anthropic and Gemini models. Always verify against your provider's current pricing page.
To hide estimated costs and price-related details from the package's Filament resource and summary widget, set:
// config/ai-usage.php
'show_costs' => false,
This only affects the UI. The package continues to snapshot configured or manually supplied prices into usage logs, so historical cost data remains available if you later re-enable the setting.
[!TIP] Using
laravel/ai? You're already done. If auto-discovery is enabled (default) andlaravel/aiis installed, every AI agent call is logged automatically — no code needed. The sections below are for manual logging or custom integrations.
When auto_discover is true (default) and laravel/ai is installed, the package automatically listens for Laravel\Ai\Events\PromptingAgent and Laravel\Ai\Events\AgentPrompted. A pending record is created when the agent starts, then updated with tokens, duration, model info, and cost data when the agent finishes.
To disable auto-discovery, set auto_discover to false in config/ai-usage.php.
To associate each automatically discovered log with the authenticated user, enable the following option:
// config/ai-usage.php
'attach_authenticated_user' => true,
The package uses the user from Laravel's default authentication guard. Numeric IDs, UUIDs, and ULIDs are supported. Guests and contexts without authentication, such as jobs and commands, are logged without an owner. If the authenticated user cannot be resolved, is not an Eloquent model, or has no primary key, the package writes a warning and creates the usage log without an owner.
Use the AiUsage facade with a fluent builder:
use BacktikCh\LaravelAiUsage\Facades\AiUsage;
AiUsage::driver('openai')
->model('gpt-4o')
->label('summarize-article')
->agentClass(MyAgent::class) // optional — FQCN of the agent
->tokens(
prompt: 512,
completion: 256,
cacheWrite: 0, // optional
cacheRead: 0, // optional
reasoning: 0, // optional
)
->duration(milliseconds: 1200)
->prompt('Summarize this article...')
->response('The article discusses...')
->status('completed')
->requestMeta(['temperature' => 0.7]) // optional arbitrary metadata
->responseMeta(['finish_reason' => 'stop'])
->log();
AiUsage::driver('openai')
->model('gpt-4o')
->tokens(300, 150)
->owner($user) // any Eloquent model
->log();
AiUsage::driver('openai')
->model('gpt-4o')
->tokens(300, 150)
->costPrices(['prompt' => 2.50, 'completion' => 10.00])
->log();
If costPrices() is not called, prices are resolved automatically from config('ai-usage.prices').
Token prices (USD per 1 million tokens) are snapshotted from your config at log time and stored alongside each record. This means historical cost data remains accurate even when you update prices later.
The AiUsageLog model exposes an estimated_cost computed attribute derived from the stored token counts and prices:
$log = AiUsageLog::find(1);
echo $log->estimated_cost; // e.g. 0.003450
Returns null when no price data is available (i.e., the model isn't listed in your prices config).
To add a new model, simply add its prices to config('ai-usage.prices.{driver}.{model}'). Supported price keys: prompt, completion, cache_read, cache_write, reasoning.
Logs use the AiUsageStatus enum: pending, processing, completed, failed.
Requires filament/filament. Register the plugin in your panel provider:
use BacktikCh\LaravelAiUsage\Filament\AiUsagePlugin;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugin(AiUsagePlugin::make());
}
This registers:
AiUsageResource — browsable, filterable list of all log entries with a detail view.AiUsageStatsWidget — stats overview: total calls, prompt/completion tokens, average duration, failed count.AiUsageSummaryWidget is a full-width Livewire widget with a period selector and per-driver / per-model token breakdowns. Add it to any page:
use BacktikCh\LaravelAiUsage\Filament\Widgets\AiUsageSummaryWidget;
protected function getHeaderWidgets(): array
{
return [AiUsageSummaryWidget::class];
}
php artisan ai-usage:prune --days=90
If an AI call throws an exception, the laravel/ai SDK never fires AgentPrompted, so the record stays in processing status indefinitely. Run this command on a schedule to mark those stale records as failed:
php artisan ai-usage:mark-stale-failed
The timeout is controlled by stale_timeout_minutes in your config (default: 60). You can also override it per-call:
php artisan ai-usage:mark-stale-failed --minutes=30
Add both commands to your scheduler in routes/console.php:
Schedule::command('ai-usage:mark-stale-failed')->hourly();
Schedule::command('ai-usage:prune')->daily();
composer test
MIT — see LICENSE.