Skip to main content

HubSpot UI extensions enable you to customize HubSpot’s UI to suit your needs. UI extensions can be created for CRM records and the ticket panels within help desk, and they can interact with both HubSpot and external data using a private or public app included in the project.

Below, learn more about how UI extensions work, including how they fetch data, along with best practices.

UI extensions are built using React as a primary front-end framework. For UI extensions in private apps, the back-end is provided by HubSpot using serverless functions for operations such as fetching data. For UI extensions in public apps, you'll need to provide a custom back-end to handle OAuth authentication.

Extensions are built locally using the HubSpot CLI, which you'll use to run a HubSpot local development server for the front-end and deploy back-end changes to the HubSpot account. Extensions are powered by the UI extensions SDK, which offers a number of utilities, including UI components to create the visual elements of the extension. The UI extensions SDK is published as an npm package, which you'll include in the package.json file within the extensions directory.

The UI extensions SDK enables you to:

  • Register an extension with HubSpot

  • Run serverless functions (private apps only)

  • Add actions to your extension, such as opening an iframe in a modal, adding success and failure alerts, and fetching CRM properties

  • Build the extension's UI with components

  • Fetch user and account data

Within the project structure, UI extensions are stored in a /src/app/extensions directory. The extension then uses UI components to render a UI and display information retrieved by the app’s serverless function. UI components are provided by the UI Extension SDK and can be customized through their included fields. Because you’re using React, you can also create your own component building blocks by packaging these components and importing them as needed.

At a high level, a React-based UI extension consists of:

  • A back-end: for private apps, the back-end is provided for you through serverless functions. The app.functions directory contains the serverless function JavaScript file and a JSON configuration. You can also add a package.json file to include any needed dependencies. The serverless function sends and fetches data that your React components can later use. For public apps, this directory is not needed, as you'll provide your own back-end.
  • React front-end: an extensions directory containing .jsx or .tsx files to render components, along with the app card’s .json configuration and a required package.json that includes any needed dependencies.

public-apps-vs-private-apps

UI extensions can be created for a variety of locations and CRM objects in HubSpot. An extension can only appear in one location, but can be appear in that location for multiple CRM objects.

UI extensions can be built for the following locations:

  • The middle column of CRM record pages

    uie-card-location-middle-column

  • The right sidebar of CRM record pages

    uie-card-location-right-sidebar

  • The CRM record preview panel that appears on the right side throughout HubSpot

    uie-card-location-preview-panel

  • The ticket sidebars within the help desk tool (both the preview sidebar and the help desk ticket record view)

    help-desk-uie-example-ticket-page

Learn more about extension locations.

UI extensions can be built for the following CRM objects:

  • Contacts
  • Companies
  • Deals
  • Tickets
  • Custom objects

In addition, the following CRM objects are supported if you've enabled the corresponding data model template (BETA):

  • Appointments and services (Healthcare template)
  • Courses (Education template)
  • Listings (Real estate template)

Learn more about compatible objects.

You can fetch data in multiple ways, depending on the data source:

  • To fetch third-party data, you can make API requests authenticated by secrets.
  • To fetch HubSpot data, you can:
    • use the fetchCrmObjectProperties action to fetch data from the currently displaying CRM record.
    • use HubSpot's API endpoints to fetch data outside of the currently displaying CRM record.
    • use GraphQL to query CRM data directly.

To fetch data with a private app, you'll use serverless functions. To fetch data with a public app, you'll use the hubspot.fetch API.

To fetch data from the HubSpot account, such as displaying property data from the record you’re viewing, you’ll pass the fetchCrmObjectProperties method to the extension via hubspot.extend() in your React files. This method automatically handles authentication, so you don't need to include a private app access token. Learn more about the fetchCrmObjectProperties method.

In addition to using fetchCrmObjectProperties, CRM data components can fetch and visualize HubSpot data out of the box. You can also use GraphQL to query CRM data through the /collector/graphql endpoint. Learn more about querying CRM data using GraphQL.

For security, the React front-end cannot fetch data directly with APIs. For private apps, you can fetch data on the back-end using serverless functions. Then, on the front-end you'll use the hubspot.serverless API to call the serverless function and send your JSON payload as parameters. Learn more about serverless functions.

Because UI extensions are split between front-end and back-end, you can call multiple serverless functions from the same card. Or, you can reuse the same serverless function to run different operations and pass them as needed to the front-end.

If your serverless function requires secrets, learn more about managing secrets for deployed serverless functions and local development.

To render UI extensions, HubSpot uses sandboxed iframes for isolation, web workers for untrusted code execution, and Shopify's remote-ui library for UI abstraction. This enables you to build with familiar tools like React and JavaScript, and remote-ui translates that into specific components to the host via postmessage. This process is essentially serializing a React element tree and sending it through postmessage for the host to evaluate. This results in benefits, such as:

  • Helping to protect both you and HubSpot with a sound and resilient solution for isolated code execution, while ensuring a consistent in-app user experience through the use of HubSpot's component library.
  • Providing you with a productive and delightful developer experience by leveraging mainstream frameworks like React.

However, it also separates the UI extensions from typical web applications built with React. Below, learn more about some of differences you can expect when developing React-based UI extensions.

A project cannot contain file paths that exceed 500 characters. If your project includes a file whose path exceeds that limit, you'll receive the following error in the console when uploading your project:

"[ERROR] File paths must not exceed 500 characters. Shorten the following file path, and then try again. {Relevant erroring file path}."

When building UI extensions on HubSpot, you can only use the components provided through the UI extensions SDK. Each component has a set of parameters that you can use for customization, but these components cannot be customized beyond those parameters.

Because UI extensions are rendered through sandboxed iframes, they cannot directly access the DOM. This restriction means that common methods of DOM manipulation and event listening, such as document.getElementById or document.addEventListener, are unavailable within the iframe's local script context. However, some components provide callback functions that you can use for certain events, like clicks, focus, and input.

  • React Router's useNavigate() hook will not function as expected within a UI extension. This hook manipulates the browser's window object to change the URL, which is not allowed within a sandboxed iframe.
  • The useForm() hook from react-hook-form is not supported because it relies on creating event listeners directly on DOM elements for form validation and submission, which is not allowed within a sandboxed iframe.

Because you can't access the DOM and components don't pass the style prop to the renderer, you can only style components with the provided component props.

You cannot make client-side HTTP requests through UI extensions, meaning browser features like fetch and XMLHttpRequest will not work, nor will libraries like Axios, which is built around those features. Instead, requests should be made through the serverless function, executed by HubSpot behind the scenes.

Requests made within the sandbox do not contain cookies, so rather than trying to store session information with cookies, you can look to the context object, which is passed to the extension component via hubspot.extend. This object contains information related to the authenticated user and HubSpot account. Learn more about fetching account and user data.