Integrations

Connect Magento (Adobe Commerce)

There's no Magento app yet, but the setup is two pieces you can do today – paste the tracking script into the Magento admin, then send completed orders to LeadJourney's Conversion API. Includes the CSP whitelist that Magento 2.4.7 needs and both a no-code and a developer path.

LeadJourney doesn't have a native Magento app yet. That doesn't stop you from getting full attribution out of a Magento store – it just means you assemble two pieces yourself, and both are short.

In short

  1. Paste the tracking script into the Magento admin so it loads on every page.
  2. On Magento 2.4.7 and later, allow your tracking domain through the Content Security Policy, or the script is blocked exactly where it matters – on the payment pages.
  3. When an order is placed, send it to LeadJourney's Conversion API with the order value and the customer's email.

Why the order has to come from your server

The tracking script can read the click ID in the browser, but it can't report a purchase: sending a conversion needs your Postback Secret, which must never sit in browser code. So the completed order is reported by Magento, server-side. That's the one part that isn't copy-paste.

Before you start

  • A tracking domain and your tracking script snippet, from Settings → Tracking.
  • Your Webhook URL and Postback Secret, from Settings → Events → Conversion API.
  • A conversion type for completed orders. WonClient exists in every workspace – see Events & the Events Manager.
  • Admin access to Magento, and for the order part either a developer or an automation tool like Zapier or Make.

Step 1: Add the tracking script

Paste it into the design configuration

In the Magento admin, go to Content → Design → Configuration. Pick the scope you want to track and click Edit – choose the Default row to cover the whole store, or a single store view if you only want it there.

Expand HTML Head and paste your LeadJourney snippet into Scripts and Style Sheets. Save.

Flush the cache

Go to System → Cache Management and click Flush Magento Cache. Until you do, the storefront keeps serving the old <head>.

Check that it runs

Open your shop, then the browser console, and run:

await window.lj.getClickId();
window.lj.getTrackingStatus();

You should get a click ID and a status of tracked. Now do the same inside the checkout – that page is where the Content Security Policy bites, and it's the page the next step is about.

Step 2: Let the script through the Content Security Policy

Magento ships a Content Security Policy. From Magento 2.4.7 it runs in restrict mode on the payment pages (report-only everywhere else), which means an external script that isn't on the whitelist simply doesn't execute there. Before 2.4.7 everything is report-only, so the script runs and you only see warnings in the console.

Whitelist your tracking domain in a csp_whitelist.xml inside a module's etc/ folder:

<?xml version="1.0"?>
<csp_whitelist xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Csp:etc/csp_whitelist.xsd">
    <policies>
        <policy id="script-src">
            <values>
                <value id="leadjourney" type="host">https://track.yourdomain.com</value>
            </values>
        </policy>
        <policy id="connect-src">
            <values>
                <value id="leadjourney" type="host">https://track.yourdomain.com</value>
            </values>
        </policy>
    </policies>
</csp_whitelist>

Replace track.yourdomain.com with your own tracking domain. Both entries are needed: script-src lets the script load, connect-src lets it report the visit.

Cookie Restriction Mode

If Stores → Configuration → General → Web → Default Cookie Settings → Cookie Restriction Mode is on, Magento withholds cookies until the shopper consents. The click ID is stored in a cookie, so until consent is given there is nothing for the order to carry. That's a deliberate privacy setting – just know that it caps how many orders can be attributed exactly.

Step 3: Send the order to LeadJourney

Pick the path that matches what you have. They differ in one thing: whether the order carries the click ID.

Developer pathNo-code path
HowA small Magento moduleZapier or Make
AttributionClick ID – exact click, campaign, ad set and adEmail – matched to a known visitor
EffortA few hours for a Magento developerAn afternoon, no code
Best whenYou want attribution you can rely onYou need results this week

Why email works reasonably well for a shop

In e-commerce the purchase usually happens in the same session as the click, and the email is always captured at checkout – so LeadJourney can often match the order to a visitor it already knows. It's a fallback, not a guarantee: an order from an email LeadJourney has never seen lands unattributed. Start no-code if you must, but plan for the module.

The developer path

The convenient part of Magento is that it runs on the same host as the tracking script, so the click ID is already in the request. No checkout customisation, no hidden fields, no theme edits:

The script stores the visitor's click ID in a cookie called clickId, valid for 60 days. Your observer reads it straight from the request:

// via Magento\Framework\Stdlib\CookieManagerInterface
$clickId = $this->cookieManager->getCookie('clickId');

Hook into the order

Observe sales_order_place_after, which fires once the order exists. Build the payload from the order and the cookie:

$payload = [
    'type'     => 'WonClient',
    'email'    => $order->getCustomerEmail(),
    'revenue'  => (float) $order->getBaseGrandTotal(),
    'custom_fields' => ['order_id' => $order->getIncrementId()],
];
if ($clickId) {
    $payload['click_id'] = $clickId;
}

Use getBaseGrandTotal(), not getGrandTotal(): the base total is in your store's base currency, so a shop selling in several currencies doesn't mix them in your reports.

Post it to LeadJourney

Send the payload to your Webhook URL with the Authorization: Bearer <secret> header. Put it in a queue or a cron consumer rather than sending it inline – a slow call must never hold up checkout. Retry on any non-2xx response. The full request format is in Send webhooks to LeadJourney.

Only count paid orders?

sales_order_place_after fires when the order is placed, which for bank transfer or invoice orders is before any money has arrived. If you'd rather count paid orders, hook into your payment or invoice step instead and send the event from there.

The no-code path

Zapier's Magento 2.X app has a New Order trigger, and Make has an Adobe Commerce module. Either one can post to LeadJourney without a line of code:

Connect Magento

Create the integration in System → Extensions → Integrations in the Magento admin, activate it, and use its API credentials in Zapier or Make. Grant it read access to sales data.

Trigger on a new order

Use the New Order trigger. If you only want paid orders, add a filter step on the order's status.

Post to LeadJourney

Add a Webhooks action: POST to your Webhook URL, Content-Type: application/json, header Authorization: Bearer <your Postback Secret>, and a body built from the order:

{
  "type": "WonClient",
  "email": "{{customer_email}}",
  "revenue": 149.00,
  "custom_fields": { "order_id": "{{increment_id}}" }
}

Map revenue to the order's base grand total and email to the customer email.

The secret lives in the automation tool

Zapier and Make store the header for you, which is fine – they're server-side. Don't paste the Postback Secret into anything that runs in a browser, and don't commit it to a repository.

What to send with an order

FieldValue from MagentoNotes
typeWonClient for a completed order. Exact spelling.
emailCustomer emailAlways send it. It's the fallback when there's no click ID.
click_idThe clickId cookieDeveloper path only. Leave the field out when it's empty.
revenueBase grand totalA number, in your workspace currency.
custom_fields.order_idIncrement ID (e.g. 000000123)Lets you tie a LeadJourney conversion back to the order.

order_id is one of the e-commerce custom fields LeadJourney sets up for stores, alongside product_name, product_id, variant and product_category. Send whichever of them you have and your reports can group by them.

Cart and checkout signals are optional

Once orders are flowing you can add AddToCart and InitiateCheckout the same way, from the matching Magento events. They're upper-funnel signals for optimisation and for spotting where the funnel leaks – the headline number stays cost per order. See the E-commerce playbook.

Refunds

When a credit memo is created, send the same conversion again with a negative revenue, so your ROAS corrects itself:

{
  "type": "Refund",
  "email": "[email protected]",
  "revenue": -149.00,
  "custom_fields": { "order_id": "000000123" }
}

Create the Refund event in the Events Manager first.

Testing

Open the shop through a tracked link – a test ad URL or one from the UTM Builder – accept cookies if you use a consent banner, and buy something. A test product at the smallest possible price works.

Check that the event arrived

In Settings → Events, the event's Total goes up and Last Received updates. Open the API Postbacks log to see the exact payload you sent, the status code, and whether it matched a click, an email or a phone number.

Confirm the attribution

Open CRM → Sales, find the order and check that it shows a source. If it's there but unattributed, the event arrived without a usable identifier – see the troubleshooting below.

Troubleshooting

The script works everywhere except the checkout

That's the Content Security Policy in restrict mode on payment pages. Add your tracking domain to csp_whitelist.xml for both script-src and connect-src, deploy, and flush the cache. The browser console names the blocked host.

Orders arrive but aren't attributed

The event reached LeadJourney without anything to match on. Check in order: is the tracking script live on the storefront, does the order carry the clickId cookie value, and is the customer email being sent? On the no-code path there is no click ID by design, so attribution depends on LeadJourney already knowing that email — see Missing leads.

Revenue looks wrong in a multi-currency shop

You're most likely sending getGrandTotal(), which is in the currency the shopper paid in. Switch to getBaseGrandTotal() and send every order in one currency – see Change workspace currency.

No click ID on any order

Either the script isn't running on the storefront, or Cookie Restriction Mode is holding the cookie back until the shopper consents. Check window.lj.getClickId() in the console on a product page after accepting cookies.

Common questions