PHPackages                             clicktrail/laravel - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. clicktrail/laravel

ActiveLibrary[Database &amp; ORM](/categories/database)

clicktrail/laravel
==================

Laravel adapter for ClickTrail attribution: service provider + facade, capture middleware, queued delivery jobs, Blade components/directives, artisan diagnostics, first-party proxy stub, webhook signature verification, consent resolver interface.

v0.1.0(today)10MITPHPPHP &gt;=8.1CI passing

Since Aug 25Pushed todayCompare

[ Source](https://github.com/vizuh/clicktrail-laravel)[ Packagist](https://packagist.org/packages/clicktrail/laravel)[ RSS](/packages/clicktrail-laravel/feed)WikiDiscussions main Synced today

READMEChangelog (1)Dependencies (4)Versions (2)Used By (0)

[English](README.md) | [Português](README.pt-BR.md) | [Deutsch](README.de.md) | [中文](README.zh-CN.md)

**clicktrail/laravel**

See which campaign, keyword, click ID and landing page created each form submission and conversion in any Laravel 10/11 app.

[![CI](https://github.com/vizuh/clicktrail-laravel/actions/workflows/ci.yml/badge.svg)](https://github.com/vizuh/clicktrail-laravel/actions/workflows/ci.yml)[![Latest Version on Packagist](https://camo.githubusercontent.com/71123b655c83ff7f083fd1aaec848c428712693a6de60fbfe318ec4ac9c9a27a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f636c69636b747261696c2f6c61726176656c2e737667)](https://packagist.org/packages/clicktrail/laravel)[![License: MIT](https://camo.githubusercontent.com/08cef40a9105b6526ca22088bc514fbfdbc9aac1ddbf8d4e6c750e3a88a44dca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d626c75652e737667)](LICENSE)

Index
-----

[](#index)

- [Why](#why)
- [Installation](#installation)
- [Quick start](#quick-start)
- [Blade output](#blade-output)
- [Queued delivery](#queued-delivery)
- [Failed events and replay](#failed-events-and-replay)
- [Consent](#consent)
- [First-party proxy](#first-party-proxy)
- [Diagnostics](#diagnostics)
- [Webhook signatures](#webhook-signatures)
- [How it differs](#how-it-differs)
- [Testing](#testing)
- [License](#license)

Why
---

[](#why)

Most tracking packages store what a page showed. ClickTrail proves which campaign created the lead or sale. This package is a thin adapter over [clicktrail/php-sdk](https://github.com/vizuh/clicktrail-php): the SDK owns parse/classify/merge/serialize; Laravel owns capture middleware, consent-gated session persistence, queued delivery, Blade output, and artisan diagnostics.

Installation
------------

[](#installation)

```
composer require clicktrail/laravel
```

Package auto-discovery registers the service provider and the `ClickTrail` facade. Publish the config and fill `CLICKTRAIL_SITE_ID` and `CLICKTRAIL_ENDPOINT` in `.env`:

```
php artisan vendor:publish --tag=clicktrail-config
```

Quick start
-----------

[](#quick-start)

`clicktrail()` is the main entry point (a `ClickTrail` facade also exists).

```
// 1. Register capture on the route groups whose traffic should build
//    first/last-touch state (routes/web.php):
Route::middleware(['web', 'clicktrail.capture'])->group(function () {
    Route::get('/', fn () => view('welcome'));
});

// 2. A visitor arrives from Google Ads; the middleware merges the touch.
//    After the request:
session('clicktrail.attribution');
// JSON with first->source === 'google', first->clickIds['gclid'] set.
// Persisted ONLY when consent permits analytics storage; unknown = denied.

// 3. Inspect or merge from your own code via the helper:
$state = clicktrail()->capture($request);   // StoredState for this request
clicktrail()->pendingPayloads();            // [] means nothing queued yet

// 4. On conversion (form submit, order), queue delivery:
\ClickTrail\Laravel\Jobs\DeliverEventsJob::dispatch();
// batched POST to CLICKTRAIL_ENDPOINT with idempotency keys; retries after
// 200ms/1s/5s; nothing is sent during the request itself.
```

A direct visit afterwards changes nothing: first touch stays, stored last touch persists. That is the SDK's merge law, tested, not promised.

Blade output
------------

[](#blade-output)

```
{{-- renders the first-party loader  tag from config --}}
@clicktrailHead

{{-- hidden attribution inputs inside a , so the server-side
     submit carries source / click IDs verbatim --}}
@clicktrailAttribution

{{-- normalized consent snapshot as data-ct-consent-* attributes --}}
...

{{-- or as explicit components --}}

```

Queued delivery
---------------

[](#queued-delivery)

Events are never sent during the request. Dispatch the delivery job from your own triggers:

```
\ClickTrail\Laravel\Jobs\DeliverEventsJob::dispatch();
// flush() throws RetryableException on 429/5xx/network. Laravel re-runs the
// job via backoff([200ms, 1000ms, 5000ms]). A PermanentException fails the
// job and routes payloads to the failed-events table.
```

The job uses the `BatchClient`, so bind a PSR-18 client as `Psr\Http\Client\ClientInterface` plus PSR-17 request/stream factories before dispatching. Queue connection and queue name come from `clicktrail.queue_connection` / `clicktrail.queue`.

Failed events and replay
------------------------

[](#failed-events-and-replay)

After all retries fail, payloads are stored verbatim in the `clicktrail_failed_events` table (`clicktrail.persist_failed_events`, default `true`). Diagnose, then replay through the same helper:

```
foreach (\ClickTrail\Laravel\Models\ClickTrailFailedEvent::get() as $row) {
    clicktrail()->restorePayloads(json_decode($row->payload, true));
}
// payloads are back in the BatchClient queue; the next DeliverEventsJob run
// sends them unchanged, same idempotency keys, no duplicates.
```

Consent
-------

[](#consent)

ClickTrail is a consent consumer, not a CMP. Implement `ClickTrail\Laravel\Consent\ConsentResolverInterface` with your CMP adapter and bind it, or set `clicktrail.consent_resolver` to its class name. Until then the shipped `NullConsentResolver` returns an unknown snapshot, which is treated as denied everywhere: no identifiers are persisted and no events are delivered. Setting `clicktrail.consent_required` to `false` declares this use needs no CMP gating.

First-party proxy (optional)
----------------------------

[](#first-party-proxy-optional)

With `CLICKTRAIL_FIRST_PARTY_PROXY=true` the provider registers `POST /clicktrail/collect`. It minimally validates the batch payload shape and re-queues delivery through your own infrastructure.

Diagnostics
-----------

[](#diagnostics)

```
php artisan clicktrail:diagnose
```

Checks config presence, endpoint reachability (TCP-level flag), and consent resolver resolution.

Webhook signatures
------------------

[](#webhook-signatures)

Verify ClickTrail webhook callbacks with HMAC-SHA256 constant-time comparison:

```
\ClickTrail\Laravel\Support\WebhookSignature::verify($payload, $request->header('X-ClickTrail-Signature'), $secret);
// === true only when the signature matches; constant-time, no timing leak
```

How it differs
--------------

[](#how-it-differs)

PackageWhat it doesBoundary**combindma/laravel-trail**Stores UTMs/referrers in cookiesClickTrail proves which campaign created the lead or sale: deterministic first/last-touch merge laws validated by golden fixtures shared with our WordPress and GTM engines, consent-gated persistence, batched delivery with idempotency keys**DirectoryTree/Metrics**Counts anonymous eventsComplementary: ClickTrail connects campaigns to identities and revenueSee `../docs/COMPETITOR-NOTES.md` for the full analysis.

Testing
-------

[](#testing)

```
php tests/_runner.php                 # full suite, standalone (no kernel boot)
vendor/bin/phpunit --testdox          # PHPUnit pass (CI, PHP 8.3)
```

CI lints all files and runs both stages on PHP 8.1–8.3 (`.github/workflows/ci.yml`).

License
-------

[](#license)

MIT. Copyright (c) 2026 Vizuh OÜ

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance100

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity32

Early-stage or recently created project

 Bus Factor1

Top contributor holds 90.9% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

0d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/20295730?v=4)[Hugo ](/maintainers/Atroci)[@Atroci](https://github.com/Atroci)

---

Top Contributors

[![Atroci](https://avatars.githubusercontent.com/u/20295730?v=4)](https://github.com/Atroci "Atroci (10 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (1 commits)")

---

Tags

analyticsattributionbladeclickstreamconsent-managementconversion-trackingeloquentfirst-party-datagdprlaravellaravel-packagemarketing-analyticsphpqueueutmlaravelbladeUTMattributionconsentgclid

### Embed Badge

![Health badge](/badges/clicktrail-laravel/health.svg)

```
[![Health](https://phpackages.com/badges/clicktrail-laravel/health.svg)](https://phpackages.com/packages/clicktrail-laravel)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.4M354](/packages/psalm-plugin-laravel)[api-platform/laravel

API Platform support for Laravel

58190.1k21](/packages/api-platform-laravel)[mike-bronner/laravel-model-caching

Automatic caching for Eloquent models.

2.4k161.4k2](/packages/mike-bronner-laravel-model-caching)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

265.2k](/packages/aedart-athenaeum)[forjedio/inertia-table

Backend-driven dynamic tables for Laravel + Inertia.js

272.0k](/packages/forjedio-inertia-table)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
