Skip to main content

WhatsApp Tracking & Analytics

Joryio provides comprehensive tracking for WhatsApp messages, including delivery status, opens, clicks, and button interactions. This data feeds real-time analytics.

Overview​

WhatsApp tracking enables you to:

  • Track message delivery - Sent, delivered, read status
  • Monitor engagement - Button clicks, link clicks
  • Analyze campaigns - Attribution of conversions to specific campaigns
  • Trigger workflows - Use inbound WhatsApp messages to trigger Canvas journeys

Events Tracked​

Outbound Message Events​

When you send WhatsApp messages through campaigns or Canvas, the following events are tracked:

Event NameDescriptionProperties
message.sentMessage was accepted by the WhatsApp APIchannel, messageId, messageType, templateName, to, campaignId, variantId, canvasId, nodeId, wabaId, senderId, contentSource, templateId, decisionId
message.deliveredMessage reached the recipient's devicechannel, messageId, status, recipientPhone, conversationId, campaignId, variantId, canvasId, nodeId, templateName, contentSource, templateId, decisionId
message.openedRecipient read the message. WhatsApp's read receipt is recorded as message.openedchannel, messageId, status, recipientPhone, campaignId, variantId, canvasId, nodeId, templateName, contentSource, templateId, decisionId
message.failedMessage failed to sendchannel, messageId, errorCode, errorMessage, reason, campaignId, variantId, canvasId, nodeId, contentSource, templateId, decisionId
message.clickedUser clicked a button in the messagechannel, campaignId, variantId, canvasId, clickType, buttonId, buttonTitle, replyToMessageId, contentSource, templateId, decisionId
These are the same event names every channel uses - there is no whatsapp.-prefixed outbound event. WhatsApp rows are identified by the channel property, which is whatsapp on all five, so a WhatsApp-only report is message.sent filtered on channel = whatsapp.

Every row of the table also carries the send identity: contentSource (template, campaign or canvas), templateId when a saved template was used, and decisionId when an AI Decision node, an Experiment node or a personalized-variant model chose the content. The identity is stamped once on message.sent and echoed on the later events, so a delivery or a click joins to the exact content and decision that produced it. The send row also carries the content reference: contentKind (static or dynamic), contentHash (the authored content as the marketer saved it), and for dynamic content contentTrace (which branches, content blocks, recommendation models and generated text the render resolved, as identifiers) and contentKey (the classification key derived from them).

Two behaviours worth knowing:

  • Meta also fires a sent status webhook for a message the sending worker already recorded. That webhook status is skipped, so one send is one message.sent.
  • A status receipt for a message this platform did not send - a reply typed in the WhatsApp Business app, or another tool on the same number - is ignored rather than counted as your delivery.

Inbound Message Events​

When users send messages to your WhatsApp Business Account:

Event NameDescriptionProperties
whatsapp.message.receivedInbound message receivedchannel, messageType, type, content, contentType, contentText, profile, phoneNumber, messageId, wabaId, accountName, toNumber, replyToMessageId

This one is WhatsApp-specific: it is the event an inbound WhatsApp trigger listens for, alongside sms.message.received and viber.message.received.

Button Click Tracking​

When users click buttons in your WhatsApp template messages, Joryio automatically:

  1. Associates clicks with campaigns - Links the button click to the original outbound message
  2. Records the event - Records message.clicked event with full context
  3. Updates campaign analytics - Increments click counts for campaign reporting

How It Works​

1. You send a WhatsApp template with buttons
2. We store the message with campaign attribution (whatsapp_messages table)
3. User clicks a button → WhatsApp sends webhook
4. We look up the original message to get campaign context
5. We track message.clicked event with campaignId, variantId, buttonId

Tracked Button Data​

  • buttonId - The button payload/ID
  • buttonTitle - The button text
  • campaignId - Associated campaign
  • variantId - A/B test variant (if applicable)
  • messageId - WhatsApp message ID

WhatsApp link tracking uses the dynamic URL suffix on a template's URL button - the one per-recipient URL slot Meta sanctions. Joryio fills that suffix with a signed token pointing at your tracking domain; the tap is logged and then redirected to the real destination. Because the button's base URL is part of the approved template, nothing about the message is rewritten at send time - the template stays valid.

Setup​

1. Configure your tracking domain. Set it once under Settings → Tracking domain (e.g. track.yourbrand.com). See Tracking domain.

2. Author the Meta template with a tracking-domain URL button. Give the button a dynamic URL whose base is your tracking domain:

Button URL: https://track.yourbrand.com/wa/{{1}}

Submit the template for approval as usual. Meta approves it with your tracking domain - the {{1}} dynamic suffix is the sanctioned varying part.

3. Map the destination in the campaign. When you pick the template in the campaign composer, any URL button with a dynamic suffix shows a Button link field - marked tracked when its base is a …/wa/{{1}} tracking URL. Enter the real destination, either a fixed URL or a Liquid expression:

{{ user.custom.offerUrl }}

That's it - no code. At send, Joryio:

  1. Resolves the destination per recipient (Liquid, catalog feeds and content blocks all work).
  2. Mints a signed tracking token carrying the destination plus attribution (campaign or journey, variant, user).
  3. Sends the token as the dynamic suffix, so the recipient receives https://track.yourbrand.com/wa/<token>.

Tracking Flow​

1. Template button (approved): https://track.yourbrand.com/wa/{{1}}
2. Send: suffix ← signed token { destination, org, user, campaign/canvas, variant }
3. Recipient taps → GET /wa/:token on your tracking domain
4. Token verified (HMAC) → message.clicked logged (channel = whatsapp) → 302 to the destination

The token is HMAC-signed, so a tampered or forged suffix is rejected, and the destination travels inside the token - no database lookup is needed to attribute the click.

Buttons that aren't on your tracking domain

A URL button whose base is not your tracking domain (for example https://shop.com/{{1}}) is treated as an ordinary Meta dynamic suffix: the value you map is sent as-is and the click is not wrapped. Only tracking-domain buttons become tracked links - Joryio never rewrites a URL Meta didn't approve.

WhatsApp Message Triggers for Canvas​

You can use inbound WhatsApp messages as triggers for Canvas workflows.

Configuration​

When creating a Canvas, select "WhatsApp Message" as the entry trigger type.

Trigger Options​

OptionDescription
WhatsApp AccountSpecific WABA to listen to (or all accounts)
Message TypesFilter by message type (text, image, button_reply, etc.)
ConditionsContent-based conditions (text contains, equals, regex)

Condition Types​

PropertyDescriptionExample
content.textMessage text contentContains "support"
messageTypeType of messageEquals "button_reply"
phoneNumberSender's phone numberStarts with "+1"

Operators​

  • equals - Exact match
  • not equals - Not exact match
  • contains - Text contains value
  • starts with - Text starts with value
  • ends with - Text ends with value
  • matches regex - Regular expression match

Template Variables in Canvas​

When a WhatsApp message triggers a canvas, you can use these variables in subsequent nodes:

{{ trigger.messageType }} # 'text', 'image', 'button_reply', etc.
{{ trigger.content.text }} # Message text content
{{ trigger.content.type }} # Content type
{{ trigger.phoneNumber }} # Sender's phone number
{{ trigger.messageId }} # WhatsApp message ID
{{ trigger.timestamp }} # When message was received
{{ trigger.wabaId }} # WhatsApp Business Account ID
{{ trigger.context }} # Reply context (if replying to a message)

Example: Support Bot Canvas​

Entry Trigger: WhatsApp Message
- Message Type: text
- Condition: content.text contains "help" OR "support"

Flow:
→ Send WhatsApp Reply: "Hi {{ user.firstName }}, how can we help?"
→ Behavior Split: Wait for response (24h)
→ Responded: Route to support agent
→ No response: Send follow-up message

Analytics Dashboard​

View WhatsApp analytics in:

  1. Campaign Analytics - Per-campaign metrics

    • Messages sent, delivered, read
    • Button click rates
    • Conversion rates
  2. Canvas Analytics - Journey-level metrics

    • Users triggered by WhatsApp
    • Path completion rates
    • Response rates
  3. Event export / custom analytics - Build your own reporting

    • Browse the raw events (message.sent, message.delivered, message.opened, message.clicked, filtered on channel = whatsapp) in the Event Explorer
    • Export events via the API to power custom dashboards

Best Practices​

1. Use Templates with Buttons​

  • Buttons have higher engagement than plain text
  • Button clicks are automatically tracked
  • Use meaningful button text for better analytics
  • Wrap URLs in your tracking domain
  • Get full attribution for external link clicks
  • Measure true conversion rates

3. Set Up Canvas Triggers​

  • Automate responses to common inquiries
  • Route users to appropriate flows based on message content
  • Use regex patterns for flexible matching

4. Monitor Delivery Rates​

  • Track delivered vs sent ratio. Each receipt is counted once, however many times the provider redelivers the webhook, so the ratio cannot climb past 100%
  • Note the failure rate is failures over attempted (sent + failed): a send WhatsApp rejects outright never emits a sent to divide by
  • Identify phone number quality issues
  • Monitor for failed messages

5. Analyze Response Patterns​

  • Track time between message sent and user action
  • Identify optimal send times
  • Measure 24-hour session utilization

Troubleshooting​

Button Clicks Not Tracking​

  1. Check webhook configuration - Ensure WhatsApp webhooks are properly configured
  2. Verify message storage - Original message must exist in whatsapp_messages table
  3. Check campaign attribution - Message must have campaignId for full tracking

Inbound Messages Not Triggering Canvas​

  1. Verify canvas is active - Canvas must be in "active" status
  2. Check trigger conditions - Ensure message matches configured conditions
  3. Verify WABA connection - Account must be active and connected

Missing Analytics Data​

  1. Check the Event Explorer - Confirm WhatsApp events are still arriving; if events have stopped entirely, contact support
  2. Verify event emission - Check backend logs for event tracking
  3. Check time range - Analytics have a processing delay