Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Segment Laravel Package

cachethq/segment

Laravel integration for Segment analytics, offering a simple facade and service provider to identify users, track events, and record page views. Add your Segment write key and send customer analytics data from your PHP app with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

A quick reality check before you install: cachethq/segment is a 2015-era Laravel 5 wrapper around Segment's HTTP API, archived, with no releases since June 2015 and no dependents. Treat it as a reference implementation you may fork — not as a dependency you adopt in a new project. If you're inheriting an app that already uses it, the steps below are what you need to get oriented.

Install (legacy app only):

composer require cachethq/segment

Composer will almost certainly fail on PHP 8 or Laravel 6+ because of the pinned illuminate/support and PHP constraints. If you must keep it, fork it, widen the constraints in composer.json, and re-tag — the runtime code is small enough to verify by hand.

Register the provider and alias in config/app.php (Laravel 5 style — there is no package discovery):

'providers' => [
    CachetHQ\Segment\SegmentServiceProvider::class,
],
'aliases' => [
    'Segment' => CachetHQ\Segment\Facades\Segment::class,
],

Confirm the exact class names against composer.json's autoload.psr-4 block and the README — this repo is a fork of graham-campbell/segment, so namespaces may differ from what older blog posts show.

Publish config and set the key:

php artisan vendor:publish --provider="CachetHQ\Segment\SegmentServiceProvider"
SEGMENT_WRITE_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Where to look first: src/ (the manager class and facade), config/segment.php (write key, enabled flag, and any default context), and the README. That's the whole surface area — the package is a thin delegation layer, not a framework.

First use case — instrument a signup so you can see the event land in Segment's debugger:

Segment::identify($user->id, [
    'email' => $user->email,
    'created_at' => $user->created_at->toIso8601String(),
    'plan' => $user->plan,
]);

Segment::track($user->id, 'Signed Up', [
    'source' => 'web',
    'referrer' => request()->headers->get('referer'),
]);

Then check the Segment source debugger in the dashboard. If nothing appears, the package is not the likely culprit — check the write key, outbound HTTPS, and whether the call threw an exception you swallowed.

Implementation Patterns

Wrap the facade behind your own interface. The single most valuable thing you can do here is never call Segment:: from a controller again. Define a small Analytics contract with identify, track, group, and alias, and implement it with the facade. When the fork finally dies — or you migrate to segmentio/analytics-php, a plain Http::withBasicAuth($key, '') client, or a different vendor entirely — you change one binding.

interface Analytics
{
    public function identify(string $userId, array $traits = []): void;
    public function track(string $userId, string $event, array $properties = []): void;
}

class SegmentAnalytics implements Analytics
{
    public function track(string $userId, string $event, array $properties = []): void
    {
        Segment::track($userId, $event, $properties);
    }
}

Push every call into a queued job. The wrapper makes a synchronous HTTP request to api.segment.io. Segment is fire-and-forget by design, but your users still pay the round-trip latency. In a request path that emits three events, that's three sequential TLS handshakes. Wrap the call:

class TrackSegmentEvent implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable;

    public function __construct(
        public string $userId,
        public string $event,
        public array $properties = [],
    ) {}

    public function handle(): void
    {
        Segment::track($this->userId, $this->event, $this->properties);
    }

    public function retryUntil() { return now()->addHours(6); }
}

Queues give you what the package doesn't: retries with backoff, a failure log, and the ability to drop analytics traffic instantly during an incident.

Map domain events to Segment events through listeners. Don't sprinkle tracking calls through business logic. Listen to events you already fire and translate:

class TrackOrderCompleted
{
    public function handle(OrderCompleted $event): void
    {
        TrackSegmentEvent::dispatch(
            (string) $event->order->user_id,
            'Order Completed',
            [
                'order_id' => $event->order->id,
                'revenue' => $event->order->total_cents / 100,
                'currency' => $event->order->currency,
                'products' => $event->order->lines->map->only(['sku', 'name', 'price', 'quantity'])->all(),
            ],
        );
    }
}

This keeps the Segment vocabulary in one place and makes it trivially auditable when your tracking plan drifts.

Respect Segment's naming spec. Event names are Object Past-Tense-Verb with Title Case — Signed Up, Order Completed, Trial Started. Properties are snake_case. Segment's schema and downstream destinations (Amplitude, Mixpanel, warehouse syncs) are unforgiving about this; renaming an event six months in means historical data splits into two streams.

Always pass a stable userId. The most common integration bug is emitting anonymous events with anonymous_id and identified events with userId and wondering why the funnel is broken. Call identify on registration and login, then use $user->id everywhere. For pre-signup behaviour, let the client-side snippet establish the anonymous ID and call alias (or rely on Segment's identity merge) at signup.

Use the integrations filter for environment control. Segment's API accepts an integrations object per call to route an event to specific destinations. Depending on the call signature your fork exposes, this may be the fourth or fifth argument, or you may need to extend the manager to pass it through. If your fork doesn't support it, that's a strong argument for replacing it with a direct HTTP client — it's a one-line payload addition.

Test by binding a fake, not by hitting Segment.

class FakeAnalytics implements Analytics
{
    public array $tracked = [];
    public function track(string $userId, string $event, array $properties = []): void
    {
        $this->tracked[] = compact('userId', 'event', 'properties');
    }
    public function identify(string $userId, array $traits = []): void {}
}

Bind it in TestCase::setUp() and assert against $this->app->make(Analytics::class)->tracked. Avoid Segment::shouldReceive(...) facade mocks in anything beyond a single unit test — they leak across the suite when the facade is resolved early.

Attach context centrally. Segment's context object carries IP, user agent, locale, and library metadata. Doing this per-call is noise; do it once in your SegmentAnalytics decorator so every event has consistent enrichment.

Gotchas and Tips

It is archived — plan the exit before you need it. No security patches, no PHP 8 support, no Laravel package auto-discovery. Audit any app still running it: composer why cachethq/segment, then check whether the write key is committed anywhere. Migrating away is genuinely small — the wrapper is a few hundred lines and the underlying HTTP contract (POST https://api.segment.io/v1/track with the write key as basic-auth username and an empty password) has been stable for a decade. A 30-line Http:: based client is a credible drop-in replacement that you control.

Composer resolution failures are the first wall. Expect Your requirements could not be resolved on PHP 8 and Laravel 6+. Don't fight it with --ignore-platform-reqs; fork and widen the constraints, then run the test suite to confirm the manager still behaves. The delegation code is simple enough that this is safe, but verify rather than assume.

Config caching bites. In the 2015 idiom, the config file may read env() directly at runtime. If you php artisan config:cache, anything not surfaced in config/segment.php will be null. The enabled flag — if your fork has one — is the right place to gate analytics in local/CI.

Silent failures. The wrapper almost certainly doesn't inspect the HTTP response. A 401 (bad key), 429 (rate limited), or 400 (malformed payload) will vanish. Add logging around the call in your own decorator, or replace it with a client that throws on non-2xx and lets your queue retry.

Synchronous calls in loops. A nightly job that iterates 50,000 orders and calls Segment::track will take hours and hammer Segment's ingestion limits. Segment's HTTP API recommends batching where you can and staying well under their per-second ingestion ceilings. If you're backfilling, chunk the job and rate-limit it explicitly — this package offers no batching or throttling whatsoever.

Payload size limits. Segment rejects events over roughly 32KB. products arrays on large orders are the usual offender — trim to what a destination actually needs. The wrapper won't warn you; the event just disappears.

PII and GDPR. Server-side tracking bypasses any client-side consent gate you've built. If your consent logic lives in the browser snippet, the server-side wrapper will happily send an email address to Segment for a user who declined. Gate calls on a persisted consent flag before you dispatch the job, not inside the handler.

Double-counting. If the frontend snippet also fires Signed Up, you'll get two events. Pick one owner per event — usually client-side for UI interactions, server-side for anything that represents a committed business fact (payments, subscriptions, account changes).

Facade alias collision. The alias Segment can clash with Segment\ namespaced classes if you later pull in Segment's own PHP SDK. Prefer the fully-qualified facade class in your wrapper and leave the alias out of new code.

Extension points are thin but present. The manager is a concrete class you can extend to add context enrichment, response logging, or integration filtering. If you're forking anyway, add a context merge and a Http client injection point — those two changes cover most of what the package is missing.

Watch for fork drift. The repository is GrahamDeprecated/Laravel-Segment under the cachethq/segment name — a deprecated fork of a deprecated fork. Before you trust any line of it, diff the src/ against the original graham-campbell/segment and read what actually changed. The answer is likely "the namespace."

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
laravel2580/idehelpers
delatbabel/viewpages
anavel/gettext
muhamadrezaar/highcharts
delatbabel/keylists
frankkessler/salesforce-laravel-oauth2-rest
anavel/foundation
wdmtech/enviricons
eii/laravel-captcha
muka/shape-reader
tdt/json
refinery29/php-cs-fixer-config
hotmeteor/eco-env
mvaliolahi/hydrate
wearede/tbcpay-php
parsnick/steak
thibaud-dauce/mattermost-php
multilinguals/apollo-client
antaresbr/collection
kr0lik/phpstan-rules