Create custom cards with projects (BETA)
Sales Hub
- Enterprise
Service Hub
- Enterprise
Customize your CRM by creating custom cards for CRM records including contacts, companies, deals, tickets, and custom object records. A custom card is a type of UI extension that can display information from external systems, organize HubSpot information, and more. You can position cards in the record's middle pane and the sidebar, and you can customize the content using components.
In the context of HubSpot projects, UI extensions are defined within private apps and are powered by serverless functions. An app must include scopes for the CRM object that a custom card will display on. For example, to display a custom card on a contact record, the app must have crm.objects.contacts.read
and crm.objects.contacts.write
scopes.
Below, learn how to set up a custom card and configure its options, such as components and actions.
To view example projects that contain fully built custom cards, check out HubSpot's example extension library on GitHub.
To get started, you can follow the quickstart guide to create a custom card that retrieves and displays data from an external API on button click.
If you followed the guides to create a project and private app from scratch, start creating a custom card by adding the following to the project's app
folder.
- An
custom-card.json
file, which configures the card, including which types of CRM records it will display on. - A
serverless
folder which will contain serverless function files. Within this folder, create the following files:
package.json
: contains metadata about the serverless function.serverless.json
: the serverless function config file.custom-card.js
: contains the code that the serverless function runs.
Below, learn more about each file along with example code to add to each.
type string
The type of UI extension. For CRM cards, use |
data object
Defines the custom card and its functionalities. Includes the following fields: |
⮑title string
The name that displays in the card on CRM records. |
⮑location string
Where the card appears on the CRM record.
|
⮑fetch string
Defines the data that gets fetched. Contains |
⮑targetFunction string
Defines an optional target app function to fetch data. This function will be contained in the |
⮑objectTypes array
Defines which object types will display the card, along with the HubSpot properties to send to the serverless function. |
⮑name string
The name of the object. For custom objects, use |
⮑propertiesToSend array
The properties to make available to the serverless function. For example, when wanting to display the contact's first name, include |
When configuring a serverless function, note that you need to call the sendResponse
function which takes in an object with two available properties:
sections
: an array that contains component objects. In the Getting Started template, components are defined first with constants, then later inserted into thesections
array. You can also build components within the sections array itself, or use a combination of both.messages
: an object that defines a floating success or error banner. For example, a success alert that appears on successful form submission.
Custom cards can be created for any CRM objects, including standard and HubSpot-defined objects, as well as custom objects. In the card's JSON file, you'll define this within the objectTypes
array.
When building a custom card for custom objects, you'll reference the object with the following format: p_objectName
, where objectName
matches the name
of the custom object (case sensitive). You'll also use this format when referencing custom objects in the property list and table components for cards in the middle pane.
In the custom card's JSON file, you can configure positioning either within the middle pane or right sidebar of a record by setting the location
property. To see an example, follow the quickstart guide to create an extension that displays in the middle pane.
By default, when creating a custom card for the middle pane, it will be added to the Custom tab. However, you can add it to the Overview tab by clicking Customize this tab on a record page.
In addition, when customizing a tab, you can create views based on teams to control which users can view which extensions.
- To display a custom card in the middle pane of the CRM record, set
location
to"crm.record.tab"
. By default, the card will be added to the Custom tab, but you can add it to the Overview tab by clicking Customize this tab on a record page.
- To display a custom card in the right sidebar of the CRM record, set
location
to"crm.record.sidebar"
.
You can display property values from the CRM record by including those properties in the custom card's JSON file and serverless function. Accessing property data through this method does not count against your API call limits, unlike using your private app's access token to retrieve data.
To display property data in standard components:
- In the card's JSON file, add the properties to the
propertiesToSend
array (line 10). - Then, in the serverless function (
crm-card.js
), define aconst
to retrieve those values from thecontext
argument (line 2). - Reference those properties within components in the serverless function's
sections
array (lines 15, 19, 23)
Custom cards in the middle pane can also use the property list and table components to display CRM property data without having to send properties. To do so, reference the properties directly as strings.
You can also use GraphQL to query CRM data through the /collector/graphql
endpoint. Learn more about querying CRM data using GraphQL.
For example, the serverless function on the right uses GraphQL to query the currently displaying CRM record's first name property, then displays it in a text component. Note that the card's JSON config file would also need to include "propertiesToSend": ["hs_object_id"]
.
Please note: to make GraphQL requests, your app must include the following scopes:
collector.graphql_schema.read
collector.graphql_query.execute
Components are the UI elements that make up the content of the custom card, such as forms and tables. Components should be included in the sections
array of your serverless function. Standard components can be used by cards in all locations, while other components can only be used by cards in the middle pane.
You can find a full list of available components in the components reference guide.
When a custom card fails to load, an error message will appear on the CRM record.
- To navigate to the app's CRM card logs, click the link in the error message.
- On the Logs tab, click the error to view more information, including the type of error, the error message, and full log details.

Learn more about debugging serverless functions.
To enable your extension to interact with data, either externally or within HubSpot, you can add actions through components, such as a button or image, with the onClick
property.
Using the UI Extensions Playground, you can view the payload of different actions types by using the Action details tab:
- In your HubSpot account, navigate to CRM Development in the main navigation bar.
- In the left sidebar menu, click UI Extensions Playground.
- In the UI Extensions Playground, click the button component to add it to the middle pane.
- In the right pane, set the type of action. For example,
SERVERLESS_ACTION_HOOK
. - In the middle pane, click the button to trigger the event.
- In the right pane, click the Action details tab to view the action output.
Below, learning more about the available types of actions.
Call a serverless function included in the project. You'll reference the name of the function within the targetFunction
field of the extension's JSON config file. The name of the function should match the function's name within the serverless.json
file as well as the function that gets called in the JavaScript file.
To see an example of a serverless action hook, use the quickstart guide to download and view the Getting Started project template files.
type string (required)
The type of action. For serverless action hooks, use |
serverlessFunction string (required)
The name of the serverless function as declared in the project's |
associatedObjectProperties array
A list of properties on the displayed CRM record. These property values will be included in the serverless function's |
Open a modal dialog within an iframe to display content.
To see an example of using an iframe, check out HubSpot's extension example library on GitHub.
type string(required)The type of action. For iframe hooks, use |
height number (required)
The height of the frame. |
width number (required)
The width of the frame. |
uri string (required)
The URI of the content. |
associatedObjectProperties array
A list of properties on the displayed CRM record. Property values will be appended to the iframe |
Submits a form to the specified serverless function with a form's current state. This action type should only be used with forms. To see an example of a simple form with a submit action, check out HubSpot's extension example library on GitHub.
Using the payload
object, you can retrieve the end user's submitted value. For example, to retrieve the value submitted for an input with a name
of example_select_input
, use payload.formState.example_select_input
.
type string (required)
The type of action. For form submissions, use |
serverlessFunction string (required)
The name of the serverless function to invoke, as declared in the project's |
Events are added to the serverless context when a user's action triggers a serverless function. Events will be included in the serverless functions context
under event
if the serverless function was triggered by a specific user event, similar to web events.
To see an example of a project that uses a form and event, check out HubSpot's extension example library on GitHub.
To use events, you'll first set up a for submit type action within a button component that triggers a serverless function:
Then, in the serverless function you can reference the event within the context
argument. The example below checks for a SUBMIT
event, then creates a task in Asana using the values in the submitted form:
If your extension includes an action that's triggered by user input, such as a button, you can display a notification to indicate whether the action succeeded or failed. After the action completes, you can trigger the notification by providing a message
in a sendResponse
call.
To see examples of success and error banners, check out HubSpot's extension example library on GitHub.
type string (required)
The type of notification banner. Use |
body string (required)
The message displayed within the notification banner. |
For example, if your extension has a button that triggers an API call, you could specify the success and error handling within a separate serverless function (e.g., handle-response.js
), then reference that serverless function within the original JavaScript file (e.g., crm-card.js
)
Thank you for your feedback, it means a lot to us.