When you need to fetch data in your React modules, you can use a variety of methods on both the server- and client-side, depending on your use case. This includes:
- GraphQL (Professional and Enterprise only)
- HubL
getServerSideProps
function (Professional and Enterprise only)
Below, learn more about each available method.
Please note: the methods described in this guide are only for reading data. At this time, there are no methods for updating HubSpot data through React modules.
The sections below detail the methods available for fetching data on the server-side.
If you have a Professional or Enterprise subscription, you can bind GraphQL queries to your modules to fetch data from HubDB, CRM objects (including custom objects), blogs, and knowledge base.
You can explore your account's schema and run test queries by using the GraphiQL tool in your account.
Using GraphQL comes with some key advantages, such as:
- Co-locating the query and component for compartmentalization.
- Needing only a single query for fetching association data.
- Triggering prerendering of pages using the query when you make updates to the query or relevant data.
Learn more about binding GraphQL queries to modules.
You can pass data from the template to the module by using HubL at the template level, then using props.hublParameters
at the React component level.
In the template, add parameters for each data property in the HubL module tag, then use HubL tokens to fetch the data.
{% module "contact_profile"
path="@projects/contact-profile-project/contact-profile-app/components/modules/ContactProfile",
firstName="{{contact.firstname}}",
lastName="{{contact.lastname}}",
email="{{contact.email}}"
%}
Then, use props.hublParameters
to pass the data to the React module.
xxxxxxxxxx
// contact-profile-project/contact-profile-app/components/modules/ContactProfile/index.jsx
export const Component = (props) => {
return (
<div>
<span>{props.hublParameters.firstName}</span>
<span>{props.hublParameters.lastName}</span>
<span>{props.hublParameters.email}</span>
</div>
);
};
Since the data is passed at the template level, it will not work for cases where modules are added to the page via the drag and drop content editor (as that module doesn't exist at the template level). For those cases, use the hublDataTemplate
API instead.
To automatically attach and pass HubL context variables to your React modules:
- In the module, export a string via
hublDataTemplate
. In the string, include a HubL statement to set thehublData
variable.
xxxxxxxxxx
export const hublDataTemplate = `{% set hublData = "Hello from HubL!" %}`;
- The data will come through in your React module as a top level prop of
hublData
. Useprops.hublData
to access the returned data.
xxxxxxxxxx
export function Component(props) {
return <div>{props.hublData}</div>;
}
You can add any valid HubL to this template, including filters, functions, and module field references. This can be especially useful for building more complex maps of data.
import ModuleFields from './ModuleFields.js';
import ModuleMeta from './ModuleMeta.js';
export function Component(props) {
return (
<div>
<div>My total posts: {props.hublData.totalBlogPostCount}</div>
<a href={props.hublData.blogAllPostsUrl}>View all posts</a>
</div>
);
}
export const meta = ModuleMeta;
export const fields = ModuleFields;
export const hublDataTemplate = `
{% set blogId = module.blog_field %}
{% set hublData = {
"totalBlogPostCount": blog_total_post_count(blogId),
"blogAllPostsUrl": blog_all_posts_url(blogId)
}
%}
`;
Learn more about passing HubL data in modules.
If you have a Professional or Enterprise account, you can export a getServerSideProps
function from React modules. This function must return an object with a serverSideProps
property and a cacheConfig
property, which configures caching of the module.
In the React component, the information returned in serverSideProps
can be accessed via props.serverSideProps
. For fetching specific data based on dependencies such as URLs, query parameters, or the contact object, HubSpot provides the following utility functions:
These helper functions wrap your data fetching functions and automatically inject relevant dependencies (with TypeScript types), ensuring that your module has the necessary context to fetch and process the data.
For example, when you use withUrlPath
, the wrapped function will receive a URL without query parameters, making it easy to fetch data based on the path alone. Similarly, withContact
ensures that your function has access to the URL, query, and contact information, allowing for more complex data-fetching scenarios.
Wraps a function to provide module properties without additional dependencies. Access to fieldValues
, hublData
, and dataQueryResult
etc. is available.
xxxxxxxxxx
import { withModuleProps } from 'path/to/helpers';
const fetchData = (props: ModulePropsWithoutSSP) => {
// Your data fetching logic
};
export const getServerSideProps = withModuleProps(fetchData);
Provides module properties like withModuleProps
, but also includes the page URL (without query parameters). Caching at the module level is partly based on the props and dependencies used in data fetching. By omitting the query parameters, you can optimize this caching, as it won't create new cache records for every query parameter variation.
To include query parameters, use withUrlAndQuery
instead.
xxxxxxxxxx
import { withUrlPath } from 'path/to/helpers';
const fetchData = (props: ModulePropsWithoutSSP, { url }: { url: URLWithoutQuery }) => {
// Your data fetching logic
};
export const getServerSideProps = withUrlPath(fetchData);
Builds on withUrlPath
and provides module properties like withModuleProps
, but also includes the page URL with query parameters. A new cache record will be created for each permutation of the URL with query parameters for this module.
xxxxxxxxxx
import { withUrlAndQuery } from 'path/to/helpers';
const fetchData = (props: ModulePropsWithoutSSP, { url }: { url: URL }) => {
// Your data fetching logic
};
export const getServerSideProps = withUrlAndQuery(fetchData);
Like withUrlAndQuery
, this function provides the module properties, along with a URL with query parameters, but also includes a contact object.
xxxxxxxxxx
import { withContact } from 'path/to/helpers';
const fetchData = (props: ModulePropsWithoutSSP, { url, contact }: { url: URL; contact: Contact }) => {
// Your data fetching logic
};
export const getServerSideProps = withContact(fetchData);
The caching that happens between HubSpot's edge CDN and the data center where React modules are rendered is outside of the standard prerendering caching behavior. This means that parts of the page outside of the React module can be statically prerendered, and the module itself can be dynamic or cache by caching rules that you define. By default, HubSpot provides a 10-second cache (Cache-control: max-age=10
) for data fetching modules.
Cache keys are based on the following:
- Project build number
- Module props (e.g.,
fieldValues
,hublData
,dataQueryResult
) - Injected dependency values (e.g., using
withUrlPath
will result in a new cache key being created each time the module is rendered on a page at a new URL path).
This means that, if you haven't made any changes to the data flowing into a module, you can bust the cache by triggering a new project build.
The getServerSideProps
function includes a caching
property which you can use to control caching. This property only contains the cacheControl
property, which represents the Cache-Control header, and it can include any of the standard directives.
In the example below, the module will be cached for 60 seconds, and any request after that will trigger a re-cache.
xxxxxxxxxx
import { withModuleProps } from 'path/to/helpers';
const fetchData = async (props: ModulePropsWithoutSSP) => {
// Your data fetching logic
const results = await fetch( ).then(response => response.json())
return {
serverSideProps: {
results
},
caching: {
cacheControl: {
maxAge: 60
}
}
}
};
export const getServerSideProps = withModuleProps(fetchData);
In local development, the module is rendered on your machine, so no caching is at play.
Use serverless functions to fetch data on the client-side securely without needing to spin up and maintain a back-end server. There are multiple ways to authenticate serverless function requests if needed, either by using private app access tokens or secrets.
Serverless functions for the CMS are executed when their public endpoint is called. The URL is determined by the serverless.json
configuration, but always follows a common structure: https://<domain>/hs/serverless/<path>
.
Please note:
The above path is used for calling serverless functions built with projects, which is the recommended method. You can invoke serverless functions built with the design manager in CMS React modules with: https://<domain>/_hcms/api/<path>
.
You can choose to package the serverless function in the same project as your CMS assets, but you can also invoke serverless functions that exists outside of the project. Below is an example of what your project file structure might look like if it contained CMS React assets alongside a private app with a serverless function.
xxxxxxxxxx
project-folder/
│── hsproject.json
│── src/
│ └── cms-react/
│ │ ├── assets/
│ │ ├── components/
│ │ ├── styles/
│ │ ├── cms-assets.json
│ │ └── package.json
│ │
│ └── app/
│ ├── app.json
│ ├── app.functions/
│ │ ├── function.js
│ │ ├── package.json
│ └─ └── serverless.json
└
For debugging, HubSpot provides serverless function logs in the app settings page of HubSpot.
Check out the following documentation for more information about building and using serverless functions:
- HubSpot's example serverless function project
- Serverless functions overview
- Serverless functions reference
- Get started with serverless functions
To start using secrets for authentication, create a secret with the hs secrets add
command in the HubSpot CLI, then add the names of secrets used by your components to a secretNames
array in your cms-assets.json
config. For example:
xxxxxxxxxx
{
"label": "My CMS project",
"secretNames": ["TEST_SECRET"]
}
To access the secret, @hubspot/cms-components
exports a getSecret()
function to return a given secret's value. To prevent accidentally leaking secrets, getSecret()
can only be called from component code executed on the server and not from the browser (i.e. within an island). If a secret value isn't sensitive and you need to access it in island components, you may call getSecret()
outside the island and pass the value down via a prop.
xxxxxxxxxx
import { getSecret } from '@hubspot/cms-components';
// in a React component outside of an island
export function Component(props) {
const mySecretValue = getSecret('TEST_SECRET');
return <OtherComponent secret={mySecretValue} >;
};
// Note, this code will fail since it is not called from within a component's render function (or from a utility function called from the component's render function)
// const FAILED_SECRET = getSecret('secrets-dont-work-at-module-top-level');
To make secrets available with local development via @hubspot/cms-dev-server
, create a .env
file to define secret values for local use only. Keys in this file need to be prefixed with HS_
to be recognized by the dev server as secrets. For example:
xxxxxxxxxx
// In your .env file
HS_TEST_SECRET = localsecretvalue;
This secret will be accessible locally without the HS_
prefix you included in your .env
file. In the example above, the secret can be accessed with getSecret('TEST_SECRET')
.