Let AI set up TraceKit for you

AI assistants can guide you through the entire setup process

Try AI Setup

Laravel Integration Guide

Learn how to instrument your Laravel applications with TraceKit APM for zero-config distributed tracing and performance monitoring.

Using Laravel?

See our dedicated Laravel observability guide for framework-specific setup, pain points, and best practices.

Laravel Distributed Tracing Guide

Go deeper with our Laravel distributed tracing guide -- covering common pain points, production patterns, and code examples.

New: Frontend Observability

Looking for browser-side error tracking? Check out the new Browser SDK with React, Vue, Angular, Next.js, and Nuxt integrations via Framework Wrappers.

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

  • • 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:

ComponentSpan TypeCaptured AttributesAuto-Traced?
HTTP RequestsSERVERRoute, method, status, durationYes
Database QueriesDBSQL, bindings, duration, connectionYes
Outgoing HTTP CallsCLIENTmethod, url, status_code, duration, peer.serviceYes (via Http facade)
Queue JobsCustomjob.class, queue, attempts, durationYes
ExceptionsN/Aexception.type, exception.message, stack_traceYes
Custom SpansCustomuser-defined attributesManual

Installation

Install the TraceKit Laravel package via Composer:

composer require tracekit/laravel-apm

Package 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=true

Important 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),
];

All configuration options available for the Laravel SDK:

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.)

Note: 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!

→ 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=1000

Usage: 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

Exception Handling

Exceptions are automatically captured with full stack traces for code discovery:

<?php

// Exceptions are AUTOMATICALLY captured with full stack traces!
// No additional code needed - just throw exceptions as normal

Route::get('/payment/{id}', function ($id) {
    $payment = Payment::find($id);

    if (!$payment) {
        // This exception will be captured with:
        // - Full stack trace
        // - File and line number
        // - Request context (route, headers, params)
        // - All for code discovery!
        throw new \Exception('Payment not found');
    }

    return $payment;
});

// You can also manually capture at exception points
Route::post('/process', function (Request $request) {
    try {
        $result = $this->riskyOperation($request->all());
    } catch (\Exception $e) {
        // Optionally add a snapshot before re-throwing
        tracekit_snapshot('operation-failed', [
            'error' => $e->getMessage(),
            'input' => $request->all(),
        ]);
        
        throw $e; // Auto-captured!
    }
});

Production Safe

Snapshots are sampled and have minimal performance impact. Capture rates and conditions can be controlled via the TraceKit dashboard.

Production Safety

The Laravel SDK includes multiple layers of protection to ensure code monitoring is safe for production environments:

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 Cache facade for cross-request persistence in PHP's process-per-request model.

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.

End-to-End Workflow

1

Enable Code Monitoring

Set the TRACEKIT_CODE_MONITORING_ENABLED environment variable in your .env file. Code monitoring defaults to disabled in Laravel -- you must explicitly enable it.

# .env
TRACEKIT_CODE_MONITORING_ENABLED=true

# Optional: fine-tune polling and capture settings
TRACEKIT_CODE_MONITORING_POLL_INTERVAL=30
TRACEKIT_CODE_MONITORING_MAX_DEPTH=5
TRACEKIT_CODE_MONITORING_MAX_STRING=1024

This maps to config/tracekit.phpcode_monitoring.enabled

2

Add Snapshot Capture Points

Use either the Facade or the helper function to add capture points in your code:

// Option 1: Facade
use App\Facades\Tracekit;

Tracekit::captureSnapshot('order-checkout', [
    'order_id'  => $order->id,
    'total'     => $order->total,
    'items'     => count($order->items),
]);

// Option 2: Helper function
tracekit_snapshot('order-checkout', [
    'order_id'  => $order->id,
    'total'     => $order->total,
    'items'     => count($order->items),
]);
3

Deploy and Verify Traces

Run php artisan serve or deploy to your environment. Navigate to the /traces dashboard and confirm traces are flowing from your Laravel application.

4

Navigate to Code Monitoring

Go to /snapshots and click the "Browse Code" tab. You will see auto-discovered files and functions from your traces.

5

Set Breakpoints

Breakpoints are auto-registered on the first captureSnapshot() call. You can also manually set breakpoints via the UI. Laravel uses the Cache facade for breakpoint storage, so breakpoints persist across requests.

6

Trigger Snapshot Capture

Make an HTTP request that hits a code path with a capture point. The SDK uses debug_backtrace() for file and line detection. Both the Facade and helper function check that tracekit.enabled and tracekit.code_monitoring.enabled are both true before capturing.

7

View Captured Snapshot

Go to /snapshots and click the captured snapshot. You can inspect:

  • Variables -- the data you passed to captureSnapshot
  • Stack Trace -- complete call stack with file names and line numbers
  • Request Context -- HTTP method, URL, headers, client IP
  • Security Flags -- any sensitive data detected and redacted

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

AttributeDescription
gen_ai.systemProvider name (openai, anthropic)
gen_ai.request.modelModel name (gpt-4o, claude-sonnet-4-20250514, etc.)
gen_ai.usage.input_tokensPrompt token count
gen_ai.usage.output_tokensCompletion token count
gen_ai.response.finish_reasonsFinish reason (stop, end_turn, tool_calls)

Configuration

PHP — 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, ], ];

Environment Variable Override

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

1. Install the Local UI:

npm install -g @tracekit/local-ui

2. Start the Local UI:

tracekit-local

3. Run your app (Laravel automatically uses APP_ENV=local):

php artisan serve

4. Open your browser:

http://localhost:9999

Features

Auto-Detection

SDK checks for Local UI at localhost:9999 on 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 - everything runs locally

Benefits

  • See your first trace in under 60 seconds
  • Debug locally without switching to the cloud dashboard
  • Stay in your flow - everything runs on your machine
  • Works completely offline
  • Perfect for development and demos

Troubleshooting

If traces aren't appearing in Local UI, check:

  • Local UI is running (curl http://localhost:9999/api/health)
  • APP_ENV=local is set in .env file
  • SDK version is v1.1.1 or higher
  • Check logs for " Local UI detected" message

Auto-Instrumentation API

Laravel SDK auto-registers these listeners and middleware via the TracekitServiceProvider. No manual setup is needed:

Component Type Registration Description
HttpClientMiddleware Middleware Auto (ServiceProvider) Automatically instruments outgoing HTTP calls via the Http facade. Creates CLIENT spans for every Http::get/post/etc. call.
QueryListener Event Listener Auto (ServiceProvider) Automatically traces all database queries by listening to DB events. Creates DB spans with query text, bindings, and duration.
JobListener Event Listener Auto (ServiceProvider) Automatically traces queued job execution by listening to Queue events. Creates spans for each job with class name, queue, and duration.
InstallCommand Artisan Command Auto (ServiceProvider) Run php artisan tracekit:install to scaffold config file and .env setup.
startTrace($op, $attrs) Method Manual Create a root trace in Laravel. Parameters: string $operationName, array $attributes = []. Returns: array (span data).
startServerSpan($op, $attrs, $ctx) Method Manual Create a server span in Laravel with optional parent context. Parameters: string $operationName, array $attributes = [], ?ContextInterface $parentContext = null. Returns: array (span data).

Service Discovery

TraceKit automatically instruments outgoing HTTP calls made with Laravel's HTTP client to create service dependency graphs. When your service makes an HTTP request to another service, TraceKit creates CLIENT spans and injects trace context headers.

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:

URLExtracted Service Name
http://payment-service:3000payment-service
http://payment.internalpayment
http://payment.svc.cluster.localpayment
https://api.example.comapi.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

The Tracekit Facade proxies all TracekitClient methods. Use it anywhere in your Laravel application:

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.

Note: The Tracekit Facade proxies all TracekitClient methods. Use it anywhere in your Laravel application without injecting the client directly.

Automatic Instrumentation Example

Listeners and middleware are auto-registered. Use the Facade for manual tracing:

// These are auto-registered by TracekitServiceProvider -- no manual setup needed:
// QueryListener: traces all database queries via DB events
// JobListener: traces all queued jobs via Queue events
// HttpClientMiddleware: traces Http::get/post/etc. calls

// Manual tracing via Facade:
use App\Facades\Tracekit;

$spanData = Tracekit::startTrace('process-order', ['order.id' => $orderId]);

// ... process order (DB queries and HTTP calls are auto-traced!)

Tracekit::endSpan($spanData);

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;
    }
}

You're all set!

Your Laravel application is now sending traces to TraceKit. Visit the Dashboard to see your traces.

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=true in .env
  • Check TRACEKIT_API_KEY is set
  • Review storage/logs/laravel.log for 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:discover followed by php artisan config:clear
  • Verify the provider appears in bootstrap/cache/packages.php
  • If still missing, manually add TraceKit\Laravel\TracekitServiceProvider::class to config/app.php providers array

Code monitoring not working?

Cause: Code monitoring is disabled by default in Laravel.

Fix:

  • Set TRACEKIT_CODE_MONITORING_ENABLED=true in .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, use TRACEKIT_API_KEY=ctxio_xxx (no quotes around value)
  • Run php artisan config:clear
  • Verify with php artisan tinker then config('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

🔄 Migrating from OpenTelemetry

TraceKit wraps OpenTelemetry internally and integrates with Laravel via package auto-discovery. Here's how to migrate from a manual OpenTelemetry setup to TraceKit's Laravel package.

Before vs After

Before: Raw OpenTelemetry ~30 lines
// Manual ServiceProvider + config + middleware
// app/Providers/TracingServiceProvider.php
use OpenTelemetry\Contrib\Otlp\OtlpHttpTransportFactory;
use OpenTelemetry\SDK\Trace\TracerProvider;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;

class TracingServiceProvider extends ServiceProvider {
    public function register() {
        $transport = (new OtlpHttpTransportFactory())
            ->create(config('tracing.endpoint'), ...);
        $exporter = new SpanExporter($transport);
        $provider = TracerProvider::builder()
            ->addSpanProcessor(new SimpleSpanProcessor($exporter))
            ->build();
        // + config/tracing.php publishing
        // + middleware registration
        // + manual span creation
    }
}
After: TraceKit Laravel 5 lines
# .env
TRACEKIT_API_KEY=your-api-key
TRACEKIT_SERVICE_NAME=my-laravel-app

# bootstrap/app.php (Laravel 11+)
->withMiddleware(function (Middleware $middleware) {
    $middleware->append(\Tracekit\Laravel\TracekitMiddleware::class);
})

Migration Steps

1

Install the package: composer require tracekit/laravel-apm

2

Remove manual ServiceProvider: Delete your custom OTel TracingServiceProvider — TraceKit auto-discovers via Laravel package discovery

3

Set .env vars: Add TRACEKIT_API_KEY and TRACEKIT_SERVICE_NAME

4

Register middleware: Add TracekitMiddleware in bootstrap/app.php

5

Remove OTel packages: composer remove open-telemetry/sdk open-telemetry/exporter-otlp

6

Verify: Run php artisan serve and check the Traces page for incoming data

Key Migration Benefits

  • 30 lines to 5 lines — no manual ServiceProvider or config publishing needed
  • Package auto-discovery — no manual provider registration required
  • Built-in code monitoring — not available with raw OpenTelemetry
  • Built-in security scanning — automatic variable redaction on snapshots
  • .env configuration — no hardcoded config files needed

Performance Overhead

TraceKit is built on OpenTelemetry's efficient batch processing pipeline. The SDK adds minimal overhead to your Laravel application.

Low

Request Tracing

< 2ms per request

Spans are batched and exported asynchronously.

Negligible

Code Monitoring (Idle)

Zero overhead

No performance impact when no active breakpoints.

Low

Code Monitoring (Capture)

< 5ms per snapshot

Includes variable serialization and security scanning.

Negligible

Memory Footprint

~5-10 MB

SDK runtime and span buffer.

Low

SDK Initialization

< 100ms per request

Laravel's per-request lifecycle means initialization occurs on every request. The overhead is amortized across the request but occurs each time.

Note: Performance characteristics are typical for production workloads and may vary with application complexity, request volume, and number of instrumented libraries. Use sampling configuration to reduce overhead in high-traffic services.

Best Practices

DO: Use middleware registration (not manual init)

The TraceKit Laravel package registers middleware automatically via package discovery. Do not manually call init functions.

DO: Configure via .env not config/tracekit.php hardcoding

Use Laravel's .env file for all TraceKit configuration. This keeps secrets out of version control and allows per-environment settings.

# .env
TRACEKIT_API_KEY=your-api-key
TRACEKIT_SERVICE_NAME=my-laravel-app
TRACEKIT_ENVIRONMENT=production

DO: Use the Http facade for auto-traced outbound HTTP calls

Laravel's Http facade is automatically instrumented by TraceKit. Use it instead of raw Guzzle or cURL for outbound requests.

DO: Use environment variables for API keys

Store your API key in TRACEKIT_API_KEY rather than hardcoding it. The SDK reads this automatically.

DO: Enable code monitoring in staging first

Test breakpoint capture and snapshot behavior in a staging environment before rolling out to production.

DO: Use sampling in high-traffic services

Set TRACEKIT_SAMPLING_RATE to a value below 1.0 for services handling thousands of requests per second to reduce overhead without losing visibility.

DO: Set meaningful service names

Use TRACEKIT_SERVICE_NAME to give your service a descriptive name that makes it easy to identify in the trace viewer.

DON'T: Create a manual ServiceProvider for TraceKit

Package auto-discovery handles service provider registration. Creating a manual TracekitServiceProvider causes double-registration and initialization conflicts.

DON'T: Call tracekit.init() in AppServiceProvider

The TraceKit package middleware handles initialization. Calling init in AppServiceProvider conflicts with the package middleware and can cause duplicate spans.

DON'T: Create spans for every function

Trace boundaries like HTTP handlers, database calls, and external service calls. Instrumenting internal helper functions adds noise and overhead without useful insight.

DON'T: Add high-cardinality attributes

Avoid using user IDs, request IDs, or session tokens as span attributes. These create excessive unique time series and degrade query performance.

DON'T: Disable TLS in production

The TRACEKIT_INSECURE flag is for local development only. Always use TLS when sending traces to TraceKit in production.

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!

Copilot

No conversations yet

TraceKit Copilot

Ask about services, traces, alerts, snapshots, and LLM usage.

Copilot uses AI to analyze your APM data. Responses may not always be accurate.

Try TraceKit in 10 seconds

Explore real traces, dashboards, and live code monitoring. No signup needed.

Sign Up Free
No credit card No signup Real data