vizuh/filament-clicktrail

Filament 3 plugin for ClickTrail attribution: settings page, attribution record dashboard, diagnostics widget, and Laravel/Filament event mapping.

Maintainers

Package info

github.com/vizuh/clicktrail-filament

pkg:composer/vizuh/filament-clicktrail

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 2

v0.1.1 2026-08-25 11:40 UTC

This package is auto-updated.

Last update: 2026-08-25 12:16:56 UTC


README

English | Português | Deutsch | 中文

vizuh/filament-clicktrail

ClickTrail attribution inside your Filament 3 panel — settings, read-only attribution records, suppression diagnostics, and event mapping. Nothing to build by hand.

CI License: MIT

Index

Why

Attribution data nobody can see is attribution nobody trusts. This plugin surfaces ClickTrail's stored first/last-touch records, consent snapshots, and suppression diagnostics directly inside an existing Filament panel — strictly read-only, because attribution state belongs to the capture pipeline, never to hand edits.

Requires PHP >= 8.1, Laravel 12.60+ or 13.10+, Filament 3.3.55+, and clicktrail/php-sdk.

Installation

composer require vizuh/filament-clicktrail
php artisan vendor:publish --tag=clicktrail-filament
php artisan migrate

Quick start

Register the plugin on any panel:

use ClickTrail\Filament\ClickTrailPlugin;

public function panel(Panel $panel): Panel
{
    return $panel->plugin(ClickTrailPlugin::make());
}
// The panel now shows a "ClickTrail" navigation group: the Settings page,
// the read-only Attribution Records table (auto-refreshing every 60s), and
// the diagnostics stats widget. No further wiring.

Event mapping

Support\EventMap maps Eloquent model events onto canonical Stable::EVENT_* names, so your lead and order models speak ClickTrail's vocabulary without glue code:

use App\Models\Lead;
use ClickTrail\Filament\Support\EventMap;

EventMap::resolve(new Lead(), 'created');  // 'lead.submitted' — canonical event name
EventMap::resolve(new Lead(), 'deleted');  // 'sale.refunded' — deletion maps to refund

Model basenames map by default (lead, appointment, sale, order). Extend or override per model through the clicktrail-filament.event_map config key; a basename ending in refund resolves to sale.refunded, and events containing attended resolve to appointment.attended.

Attribution records

The AttributionRecordResource table shows stored first/last-touch records with channel filters and a compact consent-snapshot column:

TextColumn::make('first_channel')->badge();          // paid_search | organic_search | ...
SelectFilter::make('first_channel');                 // filter by canonical channel name
TextColumn::make('consent_snapshot_summary');        // "analytics_storage=granted, ad_user_data=denied"

There are no create/edit/delete pages and no routes to them: canCreate(), canEdit(), canDelete() all return false. The table polls every 60 seconds.

Settings and configuration

The settings page edits the published clicktrail-filament.php config:

'site_id'           => env('CLICKTRAIL_SITE_ID', ''),   // issued by the collector
'endpoint'          => env('CLICKTRAIL_ENDPOINT', 'https://collect.clicktrail.dev/v1/events/batch'),
'consent_resolver'  => env('CLICKTRAIL_CONSENT_RESOLVER', ''), // empty => NullConsentResolver
'capability_gates'  => ['analytics' => true, 'advertising' => true, 'ad_user_data' => true],

A capability gate that is off means that use does not require CMP consent (gate-toggle semantics). Note: settings save currently writes back to the config repository at runtime; durable persistence lands with the settings-storage work in progress.

Diagnostics

The stats widget reads clicktrail_diagnostics counters — one stat per suppression reason, colored warning when nonzero:

Stat::make('adUserDataUnknownAtCapture', '12') // count of suppressed deliveries for this reason
    ->description('Last seen 2 hours ago')

With no suppressions recorded you get a green Suppressions = 0 stat. Queue depth shows - until the queued-delivery job ships (deferred pending live verification).

Consent contract

This plugin is a consent consumer, not a CMP. It reads a normalized ConsentSnapshot (granted / denied / unknown / not_applicable) through the Laravel adapter's ConsentResolverInterface. Every unresolved signal counts as denied: suppressed deliveries become diagnostics rows instead of being sent.

if (! ConsentBehavior::can($snapshot, 'ad_user_data')) {
    // delivery suppressed; reason recorded in clicktrail_diagnostics,
    // visible in the Diagnostics widget immediately
}

How it differs

This plugin Generic admin CRUD
Attribution records Read-only display of pipeline-owned state Editable rows invite silent data corruption
Consent Unknown = denied, enforced upstream of delivery Often a display-only flag
Events Canonical Stable::EVENT_* names shared with every ClickTrail adapter Per-project invented event names

It does not capture touches or deliver batches itself — the Laravel adapter pipeline owns that; this plugin makes its results visible and auditable.

Testing

No PHPUnit suite ships yet. CI lints every PHP file on PHP 8.1–8.3:

composer install --prefer-dist --no-interaction || echo "no deps"
find . -name '*.php' -not -path './vendor/*' -print0 | xargs -0 -n1 php -l   # exits clean on success

License

MIT.