Signals Docs
Reference

Offline & CRM events

Send POS, CRM and call-center conversions server-side, tagged with the right action source.

Not every conversion happens in a browser. A cash sale at a counter, a deal closed on a phone call, an order entered by a call-center agent, a subscription renewed by a back-office job: none of these fire a pixel, but they are still conversions your ad platforms should learn from. PixelFox accepts them through the same ingest API, tagged so Meta records them correctly.

What makes an event "offline"

Two things:

  1. There is no browser cookie, so matching relies entirely on the customer's hashed email and phone. Always send whichever you have.

  2. The action_source tells Meta where it happened. PixelFox forwards it to the Conversions API verbatim (browser events default to website):

    action_sourceUse for
    physical_storeIn-store POS sales
    phone_callOrders taken over the phone
    chatWhatsApp / Messenger / live-chat sales
    emailDeals closed over email
    system_generatedBack-office jobs (renewals, reconciliations)

Python

from pixelfox import PixelFox

signals = PixelFox(api_key="sig_live_...")

signals.offline(
    event="purchase",
    value=2400,
    currency="BDT",
    order_id="POS-5591",
    phone="+8801712345678",     # hashed server-side, never stored raw
    email="[email protected]",
    action_source="physical_store",
)

PHP / Laravel

use PixelFox\Facades\PixelFox;

// track(string $event, array $properties = [], ?string $distinctId = null)
PixelFox::track('purchase', [
    'value'             => 2400,
    'currency'          => 'BDT',
    'order_id'          => 'POS-5591',
    'phone'             => '+8801712345678',
    'email'             => 'maya@example.com',
    'first_name'        => 'Maya',
    'last_name'         => 'Rahman',
    'city'              => 'Dhaka',
    'country'           => 'BD',
    '$action_source'    => 'physical_store',
], 'pos-terminal-3');

// Or the purchase helper, with the shopper's own IP and user agent from the
// checkout request so Meta matches the browser session, not your server:
PixelFox::purchase('1001', 129.5, 'BDT', $order->email, [], [
    'first_name' => $order->first_name,
    'last_name'  => $order->last_name,
    'phone'      => $order->phone,
    'city'       => $order->city,
    'zip'        => $order->postcode,
    'country'    => 'BD',
    'external_id'=> (string) $order->user_id,
    'ip'         => $request->ip(),
    'user_agent' => $request->userAgent(),
], $request->cookie('signals_did'));

Server-side events carry your server's IP unless you pass the shopper's as client_ip_address (and client_user_agent); the helpers above do that for you.

Raw HTTP

Any language can post to the ingest API directly. $action_source is just an event property:

curl -X POST https://api.pixelfox.app/v1/ingest \
  -H "X-Signals-Key: sig_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "events": [{
      "event": "purchase",
      "distinct_id": "callcenter-agent-7",
      "properties": {
        "value": 2400, "currency": "BDT", "order_id": "CALL-118",
        "phone": "+8801712345678", "$action_source": "phone_call"
      }
    }]
  }'

Notes

  • Send within 7 days. Meta's attribution window means an offline conversion reported much later matches poorly. Report POS and call sales daily, not monthly.
  • Reuse the browser distinct id when you have it. If the customer browsed your site first (from the signals_did cookie), pass it as distinct_id so the offline sale joins the same journey and identity stitching connects it to their online behavior.
  • Offline events flow to every configured destination, count in your dashboard and funnels, and dedupe by event_id like any other event.

On this page