Link API-triggered Canvas requests to Currents messaging events
Trace an API-triggered Canvas request through to its messaging outcomes by passing a correlation ID as a Canvas entry property, stamping it onto the send event with
message_extras, and joining engagement events ondispatch_idanduser_id.
About this example
Pyrite Financial, a fictional financial services brand, triggers a Canvas from its own systems each time a consumer transaction needs an alert. It calls /canvas/trigger/send per event. Its analytics team wants to know which trigger request produced which send, delivery, and click in Currents or Snowflake Data Sharing. Both include the same messaging event data.
Messaging events in Currents and Snowflake Data Sharing do not carry your trigger request identifier on their own. This example shows how to:
- Generate a correlation ID in your sending system and pass it as a Canvas entry property on the trigger request.
- Reference that property in the message body with the
message_extrasLiquid tag, which writes it to themessage_extrasfield on the send event. - Join the send event to delivery and click events on
dispatch_idanduser_id.
Use this when an external system owns the trigger and you need to report on downstream engagement per request. If a campaign rather than a Canvas fits your use case, use a send identifier instead. The send_id field is supported by the campaign messaging endpoints, not by /canvas/trigger/send.
Considerations
dispatch_idalone is not a unique key for Canvas. Braze treats Canvas steps as triggered events, so a step may generate a uniquedispatch_idper user per send, or a shareddispatch_idacross users in the same send. Always pair it withuser_id. For more information, see Dispatch ID behavior.- The
message_extrasfield appears on send events only. Delivery, open, and click events don’t include it, which is why the correlation ID travels through the send event and then joins outward. - Message extras are attached at send time per message, so a Canvas with several Message steps needs the tag in each step you plan to report on.
- All
message_extraskeys and values together must stay under 1,000 bytes (1 KB), and Braze truncates longer values. Whitespace counts toward the limit. - The resulting JSON contains string values only. Use a Liquid variable as a key or value. Don’t nest other Liquid tags inside
message_extras. - Currents events store the Braze user ID in
user_idand your own identifier inexternal_user_id. Join onuser_id, and selectexternal_user_idwhen you need to match rows back to your systems. - Use Currents or Snowflake Data Sharing for this pattern. Both expose the same messaging event fields, including
message_extrason send events. - Currents and Snowflake schemas flag
message_extrasas PII. Use an opaque request ID rather than consumer data. - The
contextobject on a Canvas trigger request can be up to 50 KB, shared across all properties you pass.
Setup
Step 1: Generate a correlation ID per request
In your sending system, create an identifier for each trigger request—for example, a UUID—and store it with your own request log. Keep it opaque and short enough to fit the message_extras size limit.
Step 2: Pass the ID as a Canvas entry property
Include the ID in the context object on your /canvas/trigger/send request. Set it per recipient when each user has a distinct ID, or at the top level when one ID covers every recipient in the request.
{
"canvas_id": "canvas_identifier",
"recipients": [
{
"external_user_id": "user_identifier",
"context": {
"request_id": "8f14e45f-ceea-467a-9e30-6b1b1c4a7d20"
}
}
]
}
Canvas entry properties are available as context variables throughout the Canvas.
Step 3: Stamp the ID onto the send event
In each Message step you want to report on, assign the context variable and pass it to message_extras.
{% assign request_id = context.${request_id} %}
{% message_extras :key request_id :value {{request_id}} %}
Braze attaches the key-value pair to the message_extras field on the send event at send time.
Step 4: Verify with a test send
Send a test entry through the Canvas, then confirm the send event in Currents or Snowflake Data Sharing contains message_extras with your request_id key. If the field is empty, check the tag syntax. Mistyped delimiters and out-of-order keys and values are the common causes.
Step 5: Join sends to delivery and click events
With the ID on the send event, join outward on dispatch_id and user_id. The following Query Builder example reports delivery and click outcomes per request for email:
WITH sends AS (
SELECT
USER_ID,
EXTERNAL_USER_ID,
DISPATCH_ID,
PARSE_JSON(MESSAGE_EXTRAS):request_id::STRING AS request_id,
TIME AS send_time
FROM USERS_MESSAGES_EMAIL_SEND_SHARED
WHERE MESSAGE_EXTRAS IS NOT NULL
AND PARSE_JSON(MESSAGE_EXTRAS):request_id IS NOT NULL
)
SELECT
s.request_id AS "Request ID",
s.EXTERNAL_USER_ID AS "External User ID",
MIN(s.send_time) AS "Sent",
MIN(d.TIME) AS "Delivered",
MIN(c.TIME) AS "First Click"
FROM sends AS s
LEFT JOIN USERS_MESSAGES_EMAIL_DELIVERY_SHARED AS d
ON d.USER_ID = s.USER_ID
AND d.DISPATCH_ID = s.DISPATCH_ID
LEFT JOIN USERS_MESSAGES_EMAIL_CLICK_SHARED AS c
ON c.USER_ID = s.USER_ID
AND c.DISPATCH_ID = s.DISPATCH_ID
GROUP BY 1, 2
ORDER BY 3 DESC;
Swap in the tables for the channel you send on—for example, USERS_MESSAGES_PUSHNOTIFICATION_SEND_SHARED and USERS_MESSAGES_PUSHNOTIFICATION_OPEN_SHARED for push. For the full column list per table, see the SQL table reference.
The Query Builder example is one path. Apply the same joins in Snowflake Data Sharing or on Currents exports to your own warehouse: parse message_extras on the send event, then join engagement events on dispatch_id and user_id.