onetrace-laravel maintained by onetracepro
OneTrace.pro for Laravel
Laravel integration for OneTrace.pro, the customer data platform. Track orders and sign-ups from your backend without slowing responses down, put the website tracker on your pages with one Blade directive, keep the product catalog in sync with your Eloquent models, and test it all with a fake.
Built on onetracepro/onetrace-php: everything that library can do is available through the facade.
- Laravel 10–13, PHP 8.1–8.5
- Events go out in one batch after the response, through your queue, or immediately
anonymousIdfrom the tracker cookie and the signed-in user are added to events automaticallyidentifyon login and registration, tracker reset after logoutOneTrace::fake()for your application's tests
Installation
composer require onetracepro/onetrace-laravel
Add the keys from your project's API keys section to .env:
ONETRACE_URL=https://cdp.onetrace.pro # or the domain of your white-label brand
ONETRACE_WRITE_KEY=cdp_wk_… # events and the website tracker
ONETRACE_SECRET_KEY=cdp_sk_… # products, profiles, segments, journeys, campaigns
To change the defaults, publish the config: php artisan vendor:publish --tag=onetrace-config. php artisan about shows the current settings.
Website tracker
Put the directive into the <head> of your layout:
<head>
…
@onetrace
</head>
It prints the tracker install code with your write key and records the page view. For a signed-in user it links the browser to the user's id (only the id is printed into the page, no personal data), and on the first page after logout it resets the visitor so the next person on the device starts fresh. Options: @onetrace(['nonce' => $nonce, 'page' => false]); Vite's CSP nonce is used automatically. Product events, widgets and Web Push in the browser are described in your account under Site.
Events from the backend
use OneTrace\Laravel\Facades\OneTrace;
OneTrace::track('order_completed', [
'order_id' => $order->number,
'amount' => $order->total,
'products' => $order->lines->map(fn ($line) => [
'product_id' => $line->sku, 'quantity' => $line->quantity, 'price' => $line->price,
])->all(),
], ['messageId' => 'order-' . $order->number]); // a repeat within 24 hours is ignored
OneTrace::identify($user, ['plan' => 'pro']); // the user's email and name are added
OneTrace::identify(null, ['email' => $request->email]); // a visitor who left an email in a form
OneTrace::page('Checkout');
OneTrace::alias($oldUserId); // merge an old id into the signed-in user
Each event gets the signed-in user (userId), the visitor id from the tracker cookie (anonymousId), the IP and user agent, a messageId and a timestamp. Calls validate the event right away and return immediately; sending depends on ONETRACE_SEND:
ONETRACE_SEND |
|
|---|---|
after_response (default) |
one batch after the response is sent to the browser; after each job in queue workers; at the end of artisan commands |
queue |
the same batch is pushed as a job (ONETRACE_QUEUE_CONNECTION, ONETRACE_QUEUE); retries keep the same messageIds |
sync |
sent immediately, the call waits for the API |
Errors of background sending are reported to your exception handler; they never break the response. OneTrace::flush() sends right away (useful in long-running loops). ONETRACE_ENABLED=false turns sending off; without keys nothing is sent either.
Automatic identify
On Laravel's Login and Registered events the user is identified with email and name. To choose the traits, implement HasOneTraceTraits on the user model:
use OneTrace\Laravel\Contracts\HasOneTraceTraits;
class User extends Authenticatable implements HasOneTraceTraits
{
public function oneTraceTraits(): array
{
return ['email' => $this->email, 'phone' => $this->phone, 'first_name' => $this->first_name, 'plan' => $this->plan];
}
}
email, phone, telegram_chat_id and viber_id identify the profile; the rest become profile attributes. Turn it off with onetrace.identify.on_login / on_register.
Product catalog
use OneTrace\Laravel\Contracts\OneTraceProduct;
use OneTrace\Laravel\Eloquent\SyncsWithOneTrace;
class Product extends Model implements OneTraceProduct
{
use SyncsWithOneTrace;
public function toOneTraceProduct(): array
{
return [
'id' => $this->sku, // the product_id your events use
'name' => $this->title,
'price' => $this->price,
'currency' => 'EUR',
'url' => route('products.show', $this),
'image' => $this->image_url,
'category_ids' => [$this->category_slug],
'available' => $this->stock > 0,
];
}
public function shouldSyncWithOneTrace(): bool
{
return $this->is_published; // optional
}
}
Saved models are created or updated in the catalog, deleted ones removed (soft-deleted too; restored ones come back) — sent the same way as events, in batches of up to 1000. Upload the whole catalog once, or on a schedule:
php artisan onetrace:sync-products "App\Models\Product"
Without models: OneTrace::syncProducts([['id' => 'SKU-1', 'name' => '…']]) and OneTrace::deleteProducts(['SKU-1']). Products need the secret key.
The rest of the API
The facade passes everything else to the OneTrace\Client:
use OneTrace\Identity;
OneTrace::profiles()->get('email', 'anna@example.com');
OneTrace::profiles()->updateConsent('user_id', '42', 'email', 'unsubscribed');
OneTrace::segments()->addMembers(12, [Identity::userId($user->id)]);
OneTrace::journeys()->enroll(7, Identity::userId($user->id), ['order_id' => 'A-1001'], 'order-A-1001');
OneTrace::recommendations()->get('viewed_with', ['item' => $product->sku, 'limit' => 4]);
OneTrace::client(); // the client itself, also injectable as OneTrace\Client
See the library's README for errors, retries and pagination, and the API reference.
Testing your application
use OneTrace\Laravel\Facades\OneTrace;
public function test_checkout_tracks_the_order(): void
{
$fake = OneTrace::fake();
$this->actingAs($user)->post('/checkout', $payload);
$fake->assertTracked('order_completed', fn (array $message) => $message['properties']['amount'] === 9980);
$fake->assertIdentified($user->id);
$fake->assertProductSynced('SKU-1');
$fake->assertNotTracked('refund_issued');
}
Also: assertTrackedTimes(), assertPageViewed(), assertProductDeleted(), assertNothingSent(), sent(). Calls through the client (OneTrace::segments()->…) are recorded too: $fake->respondWith([...]) sets the response, $fake->requests() returns what was sent.
Configuration
| Key | Env | Default | |
|---|---|---|---|
url |
ONETRACE_URL |
https://cdp.onetrace.pro |
your account's address |
write_key |
ONETRACE_WRITE_KEY |
— | events, tracker |
secret_key |
ONETRACE_SECRET_KEY |
— | products and the management API |
enabled |
ONETRACE_ENABLED |
true |
|
send |
ONETRACE_SEND |
after_response |
after_response, queue, sync |
queue.connection, queue.name |
ONETRACE_QUEUE_CONNECTION, ONETRACE_QUEUE |
default | for queue |
language |
ONETRACE_LANGUAGE |
en |
language of API error messages |
timeout, max_retries |
ONETRACE_TIMEOUT, ONETRACE_MAX_RETRIES |
10, 3 |
|
anonymous_cookie |
cdp_aid |
the tracker's visitor cookie | |
identify.on_login, identify.on_register |
true |
automatic identify | |
tracker.identify, tracker.reset_on_logout |
true |
@onetrace behaviour |
The visitor cookie is set by JavaScript and read from the raw header, so it does not need to be excluded from EncryptCookies. The package is safe for Octane and long-running queue workers: the collector is scoped to the request or job.
Development
composer install
composer check # PHPStan and PHPUnit (Testbench)
License
MIT, see LICENSE.