A Laravel package that reports exceptions to a Notion database, similar to Sentry.
- π Automatic exception reporting to Notion database
- π Groups identical exceptions (updates occurrence count instead of creating duplicates)
- π Collects request context (URL, method, IP, etc.)
- βοΈ Highly configurable field names and behaviors
- π― Laravel 10, 11, and 12 support
- PHP 8.1+
- Laravel 10.x, 11.x, or 12.x
- A Notion integration and database
composer require yarad/laravel-notion-errors-handler- Go to My Integrations
- Click "New integration"
- Give it a name and select the workspace
- Copy the "Internal Integration Token"
Create a database in Notion with the following properties:
| Property Name | Type |
|---|---|
| Title | Title |
| First Seen | Date |
| Last Seen | Date |
| Occurrences | Number |
| Environment | Select |
| Exception Class | Text |
| File | Text |
| Line | Number |
| Fingerprint | Text |
Important: Share the database with your integration by clicking "Share" and adding your integration.
Copy the database ID from the URL:
https://www.notion.so/myworkspace/a8aec43384f447ed84390e8e42c2e089?v=...
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is the database ID
Add to your .env file:
NOTION_API_KEY=secret_xxx
NOTION_DATABASE_ID=a8aec43384f447ed84390e8e42c2e089php artisan vendor:publish --tag=notion-exceptions-configIn your bootstrap/app.php:
use Yarad\NotionExceptionHandler\Integration;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(...)
->withMiddleware(...)
->withExceptions(function (Exceptions $exceptions) {
Integration::handles($exceptions);
})->create();use Yarad\NotionExceptionHandler\Integration;
try {
// Your code
} catch (Exception $e) {
Integration::captureException($e);
throw $e;
}use Yarad\NotionExceptionHandler\Facades\NotionExceptionHandler;
NotionExceptionHandler::report($exception);
NotionExceptionHandler::isConfigured();
NotionExceptionHandler::getStatus();// config/notion-exceptions.php
return [
// Notion API credentials
'api_key' => env('NOTION_API_KEY'),
'database_id' => env('NOTION_DATABASE_ID'),
// Enable/disable the handler
'enabled' => env('NOTION_EXCEPTION_HANDLER_ENABLED', true),
// Custom field names (must match your Notion database)
'fields' => [
'title' => 'Title',
'first_seen' => 'First Seen',
'last_seen' => 'Last Seen',
'occurrences' => 'Occurrences',
'environment' => 'Environment',
'fingerprint' => 'Fingerprint',
'exception_class' => 'Exception Class',
'file' => 'File',
'line' => 'Line',
],
// Context categories to collect
'context' => [
'request' => true, // URI, method, IP
'headers' => true, // User-Agent, Referer, Accept, Content-Type
'user' => true, // Authenticated user ID
],
// Exceptions to ignore
'ignored_exceptions' => [
// Symfony\Component\HttpKernel\Exception\NotFoundHttpException::class,
],
// Environment name (defaults to APP_ENV)
'environment' => env('NOTION_EXCEPTION_ENVIRONMENT'),
];Exceptions are grouped by a fingerprint generated from:
- Exception class name
- Exception message (normalized to remove dynamic values like UUIDs, IDs, timestamps)
- File path
- Line number
This means the same error occurring multiple times will update a single Notion entry instead of creating duplicates.
Each exception page in Notion includes:
- Exception Message - The full error message
- Stack Trace - Code block with the stack trace
- Request Context - Grouped by category:
- Request: URI, HTTP method, client IP
- Headers: User-Agent, Referer, Accept, Content-Type (no sensitive headers)
- User: Authenticated user ID (if available)
# All tests
./vendor/bin/phpunit
# Unit tests only
./vendor/bin/phpunit --testsuite Unit
# Feature tests only
./vendor/bin/phpunit --testsuite Feature# Static analysis
./vendor/bin/phpstan analyse
# Code style fix
./vendor/bin/php-cs-fixer fixNOTION_API_KEY=xxx NOTION_DATABASE_ID=xxx ./vendor/bin/phpunit --filter RealNotionApiTestMIT License. See LICENSE file.