Create UI extensions with React (BETA)

  • Sales Hub
    • Enterprise
  • Service Hub
    • Enterprise

After creating a project and a private app within it, you can create a UI extension to customize your HubSpot CRM UI. In this guide, you'll learn how UI extensions work and how to build them.

To learn more about configuring UI extensions, check out the UI extensions SDK reference.

You can also follow the quickstart guide to build and deploy an example UI extension to your account. Or, check out HubSpot's other sample projects.


  • This guide assumes that you're familiar with the general steps to set up your local environment with the CLI and configure a development sandbox, if needed. If you haven't done so, check out the projects setup guide before proceeding.
  • Before getting started, check out the UI extensions overview for general information, best practices, and limitations.
  • You should also ensure you've updated to the latest version of the CLI by running npm install -g @hubspot/cli@next.
  • This guide assumes that you've already created a project and a private app within it.

Set up extension files

Below, learn more about each file along with example code. You can also follow the quickstart guide to create these files from an example project, or view HubSpot's other sample projects.

Within your project's app directory, create an /extensions directory with the following files:

  • example-card.json: the custom card configuration.
  • Example.jsx: the React file that serves as the front end. You can learn more about how to customize your UI extension front end in the UI extension SDK reference below.
  • package.json: metadata about the extension's front end. This file is required and can be used to include dependencies for your React front end.

In the extensions directory, you'll also need to install the HubSpot UI extensions npm package by running npm i @hubspot/ui-extensions.


type   string

The type of extension. Must be crm-card.

data   object

Custom card metadata, including:

  • title (string): the name of the card.
  • location (string): where the card appears on the CRM record. Learn more about extension location.
    • places the card on a tab of the middle pane.
    • crm.record.sidebar: places the card in the right sidebar.
    • crm.preview: places the card in the right side preview panel that you can access from record pages, index pages, board views, and segments pages.
  • uid (string): the extension's unique identifier. This can be any string, but should meaningfully identify the extension. HubSpot will identify the extension by this ID so that you can change the extension's title without removing historical or stateful data, such as the card's position on the CRM record.
  • module (object): where the custom card font end React code lives.
objectTypes   array

Defines which types of CRM object records the extension will appear on. This will also enable you to pull data from those records when using the fetchCrmObjectProperties method. Learn more about compatible objects.

// Example extension config file { "type": "crm-card", "data": { "title": "Example Card", "location": "", "uid": "unique-extension-name", "module": { "file": "Example.jsx" }, "objectTypes": [{ "name": "contacts" }] } }


// Example React front end import React, { useState } from 'react'; import { Button, Text, Input, Stack, hubspot, } from '@hubspot/ui-extensions'; hubspot.extend(({ context, runServerlessFunction, actions }) => ( <Extension context={context} runServerless={runServerlessFunction} sendAlert={actions.addAlert} /> )); const Extension = ({ context, runServerless, sendAlert }) => { const [text, setText] = useState(''); const run = () => { runServerless({ name: 'myFunc', parameters: { text: text } }).then((resp) => sendAlert({ message: resp.response }) ); }; return ( <> <Text> <Text format={{ fontWeight: 'bold' }}> Your first UI Extension is ready! </Text> Congratulations {context.user.firstName}! You just deployed your first HubSpot UI extension. This example demonstrates how you would send parameters from your React frontned to the serverless function and get response back. </Text> <Stack> <Input name="text" label="Send to serverless" onInput={(t) => setText(t)} /> <Button type="submit" onClick={run}> Click me </Button> </Stack> </> ); };


// Example package.json { "name": "example-extension", "version": "0.1.0", "description": "", "license": "MIT", "main": "Example.jsx", "scripts": { "dev": "hs-ui-extensions-dev-server dev", "build": "hs-ui-extensions-dev-server build" }, "repository": { "type": "git", "url": "" }, "dependencies": { "@hubspot/ui-extensions": "latest", "react": "^18.2.0" } }

Compatible objects

You can create extensions for both standard object and custom object records. In the card's JSON configuration file, you'll define this within the objectTypes array. 

When building an extension for custom objects, you'll reference the object as p_objectName (case sensitive). To get this value, make a GET request to the custom object schema API, then look for the fullyQualifiedName in the response. Take the fullyQualifiedName, then remove the HubID number, and use the resulting value for the configuration file.

// example card.json "objectTypes": [ { "name": "p_Cats" } ]

For example, for a custom object with the fullyQualifiedName of p123456_Cats, the correct value to use for the configuration file would be p_Cats.

Extension location

You can configure where the extension appears in the CRM using the location property in the extension's JSON config file. Location values include:

  • places the extension in the middle column of CRM record pages, either in one of HubSpot's default tabs or in a custom tab. If you've customized the middle column previously, you'll need to customize the middle column view to make any newly created extensions visible.
  • crm.record.sidebar: places the extension in the right sidebar of CRM record pages. Extensions in the sidebar cannot use CRM data components.
  • crm.preview: places the extension in the preview panel that you can access throughout the CRM. When using this location, the extension will be available when previewing the objectTypes specified in the JSON config file. This includes previewing records from within CRM record pages, index pages, board views, and the lists tool. Learn more about customizing previews.

Start local development

With your project files created locally, you can now use hs project dev to upload the files to HubSpot and start a local development server to view the extension in HubSpot.

If your project includes multiple extensions, you can select which extensions you'd like to run locally. The local development server supports running multiple extensions from the same app simultaneously, but you cannot run multiple extensions across different apps at the same time.

hs project dev
  • After running hs project dev, select the account you want to work in:
    • To create your extension in an existing sandbox, use the arrow keys to select the sandbox, then press Enter.
    • To create and test your extension in a new development sandbox, select < Test on a new development sandbox >. Then, name the sandbox and press Enter. HubSpot will then create the new development sandbox in the production account. This sandbox will sync with the production account's data, including CRM object definitions and up to 100 of the most recently created contacts and their associated deals, tickets, and companies (up to 100 each).
Please note: when creating a new development sandbox, if you receive the error The personal access key you provided doesn't include sandbox permissions, you'll need to deactivate the account's Personal Access Key, then create a new one with sandbox permissions. To do so, run hs auth, then follow the prompts to select your account. Then, click Deactivate next to the personal access key, and generate a new one with the proper scopes.
  • To create and test your extension in the production account, select < ! Test on this production account ! >.
  • If your project has multiple extensions, you'll be prompted to select which extension to run. You can run multiple extensions from the same app, but not multiple extensions across multiple apps.

Once the project is created, built, and deployed in the selected account, the local development server will start and you can begin building and modifying your extension. 

  • The browser will automatically refresh to pick up the latest saved front end code (updates made to the React files).
  • Changes made to configuration files, such as app.json and hsproject.json, require a manual upload before you can continue development. To upload those changes, first stop the local development server with q, then run hs project upload. After your changes are uploaded, run hs project dev again to restart the server.

Add the card to the record view

With the local development server running, you can add the card to the contact record view, then view the custom card:

  • Log in to your HubSpot account.
  • In your HubSpot account, navigate to ContactsContacts. Then, click the name of a contact to view its record.
  • At the top of the contact record, click Customize tabs. A new tab will open showing the record editor sidebar.
  • In the right sidebar, click Default view to edit the default contact record view.
  • For the purposes of this tutorial, click the + plus icon tab at the top of the editor to add a new tab.
  • In the dialog box, enter a name for your new tab, then click Done.
  • With the new tab added, click the Add cards dropdown menu, then select your new card.
  • In the top right, click Save and exit.
  • Navigate back to the contact record, then refresh the page. You should now see your new tab, which will contain your new card. With the local development server running, you'll see a Developing locally tag displayed at the top of the card.

ui-ext-card-quickstart-resultLearn more about configuring UI extensions using the UI extensions SDK.

Was this article helpful?
This form is used for documentation feedback only. Learn how to get help with HubSpot.