Configuration - PHP

4 min read Updated: 11.09.2026

Options worth knowing

OptionDefaultMeaning
environmentnullenvironment column in the panel
releasenullversion of the deployed application
error_typeserror_reporting()which PHP errors become events
sample_rate1.0share of error events sent
traces_sample_rate0.0share of transactions sent; 0 disables tracing
send_default_piifalseattaches user id and e-mail, IP address and user agent
enable_compressiontruegzips the request body
send_after_responsetrue on web, false on CLIqueues events and sends them after the response
max_request_body_sizemediumnone, small, medium or always
in_app_exclude[]paths whose frames are marked as vendor code
before_sendidentitylast chance to modify or drop an event

Environments

Every environment should report under an unambiguous name - production, staging, preview. The name is a column in the panel and a filter on the error list, so without it a production outage looks exactly like an error someone triggered in a test. Leave your local environment without credentials: with no token and no key the integration loads and stays silent, so you do not need a separate switch to turn it off.

in_app_exclude decides whether a stack is readable

This is the most underrated option in the SDK. Frames under the paths listed in in_app_exclude are marked as vendor code, so the panel shows the failing place in your application rather than the deepest frame inside a library:

php
init([
    'in_app_exclude' => [__DIR__.'/../vendor'],
]);

Without it every error looks like it happened in vendor/ - and what travels to Jira and Notion is precisely the significant part of the stack, meaning the frames marked as application code.

When events are sent

By default after the response. Events are queued during the request and delivered from a shutdown handler, once PHP-FPM or LiteSpeed has closed the connection to the browser - a slow or unreachable monitoring service then does not delay the page for the visitor. Where the SAPI cannot close the connection early (mod_php, for instance), the queue is still flushed at shutdown, so reporting does not happen in the middle of handling a request.

The queue holds at most 50 events per request; beyond that new events are dropped, since repeated events are grouped by fingerprint anyway. 'send_after_response' => false switches to sending inline; on CLI that is already the default, because a long-running worker should not hold reports until the process ends.

HTTP transactions

php
use Dock\Ray\Framework\HttpTransaction;

$transaction = HttpTransaction::start('GET /checkout', $url, 'GET');

$transaction->measureHandling('app.handle');

// ... handle the request ...

$transaction->finish($response->getStatusCode());

The first argument is a route pattern, not a concrete URL: GET /orders/{order}, not GET /orders/8123. Otherwise the transaction list falls apart into thousands of entries. Transactions are only sent when traces_sample_rate is above zero.

Enriching events

php
use Dock\Ray\Breadcrumb;
use function Dock\Ray\{addBreadcrumb, configureScope};

addBreadcrumb(new Breadcrumb(
    Breadcrumb::LEVEL_INFO,
    Breadcrumb::TYPE_DEFAULT,
    'auth',
    'User logged in'
));

configureScope(function (\Dock\Ray\State\Scope $scope) {
    $scope->setTag('feature', 'payments');
    $scope->setUser(['id' => 42, 'email' => 'user@example.com']);
});

Tags are the cheapest way to filter one area of the application in the panel. Set user data deliberately - it is personal data, and send_default_pii is off by default for a reason.

Browser errors

A browser cannot authenticate directly with DockRay, because the project private key must stay on the server. The SDK therefore provides a collector script and a server-side normaliser, and the event travels like this:

browser  →  your application  →  DockRay
         (no key)              (project key)
php
use Dock\Ray\Browser\BrowserEvent;
use Dock\Ray\Browser\Collector;

// Rendering the page: point the collector at your own endpoint.
$config = Collector::config(endpoint: '/errors/browser', token: $csrfToken);

// Collector::scriptPath() is the file to serve or enqueue.

// Receiving a report: everything in $payload is untrusted.
$event = BrowserEvent::fromArray($payload, $referer, $userAgent);

if ($event !== null) {
    $hub->captureEvent($event);
}

fromArray() returns null for anything it cannot turn into an event and truncates every string it keeps. You write the endpoint's guards yourself - a CSRF token, a body size limit and a per-IP rate limit are exactly what our own plugins use. The collector caps itself too: one report per distinct error per page view and ten per page view, with ResizeObserver loop and cross-origin Script error. filtered out.

Protecting the private key

The private key is a project secret, not an identifier. Keep it in environment variables, in a secrets manager or in the server configuration - never in the repository, in logs, in a screenshot or in code sent to the browser. One project can hold many keys, so production and staging should each get their own: either can be revoked on its own without interrupting the others. A suspicion that a key leaked is reason enough to revoke it and generate a new one.

Next Verification and common problems - PHP
Chat with us The chat is closed right now Available: Mo–Fr 08:00–18:00