How to Insert and Test Merge Fields in GoHighLevel Email and SMS Templates

by Fahim

Nothing kills lead conversion faster than an email landing with “Hey {{contact.first_name}},” because a merge tag broke. I’ve watched teams make this mistake over and over: you build an intricate email or SMS template, hit the quick “Send Test” button, see blank spaces or raw curly brackets, and start guessing how to fix it.

Here’s how GoHighLevel actually evaluates dynamic tags under the hood, how to insert custom values and contact fields without breaking your layouts, and how to test them against real contact payloads before launching your campaigns.

How to Insert and Test Merge Fields in GoHighLevel Email and SMS Templates
How to Insert and Test Merge Fields in GoHighLevel Email and SMS Templates

Syntax Breakdown: How HighLevel Evaluates Merge Fields

GoHighLevel uses a double curly-brace syntax modeled after Liquid. When a workflow action, bulk campaign, or manual message fires, the templating engine parses the string, looks for matching keys, and injects data from the current execution context.

If you misspell a field key, leave accidental whitespace inside the braces, or reference an object that doesn’t exist in the current execution trigger, HighLevel does one of two things: it leaves the tag completely blank, or it prints the raw tag text right into the lead’s inbox.

Here are the standard merge field objects you’ll work with inside HighLevel templates:

{ "contact": { "first_name": "{{contact.first_name}}", "last_name": "{{contact.last_name}}", "name": "{{contact.name}}", "email": "{{contact.email}}", "phone": "{{contact.phone}}", "company_name": "{{contact.company_name}}" }, "user": { "name": "{{user.name}}", "email": "{{user.email}}", "phone": "{{user.phone}}" }, "appointment": { "start_time": "{{appointment.start_time}}", "only_start_date": "{{appointment.only_start_date}}", "only_start_time": "{{appointment.only_start_time}}" }, "custom_values": { "business_booking_link": "{{custom_values.business_booking_link}}" }
}

Pay close attention to the difference between contact, user, and custom_values. The contact object belongs to your lead. The user object belongs to the assigned staff member handling that lead. If a contact has no assigned user and your template calls {{user.name}}, HighLevel simply renders an empty space.

Inserting Merge Fields in the Email Builder vs SMS Templates

HighLevel gives you two main editors for outgoing copy: the Drag-and-Drop / HTML Email Builder and the Plain Text / SMS Template Editor. Inserting tags works slightly differently in each.

1. The Visual Email Builder

Inside the visual email designer, click any text block to bring up the inline WYSIWYG bar. Click the Tag / Merge Field icon (the tag symbol or curly braces). From the dropdown, pick your data source:

  • Contact: Standard profile fields (First Name, Last Name, Email, Phone, Address, Postal Code).
  • Custom Fields: Any custom property you created under Settings > Custom Fields (like “Lead Score” or “Selected Service”).
  • Custom Values: Global account-level variables defined under custom values in GoHighLevel.
  • User / Assigned User: Profile details for the team member assigned to the contact.
  • Appointment: Only available if the email is dispatched from an appointment-triggered workflow.

If you’re writing raw HTML in a Code block inside the email builder, type the variable directly into your markup:

Hi { {contact.first_name} } , Thanks for reaching out about your project. Our specialist, { {user.name} }, has reviewed your request. You can schedule a follow-up consultation directly on our calendar: Book Your Call

2. SMS Template Editor

Head to Marketing > Templates > SMS Templates or open a workflow SMS action. Click the Custom Values picker in the bottom-left corner of the message box. It drops the exact tag right at your cursor position.

Before blasting dynamic emails at scale, make sure your sending domain is authenticated properly by checking our guide on setting up a dedicated email sending domain in GoHighLevel.

The Empty Field Problem: Adding Fallback Values

What happens when a lead submits a form with only an email and phone number, but your template says Hi {{contact.first_name}},? HighLevel renders: Hi ,. It looks sloppy and screams automated blast.

You have two ways to handle missing contact data cleanly:

Approach A: Using Liquid Filters for Fallback Values

HighLevel’s template parser supports default fallback filters in many notification contexts. Appending | default: 'Fallback Text' inside the curly braces gives the engine a safe default string:

Hi {{contact.first_name | default: 'there'}}, We received your request for more information.

If contact.first_name contains “Sarah”, you get Hi Sarah,. If that field is null or empty, the parser renders Hi there, instead of an awkward blank space.

Approach B: Conditional Workflow Branches

If your builder version strips Liquid filter pipes when saving, use an If/Else Condition step in your workflow instead. We covered advanced branching logic in our guide to GoHighLevel merge fields and fallback values in workflows.

  1. Add an If/Else step right before your message action.
  2. Set the condition: Contact Details > First Name > Is not empty.
  3. Branch A (Has First Name): Send the SMS with Hi {{contact.first_name}}, ...
  4. Branch B (First Name Empty): Send the SMS with Hi there, ...

Why “Send Test Email” Fails (and How to Fix It)

This is the #1 gotcha for people new to HighLevel. You’re inside the email template builder, you hit “Send Test”, put in your email, and the inbox receives broken tags or empty gaps.

The reason is simple: that test button doesn’t attach an active contact record context. It sends an unattached test payload, meaning contact.* and appointment.* fields evaluate to empty strings.

Here’s how to run a real test with populated data:

  1. Create a dedicated test contact in Contacts > Smart Lists using your own email and mobile number.
  2. Fill out all the fields you plan to use: First Name, Last Name, custom fields, and assign the contact to an active user.
  3. If your template editor shows the “Select Test Contact” dropdown in the preview modal, pick your test contact before sending. If not, test through a Workflow execution.

Testing Merge Fields with the Workflow Execution Simulator

The most dependable way to verify merge tags is running an end-to-end workflow test against your test contact. It guarantees that custom fields mapped from forms, surveys, or inbound webhooks actually resolve.

If you’re capturing custom data via webhooks or forms, verify your mappings first using our guide on how to map form submission data to custom fields in GoHighLevel.

Here’s the workflow testing routine:

  1. Open your Workflow containing the Email or SMS action.
  2. Click Test Workflow in the top-right corner of the canvas.
  3. Search for and select your test contact.
  4. Click Run Test.
  5. Open the Execution Logs tab in the workflow header.
  6. Click the Email or SMS step to inspect the exact rendered payload.

The execution payload log shows the precise string delivered to the email provider or telephony carrier (LC Phone / Twilio), so you catch unparsed tags before leads see them.

The Hidden SMS Cost: Character Count and Encoding Blowouts

Merge fields in SMS copy can quietly destroy your margins. A template that looks like 120 characters in the editor can easily balloon into 3 billable segments once dynamic strings drop in.

Standard SMS uses GSM-7 encoding (160 characters per single segment). Exceed 160 characters, and the message splits into concatenated segments of 153 characters each. Worse: if a custom field injects special Unicode characters (like smart quotes “ ” or emojis), the carrier forces UCS-2 encoding. That drops your single segment limit down to just 70 characters (67 per segment when concatenated).

For technical details on encoding limits, check Twilio’s GSM-7 character encoding reference and the official HighLevel Help Center docs on SMS segment billing.

Here’s a look at how a short SMS template expands during execution:

Hey { {contact.first_name}
}, thanks for requesting details on { {contact.interested_service}
}
. Your rep { {user.name}
}
will call you shortly at { {contact.phone}
}
. Reply STOP to opt out.

Here is what happens under the hood when that message goes out:

  • Template string length: 158 characters. Appears as 1 segment in the builder.
  • Rendered output: “Hey Christopher-Alexander, thanks for requesting details on Commercial HVAC Maintenance and Installation. Your rep Maximillian Alexander will call you shortly at +15551234567. Reply STOP to opt out.”
  • Rendered string length: 226 characters (GSM-7).
  • Billed SMS segments: 2 segments (153 + 73 characters).

If your texts run into delivery issues or get flagged by carriers, walk through our guide on how to fix GoHighLevel LC Phone SMS carrier filtering and delivery errors.

Custom Field vs Custom Value vs User Field: Common Mapping Errors

Mixing up Custom Fields and Custom Values is one of the most common mistakes I see in HighLevel setups. They sit side-by-side in dropdowns, but their scope is totally different.

Field Type Syntax Example Scope Use Case Contact Field {{contact.first_name}} Per Contact First name, email, phone number. Custom Field {{contact.quote_amount}} Per Contact Data from forms, surveys, or inbound webhooks. Custom Value {{custom_values.company_phone}} Sub-Account Global Business hours, booking links, support numbers. User Field {{user.email}} Assigned User Sales rep signature, direct phone, calendar owner.

When you create a custom field called “Service Type”, HighLevel creates an internal key like contact.service_type. If you’re verifying keys for API payloads or advanced templates, cross-reference them against the official HighLevel API documentation.

Frequently Asked Questions

Why does my appointment merge field show blank in an email?

Appointment fields like {{appointment.start_time}} only work when the workflow is triggered by an appointment event (such as “Customer Booked Appointment” or “Appointment Status Changed”). If the trigger is a form submission or tag addition, there’s no appointment context, so HighLevel prints an empty string.

Can I use merge fields inside email subject lines?

Yes. You can paste any valid contact tag (like {{contact.first_name}}) or custom value directly into the Subject Line field in campaign builders or workflow email steps. Always test via a workflow execution to confirm it parses cleanly.

What happens if a custom field contains HTML characters?

In SMS messages, raw HTML tags in custom fields get sent as literal text, eating up character counts and looking messy. In emails, the rich text builder displays standard text, but if you inject unescaped HTML inside custom code blocks, the browser parses it as real markup.

Why is my custom value not updating in templates?

Custom values evaluate at the exact moment of sending. If an old value keeps showing up, check whether someone hardcoded a static string or URL instead of pasting the dynamic {{custom_values.my_link}} tag.

Next Steps

Once you’ve got your basic merge tags rendering, set up reliable fallback logic across all your communications by checking our in-depth guide on GoHighLevel merge fields and fallback values in workflows.

all_in_one_marketing_tool