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

Analytics Meta Api Laravel Package

liberusoftware/analytics-meta-api

A Laravel package for integrating Meta (Facebook) analytics into your PHP applications. It wraps Meta API authentication and requests, letting you pull marketing and page insights into your app with a clean, framework-friendly interface.

View on GitHub
Deep Wiki
Context7

Getting Started

liberusoftware/analytics-meta-api is a presentation-layer adapter for Meta's Conversions API (CAPI) — the server-side counterpart to the browser Pixel. In practice you use it to push Purchase, Lead, AddToCart, ViewContent, and similar events from your Laravel backend into a Meta dataset, so attribution survives ad blockers, iOS ATT, and cookie loss.

Assumptions to verify first (this package is young — 0 stars, 0 dependents): install it, then open the source before trusting the README. In order, read:

  1. composer.json — confirm the Laravel/illuminate/* version constraints match your app.
  2. src/Providers/*ServiceProvider.php — what it registers, what it binds into the container, whether config is published.
  3. config/*.php (or src/Config/) — the actual env keys. Do not guess these.
  4. The adapter/facade class (*Adapter.php, *Client.php, Meta*) — the public method signature is your real API surface.
  5. LICENSE — GitHub reports NOASSERTION, which means it detected a license file but not a recognized one. Read it before this touches production.

Minimal setup (typical shape for this family of packages):

composer require liberusoftware/analytics-meta-api
php artisan vendor:publish --provider="Liberu\Analytics\MetaApi\MetaApiServiceProvider"

Then populate the published config with a system-user token scoped to the dataset:

META_CAPI_ENABLED=true
META_CAPI_PIXEL_ID=1234567890        # dataset / pixel ID
META_CAPI_ACCESS_TOKEN=EAAG...       # long-lived system user token
META_CAPI_API_VERSION=v21.0
META_CAPI_TEST_EVENT_CODE=           # only in local/staging

First use case — prove the pipe works before wiring checkout. Fire one ViewContent from a Tinker session or an artisan command, with test_event_code set, and confirm it appears in Events Manager → Test Events with a green "Server" badge:

app(MetaTracker::class)->track('ViewContent', [
    'event_id'       => (string) Str::uuid(),
    'event_time'     => now()->utc()->timestamp,
    'event_source_url' => 'https://shop.test/products/example',
    'user_data' => [
        'client_ip_address' => '203.0.113.10',
        'client_user_agent' => 'Mozilla/5.0 ...',
        'em'                => hash('sha256', strtolower(trim('[email protected]'))),
    ],
    'custom_data' => [
        'content_ids' => ['SKU-1'],
        'content_type' => 'product',
        'value' => 49.00,
        'currency' => 'GBP',
    ],
]);

Clear META_CAPI_TEST_EVENT_CODE afterwards. If you see nothing in Test Events, the problem is almost always the token (missing dataset scope) or action_source, not the package.

Implementation Patterns

Deduplicate with the browser Pixel, always. Meta merges a browser event and a server event when event_name + event_id match within a 48-hour window. Generate one event_id per real-world action and pass it to both sides (e.g. render it into your front-end dataLayer and reuse it server-side). Without this you double-count purchases and your ROAS is fiction.

Map domain events to CAPI events via listeners, not inline calls. Keep the adapter out of controllers and checkout services:

// app/Listeners/SendPurchaseToMeta.php
class SendPurchaseToMeta
{
    public function __construct(private MetaTracker $meta) {}

    public function handle(OrderPaid $event): void
    {
        $order = $event->order;

        $this->meta->track('Purchase', [
            'event_id'   => 'order-'.$order->id,
            'event_time' => $order->paid_at->utc()->timestamp,
            'user_data'  => [
                'em'          => hash('sha256', strtolower(trim($order->email))),
                'ph'          => $order->phone ? hash('sha256', preg_replace('/\D/', '', $order->phone)) : null,
                'external_id' => hash('sha256', (string) $order->user_id),
                'fbp'         => $order->fbp,
                'fbc'         => $order->fbc,
                'client_ip_address' => $order->ip,
                'client_user_agent' => $order->user_agent,
            ],
            'custom_data' => [
                'value'      => (float) $order->total,
                'currency'   => $order->currency,
                'order_id'   => $order->id,
                'content_ids'=> $order->items->pluck('sku')->all(),
                'content_type' => 'product',
                'num_items'  => $order->items->count(),
            ],
        ]);
    }
}

Queue it, and queue it after commit. Analytics must never be able to fail a payment. implements ShouldQueue on the listener plus afterCommit() on the connection (or Laravel's after_commit queue config) prevents sending events for orders that roll back.

Persist fbp/fbc and click IDs at session start. These are set by the browser Pixel (_fbp, _fbc cookies) — capture them into your sessions/orders table on first request. If you only look for them at purchase time you'll have lost them on many journeys, and match quality drops hard.

Wrap the adapter behind an interface. Given the adoption level, don't let MetaTracker leak into 40 files:

interface ConversionTracker {
    public function track(string $event, array $payload): void;
}

Bind the package's class to it in your own AppServiceProvider. If the package stalls, changes namespace, or you migrate to a maintained CAPI SDK, you swap one binding plus one adapter class.

Support multiple datasets per tenant/market. Ecommerce setups usually need one pixel per storefront or region. Either resolve config at runtime (config(['analytics-meta.pixel_id' => $tenant->meta_pixel_id]) before calling) or instantiate the adapter per-tenant if the constructor accepts credentials. Verify which style the package supports before designing around it.

Handle non-web events deliberately. Refunds, subscription renewals, and CRM-qualified leads are action_source: 'offline' or 'system_generated', not 'website'. They're often the highest-value events you can send, and the ones most teams forget.

Gate test mode by environment. test_event_code events do not affect optimisation but are visible in Events Manager; leaking it to production silently drops your real conversion signal into a test bucket. Bind it from an env var that's empty in prod.

Gotchas and Tips

Hash before you send — and normalise first. Meta requires SHA-256 of lowercased, trimmed em; ph must be digits only including country code, no + or spaces. fn/ln must not be pre-hashed twice. A single stray space silently reduces match rate; there's no validation error, just worse attribution. Centralise a MetaHasher helper and unit-test it.

event_time must be within 7 days. Backfilling historical orders beyond that window is rejected. It accepts Unix seconds or ISO 8601; be explicit and use UTC — a BST/EDT offset bug shifts events into the wrong day and distorts reporting.

HTTP 200 does not mean success. CAPI responses include events_received, messages, and fbtrace_id; malformed events come back as 200 with per-event errors. Log the full response body on any non-zero error count and surface fbtrace_id — Meta support will ask for it.

action_source is mandatory for most event types. Omitting it produces a rejected event rather than a default. Set it once in the adapter's defaults if the package doesn't.

Don't send raw PII. Everything in user_data should be hashed (except client_ip_address, client_user_agent, fbp, fbc, external_id which may be raw or hashed — follow current docs). Never log the pre-hash values; your application logs become a GDPR liability.

Consent first. Server-side tracking is not a consent loophole. Gate dispatch on your consent manager's marketing flag, and record which lawful basis each event was sent under.

Retry semantics. If you implement retries, key on event_id and keep them idempotent — Meta dedupes on event_id within 48h, but retrying with a freshly generated UUID will double-count. Retry on 5xx and 429 only; 400-class errors are permanent and retrying just burns quota.

Token hygiene. Use a System User token with ads_management on the dataset, not a personal token. Rotate on a schedule and alert when calls start returning OAuth errors — a silently expired token means zero conversions and nobody notices for a week.

Low-adoption risk management. Pin the exact version in composer.json, avoid dev-main. Read the adapter class before relying on it; write a small integration test that asserts the outgoing payload shape (swap the HTTP client for Http::fake()). That test is your upgrade safety net when the package moves.

Extension points to look for: container bindings in the service provider (usually your best insertion point for a decorated client), mergeable config (mergeConfigFrom) for per-tenant overrides, and whether the event payload is a typed DTO or a plain array — a DTO is far easier to extend safely than string-keyed arrays.

Debugging order when events don't show: (1) is enabled true and config cached — php artisan config:clear; (2) is the token valid for this dataset; (3) does Test Events show it — if yes, it's a dedup or action_source problem, not connectivity; (4) check the queued job actually ran (failed_jobs, Horizon); (5) inspect the raw request/response with Http::fake() or a debug log in the adapter.

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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin