Skip to content

Using OpenAI Embeddings API to implement Semantic Search into a HubSpot Workflow

This article was authored by a member of the HubSpot developer community, Roman Kozak.

Most companies are constantly seeking to improve the efficiency of their internal processes to support planned growth. For that, they often need new tools. HubSpot has many features to help businesses including the ability to automate tasks and communication through Automation services. One such service is called – Workflows. It provides a variety of built-in trigger-based actions that can streamline various business processes. Workflows are not limited by built-in actions only. There is an option to extend the existing action set with custom code actions for advanced functionality. This article is about implementing one such custom coded workflow action.

As an example, I’ll show how to create an advanced workflow through an example of a customer support team who uses HubSpot as its primary support system.

Additionally, this article will show you how to implement a semantic search in this workflow to find the most similar support tickets to a newly created one. Semantic search is quite valid here because it finds tickets with similar context and meaning, even if they don't contain exactly the same keywords. It will save time and effort for support agents since they can quickly identify how similar issues were addressed in the past. Also, it will assign a new ticket to the support agent who has previously resolved a similar support issue. This will not only improve the time to respond but also remove duplication of efforts.

How it works

This workflow will consist of the trigger and only one action. It will start when a new ticket is created and run the custom code action.

The action will do the following:

  1. Find tickets in the system that are similar to the new ticket.
  2. When no owner is assigned to the ticket, assign the ticket to a support agent from the tickets found in the previous step.
  3. Update the ticket with links to similar tickets.

To implement this workflow, we used a combination of HubSpot’s Tickets API and OpenAI embeddings API in a custom coded workflow action.

A few words about internal mechanics of how to get similar tickets. The main idea is to take the description and title of old tickets and turn them into a unique numerical vector representation (convert text to numbers) and then compare those vectors to find the most similar tickets. For text-to-vector conversion, I used OpenAI’s embeddings API. And for vector comparison, I use a simple math function.

In case you want to see what the finished code looks like – here is the link to a GitHub repo with the code needed in the custom coded workflow action. You’ll see relevant comments to most functions in the code to clarify what is happening.

Setting up workflow

To set up such a workflow in your HubSpot portal, we need to perform a series of steps. It requires creating a new workflow and setting it up.

Creating workflow

To get started, we need to create a workflow for incoming tickets. In your HubSpot account, click Automation in the main menu and choose Workflows. In the upper right, click Create workflow button and choose From scratch option. After that workflow wizard will be opened. In the left panel, select Ticket-based to enroll your workflow for tickets. In the right panel, under Choose type, select Blank workflow and click the Next button. Below is a quick video showing all steps that have been made so far.

Creating the trigger

The workflow needs to be triggered when a new support ticket is created. We can set up such enrollment by clicking the Set up triggers button, choosing filter type – Ticket, setting up ticket status “is any of” and selecting New in the drop-down. Below is the video with these steps. Also, you can read more details about it in HubSpot's official docs.

Creating custom code action

Now, when we have a workflow trigger, we need an action to perform a ticket search and assign the new ticket to a support agent. For that, we will use custom code action. Click the plus sign under the trigger box and choose the custom code option from the list of available actions. Afterward, copy all code from the action.js file in the GitHub repository and paste it into your custom code action in the left panel. Below is a video of this part.

Adding secrets and incoming data

Custom code is a pretty complex thing in this workflow. Having just the code is not enough. We must also set up incoming data and secrets. Secrets are just variables with HubSpot private app access token and OpenAI token. They have to be named precisely HUBSPOT_TOKEN and OPENAI_TOKEN to match their use in the code. And for the incoming data, we need to choose the following ticket properties: Ticket owner, Ticket name, Ticket description, and Ticket ID without changing the default key names. Below is the video of how to perform those steps.

Adding ticket custom fields

If we try to test our custom function now, we will get an error. The reason for that is that function uses two custom properties in the Tickets object, so we need to add these custom properties first. Let's create the first one. Open a new browser tab, go to your portal settings, and navigate to Properties in the left sidebar menu. Click the Select an object dropdown menu, then select Tickets properties to create a property. Click the Create property button. In the right panel, set the property’s information as follows:

  • Object type: Ticket
  • Group: Ticket information
  • Label/Name: ticket_ai_embeddings

Click next and choose Field type – Multi-line text. Click next again. We don’t need any rules so we can click the Create button here. We have created the ticket property for storing the array of numbers as a string that will come from OpenAI.

Second, we need to create a ticket property to store information about similar tickets to the current one. To do that, perform the previous steps for ticket property creation with these settings:

  • Object type: Ticket
  • Group: Ticket information
  • Label/Name: Similar tickets
  • Field type: Rich text

Testing custom action

Now we are ready to test our custom code action. Go back to the previous tab with the workflow and open Custom code action if it is not still open. Scroll the content of the right panel to the bottom. Expand the Test action accordion and choose the first ticket to test. Notice that it will modify your ticket data but only the ticket_ai_embeddings property. After that, open the tested ticket and go to View all properties. Find the ticket_ai_embeddings property and make sure that there are a lot of numbers here. Those numbers will be used to compare this ticket to the new ticket enrolled in the workflow later. The more old tickets we have with ticket_ai_embeddings data, the greater chance of finding similar tickets in the future.

Converting old tickets

Notice we still don’t have similar tickets property filled. It is because we don’t have enough old tickets with ticket_ai_embeddings data. To fix that, we can create a copy of our workflow to enroll old tickets with slightly different trigger criteria to achieve that.

Testing the whole workflow

Let’s publish our workflow and test it with a new ticket. Create a new ticket and submit it. After a few minutes, the ticket should be assigned to the support agent who has previously resolved a similar support issue.


That’s it! We have successfully implemented semantic search into the HubSpot workflow. It is a good example of how custom code workflow actions can be used to extend HubSpot's existing features and automate more complex tasks. I hope this article provided valuable insights into semantic search and potential use cases. For example, having this setup with embeddings for every ticket, we can easily advance the customer support processes by creating an integration for drafting answers for a newly assigned agent.

Take this example and use it as a starting point to experiment with other use cases. There are a lot of different scenarios where semantic search might be helpful. Contact me on LinkedIn. I would be happy to discuss your ideas and experiments.