Laravel Integration Guide
Integrate TraceKit with Laravel for automatic request tracing, live breakpoints, and production debugging. See database queries, API calls, and exceptions in real-time.
Learn how to instrument your Laravel applications with TraceKit APM for zero-config distributed tracing and performance monitoring.
Zero-Config Automatic Tracing
TraceKit Laravel package automatically traces HTTP requests, database queries, queue jobs, cache operations, and more with minimal setup. Just install and configure your API key!
Prerequisites
Before you begin, you need:
- PHP 8.1 or higher
- Laravel 10.x, 11.x, or 12.x
- A TraceKit account (create one free)
- A generated API key from the API Keys page
What Gets Traced Automatically
With TraceKit Laravel package installed, these operations are traced automatically with zero configuration:
| Component | Span Type | Captured Attributes | Auto-Traced? |
|---|---|---|---|
| HTTP Requests | SERVER | Route, method, status, duration | Yes |
| Database Queries | DB | SQL, bindings, duration, connection | Yes |
| Outgoing HTTP Calls | CLIENT | method, url, status_code, duration, peer.service | Yes (via Http facade) |
| Queue Jobs | Custom | job.class, queue, attempts, duration | Yes |
| Exceptions | N/A | exception.type, exception.message, stack_trace | Yes |
| Custom Spans | Custom | user-defined attributes | Manual |
Installation
Install the TraceKit Laravel package via Composer:
composer require tracekit/laravel-apmPackage Autodiscovery -- The service provider is automatically registered via Laravel's package discovery. No need to manually register it!
Configuration
1. Publish Configuration (Optional)
If you want to customize settings, publish the configuration file:
php artisan vendor:publish --provider="TraceKit\Laravel\TracekitServiceProvider"This creates config/tracekit.php where you can customize settings.
2. Add API Key to .env
Add your TraceKit API key to your .env file:
# TraceKit APM Configuration
TRACEKIT_API_KEY=ctxio_your_generated_api_key_here
TRACEKIT_ENDPOINT=https://app.tracekit.dev/v1/traces
TRACEKIT_SERVICE_NAME=my-laravel-app
TRACEKIT_ENABLED=trueImportant Security Note -- Never commit your API key to version control. Keep it in your .env file and use environment-specific values.
Verify It Works
Start your application and make a few requests. Then open the Traces page in your TraceKit dashboard. You should see:
- SERVER spans for each incoming HTTP request (auto-traced by middleware)
- DB spans for Eloquent and query builder queries (auto-traced by QueryListener)
- CLIENT spans for outgoing HTTP calls via the Http facade
Traces typically appear within 30 seconds. If you don't see them, check the Troubleshooting section.
Laravel 12+ Middleware Setup
For Laravel 12+, middleware registration has changed. The package attempts automatic registration, but if needed, manually add the middleware to bootstrap/app.php:
<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Middleware;
use TraceKit\Laravel\Middleware\TracekitMiddleware;
return Application::configure(basePath: dirname(__DIR__))
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
TracekitMiddleware::class,
]);
$middleware->api(append: [
TracekitMiddleware::class,
]);
})
// ... rest of your configuration
->create();Laravel 10 & 11 -- For Laravel 10 and 11, the middleware is registered automatically via the service provider. No manual configuration needed!
Environment Variables
Available configuration options in config/tracekit.php:
<?php
return [
// Enable/disable tracing
'enabled' => env('TRACEKIT_ENABLED', env('APP_ENV') !== 'local'),
// Your TraceKit API key
'api_key' => env('TRACEKIT_API_KEY', ''),
// OTLP endpoint for sending traces
'endpoint' => env('TRACEKIT_ENDPOINT', 'https://app.tracekit.dev/v1/traces'),
// Service name as it appears in TraceKit
'service_name' => env('TRACEKIT_SERVICE_NAME', env('APP_NAME', 'laravel-app')),
// Sample rate (0.0 to 1.0)
'sample_rate' => env('TRACEKIT_SAMPLE_RATE', 1.0),
// Enable/disable specific features
'features' => [
'http' => env('TRACEKIT_HTTP_ENABLED', true),
'database' => env('TRACEKIT_DATABASE_ENABLED', true),
'cache' => env('TRACEKIT_CACHE_ENABLED', true),
'queue' => env('TRACEKIT_QUEUE_ENABLED', true),
'redis' => env('TRACEKIT_REDIS_ENABLED', true),
],
// Routes to ignore
'ignored_routes' => [
'/health',
'/up',
'/_healthz',
],
// Slow query threshold (ms)
'slow_query_threshold' => env('TRACEKIT_SLOW_QUERY_MS', 100),
// Include query bindings in traces
'include_query_bindings' => env('TRACEKIT_INCLUDE_BINDINGS', true),
];Configuration Reference
| Option | Type | Default | Env Variable | Description |
|---|---|---|---|---|
api_key | string | "" | TRACEKIT_API_KEY | Your TraceKit API key for authentication |
endpoint | string | "app.tracekit.dev" | TRACEKIT_ENDPOINT | TraceKit collector endpoint URL |
traces_path | string | "/v1/traces" | TRACEKIT_TRACES_PATH | HTTP path for trace data export |
metrics_path | string | "/v1/metrics" | TRACEKIT_METRICS_PATH | HTTP path for metrics data export |
service_name | string | APP_NAME or "laravel-app" | TRACEKIT_SERVICE_NAME | Name of your service in the trace dashboard |
enabled | bool | true (non-local) | TRACEKIT_ENABLED | Enable or disable tracing globally |
sample_rate | float | 1.0 | TRACEKIT_SAMPLE_RATE | Trace sampling rate (0.0 to 1.0, where 1.0 = 100%) |
features.http | bool | true | TRACEKIT_HTTP_ENABLED | Auto-trace incoming HTTP requests |
features.database | bool | true | TRACEKIT_DATABASE_ENABLED | Auto-trace Eloquent and DB queries |
features.cache | bool | true | TRACEKIT_CACHE_ENABLED | Auto-trace cache operations (Redis, Memcached, file) |
features.queue | bool | true | TRACEKIT_QUEUE_ENABLED | Auto-trace queued jobs and events |
features.redis | bool | true | TRACEKIT_REDIS_ENABLED | Auto-trace Redis commands |
slow_query_threshold | int | 100 | TRACEKIT_SLOW_QUERY_MS | Threshold in ms to flag slow queries |
include_query_bindings | bool | true | TRACEKIT_INCLUDE_BINDINGS | Include query parameter bindings in trace data |
code_monitoring.enabled | bool | false | TRACEKIT_CODE_MONITORING_ENABLED | Enable live code debugging / snapshot capture |
code_monitoring.poll_interval | int | 30 | TRACEKIT_CODE_MONITORING_POLL_INTERVAL | How often to poll for active breakpoints (seconds) |
code_monitoring.max_variable_depth | int | 3 | TRACEKIT_CODE_MONITORING_MAX_DEPTH | Max variable inspection depth for snapshots |
code_monitoring.max_string_length | int | 1000 | TRACEKIT_CODE_MONITORING_MAX_STRING | Max string length captured in snapshots |
suppress_errors | bool | true | TRACEKIT_SUPPRESS_ERRORS | Suppress SDK errors to prevent app crashes |
service_name_mappings | array | [] | code only | Map host:port to service names for service discovery |
ignored_routes | array | ['/health', '/up', '/_healthz'] | code only | Routes excluded from tracing (health checks, etc.) |
Laravel auto-reads all TRACEKIT_* environment variables via the env() helper. Add them to your .env file and they take effect immediately (run php artisan config:clear if config is cached).
Code Monitoring (Live Debugging)
Production-Safe Live Debugging -- Capture variable state, stack traces, and request context at any point in your code without redeployment. Perfect for debugging production issues! See the full Code Monitoring Documentation.
Setup
To enable code monitoring for live debugging, add these settings to your .env:
# Enable code monitoring
TRACEKIT_CODE_MONITORING_ENABLED=true
# Polling interval (seconds)
# - 1-5: Development (fast updates, higher load)
# - 10-30: Production (recommended)
# - 60+: Low traffic/minimal overhead
TRACEKIT_CODE_MONITORING_POLL_INTERVAL=30
# Variable inspection depth (1-10)
TRACEKIT_CODE_MONITORING_MAX_DEPTH=3
# String truncation length
TRACEKIT_CODE_MONITORING_MAX_STRING=1000Usage: Add Debug Points
Use the tracekit_snapshot() helper to capture variable state:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class OrderController extends Controller
{
public function processOrder(Request $request)
{
$userId = $request->user()->id;
$cartTotal = $request->input('cart_total');
// Capture variable state at checkout start
tracekit_snapshot('checkout-start', [
'user_id' => $userId,
'cart_total' => $cartTotal,
'items_count' => $request->input('items', [])->count(),
]);
try {
$order = $this->createOrder($request->all());
$payment = $this->processPayment($order);
// Capture successful payment state
tracekit_snapshot('payment-success', [
'order_id' => $order->id,
'payment_id' => $payment->id,
'amount' => $payment->amount,
]);
return response()->json(['order' => $order], 201);
} catch (\Exception $e) {
// Exception automatically captured with stack trace!
throw $e;
}
}
}Features
- Auto-Registration -- Breakpoints automatically created on first call
- Variable Capture -- Deep inspection of arrays, objects, and primitives
- Stack Traces -- Full call stack with file and line numbers
- Request Context -- HTTP method, route, headers, and query params
Production Safety
The Laravel SDK includes multiple layers of protection:
- PII Scrubbing -- 13 built-in sensitive data patterns enabled by default. Detected values are replaced with typed
[REDACTED:type]markers before leaving your server. - Crash Isolation -- All entry points wrap operations in
catch(\Throwable)blocks. SDK errors are silently logged and never propagate to your application. - Circuit Breaker -- 3 consecutive failures within 60 seconds triggers a 5-minute cooldown. Uses Laravel's
Cachefacade for cross-request persistence. - Remote Kill Switch -- Toggle code monitoring on/off from the dashboard. Propagates instantly via SSE for Artisan commands and queue workers, or via polling for web requests.
Real-Time Updates -- The Laravel SDK uses app()->runningInConsole() to detect the execution context. Long-lived Artisan commands and queue workers receive kill switch and breakpoint updates via SSE (Server-Sent Events) for instant propagation. Web requests use lightweight polling on each snapshot call since PHP processes are short-lived.
LLM Instrumentation
TraceKit automatically instruments OpenAI and Anthropic API calls when detected. LLM calls appear as spans with OTel GenAI semantic convention attributes.
Zero-config auto-instrumentation -- The Laravel SDK auto-registers LLM instrumentation via the service provider. If your app makes OpenAI or Anthropic API calls via HTTP, TraceKit captures them automatically through event listeners.
Captured Attributes
| Attribute | Description |
|---|---|
gen_ai.system | Provider name (openai, anthropic) |
gen_ai.request.model | Model name (gpt-4o, claude-sonnet-4-20250514, etc.) |
gen_ai.usage.input_tokens | Prompt token count |
gen_ai.usage.output_tokens | Completion token count |
gen_ai.response.finish_reasons | Finish reason (stop, end_turn, tool_calls) |
Configuration
// config/tracekit.php
return [
'api_key' => env('TRACEKIT_API_KEY'),
'service_name' => env('APP_NAME', 'my-laravel-app'),
'llm' => [
'enabled' => true,
'openai' => true,
'anthropic' => true,
'capture_content' => false,
],
];Use TRACEKIT_LLM_CAPTURE_CONTENT=true to enable prompt/completion capture without code changes. Useful for enabling in staging but not production.
Streaming Support -- Streaming responses produce a single span that covers the entire stream. Token counts are accumulated from the final chunk. No special configuration needed.
LLM Dashboard -- View LLM cost, token usage, and latency metrics on the dedicated LLM Observability dashboard at /ai/llm in your TraceKit instance.
Local UI (Development Mode)
Debug your Laravel application locally without creating an account. TraceKit Local UI runs on your machine at http://localhost:9999 and automatically receives traces when you run your app in local environment.
Automatic Detection -- The Laravel SDK automatically detects when Local UI is running on port 9999 and sends traces to both Local UI and cloud (if you have an API key configured).
Quick Start
- Install the Local UI:
npm install -g @tracekit/local-ui- Start the Local UI:
tracekit-local- Run your app (Laravel automatically uses APP_ENV=local):
php artisan serve- Open your browser:
http://localhost:9999Features
- Auto-Detection -- SDK checks for Local UI at
localhost:9999on startup - Real-Time Updates -- See traces instantly with WebSocket live updates
- Development Only -- Only activates when
APP_ENV=local - Works Offline -- No internet connection required
Service Discovery
TraceKit automatically instruments outgoing HTTP calls made with Laravel's HTTP client to create service dependency graphs.
Usage with Laravel HTTP Client
Just use Laravel's HTTP client as normal -- everything is traced automatically:
<?php
use Illuminate\Support\Facades\Http;
// All HTTP calls are automatically traced!
Route::post('/checkout', function (Request $request) {
// This creates a CLIENT span for the payment-service call
$paymentResponse = Http::post('http://payment-service/charge', [
'amount' => $request->input('amount'),
'user_id' => auth()->id(),
]);
// This creates another CLIENT span for the inventory-service call
$inventoryResponse = Http::post('http://inventory-service/reserve', [
'item_id' => $request->input('item_id'),
]);
return response()->json([
'status' => 'success',
'payment_id' => $paymentResponse['payment_id'],
]);
});Custom Service Name Mappings
For local development or when service names can't be inferred from hostnames, configure service name mappings in config/tracekit.php:
// config/tracekit.php
return [
// ... other config
// Map localhost URLs to actual service names
'service_name_mappings' => [
'localhost:8082' => 'payment-service',
'localhost:8083' => 'user-service',
'localhost:8084' => 'inventory-service',
],
];
// Now requests to localhost:8082 will show as "payment-service" in your service graph
// Http::get('http://localhost:8082/charge');
// -> Creates CLIENT span with peer.service = "payment-service"Service Name Detection
TraceKit intelligently extracts service names from URLs:
| URL | Extracted Service Name |
|---|---|
| http://payment-service:3000 | payment-service |
| http://payment.internal | payment |
| http://payment.svc.cluster.local | payment |
| https://api.example.com | api.example.com |
Viewing Service Dependencies -- Visit your TraceKit dashboard to see the Service Map -- a visual graph showing which services call which, with health metrics and latency data.
Manual Instrumentation (Optional)
For custom business logic or specific operations you want to measure, you can manually create spans:
<?php
use TraceKit\Laravel\TracekitClient;
class OrderController extends Controller
{
public function processOrder(Request $request, TracekitClient $tracekit)
{
// Create a custom span
$span = $tracekit->startSpan('process-order', null, [
'order.id' => $request->input('order_id'),
'user.id' => auth()->id(),
]);
try {
$order = $this->createOrder($request->all());
$this->processPayment($order);
$this->sendConfirmation($order);
$tracekit->endSpan($span, [
'order.total' => $order->total,
'order.items_count' => $order->items()->count(),
]);
return response()->json($order, 201);
} catch (\Exception $e) {
$tracekit->recordException($span, $e);
$tracekit->endSpan($span, [], 'ERROR');
throw $e;
}
}
}Tracekit Facade API
| Facade Method | Parameters | Returns | Description |
|---|---|---|---|
Tracekit::startSpan($op, $attrs) | string $operationName, array $attributes = [] | array | Start a new span via the Facade. Returns span data array. |
Tracekit::endSpan($data, $attrs, $status) | array $spanData, array $attributes = [], ?string $status = null | void | End a span and optionally set additional attributes and status. |
Tracekit::captureSnapshot($label, $vars) | string $label, array $variables = [] | void | Capture a code monitoring snapshot with variable state at this point. |
Tracekit::counter($name, $tags) | string $name, array $tags = [] | Counter | Create or retrieve a counter metric via the Facade. |
Tracekit::gauge($name, $tags) | string $name, array $tags = [] | Gauge | Create or retrieve a gauge metric via the Facade. |
Tracekit::histogram($name, $tags) | string $name, array $tags = [] | Histogram | Create or retrieve a histogram metric via the Facade. |
The Tracekit Facade proxies all TracekitClient methods. Use it anywhere in your Laravel application without injecting the client directly.
Complete Example
Here's a complete example showing automatic and manual tracing:
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
use TraceKit\Laravel\TracekitClient;
class UserController extends Controller
{
// HTTP requests are automatically traced!
public function index()
{
// Database queries are automatically traced!
$users = User::where('active', true)->get();
return response()->json($users);
}
// You can add custom spans for specific operations
public function processUserData(Request $request, TracekitClient $tracekit)
{
// Start custom span
$span = $tracekit->startSpan('process-user-data', null, [
'user.count' => $request->input('user_ids')->count(),
]);
try {
// Your business logic here
$results = [];
foreach ($request->input('user_ids') as $userId) {
$user = User::find($userId);
$results[] = $this->processUser($user);
}
$tracekit->endSpan($span, [
'results.count' => count($results),
]);
return response()->json($results);
} catch (\Exception $e) {
$tracekit->recordException($span, $e);
$tracekit->endSpan($span, [], 'ERROR');
throw $e;
}
}
private function processUser($user)
{
// Database queries here are also automatically traced!
$user->last_processed_at = now();
$user->save();
return $user;
}
}Custom Metrics
Track custom metrics like request counts, queue sizes, and response times using the TraceKit metrics API.
Counter
Track monotonically increasing values (requests, events):
use TraceKit\Laravel\Facades\Tracekit;
// Create a counter with optional tags
$counter = Tracekit::counter('http.requests.total', [
'service' => 'api',
'method' => 'GET',
]);
// Increment by 1
$counter->inc();
// Add a specific value
$counter->add(5);Gauge
Track values that can go up or down (queue size, connections):
// Create a gauge
$gauge = Tracekit::gauge('http.connections.active');
// Set to specific value
$gauge->set(42);
// Increment/decrement
$gauge->inc();
$gauge->dec();Histogram
Track value distributions (latencies, sizes):
// Create a histogram with tags
$histogram = Tracekit::histogram('http.request.duration', [
'unit' => 'ms',
]);
// Record values
$histogram->record(45.2);
$histogram->record(123.5);Troubleshooting
Traces not appearing?
Cause: Laravel config caching can hide .env changes, or the TraceKit service provider is not loaded.
Fix:
- Clear config cache:
php artisan config:clear - Verify
TRACEKIT_ENABLED=truein.env - Check that
TRACEKIT_API_KEYis set - Review
storage/logs/laravel.logfor export errors - Ensure the TraceKit service provider is in your providers list (should be auto-discovered)
Package not auto-discovered?
Cause: Laravel's package auto-discovery cache is stale or the package was installed with --no-scripts.
Fix:
- Run
php artisan package:discoverfollowed byphp artisan config:clear - Verify the provider appears in
bootstrap/cache/packages.php - If still missing, manually add
TraceKit\Laravel\TracekitServiceProvider::classto config/app.php providers array
Code monitoring not working?
Cause: Code monitoring is disabled by default in Laravel.
Fix:
- Set
TRACEKIT_CODE_MONITORING_ENABLED=truein.env - Run
php artisan config:clear - Add
captureSnapshot()calls via the Tracekit facade:Tracekit::captureSnapshot('label') - Wait for the poll interval (default 30s) before expecting results
Authentication errors (401/403)?
Cause: API key in .env is wrong, has quotes wrapping it, or config cache is stale.
Fix:
- In
.env, useTRACEKIT_API_KEY=ctxio_xxx(no quotes around value) - Run
php artisan config:clear - Verify with
php artisan tinkerthenconfig('tracekit.api_key') - Regenerate key in dashboard if needed
Database or queue traces missing?
Cause: Specific feature flags in the TraceKit config are disabled.
Fix:
- Verify feature flags in
.env:TRACEKIT_DATABASE_ENABLED=true,TRACEKIT_QUEUE_ENABLED=true,TRACEKIT_CACHE_ENABLED=true - Check that the
slow_query_threshold(default 100ms) is not filtering out fast queries you expect to see - Review ignored_routes in config/tracekit.php to ensure your routes are not excluded
Next Steps
- Explore your traces on the Traces page to identify slow queries and performance bottlenecks
- Configure alert rules to get notified when issues occur
- Add custom spans for specific business logic you want to measure
- Adjust sampling rates for high-traffic applications
Pro Tip -- Enable query bindings to see actual SQL values in traces. Just set TRACEKIT_INCLUDE_BINDINGS=true in your .env file. Perfect for debugging!
.NET / C# Integration Guide
Learn how to integrate TraceKit with .NET and ASP.NET Core. Automatic distributed tracing with OpenTelemetry for debugging production C# applications.
Frontend Observability
Complete frontend observability for JavaScript applications. Error tracking, session replay, release management, and distributed tracing with React, Vue, Angular, Next.js, and Nuxt.