What I Do
MCP Servers
GoHighLevel MCP CloseBot MCP Votel AI MCP
Snapshots
Pest Control AI Campaign
More
Portfolio Blog YouTube: Code With Urooj About Contact Work With Me
GoHighLevel Workflows

GoHighLevel Workflows Tutorial 2026 (Beginner to Advanced): Build a Lead Follow Up Step by Step

2 November 2026 16 min read Urooj Shafait, Urooj Labs

Short answer: every GoHighLevel workflow has three parts: a trigger that starts it, actions that run in order, and settings that set the rules. In this tutorial I build one real new lead follow up from a blank page. It assigns the lead, sends an email and a text, waits a day for a reply, and if there's no reply it creates three numbered call tasks for your team. Along the way you'll use trigger filters, If/Else, a goal event, the new Loop and Router actions, Workflow AI and the execution logs.

How this was tested: everything here is a real screen in my own test account, using demo contacts only, with do not disturb switched on for every channel. Nothing reached a real person, and the workflow stays a draft the whole way through. Loop showed a Beta tag in my account. HighLevel changes menus often, so a label or two may look a little different in yours.

GoHighLevel Workflows Tutorial 2026 (Beginner to Advanced) (15:14, Code With Urooj on YouTube)

Key moments in the video

If you'd rather watch, the full build is in the video above. New GoHighLevel tutorials go up on my Code With Urooj YouTube channel. If you can, open your own account in another tab and build it with me.

What you'll build

A new lead comes in. They get a friendly email and a text, and they're handed to someone on your team straight away. Then the workflow waits for them to reply. If they reply, it stops chasing. If they don't, your team gets three numbered call tasks, and a note on what to try first.

The example is a small home services business, like a plumber or a cleaner. A new enquiry comes in, and the owner wants a quick reply and a reminder to call. We start with the basics, triggers and actions, and finish with the advanced parts: If/Else, goals, Loop, Router and Workflow AI.

How every workflow works

Before you click anything, here's the one idea that makes every workflow make sense. Every workflow has three parts:

PartWhat it isExamples
TriggerWhat starts the workflowA form is filled in, a tag is added, a lead replies
ActionsWhat happens next, in orderSend an email, create a task, wait a day
SettingsThe rules around itWhether someone can go through twice, who your messages come from

In plain words: when this happens, do these things, in this order, under these rules. Remember that sentence and you can read any workflow. HighLevel's own getting started with workflows guide covers the same building blocks if you want the official version.

Before you start: a safe test setup

My demo contacts have do not disturb switched on for every channel. So even when a step tries to send something, nothing reaches a real person. Please set yours up the same way before you test, or test only on your own contact details.

Step 1: Create the workflow

  1. Go to Automation, then Workflows.
  2. Click Create Workflow, then Start from Scratch.
  3. Give it a name you'll still recognise later. Mine is WF101 New lead follow up.
GoHighLevel Workflows page with the Create workflow menu open, showing Start from Scratch, Build Using AI, Select from Template, Import from a campaign and other options
Create Workflow, then Start from Scratch, with Build Using AI and templates in the same menu.

You'll see Build using AI and templates in that menu too. They're handy, but build from scratch once and you'll understand what they build for you.

Now look along the top of the builder:

See where it says Draft? A draft doesn't run for anyone until you publish it, so you can't break anything here. Mine stays a draft the whole way through.

Step 2: Add a trigger with a filter

Click Add New Trigger. Yes, the list is long. Don't try to learn it all today. It's grouped into sections like contact, events and opportunities, and there's a search box at the top. A few you'll use a lot are Form Submitted, Customer Replied and Contact Tag.

I'm using Contact Tag, because it's the easiest one to control. It fires when a tag is added or removed, and almost anything can add a tag: a form, another workflow, an integration, or you, by hand. You can give the trigger its own name too, which helps once you've got a few. Mine is New lead tag added.

The filter is the most important part

  1. Click Add filters and pick Tag added.
  2. Choose the exact tag. Mine is wf101-new-lead.
  3. Click Save trigger.
GoHighLevel Contact tag trigger named New lead tag added, with a Tag added filter set to the tag wf101-new-lead
The Contact tag trigger with a Tag added filter, so only contacts tagged wf101-new-lead go in.

Why the filter matters: without a filter, this trigger fires for every tag added to every contact in your account. It's one of the most common beginner mistakes, and it's easy to miss, because the workflow still looks fine. Pick a tag that nothing else uses, so nothing can start this workflow by accident.

You can add more than one trigger, and any of them will start the workflow. I'm keeping just the one.

Step 3: Assign, tag and send an email

Now the actions. Click the plus under the trigger. The list is grouped again, so search is the quickest way in.

  1. Assign to user. Pick the team member who should own new leads. I use a test team member. There's also an option to only apply this to contacts who don't have an owner yet. Why start here? Because a lead with no owner is a lead nobody calls.
  2. Add Contact Tag: wf101-contacted. Tags let you see where someone is at a glance. Later you can filter your contacts by this tag, or use it to start another workflow.
  3. Send Email. Search for email and pick Send Email.
GoHighLevel Email action panel with empty From Name and From Email fields and a note that empty fields use the default values
The Email action. Leave From Name and From Email empty to use the account's default sender.

For the email:

Then click Save action.

Step 4: Send a text with Write with AI

Click the plus and pick Send SMS. There's a Write with AI option here. You describe the message in plain words, then click Generate SMS. My prompt was:

A friendly short text thanking a new lead for getting in touch and asking a good time to call.

Write with AI draft of a text message in GoHighLevel, signed off with a yourName placeholder, with Regenerate SMS and Make some modifications options
Write with AI drafts the text message, ready to edit before you save it. Note the yourName placeholder at the end.

The draft thanks them and asks when would be a good time for a call. Not bad. But read it before you use it. It's longer than I'd like for a text, and it signs off with a your name placeholder. Save that without reading, and every lead gets a text signed "your name".

So I clear it and write my own: First Name from custom values, then thanks for getting in touch! When is a good time for a quick call? Short texts are easier to reply to. AI is great for a first draft, but you're the one who signs it off. Save the action.

Step 5: Wait for a reply

Now give the lead time to reply. Click the plus and pick Wait. There are a few kinds, including a set amount of time, until the contact replies, and until a recurring window opens. HighLevel's Wait action help article lists them all.

GoHighLevel Wait action asking How long do you want to wait, with Until the contact replies and For a set period of time options
The Wait action: wait until the contact replies, or for a set period of time.
  1. Pick until the contact replies, because you don't want to chase someone who's already answered.
  2. Choose what it's listening for. I pick email and SMS.
  3. Set the timeout to one day.

Now watch the canvas. It splits into two paths: Contact reply, for when they answer, and Time out, for when the day runs out and they haven't. That split is what makes a follow up feel polite instead of pushy.

On the contact reply path, I add the tag wf101-replied and a note that just says Replied. Then that path ends. They answered, so we stop. Everything from here on sits on the time out path.

Quick check in. So far you've got a trigger, an owner, a tag, an email, a text and a wait. That's the beginner half done.

Step 6: If/Else and an internal notification

On the time out path, you want different steps depending on what you know about the lead. That's what If/Else is for.

  1. Click the plus and pick If/Else. You can start from a scenario recipe, or build your own. I build my own and name the branch Has phone.
  2. Add a condition: Phone, is not empty.
GoHighLevel If/else action panel with a Scenario recipe dropdown set to Build your own
If/Else: build your own condition, or start from a scenario recipe.

If/Else sends the contact down the first branch that matches. Anyone who matches nothing goes down None.

On None, there's no phone number, so a call task makes no sense. I add a note instead: No phone, email only. Then an Internal Notification, which is for your team, not the lead:

Nothing goes out to the contact here. It just makes sure a real person on your team knows this lead needs a different kind of follow up.

Step 7: Check the workflow settings

Open the Settings tab. Most people skip this, and a lot of odd behaviour comes from here.

GoHighLevel workflow Settings tab showing the Allow re-entry and Allow multiple opportunities toggles switched on and Stop on response switched off
Workflow settings: Allow re-entry, Allow multiple opportunities and Stop on response.
SettingWhat it doesWhat I chose
Allow re-entryLets the same contact go through the workflow more than onceOn while testing, because I run the same demo contact through again. For a real welcome workflow I'd usually turn it off. Nobody wants to be welcomed twice.
Allow multiple opportunitiesIf a contact has more than one opportunity, they can go through once for eachLeft as it was
Stop on responseEnds the workflow for anyone who repliesOff, because the Wait step already handles replies
Timezone and time windowWith the time window on, steps only run in the hours you pickAccount timezone, time window off. Switching it on is kinder than a text at midnight.
Sender detailsFrom name, from email and from numberEmpty, to use the account defaults

HighLevel explains each of these in its workflow settings overview.

Step 8: Add a goal event

This is where the advanced part starts. Picture this: a lead books an appointment while they're sitting in that one day wait. They shouldn't have to sit there. A goal lets them jump ahead.

  1. At the top of the Has phone path, add Goal Event.
  2. The goal types include an email event, a trigger link click, a tag added or removed, and appointment status. Pick appointment status.
  3. Pick your calendar. Mine is a test calendar.
  4. The status options are new, confirmed and showed. I choose confirmed.
  5. For anyone who reaches this step without hitting the goal, pick continue anyway.
GoHighLevel Workflow goal action with the goal type set to Appointment status and the calendar set to Test Service Calendar
A goal event on Appointment status, so leads who book skip straight ahead.

So the moment an appointment is confirmed, wherever that contact is in the workflow, they jump straight to this point. HighLevel's Goal Event help article lists every goal type.

One honest note about this build: the goal sits above the Loop, so a confirmed lead still carries on into the call tasks below it. If you want confirmed leads to skip the calls completely, put the goal after the Loop instead. I left it where it is so you can see exactly how goals behave.

Step 9: Loop for numbered call tasks

Next, the new Loop action. It had a Beta tag in my account. Loop repeats whatever you put inside it, once for each item in a list, or once for each number in a range.

Why use it here? Because one call task is easy to ignore. Three numbered attempts are much harder to lose track of.

  1. Under the goal, click the plus and pick Loop.
  2. Choose A range of numbers. It starts at 1 to 10. Set it to 1 to 3, and the panel tells you the actions inside will run three times.
  3. Save, then click the plus inside the loop and add Add Task.
GoHighLevel Loop action panel with Loop over set to A range of numbers instead of A list of items
The new Loop action set to a range of numbers, to repeat steps a set number of times.
  1. For the title, type Call attempt, then add the Loop counter from custom values. That counter is what turns three identical tasks into attempt one, two and three.
  2. Description: Call the lead. Assign it to your team member, due in one day.
GoHighLevel Add task action inside a loop with the title Call attempt followed by the Loop counter custom value
An Add task inside the loop, titled Call attempt with the Loop counter, so each task is numbered.

Only the steps inside the loop repeat. Anything after it runs once. For more on Loop, including list mode, see HighLevel's Loop release note and my post on Loop, Router and AI Agent Skills.

Step 10: Router for every branch that matches

Now the new Router. At first glance it looks like If/Else, but there's one big difference. If/Else stops at the first branch that matches. Router sends the contact down every branch that matches, one after another, left to right. That matters because real leads often tick more than one box.

  1. Under the loop, click the plus and search Router. You'll spot an OpenRouter app in the results too, so make sure you pick the Router action.
  2. Each branch has a type: Custom rules, Always run or Fallback.
  3. Branch one, custom rules: Phone is not empty, with a note, Call first.
  4. Branch two, custom rules: Email is not empty, with a note, Email follow up.
  5. A Fallback branch, with a note, No contact details. It only runs when nothing else matches, and each router gets one.
GoHighLevel workflow canvas with a Router action splitting into three branches, each ending in a Note action
The Router on the canvas with three branches: phone, email and a fallback.
GoHighLevel Router branch settings with Branch 3 set to the Fallback branch type and the note that each router can have one fallback branch
A Fallback branch runs only when no other branch matches. Each router can have one.

If/Else or Router: which one to use

If/ElseRouter
Branches that runOnly the first branch that matchesEvery branch that matches, left to right
When nothing matchesThe None branchThe Fallback branch (one per router)
Use it whenA contact should take one path onlyA contact can tick more than one box and every match needs its own steps

HighLevel's Router release note has more examples.

Step 11: Build by chat with Workflow AI

You don't have to drag every step in by hand. Open Workflow AI inside the builder. There are two tabs, Build and Chat. I'm on Build, and I type:

After the Send Email step, add a note that says Welcome email sent.

Workflow AI Build tab in the GoHighLevel builder after the request to add a note after the Send Email step, with a summary of the triggers and actions
Workflow AI adds a note after the email from one chat message, then sums up what it changed.

You can watch it work: understanding, planning, updating, checking. It thought for about 24 seconds, then added the note right after the email, between the email and the text. It also tells you what it changed and sums up the workflow.

Here's the habit I'd love you to keep: check its work, the same way you'd check anything AI wrote. Is it in the right place? Does it say what you asked? Here, yes and yes. HighLevel's Workflow AI Builder help article covers what else it can change, and my post on AI Builder using your account data shows a longer example.

Step 12: Test the workflow and read the logs

This is the step people rush, and the one that matters most.

  1. Click Test workflow, pick a contact and run it. I use one of my demo contacts.
  2. Open Execution logs. Here's every step that ran for that contact, with its status.
GoHighLevel execution log details for a Send Email step on a demo contact, with the event status Skipped because DND is on for all channels
Execution logs: the email to the demo contact was skipped because do not disturb is on.

The email and the text both say skipped, because do not disturb is on for all channels. That's exactly what I want. Nothing went out to anyone. The wait says waiting: it's listening for a reply on email and SMS, with a one day timeout.

Shorten the wait to see the whole path

You don't want to wait a whole day to see the rest. So:

  1. Remove the demo contact from the workflow in Enrollment history.
  2. Change the wait timeout to one minute, just for testing.
  3. Run the test again.

A minute later, the logs show the whole path. The wait times out. Has phone is true, because the contact has a number. Then the goal. Then the loop, with iteration one, two and three. Then the Router: branch one and branch two both ran, because the contact has a phone and an email. With If/Else, they'd only have got the first one. The fallback didn't run, because other branches matched. At the end, the contact is removed by end of workflow.

GoHighLevel execution logs listing every step for a demo contact, with the condition trace showing Phone is not empty evaluated as true for the Has phone branch
The condition trace in the logs shows exactly why the contact went down the Has phone branch.

The condition trace shows exactly why a contact went down a branch, so when something goes the wrong way, start there. On the contact's page you'll find the notes Call first, Email follow up and Welcome email sent, plus three tasks, Call attempt 1, 2 and 3, all assigned and due the next day.

Two warnings. A test runs the real steps. Those tasks and notes are really there now, so only test on your own contact or a demo one. And put the wait back to one day when you're done. A one minute timeout left in a live workflow would chase people far too fast.

If you want to test straight from the AI chat instead, see my post on Test workflow inside AI Builder.

Checklist before you publish

Here's the whole build again: a trigger with a filter; assign, tag, email and text; a wait for a reply; If/Else for leads with no phone; a goal for confirmed appointments; then the Loop and the Router. Before you publish your own, check three things:

  1. The trigger has a filter, so it only fires for the tag you meant.
  2. Your settings are right, especially re-entry.
  3. You've tested on a contact you own, read the logs, and put any test timeouts back.

Then switch it from draft to publish. Mine stays a draft. Once you've got a few workflows running, my free Workflow Clean-up Checklist helps you keep them tidy.

Beginner mistakes to avoid

Where to go next

For a deeper look at the new actions, read GoHighLevel Loop, Router and AI Agent Skills. When workflows get bigger, my Workflow Maps guide covers finding errors, and my Workflows API and MCP guide shows how to ask Claude what broke in a workflow. If you want Claude working inside your account, start with connecting Claude to HighLevel's official MCP server.

Not on HighLevel yet? You can sign up through my HighLevel link.

Affiliate disclosure: this is my affiliate link, so I may earn a commission if you sign up, at no extra cost to you.

Frequently Asked Questions

What are the three parts of a GoHighLevel workflow?

A trigger, actions and settings. The trigger is what starts it, like a form submitted or a tag added. Actions are what happens next, like sending an email, creating a task or waiting a day. Settings are the rules around it, like whether a contact can go through twice and who messages come from.

Why does my GoHighLevel workflow fire for every contact?

Usually the trigger has no filter. A Contact Tag trigger with no filter fires for every tag added to every contact in the account. Add a Tag added filter and pick one exact tag that nothing else uses.

What is the difference between If/Else and Router in GoHighLevel?

If/Else sends the contact down the first branch that matches, and anyone who matches nothing goes down None. Router sends the contact down every branch that matches, one after another, left to right. A Router can also have one Fallback branch that runs only when no other branch matches.

What does the Loop action do in GoHighLevel workflows?

Loop repeats the actions inside it, once for each item in a list or once for each number in a range. Set a range of 1 to 3 and the actions inside run three times. Use the Loop counter custom value to number each run. Only the steps inside the loop repeat.

How do I test a GoHighLevel workflow without messaging real people?

Test on your own contact or on demo contacts with do not disturb switched on for every channel. Email and text steps then show as skipped in the execution logs. A test still runs the real steps, so tags, notes and tasks are really created. Shorten any wait while testing and put it back afterwards.

Does a draft workflow run for anyone?

No. A draft doesn't run for anyone until you publish it, so you can build and test without affecting your contacts. You switch it from draft to publish when you are happy with it.

Want your GoHighLevel workflows built and tested properly?

I build GoHighLevel workflows, AI agents and automations for agencies and service businesses, and I test them on demo contacts before anything goes live. Email me at urooj.shafat292@gmail.com or use the contact form.

Sources