How to Painlessly Customize HubSpot Landing Pages Using HubL

If you’ve ever used HubSpot before, you know that it has some of the most powerful sales and marketing capabilities on the planet. As a designer, HubSpot’s Design Manager offers an immense amount of freedom, giving you full access to the HTML/CSS that goes into each email/landing page. If you’re willing to dive into the code and use HubL markup, you can do almost anything in HubSpot that you can in a pure development environment.

Of course, not every person using the templates you make will have a web development background. Thankfully, HubSpot provides several easy-to-use ways to simplify customization for fellow (non-technical) editors.

Building custom modules

The most thorough way of building things the average (i.e. not a developer) person can change is by creating custom modules within HubSpot itself. Each custom module lives in its own file, flush with its own variables and parameters. They allow you to fully create components using your styles and a few options supplied by your teammates.

HubSpot Custom Module
HubSpot Custom Module

Sample code in a custom module looks like this:

<h1> {{widget.a_custom_header }} </h1>
<div id="custom-module-body">
    {% if widget.custom_image_module.src %}
        <img src="{{ widget.custom_image_module.src }}" 
        width="{{ widget.custom_image_module.width }}" 
        height="{{ widget.custom_image_module.height }}" 
        alt="{{ widget.custom_image_module.alt }}">
    {% endif %}
    <p>{{ widget.body_text }}</p>
{% if widget.related_content %}
    {{ widget.related_marketing_offers }}
{% endif %}

You can learn more about them here.

Quicker customization

If you don’t want to go through the hassle of creating a new custom module every time you want the client to be able to edit something, you have the power of HubSpot’s export_to_template_context functionality. Essentially, it allows you to configure custom-defined settings and variables for the page. You can then use the widget_data tag to retrieve these parameters, store them in variables, and/or incorporate them into your template’s logic.

You can read a brief overview about it here.

Getting creative

There’s a lot you can do when combining export_to_template_context and the control flow syntax in HubSpot. Here’s an example of a repeater that allowed us to inject our custom styles into a landing page with no external files:

{% set my_options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] %}

{% choice "repeats" label="Number of repeater modules to print", 
value="1", choices="{{ my_options }}", export_to_template_context=True %}

{% for options in my_options %}
    {% if loop.index <= widget_data.repeats.value %}
        <div class="Grid-cell u-md-size1of4" style="color:white;">
            {% text "repeated_info" label="Repeated info", unique_in_loop=True %}
            <div class="ty-break-line3 marginB-5"></div>
    {% endif %}
{% endfor %}

Here, we used the export_to_template_context functionality to allow the editor to set the number of elements in the repeater. Then, the for-loop creates modules based on the number set. Our code for each element rests inside the if-statement. Since we’ve already written the for-loop, we have free reign over the content we want for each element. Here, we write in the styles that we need using pure HTML. We then allow the editor to customize each element using the text module syntax. It’s important to note that we set the value for unique_in_loop to be true so the function doesn’t repeat the same value over and over again.


All in all, it’s incredibly easy to build user-friendly flows for non-technical editors using HubSpot’s powerful modular tools.

For more information, you can check out the HubL documentation here: