Canvas App Sheet: Custom Attributes Not Available Despite Being Set via embed | Community
Skip to main content

Hi everyone 👋

We’re building a Canvas App Sheet for a live Intercom Messenger integration. Our goal is to let logged-in users view and update profile data — specifically values like First Name, Last Name, Primary Chapter, and SpotMe_Id — all of which are being passed into Intercom via a custom embed snippet.

✅ These custom attributes show correctly on the user profile inside Intercom.

🚫 But when the Canvas App loads via /sheet, the contact.custom_attributes payload does not include these fields (we checked with full logging of req.body). We tried accessing them via:

 

js

const contact = req.body.contact || req.body.context?.contact || {}; const attrs = contact.custom_attributes || {};
 

Even though we can see the correct attributes in Intercom, attrs only contains empty/default values like Member, or Global.

We’ve verified:

  • intercomSettings in the embed includes the attributes (they appear in the user profile)

  • We’re using open_mode: "conversation" in our Canvas App button

  • App is launched via a Workflow (and also tried via Messenger)

Here’s a simplified version of how we inject the data via embed:

 

js

window.intercomSettings = { app_id: "APP_ID", email: user.email, name: user.first_name + " " + user.last_name, "First Name": user.first_name, "Last Name": user.last_name, "Primary Chapter": user.chapter, "SpotMe_Id": user.spotme_id, };
 

And inside /sheet we are logging req.body but don’t see those attributes present in the contact object.

Question:

Is there a specific method or configuration needed to ensure custom People attributes are reliably passed into the /sheet payload for Canvas Apps?

Any tips from the Intercom team or community devs would be massively appreciated! 🙏

Thanks in advance!

Hi ​@Karan Sachdeva Paul here from weekend support engineering to help you out 🤝 

The custom attributes don’t appear in the /sheet payload because Canvas Apps get user data from Intercom’s backend sync, not directly from window.intercomSettings. This means newly set attributes may not be available immediately.

To fix this:

  • Use Identity Verification with secure user hashes to ensure real-time, consistent user data syncing.

  • Update user attributes via the Intercom REST API instead of relying only on the embed snippet.

  • Optionally, pass needed data via URL parameters when launching the Canvas App and read them from req.body.context.canvas.url_parameters.

Let me know if you want help with the API or setup!


Hey ​@Paul Byrne  thanks for all the help so far! Quick follow-up question to clarify:

You mentioned that it's possible to pass needed data via URL parameters when launching the Canvas App, and that the Workflow can dynamically build the URL for the Canvas button using those attributes.

In my testing, I couldn't find a way to insert dynamic variables (like {{user.email}}) directly into the Canvas button URL when configuring the button inside the initialize response or within the Workflow step that launches the Canvas App.

Could you confirm:

✅ Is there an official way to dynamically populate the Canvas button URL with user attributes from within a Workflow or Messenger configuration?
✅ If so, can you share where that option exists or how to structure that?
✅ Or is this only possible for External Links in Workflows, but not for launching a Canvas App Sheet?

Appreciate your time clarifying this so I can implement the correct approach! 🙏


Hey ​@Paul Byrne 

I also tried the POST call method and it did not work as well 

✅ I implemented the Data Connector POST to my backend BEFORE the Sheet loads approach.
✅ My backend (Node + Express) stores the incoming payload server-side, and the /sheet endpoint serves the UI based on that stored payload.
✅ This technically works, but, I run into a timing issue:

  • When the user clicks the Canvas App button, the first /sheet call sends the Data Connector payload with People Attributes – I store that.

  • But right after that, Intercom makes a second /sheet POST call (the so-called "ghost call") that doesn't contain the attributes – just component_id etc.

  • Since my backend logic uses the latest payload, the good data gets overwritten with empty/null
    values from the ghost call, so the Sheet ends up showing blank/default values

    I tried ignoring the ghost call with the payload after the initialize and canvas app gets stuck on loading 

Question:
Is there a recommended way to avoid this timing problem? Should I only store the first valid payload and ignore ghost calls? Or is there a better, officially supported pattern to handle this without resorting to URL parameters?

Thanks again for your help – appreciate the guidance so I can get this stable!