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
- Paste the tracking script into the Magento admin so it loads on every page.
- 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.
- 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.
WonClientexists 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 path | No-code path | |
|---|---|---|
| How | A small Magento module | Zapier or Make |
| Attribution | Click ID – exact click, campaign, ad set and ad | Email – matched to a known visitor |
| Effort | A few hours for a Magento developer | An afternoon, no code |
| Best when | You want attribution you can rely on | You 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:
Read the click ID from the cookie
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
| Field | Value from Magento | Notes |
|---|---|---|
type | — | WonClient for a completed order. Exact spelling. |
email | Customer email | Always send it. It's the fallback when there's no click ID. |
click_id | The clickId cookie | Developer path only. Leave the field out when it's empty. |
revenue | Base grand total | A number, in your workspace currency. |
custom_fields.order_id | Increment 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
Place a test order through a tracked link
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
Related articles
Send webhooks to LeadJourney
The endpoint, authentication and every field you can send.
Read and store the click ID
Where the click ID lives and how your server reads it.
E-commerce playbook
The full chain from ad click to repeat order, AOV and LTV.
Install the tracking script
What the snippet is and how to verify it's live.
Connect Shopify
Connect your Shopify store with the LeadJourney app, switch on the tracking embed in your theme, then map orders, refunds and checkouts onto your conversions so every sale is attributed to the ad that drove it.
Connect Typeform
Connect your Typeform account in minutes. Authorize once, LeadJourney registers a webhook on every form, then give each form an lj_click_id URL parameter so submissions are attributed to the ad that drove them.