Skip to main content
Notification Center includes built-in delivery tracking. Every Delivery record is assigned two unique slugs at creation time — one for opens and one for actions — that power engagement tracking without any additional configuration.

How Tracking Works

Each Delivery record stores two URL-safe identifiers:
FieldPurpose
open_slugRecorded when the recipient opens or views the notification.
action_slugRecorded when the recipient clicks the call-to-action.
These slugs are embedded in notification content (e.g., as a tracking pixel URL or wrapped CTA link). When a recipient interacts with the notification, their client resolves the slug URL, the package records the event, and the delivery status advances accordingly.

Tracking Routes

The following routes are registered automatically by the package:
MethodPathNameDescription
GET/o/{slug}notification-center.track.openRecords an open event for the matching delivery.
GET/a/{slug}notification-center.track.actionRecords an action event for the matching delivery.
GET/notifications/{id}notification-center.notifications.renderRenders the full notification content for web-based channels.
No route registration is required in your application — these routes are loaded by the package’s service provider.

The Event Model

Every tracking interaction creates an Event record linked to the delivery:
// Opscale\NotificationCenter\Models\Event

$fillable = [
    'delivery_id',  // FK to the Delivery that was interacted with
    'name',         // Event name, e.g. "Opened" or "Verified"
    'payload',      // Optional JSON metadata (e.g., user agent, IP)
];

$casts = [
    'payload' => 'array',
];
The relationship chain is:
Delivery
  └── has-many  Event
                  └── belongs-to  Delivery
You can query all events for a notification via its deliveries:
$notification->deliveries->flatMap->events;

Google Analytics GA4 Integration

Notification Center can automatically include the Google Analytics gtag.js snippet in rendered notifications. Set your GA4 Measurement ID in your environment:
GOOGLE_ANALYTICS_ID=G-XXXXXXXXXX
This value is read by the config:
// config/notification-center.php
'google_analytics_id' => env('GOOGLE_ANALYTICS_ID'),
When GOOGLE_ANALYTICS_ID is set, the gtag.js script is injected into notifications rendered via the /notifications/{id} route. Page views and events fired within the rendered notification will flow into your GA4 property.
GA4 integration applies to web-rendered notifications (the renderNotification route). Push and channel-native deliveries (SMS, WhatsApp, etc.) are tracked exclusively through the slug-based open and action routes.

Viewing Tracking Data in Nova

1

Open a notification

Navigate to Notifications in the Nova sidebar and select a published notification.
2

View deliveries

The Deliveries relationship panel lists every delivery record with its current status (Pending, Sent, Opened, Verified, etc.).
3

Inspect events

Open an individual delivery to see the Events panel, showing every tracked interaction (opens, actions) with timestamps and payload data.
Delivery statuses are updated as tracking events are recorded. A delivery moves from SentOpened when the open slug is resolved, and from OpenedVerified when the action slug is resolved.

Service actions

TrackEvent

Opscale\NotificationCenter\Services\Actions\TrackEvent is the internal service that records delivery lifecycle events. It is registered as an event listener for both NotificationSent and NotificationFailed Laravel events, so delivery statuses update automatically on every send. It can also be called directly to record custom events:
use Opscale\NotificationCenter\Services\Actions\TrackEvent;

TrackEvent::run([
    'delivery_id' => $delivery->id,
    'event'       => 'Opened',   // Sent | Received | Opened | Verified | Failed | Expired | custom
    'payload'     => ['ip' => request()->ip()],
]);

EnrichGeoData

Opscale\NotificationCenter\Services\Actions\EnrichGeoData enriches an existing Event record’s payload with geolocation data from ipgeolocation.io. It requires an API key set via:
// config/notification-center.php (add manually)
'ipgeolocation' => [
    'api_key' => env('IPGEOLOCATION_API_KEY'),
],
use Opscale\NotificationCenter\Services\Actions\EnrichGeoData;

EnrichGeoData::run(['event_id' => $event->id]);
ipgeolocation.api_key is not part of the default published config. Add it manually if you want to use geo enrichment.

Build docs developers (and LLMs) love