How to Use GoHighLevel Custom Values for Dynamic Images in Funnels
Learn how to dynamically replace images in GoHighLevel funnels using custom values. Includes JavaScript code, setup instructions, and use cases for client-specific branding.
The Problem with Static Images in GoHighLevel Funnels
GoHighLevel funnels are built with static image elements. You upload an image, it displays on the page, and every visitor sees the exact same thing. That works fine for most use cases, but it breaks down when you need images to change based on who is viewing the page.
Custom values in GHL let you personalize text content -- names, emails, company names, and custom fields -- anywhere that supports them. But image elements do not accept custom values. You cannot drop `{{contact.profileimage}}` or `{{customvalues.logo_url}}` into an image element's source field and have it work.
This is a problem for agencies managing multiple clients on the same funnel templates, businesses displaying personalized product images, or anyone who needs image content to adapt dynamically. The solution is a JavaScript snippet that reads an image URL from a custom value rendered in a hidden paragraph element and then swaps the source attribute on one or more image elements on the page.
How the Dynamic Image Replacement Works
The technique follows the same principle as custom value text replacement. GHL renders custom values in paragraph and headline elements before the page reaches the browser. By placing an image URL inside a custom value and dropping it into a hidden paragraph, you get a rendered URL in the DOM that JavaScript can read and use to update image elements.
Here is the flow:
1. A custom field stores the image URL for each contact (e.g., a logo URL, product image, or headshot).
2. A hidden paragraph element on the funnel page contains the custom value that outputs that URL.
3. When the page loads, GHL renders the custom value into the actual URL.
4. The JavaScript reads that URL from the hidden paragraph and sets it as the src attribute on your target image elements.
The Script
Here is the complete code:
1<script>2 /**************************3 * Copyright 2020 GHL Experts, All Rights Reserved4 * Author: Anas Uddin5 * Website: https://ghlexperts.com6 **************************/7 var imageURLid = '#paragraph-id'; // add selector for paragraph containing custom value.8 var images = ['#image-id']; // add in all the selectors ids for the images910 var imageURL = document.querySelectorAll(imageURLid + " div p")[0].innerHTML;11 images.forEach(image => {12 document.querySelector(image + " img").src = imageURL;13 });14</script>
The script does two things:
1. Reads the rendered image URL from the hidden paragraph element using innerHTML.
2. Loops through an array of image element selectors and sets each image's src attribute to that URL.
The images array accepts multiple selectors, which means you can update several image elements on the same page from a single custom value. This is useful when the same image (like a client logo) appears in multiple sections of the page.
Step-by-Step Setup Instructions
Step 1: Create a Custom Field for the Image URL
Before you can use a custom value for images, you need a custom field that stores the image URL.
1. In GoHighLevel, go to Settings > Custom Fields.
2. Create a new custom field. Name it something descriptive like "Client Logo URL" or "Profile Image URL."
3. Set the field type to Single Line Text (you are storing a URL, not uploading a file).
4. Save the field and note the custom value placeholder it generates, such as {{contact.client_logo_url}}logourl}}`.
Now populate this field for your contacts. You can do this manually, via CSV import, through a workflow, or through the API. The value must be a full image URL (e.g., https://yourdomain.com/images/client-logo.png).
Step 2: Add a Hidden Paragraph with the Custom Value
In your GHL funnel editor:
1. Add a Paragraph or Text element to the page.
2. Set the text content to your custom value placeholder: {{contact.client_logo_url}}logourl}}`
3. Do not add any other text or formatting -- just the custom value by itself. Extra characters will break the URL.
4. Hide the paragraph element. You can set its visibility to hidden in the element settings or use custom CSS:
1#paragraph-id {2 display: none;3}
Replace #paragraph-id with the actual element ID of your paragraph.
Step 3: Get Your Element IDs
You need the ID of the hidden paragraph and the IDs of every image element you want to update.
1. Click on the hidden paragraph in the funnel editor and note its element ID (e.g., paragraph-AbCdEfG).
2. Click on each image element you want to make dynamic and note their IDs (e.g., image-XyZ1234).
If the ID is not visible in the editor, preview the page in your browser, right-click the element, choose "Inspect," and find the id attribute on the wrapping div.
Step 4: Update the Script
Replace the placeholder selectors with your actual element IDs:
1var imageURLid = '#paragraph-AbCdEfG'; // your hidden paragraph ID2var images = ['#image-XyZ1234']; // your image element ID(s)
To update multiple images from the same URL, add more selectors to the array:
1var images = ['#image-XyZ1234', '#image-QrS5678', '#image-LmN9012'];
Step 5: Add the Script to Your Funnel Page
1. Open the funnel page settings in the GHL editor.
2. Navigate to the Tracking Code or Custom Code section.
3. Paste the script into the Body Tracking Code (footer) area so it runs after the page elements have loaded.
4. Save and publish.
Step 6: Test with a Real Contact
Custom values only render when the page is loaded through a contact-tracked link. To test:
1. Make sure your test contact has a valid image URL in the custom field.
2. Send yourself an email or SMS from a GHL workflow that links to the funnel page.
3. Click the tracked link and confirm that the image elements update with the custom URL.
Loading the page directly without a tracked link will leave the custom value unrendered, and the script will try to set the image source to the raw placeholder text, which will result in a broken image.
Use Cases for Dynamic Images
Client-Specific Branding on White-Label Funnels
This is the most common use case. Agencies using GHL's white-label features often build a single funnel template and reuse it across multiple clients. By storing each client's logo URL in a custom field, you can dynamically display the correct logo without maintaining separate funnels for every client.
Personalized Product Images
E-commerce or product-based businesses can store a product image URL tied to each contact's interests or purchase history. When the contact visits the funnel, they see an image of the product most relevant to them.
Team or Agent Headshots
Real estate teams, insurance agencies, and service businesses can display the assigned agent's headshot on landing pages. Each contact is assigned an agent in GHL, and the agent's photo URL is stored in a custom field.
Event-Specific Graphics
If you run multiple events or webinars through the same funnel, store the event banner URL in a custom field and swap it dynamically. One funnel template serves every event.
Dynamic Testimonial Images
Display a testimonial image that matches the contact's industry or use case. Store the relevant testimonial screenshot URL in a custom field based on the contact's segment.
Handling Multiple Different Images on One Page
The script as written uses a single URL for all image elements in the array. If you need different images in different places on the same page (e.g., a logo in the header and a product image in the body), set up two separate instances of the script with different paragraph sources and image targets:
1<script>2 // Logo image3 var logoURLid = '#paragraph-LogoParagraphID';4 var logoImages = ['#image-HeaderLogo', '#image-FooterLogo'];5 var logoURL = document.querySelectorAll(logoURLid + " div p")[0].innerHTML;6 logoImages.forEach(image => {7 document.querySelector(image + " img").src = logoURL;8 });910 // Product image11 var productURLid = '#paragraph-ProductParagraphID';12 var productImages = ['#image-HeroProduct'];13 var productURL = document.querySelectorAll(productURLid + " div p")[0].innerHTML;14 productImages.forEach(image => {15 document.querySelector(image + " img").src = productURL;16 });17</script>
Each instance reads from a different hidden paragraph and targets different image elements.
Troubleshooting
Image does not change: Verify that the hidden paragraph's element ID is correct and that the custom value renders a clean URL with no extra HTML tags, spaces, or formatting. Inspect the paragraph in the browser's developer tools to see exactly what text is inside the <p> tag.
Broken image icon appears: The URL stored in the custom field is either invalid, inaccessible, or contains extra characters. Check that the URL points to a publicly accessible image and does not require authentication.
Script errors in the console: The most common error is Cannot read property 'src' of null, which means the image element selector is wrong. Double-check your image element IDs.
Custom value shows as raw text: The page was not loaded through a tracked contact link. Custom values only render when GHL can identify the contact.
Summary
Dynamic images in GoHighLevel funnels are not supported natively, but this JavaScript workaround makes it straightforward. By storing image URLs in custom fields, rendering them through hidden paragraph elements, and using a short script to swap the image source, you can build funnels that adapt visually for each contact. This is particularly valuable for agencies running white-label funnels across multiple clients, businesses personalizing product imagery, and anyone who needs their funnel visuals to be as dynamic as their text content.
Want to try HighLevel?
If you're exploring marketing automation platforms, HighLevel offers a 30-day free trial.
Start your free trialJoin thousands of agencies using GoHighLevel to replace their entire marketing stack and boost recurring revenue.