tracekit-php-sdk

Installation
SKILL.md

TraceKit PHP SDK Setup

Auth Bootstrap

Do not tell the user to go sign up, log in separately, or manually create an API key before setup. First check for existing TraceKit auth. If ~/.tracekitconfig does not contain the production profile or TRACEKIT_API_KEY is missing, apply the tracekit-auth skill first. Use ./scripts/run-tracekit-auth.sh status to check, then guide the user through the TraceKit email verification flow with register and verify. That flow signs the user into an existing account for that email or creates the account automatically, then saves the returned credentials for the rest of the setup.

When To Use

Use this skill when the user asks to:

  • Add TraceKit to a PHP application
  • Add observability or APM to a vanilla PHP project
  • Instrument a PHP service with distributed tracing
  • Configure TraceKit API keys in a PHP project
  • Debug production PHP services with live breakpoints
  • Set up code monitoring in a PHP app

Important: If the project uses Laravel (check for laravel/framework in composer.json), use the tracekit-laravel-sdk skill instead -- it provides Laravel-specific service providers, config publishing, and facades.

Non-Negotiable Rules

  1. Never hardcode API keys in code. Always use getenv('TRACEKIT_API_KEY').
  2. Always initialize TraceKit before handling requests -- the Tracekit\init() call must happen at the top of your entry point.
  3. Always include a verification step confirming traces appear in https://app.tracekit.dev/traces.
  4. Always enable code monitoring (enable_code_monitoring => true) -- it is TraceKit's differentiator.
  5. Use env vars for all secrets -- .env files, CI secrets, or deployment secret managers.

Detection

Before applying this skill, detect the project type:

  1. Check for composer.json -- confirms this is a PHP project.
  2. Confirm no Laravel -- scan composer.json for laravel/framework. If found, use the tracekit-laravel-sdk skill.
  3. Check PHP version -- requires PHP 8.1 or higher.
  4. Only ask the user if composer.json is missing or if the framework cannot be determined.

Step 1: Environment Setup

Set the TRACEKIT_API_KEY environment variable. This is the only required secret.

Add to your .env file or environment:

export TRACEKIT_API_KEY=ctxio_your_api_key_here

The OTLP endpoint is hardcoded in the SDK init -- no need to configure it separately.

Where to get your API key:

  1. Log in to TraceKit
  2. Go to API Keys page
  3. Generate a new key (starts with ctxio_)

Do not commit real API keys. Use .env files, deployment secret managers, or CI variables.

Step 2: Install SDK

composer require tracekit/php-apm

This installs the TraceKit PHP SDK with built-in OpenTelemetry support, HTTP middleware, database query tracing, and code monitoring.

Prerequisites:

  • PHP 8.1 or higher
  • Composer package manager
  • A TraceKit account (create one free)

Step 3: Initialize TraceKit

Add this to the top of your entry point (e.g., index.php or public/index.php), before any request handling:

<?php

require_once __DIR__ . '/vendor/autoload.php';

// Initialize TraceKit -- MUST be before request handling
Tracekit\init([
    'api_key'                => getenv('TRACEKIT_API_KEY'),
    'service_name'           => 'my-php-service',
    'endpoint'               => 'https://app.tracekit.dev/v1/traces',
    'enable_code_monitoring' => true,
]);

// ... your application code below

Key points:

  • service_name should match your service's logical name (e.g., "api-gateway", "user-service")
  • enable_code_monitoring => true enables live breakpoints and snapshots in production
  • The init() call must happen before any route or request handling

Step 4: HTTP Request Tracing

Wrap your request handler with TraceKit middleware to automatically trace all HTTP requests:

<?php

require_once __DIR__ . '/vendor/autoload.php';

Tracekit\init([
    'api_key'                => getenv('TRACEKIT_API_KEY'),
    'service_name'           => 'my-php-service',
    'endpoint'               => 'https://app.tracekit.dev/v1/traces',
    'enable_code_monitoring' => true,
]);

// Option A: Use TracekitMiddleware to wrap your request handler
$handler = new Tracekit\TracekitMiddleware(function ($request) {
    // Your request handling logic
    $path = $_SERVER['REQUEST_URI'];

    if ($path === '/api/users') {
        header('Content-Type: application/json');
        echo json_encode(['users' => ['alice', 'bob']]);
        return;
    }

    http_response_code(404);
    echo json_encode(['error' => 'Not found']);
});

$handler->handle();

If you prefer manual span management:

// Option B: Manual span creation
$span = Tracekit\startSpan('handle-request', [
    'http.method' => $_SERVER['REQUEST_METHOD'],
    'http.url'    => $_SERVER['REQUEST_URI'],
]);

try {
    // Your request handling logic
    processRequest();
} finally {
    Tracekit\finishSpan($span);
}

Step 5: Database Query Tracing

TraceKit automatically traces PDO queries when using the provided wrapper:

use Tracekit\TracekitPDO;

// Wrap your PDO connection with TraceKit
$db = new TracekitPDO(
    'mysql:host=localhost;dbname=myapp',
    'username',
    'password'
);

// Queries are automatically traced
$stmt = $db->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$userId]);
$user = $stmt->fetch();

For existing PDO connections, wrap them:

$existingPdo = new PDO('mysql:host=localhost;dbname=myapp', 'user', 'pass');
$tracedPdo = Tracekit\wrapPDO($existingPdo);

Step 6: Error Capture

Capture exceptions explicitly where you handle them:

try {
    $result = someRiskyOperation();
} catch (\Exception $e) {
    Tracekit\captureException($e);
    // Handle the error...
}

Set up a global exception handler to catch unhandled exceptions:

set_exception_handler(function (\Throwable $e) {
    Tracekit\captureException($e);
    http_response_code(500);
    echo json_encode(['error' => 'Internal server error']);
});

For adding context to traces, use manual spans:

$span = Tracekit\startSpan('process-order', [
    'order.id' => $orderId,
    'user.id'  => $userId,
]);

try {
    // Your business logic
    $order = processOrder($orderId);
} catch (\Exception $e) {
    Tracekit\captureException($e);
    throw $e;
} finally {
    Tracekit\finishSpan($span);
}

Step 6b: Snapshot Capture (Code Monitoring)

For programmatic snapshots, use the SnapshotClient directly - do not call through the SDK wrapper. The SDK uses stack inspection internally to identify the call site. Adding extra layers shifts the frame and causes snapshots to report the wrong source location.

Create a Breakpoints helper (e.g., src/Breakpoints.php):

<?php

namespace App;

class Breakpoints
{
    private static $snapshotClient = null;

    public static function init($sdk): void
    {
        if ($sdk !== null) {
            self::$snapshotClient = $sdk->snapshotClient();
        }
    }

    public static function capture(string $name, array $data): void
    {
        if (self::$snapshotClient === null) {
            return;
        }
        self::$snapshotClient->checkAndCapture($name, $data);
    }
}

Initialize after SDK setup:

\App\Breakpoints::init($sdk);

Use at call sites:

\App\Breakpoints::capture('payment-failed', ['order_id' => $orderId, 'error' => $e->getMessage()]);

See the tracekit-code-monitoring skill for the full pattern across all languages.

Code Monitoring v25.0 Features

The latest SDK release adds these code monitoring capabilities (configured via the dashboard, no code changes needed):

  • Logpoint mode -- capture expressions only without full variable snapshots, reducing overhead
  • Per-breakpoint limits -- individual max captures (default: 100) and rate limits per breakpoint
  • Dynamic stack traces -- configurable stack depth per breakpoint (1-50 frames)
  • Idle auto-expiry -- breakpoints auto-expire after inactivity (default: 24h), pinnable to prevent expiry
  • Conditional expressions -- server-side evaluated conditions with full operator support (==, !=, >, <, &&, ||)

These features are available when 'enable_code_monitoring' is set to true. No SDK code changes required -- all configuration is done through the TraceKit dashboard.

For full details, see the tracekit-code-monitoring skill.

Step 7: External HTTP Call Tracing

Trace outgoing HTTP requests with the TraceKit HTTP client wrapper:

use Tracekit\TracekitHttpClient;

$client = new TracekitHttpClient();

// GET request -- automatically traced
$response = $client->get('https://api.example.com/users');

// POST request -- automatically traced
$response = $client->post('https://api.example.com/orders', [
    'json' => ['item' => 'widget', 'quantity' => 5],
]);

If using cURL directly, wrap calls manually:

$span = Tracekit\startSpan('http-client', [
    'http.method' => 'GET',
    'http.url'    => 'https://api.example.com/data',
]);

$ch = curl_init('https://api.example.com/data');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$span->setAttribute('http.status_code', $httpCode);
Tracekit\finishSpan($span);

Step 8: Verification

After integrating, verify traces are flowing:

  1. Start your application with TRACEKIT_API_KEY set in the environment.
  2. Hit your endpoints 3-5 times -- e.g., curl http://localhost:8080/api/users.
  3. Open https://app.tracekit.dev/traces.
  4. Confirm new spans and your service name appear within 30-60 seconds.

If traces do not appear, see Troubleshooting below.

Troubleshooting

Traces not appearing in dashboard

  • Check TRACEKIT_API_KEY: Ensure the env var is set in the runtime environment (not just in your shell). Verify: echo getenv('TRACEKIT_API_KEY');.
  • Check outbound access: Your service must reach https://app.tracekit.dev/v1/traces. Verify with: curl -X POST https://app.tracekit.dev/v1/traces (expect 401 -- means the endpoint is reachable).
  • Check init order: Tracekit\init() must be called before any request handling. If init happens after your router runs, requests are not traced.

Init order wrong

Symptoms: Server starts fine but no traces appear despite traffic.

Fix: Move Tracekit\init() to the very top of your entry point (index.php), before require_once of your router or framework bootstrap.

Missing environment variable

Symptoms: Tracekit init failed error on startup, or traces appear without an API key (rejected by backend).

Fix: Ensure TRACEKIT_API_KEY is exported in your shell, .env file, Docker Compose, or deployment config. For PHP-FPM, set it in the pool config (env[TRACEKIT_API_KEY]).

Service name collisions

Symptoms: Traces appear under the wrong service in the dashboard.

Fix: Use a unique service_name per deployed service. Avoid generic names like "app" or "server".

PHP-FPM environment variables

Symptoms: getenv('TRACEKIT_API_KEY') returns false in PHP-FPM.

Fix: Add to your PHP-FPM pool config (/etc/php/8.x/fpm/pool.d/www.conf):

env[TRACEKIT_API_KEY] = ctxio_your_api_key_here

Or use a .env loader like vlucas/phpdotenv:

$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();

Next Steps

Once your PHP application is traced, consider:

  • Code Monitoring -- Set live breakpoints and capture snapshots in production without redeploying (already enabled via enable_code_monitoring => true)
  • Distributed Tracing -- Connect traces across multiple services for full request visibility
  • Frontend Observability -- Add @tracekit/browser to your frontend for end-to-end trace correlation

LLM Instrumentation (Auto-Discovery)

TraceKit automatically instruments OpenAI and Anthropic API calls in PHP applications. No manual setup required - the SDK detects LLM libraries at init time via Guzzle middleware.

When To Use

Add this when the user:

  • Uses OpenAI or Anthropic APIs in their PHP application
  • Wants to monitor LLM cost, tokens, and latency
  • Asks about AI observability in PHP

How It Works

LLM instrumentation is enabled by default when the SDK initializes. It registers Guzzle middleware that detects requests to api.openai.com and api.anthropic.com and creates traced spans with GenAI attributes.

Configuration

$client = new TracekitClient([
    'api_key' => getenv('TRACEKIT_API_KEY'),
    'llm' => [
        'enabled' => true,        // Master toggle (default: true)
        'openai' => true,         // OpenAI instrumentation
        'anthropic' => true,      // Anthropic instrumentation
        'capture_content' => false // Capture prompts/completions (default: false)
    ]
]);

Environment Variable

Set TRACEKIT_LLM_CAPTURE_CONTENT=true to enable prompt/completion capture without code changes. Content is PII-scrubbed automatically.

Captured Attributes

  • gen_ai.system - Provider name (openai/anthropic)
  • gen_ai.request.model / gen_ai.response.model - Model name
  • gen_ai.usage.input_tokens / gen_ai.usage.output_tokens - Token counts
  • gen_ai.response.finish_reasons - Completion stop reason
  • Tool calls recorded as span events

Verify

Check the LLM dashboard at https://app.tracekit.dev/ai/llm for cost, token, and latency data.

Full docs: https://app.tracekit.dev/docs/languages/php#llm-instrumentation

References

  • PHP SDK docs: https://app.tracekit.dev/docs/languages/php
  • TraceKit docs root: https://app.tracekit.dev/docs
  • Dashboard: https://app.tracekit.dev
  • Quick start: https://app.tracekit.dev/docs/quickstart
Related skills

More from tracekit-dev/tracekit-for-ai

Installs
6
GitHub Stars
1
First Seen
Mar 9, 2026