HubL Reference

Table of contents

Intro to HubL

The underlying syntax used in HubSpot's COS is referred to as HubSpot Markup Language or HubL (pronounced "Hubble"). While this templating language is based on the templating engine Jinja, HubL uses a fair amount of markup that is unique to HubSpot and does not support all features of Jinja.

This article will take you through the basics of HubL's features and syntax. Bear in mind that this is an introductory doc, and that the subsequent reference articles will explain the various features of HubL in much greater detail.

Types of delimiters

Similar to other commonly used templating languages such as PHP, HubL can be mixed into your HTML in coded templates files or HubL template modules. In order to demarcate, where your HubL starts and ends, you will need to learn a few key symbols that act as delimiters.

{% %} - statement delimiters
{{ }} - expression delimiters
{# #} - comment delimiters


HubL statements are used to create editable modules, define conditional template logic, set up for loops, define variables, and more. Statements are delimited by "{%". 


Expressions print values stored in the context of the template. Expressions are delimited by "{{". For example a variable must be defined as a statement, but then a HubL expression would be used to print the variable.


The final type of delimiter that you may encounter or decide to employ, while developing with HubL, is a HubL comment. Comments are defined by a "{#". 


Modules are dynamic areas of a template that can be customized by the end user in the content editor. For example, if you were coding a template file from scratch, you would create modules with HubL tags, to give your content creators the ability to edit areas of the page.

Module tags are made up of the following components:

  • Type of module 
  • A unique name for that module
  • Parameters (optional) 
{% text "simple_section_title" label='Enter text for this section title', value='This is a section title' %}

<span id="hs_cos_wrapper_simple_section_title" class="highlight hs_cos_wrapper hs_cos_wrapper_widget hs_cos_wrapper_type_text"

style="" data-hs-cos-general-type="widget" data-hs-cos-type="text">

This is a section title


The example above is a text module with label and value parameters defined. Label defines the help text in the editor and value sets the default text for that module. 

You can learn more about module syntax, here. You will find a complete list of all module types and their parameters, here. 

Variables and macros

HubL includes many predefined HubSpot variables that print their helpful values from the app. In addition, you can define your own variables in a template. In the following example, a variable named primaryColor is defined in a statement and then printed with a HubL expression. This example mixes the HubL variable with CSS. 

{% set primaryColor = '#F7761F' %} {# defines variable and assigns HEX color #}
a {
color: {{ primaryColor }}; {# prints variable HEX value #}
     a {

HubL macros allow you to print multiple statements with a dynamic value. This technique proves useful when you find yourself writing the same basic code blocks over and over, but only need to change certain values. In the following example, a macro is used to print a CSS3 transition property that includes all the vendor prefixes. You can learn more about macros, here

{% macro trans(value) %} 
-webkit-transition: {{value}};
-moz-transition: {{value}};
-o-transition: {{value}};
-ms-transition: {{value}};
transition: {{value}};
{% endmacro %}

a {
{{ trans('all .2s ease-in-out') }}

a {

-webkit-transition: all .2s ease-in-out;
-moz-transition: all .2s ease-in-out;
-o-transition: all .2s ease-in-out;
-ms-transition: all .2s ease-in-out;
transition: all .2s ease-in-out;


Filters and functions

Filters can be added to your HubL to transform or alter the value of a template variable. A simple example displayed below is formatting a date variable. Filters use a | (pipeline symbol) and are applied without spaces to a variable.

In the example below, assume a blog post was published on the 29th of April. The publish date of the post is reformatted with a datetimeformat filter. You can view a full list of filters here.

{{ content.publish_date_local_time|datetimeformat('%B %e, %Y') }} 

April 29, 2015


While filters affect how variables render, functions process value and account information and render that info. For example, a function can be used get the total number of posts for a particular blog or to lighten/darken a color variable by a particular amount.

The example would prints the total number of blog posts from the It uses a Blog ID (available in the URL of the blog dashboard) parameter to specify which blog to target. You can view a full list of functions here.

{{ blog_total_post_count(359485112) }}

If statements

If statements allow you to use conditional logic to dictate how your template will render.  Conditional logic in HubL statements for "if", "elif", "else", and "endif". An if statement must begin with with an "if" and end with an "endif". In this article, you can read more about if statements.

The example below defines a choice module that lets the end user select a department from a dropdown. Depending on what the user selects in the editor, the template will generate a dynamic heading for a careers page. This example requires the use of the export_to_template_context parameter, which you can learn more about here

{% choice "department" label='Choose department', value='Marketing', choices='Marketing, Sales, Dev, Services' export_to_template_context=True %}
{% if widget_data.department.value == 'Marketing' %}

<h3>Want to join our amazing Marketing team?!</h3>
<h4>We have exciting career opportunities on the {{ widget_data.department.value }} team.</h4>

{% elif widget_data.department.value == 'Sales' %}

<h3>Are you a Sales superstar?</h3>
<h4>We have exciting career opportunities on the {{ widget_data.department.value }} team.</h4>        
{% elif widget_data.department.value == 'Dev' %}
<h3>Do you love to ship code?</h3>
<h4>We have exciting career opportunities on the {{ widget_data.department.value }} team.</h4>
{% else %}
<h3>Want to work with our awesome customers?</h3>
<h4>We have exciting career opportunities on the {{ widget_data.department.value }} team.</h4>
{% endif %}      
Please note that conditional logic written in templates can only be based on information available at the template level, not information from the contacts database. To change the way that a page renders for a particular contact, use smart content.

For loops

For loops allow you to iterate over items stored in a sequence. They will most commonly be used with rendering blog content in a listing format. For loops begin with a "for" statement and end with an "endfor" statement.

In the example below, an array of types of bears is stored as a variable called "bears". A for loop is then used to iterate through the different types of bears printing a list item for each type. You can learn more about for loops, here

{% set bears = ['panda bear', 'polar bear', 'black bear', 'grizzly bear', 'koala bear'] %}

<h1>Types of bears</h1>;
{% for bear in bears %}
<li>{{ bear }}</li>
{% endfor %}

<h1>Types of bears</h1>
<li>panda bear</li>
<li>polar bear</li>
<li>black bear</li>
<li>grizzly bear</li>
<li>koala bear</li>

Other HubL features

Below are a few other miscellaneous templating features that may be useful, as you develop with HubL.

Escaping HubL delimiters

Many other languages share the same delimiters as HubL, which can create issues when working in coded files on the COS. If you want to use a HubL delimiter for a different language, you need to wrap that code in:

{% raw %} {{Code you want to escape}} {% endraw %}

Including files in files

You can include multiple .html files in one HubL template using the include tag. In order to create a HTML file that does not require the standard template variables, you must uncheck the option "Make template available for new content." Global groups can be included by copying the ID of the group from the Design Manager URL, and including it from the directory: generated_global_groups. The syntax is displayed below:

{% include "custom/page/web_page_basic/my_footer.html" %}
{% include 'generated_global_groups/2781996615.html' %}
{% include "hubspot/styles/patches/recommended.css" %}

You can also compile multiple CSS files into a single CSS file with the same include tag. When you publish the parent file, the child file will be compiled into a single minified CSS file with the parent's code. Please note that if you compile multiple CSS files into a single file, in order for your changes to take effect, you need to republish the parent file after making changes to the child file.

Blocks and extends

Finally, a more advanced trick that can be used when creating complex templates is to create compartmentalized blocks that extend a master template. You can create a master template that includes the require standard_header_includes and standard_footer_includes variables. Within that template, you need to define a unique block using the following syntax where my_sidebar is a unique name:
{% block my_sidebar %}{% endblock %}

Next, you can create a child HTML file that will populate that block. First you must declare what an extends statement that references the path to the parent. This block of code would be rendered in the master template, but maintained in another smaller and more manageable file. This technique is not for everyone, but can be useful when to stay organized when coding complex email or page templates.  When using this technique, you should choose the child template, when creating content.

{% extends "custom/page/web_page_basic/my_template.html" %}
{% block my_sidebar %}
<h3>Sidebar title</h3>
<li>Bullet 1<li>
<li>Bullet 2<li>
<li>Bullet 3<li>
{% endblock %}