UTM Tracking for MoEngage: How to Build and Validate Campaign Links

MoEngage is a multi-channel customer engagement platform covering push notifications (web and mobile), email, in-app messages, SMS, and WhatsApp. UTM tracking for MoEngage requires manually adding utm_source=moengage to every campaign URL — MoEngage does not auto-append UTM parameters to campaign links by default. The correct utm_medium depends on the channel: push for mobile and web push notifications, email for email campaigns, sms for SMS, in-app for in-app message CTAs that open external URLs, and whatsapp for WhatsApp campaigns. Push notifications and SMS have no HTTP referrer — without UTM parameters, GA4 classifies taps and clicks as Direct traffic. Build tracked MoEngage URLs with mlz build --source "moengage" --medium "push" (or the appropriate medium) before entering them in the MoEngage campaign builder, and run --validate to confirm the destination URL resolves correctly before launching.

Terminal showing mlz build command with utm_source=moengage and utm_medium=push, four channel cards showing the correct utm_medium for push, email, SMS, and in-app, a utm_source=moengage card, a red failure panel showing that without UTM parameters MoEngage push traffic appears as Direct in GA4, and a validated URL pill at the bottom.

Why MoEngage requires per-channel UTM tracking

MoEngage's strength is cross-channel orchestration — a single campaign flow can touch a user via push notification, follow up with an email, and then show an in-app message if the user opens the app. But this multi-channel architecture creates a UTM tracking challenge: if you use the same tracked URL across all channels in a Flow, GA4 cannot distinguish whether a session was driven by the push notification, the email, or the in-app message. The utm_medium parameter is what makes this distinction possible.

Push notifications are the highest-risk channel from an attribution perspective. When a user taps an MoEngage push notification, the device opens the campaign URL with no HTTP referrer header. GA4 classifies sessions with no referrer as Direct traffic — your push channel contribution disappears into the Direct baseline. Email traffic is less vulnerable (email clients often pass referrer headers), but UTM parameters on email links still give you explicit attribution that is more reliable than referrer-based inference. SMS links have no referrer at all — they behave exactly like push notifications from a GA4 attribution standpoint.

The only reliable solution for all channels is explicit UTM tagging: build a separate tracked URL for each channel within a Flow, using utm_medium to identify the delivery channel and a consistent utm_campaign slug to group all touchpoints from the same campaign or Journey together in GA4 reports.

MoEngage channel Referrer passed? Without UTM Recommended utm_medium
Mobile push (iOS / Android) No Direct in GA4 push
Web push notification No Direct in GA4 push
Email campaign Often yes Usually Email in GA4 email
SMS campaign No Direct in GA4 sms
In-app message (opens browser) No Direct in GA4 in-app
WhatsApp campaign No Direct in GA4 whatsapp

Building tracked MoEngage campaign URLs with mlz build

MoEngage's campaign builders have a URL field for the redirect destination — in push notifications this is the "Redirect URL" or "CTA URL," in email it is any hyperlink, in in-app messages it is the button action URL, and in SMS it is the message link. Build your tracked URL with mlz build before opening the MoEngage campaign builder, then paste the tracked_url into the appropriate URL field for each channel. Use a separate mlz build call per channel step — changing only the --medium flag while keeping the same --campaign slug.

mlz build — MoEngage multi-channel Flow
# Push notification step in a MoEngage Flow
$ mlz build \
  --url "https://app.example.com/summer-sale" \
  --source "moengage" \
  --medium "push" \
  --campaign "summer-sale-jun-2026" \
  --validate

{
  "tracked_url": "https://app.example.com/summer-sale?utm_source=moengage&utm_medium=push&utm_campaign=summer-sale-jun-2026",
  "params": {
    "utm_source": "moengage",
    "utm_medium": "push",
    "utm_campaign": "summer-sale-jun-2026"
  },
  "stored": true
}

# Email step in the same MoEngage Flow (same campaign, different medium)
$ mlz build \
  --url "https://app.example.com/summer-sale" \
  --source "moengage" \
  --medium "email" \
  --campaign "summer-sale-jun-2026" \
  --validate

{
  "tracked_url": "https://app.example.com/summer-sale?utm_source=moengage&utm_medium=email&utm_campaign=summer-sale-jun-2026"
}

# SMS step: same campaign slug, utm_medium=sms
$ mlz build \
  --url "https://app.example.com/summer-sale" \
  --source "moengage" \
  --medium "sms" \
  --campaign "summer-sale-jun-2026" \
  --validate

{
  "tracked_url": "https://app.example.com/summer-sale?utm_source=moengage&utm_medium=sms&utm_campaign=summer-sale-jun-2026"
}

In GA4, filter by utm_campaign=summer-sale-jun-2026 to see all sessions from this MoEngage campaign, then pivot on the utm_medium dimension to compare push, email, and SMS contributions side by side. The consistent utm_campaign slug groups all touchpoints from the same campaign, while distinct utm_medium values separate them by channel — giving you a complete multi-channel attribution picture without requiring any GA4 custom dimensions.

UTM tracking for MoEngage Flows (multi-step automation)

MoEngage Flows are multi-step automated campaigns that can include push notifications, emails, in-app messages, and SMS in a single orchestrated sequence — triggered by user behavior events such as app install, cart abandonment, or inactivity. When building a Flow, every step that links to an external URL needs its own tracked URL. Use a consistent utm_campaign slug across all steps in the Flow, and set utm_medium to match the channel for each step. Use utm_content to identify the specific step number or step name within the Flow.

mlz build — MoEngage abandoned cart Flow steps
# Step 1: Push notification (1 hour after cart abandonment)
$ mlz build \
  --url "https://store.example.com/cart" \
  --source "moengage" \
  --medium "push" \
  --campaign "abandoned-cart-flow" \
  --content "push-step-1" \
  --validate

{
  "tracked_url": "https://store.example.com/cart?utm_source=moengage&utm_medium=push&utm_campaign=abandoned-cart-flow&utm_content=push-step-1"
}

# Step 2: Email (24 hours after abandonment)
$ mlz build \
  --url "https://store.example.com/cart" \
  --source "moengage" \
  --medium "email" \
  --campaign "abandoned-cart-flow" \
  --content "email-step-2" \
  --validate

{
  "tracked_url": "https://store.example.com/cart?utm_source=moengage&utm_medium=email&utm_campaign=abandoned-cart-flow&utm_content=email-step-2"
}

# Step 3: SMS (48 hours after abandonment)
$ mlz build \
  --url "https://store.example.com/cart" \
  --source "moengage" \
  --medium "sms" \
  --campaign "abandoned-cart-flow" \
  --content "sms-step-3" \
  --validate

{
  "tracked_url": "https://store.example.com/cart?utm_source=moengage&utm_medium=sms&utm_campaign=abandoned-cart-flow&utm_content=sms-step-3"
}

With this tagging structure, GA4's campaign report for utm_campaign=abandoned-cart-flow shows the total sessions, cart recoveries, and revenue generated by the entire Flow. The utm_medium dimension breaks down which channel drove each recovery, and utm_content shows which specific step in the Flow was the last touchpoint before the conversion. This is the minimum viable UTM structure for understanding a multi-step automated campaign — anything less makes it impossible to know which step is doing the work.

MoEngage UTM tracking gotchas

MoEngage does not auto-append UTM parameters to campaign URLs by default
MoEngage does not have a global setting that automatically appends UTM parameters to all campaign URLs. Every campaign step, every push notification's Redirect URL, every email hyperlink, and every SMS message link requires a manually tagged URL. Some MoEngage customers configure custom URL parameters at the campaign level in MoEngage's settings, but these are custom parameters — not standard UTM parameters — and GA4 does not read custom parameters as channel attribution without additional configuration. Build tracked URLs with mlz build before entering them in MoEngage to ensure standard UTM parameters are present on every campaign URL.
Using a single tracked URL across all channels in a Flow merges attribution
A common shortcut is to build one tracked URL with utm_source=moengage&utm_medium=push and reuse it for all steps in a Flow. This is wrong for any step that is not a push notification — email clicks, SMS clicks, and in-app message CTAs with the same URL will all be attributed to the push channel in GA4. Build a separate tracked URL per channel step, differing only in the utm_medium value. The extra build commands take less than a minute and give you channel-level attribution that is accurate, not just approximate.
MoEngage SMS uses link shortening — UTM parameters must be added before shortening
MoEngage SMS campaigns can use MoEngage's built-in link shortening feature. If you add UTM parameters to the URL after it has been shortened by MoEngage, the parameters are appended to the short URL — but the redirect chain may or may not preserve them depending on how the short link resolver handles query strings. The safe approach is to build the fully tagged URL with mlz build first, then paste the tagged URL into the MoEngage SMS campaign builder before MoEngage applies any shortening. MoEngage shortens the fully tagged URL as a unit, and the redirect from the short link to the destination URL typically preserves query string parameters. Use mlz build --validate to confirm the destination resolves and the redirect chain is clean before the SMS campaign sends.
MoEngage in-app message CTAs that open external URLs need separate tracking from in-app screen navigation
MoEngage in-app messages can have CTA buttons that either navigate within the app (in-app routing to a specific screen) or open an external browser URL. UTM parameters are only relevant for external browser URLs — in-app routing does not load a web URL and GA4 never sees the navigation event in the standard configuration. For in-app message CTAs that open external URLs (common for promotional in-app messages, feature announcements, or campaign landing pages), build a tracked URL with utm_medium=in-app and enter it as the button action URL. For buttons that use in-app routing, no UTM tagging is needed or possible.
MoEngage WhatsApp campaigns may have shorter URL character limits
WhatsApp message templates have character limits, and adding UTM parameters to campaign URLs in WhatsApp messages increases URL length. For WhatsApp campaigns where URL length is a concern, use utm_source=moengage&utm_medium=whatsapp&utm_campaign=slug and keep the campaign slug concise — avoid utm_content and utm_term in WhatsApp URLs unless the character budget allows. If the fully tagged URL is too long for the WhatsApp template, use a URL shortener on the tagged URL (not on the bare URL) so the short link resolves to the tagged destination. Validate the short URL with mlz build --validate to confirm the redirect chain preserves UTM parameters.

MoEngage UTM naming conventions

Recommended UTM parameter values for MoEngage, aligned with GA4 channel reporting and a lowercase-hyphenated taxonomy:

  • utm_source: moengage for all sends from the MoEngage platform across all channels. Always lowercase. Using a single source value for all MoEngage channels makes it easy to filter the GA4 acquisition report to see all MoEngage-attributed traffic regardless of channel.
  • utm_medium: Match the delivery channel — push for mobile and web push notifications; email for email campaigns; sms for SMS; in-app for in-app message CTAs that open external browser URLs; whatsapp for WhatsApp campaigns. Add a GA4 custom channel grouping rule (Admin > Data Display > Channel Groups) to classify utm_medium=push under a Push channel, as GA4 does not include Push in its default channel grouping. Similarly add rules for utm_medium=in-app and utm_medium=whatsapp if you want dedicated channel rows in GA4 reports.
  • utm_campaign: A consistent slug per campaign or Flow. For one-off campaigns: summer-sale-jun-2026, new-feature-launch-jun, weekly-digest-jun-7. For automated Flows: abandoned-cart-flow, onboarding-flow-day1, reengagement-flow-30d, win-back-flow-60d. Use the same campaign slug across all channel steps in a Flow so GA4 groups them together.
  • utm_content: Flow step identifier or A/B variant label. For multi-step Flows: push-step-1, email-step-2, sms-step-3. For A/B tests: variant-a, variant-b. For in-app message CTA buttons: primary-cta, secondary-cta. Omit when a campaign has a single CTA, single step, and no variants.
  • utm_term: Rarely used for MoEngage campaigns. Consider for audience segmentation where the same campaign copy is sent to different behavioral segments with different destination experiences: utm_term=high-value-users, utm_term=lapsed-30d.

See the UTM naming conventions guide for the full cross-platform reference and the UTM tracking for developers guide for programmatic generation and validation at scale.

FAQ

Does MoEngage auto-tag campaign URLs with UTM parameters?
No. MoEngage does not have a global auto-UTM setting that appends standard UTM parameters to all campaign links. MoEngage tracks campaign performance in its own analytics dashboard (delivered, clicked, conversion events) using MoEngage's internal tracking parameters — but these are not standard UTM parameters and GA4 cannot read them for session attribution. To correctly attribute MoEngage-driven sessions in GA4, you must manually add standard UTM parameters to every campaign URL before entering it in MoEngage's campaign builders.
What utm_source should I use for MoEngage?
Use utm_source=moengage for all campaigns sent through the MoEngage platform. Use a consistent single source value across all MoEngage channels (push, email, SMS, in-app, WhatsApp) rather than channel-specific source values like utm_source=moengage-push — the channel distinction belongs in utm_medium, not in utm_source. A single source value makes it easy to filter GA4 to see all MoEngage-attributed traffic in one view, then pivot on utm_medium to compare channel performance.
How do I track MoEngage Flows (automated sequences) in GA4?
Use a consistent utm_campaign slug for all steps in the Flow, match utm_medium to the channel for each step, and use utm_content to identify each step (e.g., push-step-1, email-step-2). In GA4, filter by the utm_campaign slug to see all sessions from the Flow, then pivot on utm_medium to compare channel contributions and on utm_content to compare step-level performance. This gives you a complete multi-touch picture of which Flow step and which channel drove conversions without requiring GA4 custom reports or custom dimensions.
MoEngage offers MoEngage Analytics — do I still need UTM parameters for GA4?
Yes. MoEngage Analytics tracks MoEngage-specific events: notification delivery, notification click, in-app impression, email open, email click, and custom conversion events you define within MoEngage. It does not push session or channel data into GA4's acquisition reports. GA4's channel attribution is based on UTM parameters (and referrer headers where present) — it has no visibility into MoEngage's internal event data. If you want GA4's acquisition, user, and conversion reports to correctly attribute MoEngage-driven sessions, UTM parameters on every campaign URL are required, regardless of what MoEngage Analytics reports in its own dashboard.
How do I validate MoEngage campaign URLs before launching?
Run mlz build --url "your-destination-url" --source "moengage" --medium "push" --campaign "your-campaign-slug" --validate for each campaign URL before entering it in MoEngage. The --validate flag confirms HTTPS, resolution (200 response), redirect chain integrity, and query string preservation through any redirects. For landing pages that will also be shared on social or in other channels, run mlz inspect "your-tracked-url" to verify OG tags, Twitter Card metadata, and viewport configuration — a landing page built for a push campaign that is missing OG tags will render poorly if shared on social or linked from email. See the campaign link preflight check guide for the full pre-launch validation workflow.

Build MoEngage campaign links from the terminal

Use mlz build --source "moengage" --medium "push" (or the channel-appropriate medium) to generate tracked URLs for every MoEngage campaign before entering them in the campaign builder. Build a separate URL per channel within each MoEngage Flow — using the same --campaign slug but a different --medium for each step. Add --content "push-step-1", --content "email-step-2", etc. to identify individual steps in GA4 reports. Add --validate to confirm each destination URL resolves correctly before the campaign launches. MoEngage campaigns that go out without UTM parameters will appear as Direct traffic in GA4 with no retroactive fix available.

npm install -g missinglinkz

Free plan: 1,000 links/month. No credit card. See the UTM tracking for developers guide for the full programmatic workflow including API and MCP integration.