Custom code workflow actions

In workflows, you can use the Custom code action to write and execute JavaScript in your workflow. With custom code actions, you can extend workflow functionality within and outside of HubSpot. To see examples of common custom code actions, view HubSpot's Programmable Automation Use Cases.

Custom code actions support JavaScript using the Node 12.x runtime framework. When the action executes, the runtime compute is managed through a serverless function by HubSpot and AWS Lambda

To add a custom code action to a workflow:

  • In your HubSpot account, navigate to Automation > Workflows.
  • Click the name of a workflow, or create a new workflow
  • Click the plus icon + to add a workflow action.
  • In the right panel, select Custom code


In the right panel, you can set up any needed secrets, custom code, and data outputs that can be used later in the workflow. Image 2020-09-11 at 8.26.00 AM

When building custom code actions, keep the following in mind: 

  • The exports.main() function is called when the code snippet action is executed.
  • The event argument is an object containing details for the workflow execution
  • The callback() function is used to pass data back to the workflow. It should be called in the exports.main function.

The event object will contain the following data:

//example payload
  "origin": {
    // Your portal ID
    "portalId": 1,    // Your custom action definition ID
    "actionDefinitionId": 2,
  "object": {
    // The type of CRM object that is enrolled in the workflow
    "objectType": "CONTACT",    // The ID of the CRM object that is enrolled in the workflow
    "objectId": 4,
  // A unique ID for this execution.
  "callbackId": "ap-123-456-7-8"

Available libraries

Several popular Node.js libraries are available for use within the code action.

  • "@hubspot/api-client": "^3.0.1",
  • "async": "^3.2.0",
  • "aws-sdk": "^2.744.0",
  • "axios": "^0.20.0",
  • "lodash": "^4.17.20",
  • "mongoose": "^5.10.2",
  • "mysql": "^2.18.1",
  • "redis": "^3.0.2",
  • "request": "^2.88.2"
  • bluebird 3.7.2
  • random-number-csprng 1.0.2googleapis 67.0.0

The libraries can be loaded using the normal require() function at the top of your code.


There are times you will want your code to reference something that shouldn't be widely shared.  Most often, this is a means of authentication, like an API key.  You can manage the secrets your function has access to directly in the workflow action definition.

Image 2020-09-11 at 8.26.44 AM

From there, you will be able to add whatever values you need, including your HubSpot API key. You can access your HubSpot API key from your account settings. 

Once added, the secrets will be available as environment variables. 

// Sample Functiom Example

const hubspot = require('@hubspot/api-client');
exports.main = (event, callback) => {
  return callback(processEvent(event));
};function processEvent(event) {
  // secrets can be accessed via environment variables
  const hubspotClient = new hubspot.Client({ apiKey: process.env.HAPIKEY });
  hubspotClient.crm.contacts.basicApi.getById(event["object"]["objectId"], ["email", "phone"])
  .then(results => {
    let email = results.body["properties"]["email"]
    let phone = results.body["properties"]["phone"]
    // ...
  .catch(err => {


An important tool for developers is ability to print outputs from their code. It helps you debug issues and provide better support for your end users. To see the output of the logs, you can find them in the "History" tab of the workflow.  


How to Define Outputs

In the function define the output fields you want to use later in the workflow. Then select the data output type in the UI (number, string, boolean, datetime, enum, date phone number) and input the field you want to output.

The output fields should be part of a json object formatted as follows:



You can then use the output from your code action as in input to the Copy Property Action. This removes the need to make another API call to store the value as a property on your object.



Custom code actions must finish running within 20 seconds and can only use up to 128 MB of memory. Exceeding either of these limits will result in an error. 


You may need to fetch object properties using the HubSpot API or to call other HubSpot API endpoints in your custom code action. Like any other API call, you'll still need to comply with HubSpot API rate limits. If you encounter a rate limiting error but you want HubSpot to retry your call, you'll need to throw the error in the catch block of your custom code action.


Please note: if you throw a rate limiting error, HubSpot will reattempt to execute your action for up to three days, starting one minute after failure. Subsequent failures will be retried at increasing intervals, with a maximum gap of eight hours between tries.


  • Generating random numbers: it is common to use Math.random to generate random numbers but users may see the same numbers generated across different executions. This is because Math.random is seeded by the current time. Since we may enroll many objects into a workflow at the same time and we clear our state on every execution, different executions end up seeding Math.random in the same way. To get around this, make use of the random-number-csprng 1.0.2 library which guarantees cryptographically secure pseudo-random number generation. 
  • Variable re-use: To help save memory, any variables declared outside the exports.main function may be re-used for future executions of the custom code action. This is very useful when connecting to external services like a database however any logic or information that needs to be unique to each execution of the custom code action should be inside the exports.main function.

Was this page helpful? *
This form is for feedback on our developer docs. If you have feedback on the HubSpot product, please share it in our Idea Forum instead.