Markus Michalski FAQ

Facebook Pixel: Technical Details

Facebook Pixel plugin for Sylius: flow, plugin structure, entity, admin wiring and Messenger routing of the CAPI messages.

Deutsche Version

Back to overview

Facebook Pixel: Technical Details

Live Demo: Try this and other plugins live β€” no installation, no risk: demo.markus-michalski.net

Flow

graph TD
    A["Twig hook / add-to-cart event"] --> B["ChannelConfigurationResolver"]
    B --> C{"Event tracked for channel?"}
    C -->|"No"| D["Render nothing"]
    C -->|"Yes"| E["Render fbq script"]
    C -->|"Yes"| F["PixelEventDispatched"]
    F --> G["CapiEventListener"]
    G --> H{"CAPI selected and consent ok?"}
    H -->|"No"| I["Stop"]
    H -->|"Yes"| J["PiiHasher hashes email and phone"]
    J --> K["Messenger: SendCapiEventMessage"]
    K --> L["SendCapiEventHandler"]
    L --> M["ConversionsApiClient"]
    M --> N["Meta Conversions API"]

Both halves of an event, the rendered fbq() call and the dispatched PixelEventDispatched, arise at the same call site and share one event_id generated once (PixelEventIdGenerator). For AddToCart, the server-side copy arises in the listener on sylius.cart_item_post_add, and the browser call is handed to the next page via the session.

The consent check and the hashing run synchronously in the request, because only there are the cookies and customer data available. Every error in this chain is logged and swallowed, so a tracking problem never breaks the page or the add-to-cart action.

Plugin structure

src/
β”œβ”€β”€ Api/                Shop API resource + provider (read-only settings)
β”œβ”€β”€ Capi/               Conversions API payload, client, PII hasher, server event context
β”œβ”€β”€ Command/            SetupCommand (bin/console mmd:facebook-pixel:setup)
β”œβ”€β”€ Consent/            CapiConsentPolicy + CapiConsentEvidenceProviderInterface, Klaro cookie reader
β”œβ”€β”€ Customer/           Resolves the logged-in customer's email for CAPI matching
β”œβ”€β”€ Entity/             ChannelConfiguration (one row per Sylius channel)
β”œβ”€β”€ Event/              PixelEventDispatched
β”œβ”€β”€ EventListener/      AddToCartListener, CapiEventListener, ProvisionKlaroServiceListener
β”œβ”€β”€ Form/Type/          Admin form (ChannelConfigurationFormType)
β”œβ”€β”€ Klaro/              Runtime detection of Klaro, consent gate, catalog creation
β”œβ”€β”€ Menu/               Admin sidebar entry (group MMKreativ Plugins)
β”œβ”€β”€ Messenger/          SendCapiEventMessage + its handler
β”œβ”€β”€ Migrations/         Four Doctrine migrations (see Installation)
β”œβ”€β”€ Model/              FacebookPixelEvent enum, PendingAddToCartFlash
β”œβ”€β”€ Renderer/           Builds the fbq() script markup
β”œβ”€β”€ Repository/         ChannelConfigurationRepository
β”œβ”€β”€ Resolver/           ChannelConfigurationResolver (channel to settings row)
β”œβ”€β”€ Security/           CapiAccessTokenCipher (libsodium secretbox)
β”œβ”€β”€ Service/            PixelEventIdGenerator
└── Twig/               FacebookPixelTwigExtension (the functions the hooks call)

Entity

ChannelConfiguration (table mmd_sylius_facebook_pixel_channel_configuration), one row per channel (unique on channel_id):

Column Type Notes
channel_id int, unique FK ON DELETE CASCADE
enabled bool Master switch, default off
pixel_id string(32), nullable Digits only, checked by form validation
track_page_view ... track_purchase bool One column per browser event, default on
track_gross_prices bool Default on
use_klaro_consent bool, default true Klaro gating box
capi_enabled bool Default off
capi_require_consent_evidence bool, default true Fail-closed consent requirement
capi_access_token_ciphertext text, nullable Encrypted, never plaintext
capi_test_event_code string(255), nullable
capi_event_selection json List of FacebookPixelEvent values sent via CAPI, default empty

Admin

Resource Route alias Grid
Channel settings mmd_sylius_facebook_pixel_plugin.channel_configuration mmd_sylius_facebook_pixel_plugin_admin_channel_configuration (Channel, Pixel ID, Tracking enabled, Conversions API enabled)

The page is reachable in the admin under MMKreativ Plugins > Facebook Pixel (icon tabler:brand-meta) and lives under the path /<admin-path>/facebook-pixel-channel-configurations. If the admin route import is missing, only the menu entry is missing; the other admin pages are not affected.

Messaging

SendCapiEventMessage is routed to the main Messenger transport that Sylius itself uses for asynchronous work. No transport of its own is needed, but a running worker is (bin/console messenger:consume), otherwise the messages stay in the queue.

The message carries the channel code, event name, event ID, timestamp, source URL, event data, IP address, user agent, the _fbc/_fbp cookie values and the already hashed email and phone number. It contains no plaintext email or phone number, and there is no snapshot of the settings: the handler reads the current ChannelConfiguration and the token only at delivery, so a setting changed in the meantime (or CAPI switched off) is respected.

The call to Meta is an HTTP POST to the Graph API (https://graph.facebook.com, version v21.0) with a 5-second timeout. Only HTTP 200 counts as success; anything else is logged without a retry.