Updated on July 2, 2026

TL;DR

To personalize your Kommunicate AI agent with live HubSpot data, follow these steps:

  1. Create an intent that asks for the visitor’s email mid-conversation, then extract it as an entity named email.
  2. In HubSpot, create a private app token scoped to crm.objects.contacts.read only.
  3. In that intent’s inline code, call HubSpot’s contacts endpoint with idProperty=email to fetch the record.
  4. Branch the reply on lifecyclestage: customers get one tone, late-pipeline prospects get another, unrecognized emails get a graceful fallback.
  5. Test it in Kompose’s test agent panel with a real HubSpot email before publishing.
  6. You can extend the same function to include a HubSpot associations call when you need deal stage or ticket history as well.

Most companies treat personalization as using a customer’s name in a reply. There’s no contextual information behind it, and no problem-solving shaped by what’s already known about that person.

Definition

A personalized AI agent uses live CRM data to change its reply in real time, based on who the visitor is and where they sit in your pipeline, instead of just dropping their name into a template.

That’s because most CRM-agent integrations are one-way. A message comes in, and the backend creates a contact in HubSpot, logs a ticket, and attaches a transcript.

To actually personalize responses, you need live CRM data. For example, if a contact named Priya from a Professional-plan account starts a conversation, there’s no reason the agent should open with the same generic “how can I help” that it gives a first-time visitor.

Kommunicate’s native HubSpot integration handles the first direction well. For the second, reaching into HubSpot mid-conversation and shaping the reply around what’s there, you need a small piece of custom logic. 

Kompose’s inline code editor is built for exactly this, and the function is a short one that you can set and forget.

In this article, we’ll cover:

  1. What are we building?
  2. Native sync or inline code. What should you use?
  3. How will this AI agent work?
  4. Tutorial – How to build a personalized AI agent with HubSpot?
  5. Common mistakes to avoid
  6. Summary: personalizing your AI agent with HubSpot

What are we building?

We’re building an AI agent that can identify a known contact mid-conversation, using:

  • An intent that asks for an email at the right moment
  • Kompose’s built-in entity extraction to catch it
  • An inline code function that looks up the contact in HubSpot
  • A branch in the lifecycle stage that changes the reply
  • A fallback for emails that HubSpot doesn’t recognize

The part most CRM integration guides skip is what happens after the lookup. The agent should behave differently depending on what HubSpot returns:

HubSpot Lookup Result Agent Behavior
Lifecycle stage: customer or evangelist Welcomes them back, asks if it’s a support question
Lifecycle stage: opportunity or salesqualifiedlead Offers to loop in their account rep
Lifecycle stage: lead, subscriber, or unset Asks a qualifying question, using the job title if available
Email not found in HubSpot Replies normally, continues without personalization

First, it’s worth separating this from Kommunicate’s native HubSpot sync, since the two solve different problems, and it’s easy to reach for the wrong one.

Native sync or inline code. What should you use?

The native HubSpot integration is the right tool when the goal is getting conversation data into HubSpot: 

  1. Creating contacts
  2. Attaching transcripts as notes
  3. Surfacing ticket status back in the thread

Inline code earns its place when a decision the agent makes mid-conversation depends on something only the CRM holds: 

  1. Lifecycle stage
  2. Deal value 
  3. Existing support history

That’s a lookup, not a sync, and it needs to resolve before the next message goes out.

Native HubSpot Integration Inline Code Lookup
Data direction Conversation into HubSpot HubSpot into the conversation
Setup No code One inline code function
Good for Creating contacts, tickets, and deals from chats Shaping a reply around data that already exists
Runs On conversation events, automatically When the email is captured mid-conversation
Customization Configured in the dashboard Full control over the lookup and the branch logic

Once you know you need the lookup path, you need to figure out how the entire workflow comes together.

How will this AI agent work?

Flowchart showing how a Kommunicate AI agent personalizes replies with HubSpot: anonymous visitor, ask for email, Kompose extracts email, inline code calls HubSpot, personalized reply or fallback
HubSpot AI agent flow

There are usually three methods to personalize replies: 

  1. Using pre-chat form fields
  2. Using chat context passed in from the install script
  3. Conversation metadata updated mid-session. 

All three assume the visitor’s details are already known before personalization is needed.

This tutorial uses a different method: extracting a value from whatever the visitor types, then using it to drive a live lookup instead of just inserting a value that was already passed in. This works as follows:

  1. A visitor starts chatting without being identified. 
  2. At some point, when personalization would actually change the response, the agent asks for an email address. 
  3. Kompose’s built-in email entity extraction catches it from whatever the visitor types, however they phrase it, and passes it to an inline code function as a parameter. 
  4. That function calls HubSpot, and the conversation branches.

Setting that up requires two components on the Kompose side: an intent that extracts the email and its inline code.

Now, let’s get started with the tutorial.

Tutorial – How to build a personalized AI agent with HubSpot?

1. Setting up entity extraction in Kompose

If you haven’t built a Kompose agent before, your first Kompose AI agent covers how to create the agent and its first few intents. We’re going to use a similar build here:

  • Navigate to Agent Integrations and select Create AI agent.
  • Select Kompose from the list of models given (you can select another model later).
Kompose Agent Profile screen setting the AI agent name, English language, casual tone, short response length, and custom instruction
Kompose Agent Profile Setup
  • Set up your Agent Profile in the first window. We’re using a generic name and keeping the tone casual. 
Kompose Custom Instruction field with a prompt telling the AI agent to personalize replies and ask for the customer's email address when they raise a problem
Kompose custom instruction prompt
  • In the Custom Instruction section, we’ll put in a simple prompt so that the AI agent asks for an email address when the customer is inquiring: “You are a customer service AI agent who is working for an AI SaaS product. You will personalize your interactions based on the information about the customer that messages you. The first time the customer asks about a specific problem, inquire about their email address. Do not repeat the request for the email if the customer declines to share it.”
Kompose welcome message editor with the greeting "Hi, welcome to Kommunicate. How can we help you today?" shown live in the chat preview panel
Kompose welcome message setup
  • In the Welcome message section, we’ll use, “Hi, welcome to Kommunicate. How can we help you today?” To save it, we will click on Train.
Kompose email capture intent with training phrases like "my email is priya@example.com" added under the User Says tab to teach the AI agent how visitors share an email
Kompose email capture intent

The custom instruction tells the agent when to ask for the email. The intent you build next is what actually captures and extracts that email so the inline code can use it.

  • Move to Intents (Q&A) to create the email capture intent. Add in phrases that we’ve shown above in the User says section (this doesn’t need to cover every variant; Kompose’s NLU is built to understand different phrasing).
Kompose Extract Entities enabled in the email capture intent with the Email entity selected from a list that also includes Phone Number, URL, and Name
Kompose email entity extraction
  • In the Agent says section, enable Extract Entities and choose Email
  • After you’ve done this, scroll below and enable Dynamic Message and select inline code.

Now, we are going to build the lookup section that fetches data from HubSpot. 

2. Setting up the Inline Code

Kompose’s inline code runs in a sandboxed Node environment with axios available globally. The function signature is fixed: an exported responseHandler that takes the message payload (input) and a callback you call exactly once with the reply.

The lookup itself uses HubSpot’s CRM v3 contacts endpoint with idProperty=email, which fetches a record by email address rather than by its internal record ID. Authentication is a private app access token, since HubSpot retired the old API key model, sent as a standard bearer header. The full reference is in HubSpot’s contacts API if you want the underlying detail.

Kompose Dynamic Message toggled on in the email capture intent with the Create an Inline code option selected to fetch HubSpot data
Kompose create inline code
  • After enabling Dynamic Message and clicking on Inline code, click on Create an Inline code. 
  • Create an inline code snippet called HubSpot Look-Up and enter the following code:
exports.responseHandler = async (input, callback) => {
  // Private app access token, scoped to crm.objects.contacts.read only.
  const HUBSPOT_TOKEN = “YOUR_PRIVATE_APP_ACCESS_TOKEN”;

  const extractEmailFromText = (text) => {
    const match = (text || “”).match(/[\w.+-]+@[\w-]+\.[\w.-]+/);
    return match ? match[0] : null;
  };

  try {
    const email = input.parameters?.email || extractEmailFromText(input.message);

    if (!email) {
      callback([{ message: “I didn’t quite catch a valid email there, mind sharing it again?” }]);
      return;
    }

    const properties = “firstname,lastname,company,jobtitle,lifecyclestage,hs_lead_status”;
    const url = `https://api.hubapi.com/crm/v3/objects/contacts/${encodeURIComponent(email)}?idProperty=email&properties=${properties}`;

    const hsResponse = await axios.get(url, {
      headers: { Authorization: `Bearer ${HUBSPOT_TOKEN}` }
    });

    const props = hsResponse.data.properties || {};
    const firstName = props.firstname || “”;
    const company = props.company || “”;
    const jobTitle = props.jobtitle || “”;
    const lifecycleStage = (props.lifecyclestage || “”).toLowerCase();

    const namePart = firstName ? `Hi ${firstName}` : “Hey there”;
    const companyPart = company ? `from ${company}` : “”;
    const greeting = [namePart, companyPart].filter(Boolean).join(” “) + “!”;

    const isCustomer = [“customer”, “evangelist”].includes(lifecycleStage);
    const isLatePipeline = [“opportunity”, “salesqualifiedlead”].includes(lifecycleStage);

    let followUp;
    if (isCustomer) {
      followUp = “Welcome back! Are you reaching out about a support question, or something else?”;
    } else if (isLatePipeline) {
      followUp = “Thanks for staying in touch, want me to loop in your account rep, or can I help directly?”;
    } else if (jobTitle) {
      followUp = `As a ${jobTitle}, what brought you here today, are you exploring how Kommunicate could fit your team?`;
    } else {
      followUp = “What brought you here today, are you exploring how Kommunicate could fit your team?”;
    }

    callback([{ message: `${greeting} ${followUp}` }]);

  } catch (error) {
    if (error.response?.status === 404) {
      callback([{ message: “Thanks! I don’t see that email on file yet, no worries, what can I help you with?” }]);
      return;
    }
    callback([{ message: “Thanks for that, let’s continue, what can I help you with today?” }]);
  }
};

A couple of details worth understanding rather than just copying. The extractEmailFromText regex is a fallback, not the primary path: entity extraction occasionally misses unusual phrasing, and this catches what slips through. The idProperty=email query parameter is what lets the URL use an email address instead of HubSpot’s internal record ID.

To test it, open Kompose’s test agent panel and reply with an email that exists in the connected HubSpot portal. You should see the personalized greeting come back, along with a graceful fallback for an email HubSpot doesn’t recognize.

A few things in that function are easy to get wrong if you’re moving fast. Here’s what to watch for.

Common mistakes to avoid

Mistake Better Approach
Private app token with full read and write access Scope it to crm.objects.contacts.read only
Looking up HubSpot on every message in the conversation Look up once, when the email is first captured
Hardcoding hs_lead_status values from a different portal Check your own portal’s lead status options first
Pre-chat gating just to capture an email Ask for it only when personalization would change the reply
Treating a 404 as something broken Treat it as an expected case, and reply gracefully

The table above covers the scope. Two more things worth knowing about that token specifically.

  1. It lives in plain text inside the inline code editor, which is fine as long as it stays in Kompose. The risk shows up if the agent is ever exported as a JSON or CSV backup: the token travels with it, in plain text, inside that file. If that export is ever shared outside the team that manages the agent, rotating the token afterward is mandatory.
  2. Private app tokens are fine for a single HubSpot account, and HubSpot supports Bearer-token authentication for private app access tokens. But for a multi-customer/Marketplace-style integration, HubSpot recommends using OAuth instead. 
  3. Rate limits aren’t a real concern at the volume this runs at. A single GET-by-email lookup per conversation is nowhere near what a private app token allows, even on the lower end of HubSpot’s plans. It only becomes relevant if the same inline code starts getting called on every message rather than once when the email is first captured, which the mistakes table above already steers you away from.

Summary: personalizing your AI agent with HubSpot

None of this requires abandoning the no-code builder. The agent is still built visually, intents, entities and all. The only custom part is a single function that bridges Kompose’s flow with a live CRM lookup.

On a high level, that’s four things:

  1. Ask for an email when personalization would change the reply
  2. Extract it and hand it to an inline code function
  3. Look up the contact in HubSpot and branch on the lifecycle stage
  4. Fall back gracefully when there’s no match

The same pattern extends cleanly if you need more than contact properties. Pulling in the deal stage or open ticket history is one more call to HubSpot’s associations API, slotted in right after the contact lookup succeeds, not a rewrite.

If you want this kind of CRM-aware personalization without writing the lookup yourself, book a demo, and we’ll show you what’s already built in. Or sign up for free and wire this exact function into your own Kompose agent today.

FAQs

Can a Kommunicate AI agent use live HubSpot data?

Yes. Using Kompose’s inline code, the agent looks up a contact by email in HubSpot mid-conversation and changes its reply based on the contact’s lifecycle stage.

Do I need to write code to personalize the agent with HubSpot?

Almost none. The agent is still built no-code in Kompose. Only one small inline code function handles the HubSpot lookup.

Do I need a HubSpot API key or a private app token?

A private app access token scoped to crm.objects.contacts.read. HubSpot retired the old API key model, so private app tokens sent as a Bearer header are the current method.

What happens if the email isn’t in HubSpot?

The function treats the 404 as an expected case and replies normally, without personalization.

How is this different from Kommunicate’s native HubSpot integration?

Native sync pushes conversation data into HubSpot (contacts, tickets, transcripts). Inline code pulls HubSpot data into the conversation to shape the reply.

Write A Comment

You’ve unlocked 30 days for $0
Kommunicate Offer
Kommunicate Blog
×