Skip to content
HubSpot Solution Blueprint

Canvas Kit Custom App: Capturing Level of Effort Without Leaving Intercom

Hero featured image

Support leads wanted a number that did not exist anywhere: minutes of effort per case. Intercom's Inbox has no field for it, and Canvas Kit, the framework for adding one, cannot store data locally. So the field had to be built, hosted outside the platform, and made to write somewhere else entirely. We designed a Canvas Kit app that lives in the Inbox, holds nothing, and pushes Level of Effort straight to the Salesforce case.

Executive Summary

context-header-icon

Context

A UI framework with no persistence layer changes what a custom field means. The app cannot remember what an agent typed, so every submission has to resolve its own destination at the moment it is submitted. That turns a simple input box into a question about identity: which case does this belong to, and what happens if that case does not exist yet.

what-we-built-header-icon

What We Built

A specified Canvas Kit app injected into the Intercom Inbox, hosted externally and using initialize and submit webhook flows. On submit it pushes the Level of Effort value one way to Salesforce, matched to the correct Case by Conversation ID, creating the case if the scheduled sync has not produced one yet. Agents never leave Intercom.

tech-stack-header-icon

Tech Stack

  • Intercom Canvas Kit
  • initialize/submit webhooks
  • Node.js
  • Salesforce Service Cloud
  • Case object
  • custom Task
  • Connected App

Platforms where you can add a custom field natively. This is a design for the case where the UI framework offers no persistence and the value has to land in another system.

the-challenge-header-icon

The Challenge

Support leads needed Level of Effort recorded per case, in minutes, by the agent who did the work. Intercom's Inbox had no native field for it, so the only route was a custom app.

Canvas Kit offers no local data persistence. A Canvas Kit app renders, accepts input, and forgets. Anything an agent types has to leave the platform in the same request or it is gone, which rules out the usual pattern of collecting a value and syncing it later.

Agents were the constraint on the interface. Any design that sent them to Salesforce to log minutes would not be used, so the input had to sit inside the Inbox they already work in.

The destination case might not exist yet. Effort gets logged during a live conversation, and the scheduled sync runs on its own 30-minute cycle, so the app can be asked to write to a case that has not been created.

our-approach-header-icon

Our Approach

The app was designed stateless on purpose, because the framework left no alternative. It uses the initialize webhook to render inside the Inbox and the submit webhook to act. There is no intermediate store, so a submitted value either reaches Salesforce or fails visibly.

On submit, Level of Effort is pushed one way to Salesforce. We considered holding it in Intercom and syncing it later and rejected that: Intercom has nowhere to hold it, and a second copy would introduce a reconciliation problem between two systems that already disagree about what a case is.

Conversation ID matches the submission to its case, the same key the scheduled integration uses. When no case exists yet, the app creates one rather than failing or queuing, so a live agent is never blocked by a batch that has not run.

Each submission lands as a Case-linked Task with its type stamped and the recorded time attached, which keeps effort reportable against the case without widening the Case object itself.

One requirement stayed open. Auto-closing a case on session timeout or agent logout has no native Intercom event behind it, and the design records it as needing further investigation rather than claiming a solution.

impact-header-icon

Impact

check-icon

Effort captured where the work happens

Agents record minutes in the Intercom Inbox they already have open. No second system, no context switch, which is the difference between a field that gets filled and one that does not.

check-icon

A reportable number that did not exist

Level of Effort becomes a Case-linked Task in Salesforce with time attached, so support effort can be reported per case rather than estimated.

check-icon

No dependency on the sync schedule

Because the app creates the case when one is missing, a live agent can log effort during a conversation the 30-minute batch has not reached yet.

check-icon

Bot volume stays honest

Bot-only cases carry an effort value of zero, and agents cannot edit it. Automated handling never inflates the human effort numbers.

Technical Blueprint
1

Canvas Kit cannot persist, so there is no collect-then-sync option. The submit handler has to be the whole transaction, which simplifies the design and removes an entire class of drift between two copies of the same value.

2

The value only exists if a human enters it, so the interface decision is the data-quality decision. Injecting the input into the Inbox is what makes the metric real rather than aspirational.

3

The custom app and the scheduled pipeline both resolve a case by Conversation ID. One key across two independent paths is why they can write to the same record without coordinating.

4

When the case may not exist yet, creating it on submit beats retrying later. The agent's action completes, and the batch finds the same record on its next pass.

Intercom Canvas Kit app capturing agent Level of Effort and pushing it to a Salesforce Case-linked Task.

A stateless custom-app architecture for capturing Level of Effort. A Canvas Kit app is injected into the Intercom Inbox, hosted externally, and rendered through the initialize webhook. Canvas Kit holds no local state, so the submit webhook carries the whole transaction: the agent-entered Level of Effort value is pushed one way to Salesforce and matched to its Case by Conversation ID, the same key the scheduled MuleSoft pipeline uses. Where no case exists yet, the app creates one. Each submission lands as a Case-linked Task with type and recorded time. Bot-only conversations carry a non-editable value of zero.

Scope it with us

FAQ

How do you add a custom field to a platform with no data persistence?

You do not store it, you forward it. Intercom's Canvas Kit renders a UI and handles a submit webhook, but it has nowhere to keep what the user typed. So the app treats submission as the entire transaction: the value goes straight to the system of record, in this case a Salesforce Case-linked Task, in the same request. Nothing sits in the middle waiting to be synced, which also means nothing can silently fall out of sync.

What happens if an agent logs effort before the case exists in Salesforce?

The app creates the case. Effort gets logged live, while the scheduled integration runs on its own 30-minute cycle, so the two are guaranteed to disagree sometimes. Rather than queue the submission or show the agent an error, the app resolves the case by Conversation ID and creates one when there is no match. The batch sync then finds that same case on its next pass, because both paths use the same key.

footerCTA footerCTA-mobile
Spice up your inbox
Sign up for our newsletter
Don't worry - we only average, like, two emojis per subject line.