Search by

NotOnFire for Laravel and PHP: error tracking with strict privacy defaults and privacy-friendly analytics, in one package.

v1.1.0 2026-10-25 20:13 UTC

This package is auto-updated.

Last update: 2026-10-25 20:15:09 UTC


README

Error tracking and privacy-friendly analytics for NotOnFire, in one package. The values below come from the application's settings page in the NotOnFire dashboard, which also shows them ready to copy.

Laravel

composer require notonfire/php
NOTONFIRE_DSN=https://…
NOTONFIRE_ANALYTICS_ID=…
NOTONFIRE_ANALYTICS_DOMAINS=example.com
php artisan notonfire:test

That is the whole install. The package:

  • configures the Sentry SDK from NOTONFIRE_DSN, with tracing, profiling, PII, logs, metrics, breadcrumbs, request bodies and the server name switched off;
  • reports unhandled exceptions on its own — no Integration::handles() in bootstrap/app.php;
  • adds the analytics tag before </head> of every HTML page in the web middleware group;
  • sends a runtime snapshot to the dashboard's Environment view, at most once an hour, after a web response has gone out.

Laravel 12 and 13 on PHP 8.2 and later are supported.

What is not configurable

The privacy settings are enforced over config/sentry.php and every SENTRY_* variable, on purpose. A published config/sentry.php with traces_sample_rate => 1.0 changes nothing. Every event is also stripped of the request, the user, extra data, tags, the transaction name and breadcrumbs before it is sent; what remains is the exception, its stack trace and the runtime. If you need more than that, use sentry/sentry-laravel directly instead of this package.

An application before_send still runs, before the package's own, so nothing it adds survives.

Environments

Nothing is sent and no analytics tag is rendered in the local and testing environments, so a DSN copied into a local .env does not report your typos. Everything else (production, staging, …) sends, tagged with its environment. NOTONFIRE_ENABLED=false switches all of it off everywhere.

Analytics

The tag is added to successful, complete HTML responses only: JSON, redirects, downloads, Livewire and other XHR requests are left alone, and so are admin, filament, horizon, telescope, pulse and nova. To place the tag yourself, set NOTONFIRE_ANALYTICS_INJECT=false and add this to your layout's <head>:

@notonfireAnalytics

The excluded paths live in the config file, which you can publish:

php artisan vendor:publish --tag=notonfire-config

Runtime snapshot

When a CVE comes out, the application's Environment view in the dashboard answers whether it is affected. The package keeps it current with a snapshot of the runtime:

  • the PHP version, SAPI and Zend version, thread safety, and whether OPcache and the JIT are on;
  • the OS family and release (from /etc/os-release), the kernel version and the CPU architecture;
  • the web server's SERVER_SOFTWARE, and the Laravel version;
  • the versions of OpenSSL, curl, libxml, PCRE, ICU, SQLite, GD and ImageMagick that PHP is linked against;
  • every loaded extension with its version;
  • memory_limit, max_execution_time, upload_max_filesize, post_max_size, display_errors, expose_php, allow_url_fopen, allow_url_include, disable_functions, date.timezone, session.cookie_secure, opcache.validate_timestamps, and whether open_basedir is set.

It never contains the hostname, a path, the include path, the document root, an environment variable or anything from the request, and phpinfo() is never called.

The snapshot must have no measurable impact on the website, and it is built so that it has none. Every request costs a few microseconds: the package looks at the modification time of one file, storage/framework/notonfire-runtime-<sapi>, and nothing else. Once an hour one worker spends up to 2 s after the visitor already has the page: the response is finished first, then the snapshot is sent with a 1 s connect timeout and a 2 s total timeout. Only one worker sends, the file is updated before it does, and an unreachable or slow dashboard is not retried before the next hour. It never throws an error into the application.

It is sent only where the response can be finished before it: under PHP-FPM, LiteSpeed and Laravel Octane. Applications that run under Apache's mod_php, the built-in server or only on the command line send none; their error events still carry the PHP version. It also needs ext-curl.

Nothing is sent from local and testing, with NOTONFIRE_ENABLED=false or without a DSN. NOTONFIRE_RUNTIME=false switches the snapshot off on its own, and NOTONFIRE_URL sends it to a dashboard other than https://app.notonfire.systems. php artisan notonfire:test sends one right away. That one comes from the CLI, so the dashboard shows the CLI's settings until the next web request sends its own.

Coming from a manual Sentry setup

Remove the SENTRY_* lines from .env, the Integration::handles($exceptions) call from bootstrap/app.php and a published config/sentry.php. A leftover SENTRY_LARAVEL_DSN is still picked up when NOTONFIRE_DSN is not set, and a leftover Integration::handles() does not report anything twice, but nothing else from that setup has any effect. Remove a hand-pasted analytics tag as well, or every visit is counted twice.

Checking the install

php artisan notonfire:test shows what the package found, sends a test event through the exception handler, the way a real error goes, and sends a runtime snapshot. From local it sends nothing unless you pass --force.

Plain PHP

composer require notonfire/php

Right after vendor/autoload.php, as early as possible:

\NotOnFire\NotOnFire::init(['dsn' => 'https://…']);

In the <head> of your layout:

<?= \NotOnFire\NotOnFire::analyticsScript(['id' => '…', 'domains' => 'example.com']) ?>

Both read NOTONFIRE_DSN, NOTONFIRE_ANALYTICS_ID and NOTONFIRE_ANALYTICS_DOMAINS from the environment when called without them. NOTONFIRE_ENVIRONMENT names the environment (default production); local and testing send nothing.

Under PHP-FPM and LiteSpeed, init() also sends the runtime snapshot, with the same guarantees, from a shutdown function that runs after your own. Its marker file lives in the system temp directory. Pass 'runtime' => false or set NOTONFIRE_RUNTIME=false to switch it off, and 'url' => … or NOTONFIRE_URL for another dashboard.

Check the install with:

NOTONFIRE_DSN='https://…' vendor/bin/notonfire-test

The package depends on sentry/sentry-laravel, so a plain PHP project also installs illuminate/support. Nothing from Laravel is loaded unless the project uses it.

Development

composer install
vendor/bin/pest
vendor/bin/pint

The runtime snapshot runs inside other people's production requests. Any change to src/Environment/Reporter.php or what it calls has to keep every guarantee listed in that class and under Runtime snapshot.