<img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=1639164799743833&amp;ev=PageView&amp;noscript=1">
Diagram Views

Correcting SEO Issues in the HubSpot CMS

AJ LaPorte
#Digital Marketing, #SEO, #Tutorials, #HubSpot
Published on January 11, 2019
SEO report

If you are using HubSpot's CMS you may have noticed when using SEO Audit Tools such as SEMRush and Moz that your site has some metadata issues when it comes to listing pages and dynamic pages. We're going to look at how to fix these isssues through the magic of HubL and JavaScript.

If you are using HubSpot's CMS you may have noticed when using SEO Audit Tools such as SEMRush and Moz that your site has some metadata issues when it comes to listing pages such as dynamic pages via HubDB or blog listing pages. While HubSpot does offer SEO options inside of its page editor under the Settings Tab, and some global settings in the Settings area, when it comes to listing pages (and dynamic pages), the options simply don’t exist or are not granular enough to remedy these issues. Luckily for us, with the use of HubL, JavaScript, and Custom Modules we have the ability to fix them.

A quick note: We'd like to point out that we have talked with HubSpot and they are aware of the following issues we are going to discuss. They are also actively working on implementing a short-term fix for these issues with plans to expand on the functionality later! Currently, there is no timeline available for this update but as soon as we catch wind of one, we will make sure to update this article.

Update (1/15/2019): HS is working on adding in fields for dynamic pages to the hubdb tables that utilize dynamic pages. This would allow you to add in info to columns for Meta Desc, Featured Image URL, and Canonical URL.

Update (2/4/2019): HubSpot has released an update for dynamic pages in hubdb. There are now fields available for Meta Description, Featured Image, and Canonical URL in dynamic tables that you can map too. See step 1 in their dynamic page tutorial.

Already know about SEO Platforms and simply want to get into how we fix this issue? Jump to our solution section.

How do SEO Software Platform Audits Work?

SEO Platforms such as SEMRush and Moz deploy crawlers to a specified domain that crawl the page’s source code. I recently had some conversations with support people at Moz and SEMRush and they confirmed that their crawlers are not able to render JavaScript before crawling so this can cause additional errors to pop up that may otherwise actually be fixed. 

When these crawlers finish running on your selected domain they will return an audit of the site that provides marketers (and developers) with a list of issues that should be fixed in order to be more in line with SEO best practices and increase the SEO value of the site. Below is a sample from SEMRush’s site audit dashboard and Moz’s site issues.

SEMRush Dashboard from https://www.semrush.com/kb/540-site-audit-overview
SEMRush Dashboard from https://www.semrush.com/kb/540-site-audit-overview
moz-site-audit-dashboard
Moz Dashboard from https://moz.com/products/pro/site-crawl

We’ll be using both of these tools throughout this article for different aspects as it pertains to the HubSpot CMS. Both tools offer great reporting and, where one lacks, the other usually offers a solution. 

What issues will we be focusing on?

Both tools report on issues differently and as we stated have their own beneficial feature sets. We will be using each tool as identified below for the following issues:

  • Duplicate Meta Titles (SEMRush)
  • Duplicate Meta Descriptions (SEMRush)
  • Missing Canonicals (Moz)

The reason we are using SEMRush for our Meta Titles and Meta Descriptions is that this tool allows you to exclude parameters in its crawl. When using the HubSpot CMS and interlinking pages, sometimes URL parameters may exist and this could cause the systems to treat URLs such as /contact and /contact?hsid=1 as different URLs when they are in fact the same. Without excluding parameters, we might see a large increase in errors that could actually be false positives.

We are going to use Moz for our canonical check as Moz reports on missing canonicals on pages where as SEMRush does not (they only report for AMP pages missing canonicals). For those not familiar with canonicals or what they are, Moz has an awesome article about this.

Duplicate Meta Titles and Duplicate Meta Descriptions

Back in March (2018) Joost de Valk (the creator of the extremely popular Joost SEO WordPress Plugin) proposed a question to John Muller, Webmaster Trends Analyst at Google, regarding listing pages having the same meta descriptions and Google Search Console’s warning about them.

While this may seem like no big deal when it comes to listing pages, it’s important to note that Google’s Content Guidelines still mention and recommend using quality descriptions with clearly tagged facts that can differentiate each page. So why not make them more useful for those looking to search a site?! This could be a simple identifier in the Page Title and Meta that show the page number which would then fix these issues for the listing pages.

The other page type we need to account for is HubDB’s Dynamic Pages ability. If you are unfamiliar with HubDB or Dynamic Pages, we recommend reading up on their developer documentation:

The Meta Titles for each page can be controlled through HubDB’s Page Title field while the Meta Descriptions are currently inherited from the page in which the HubDB loop is on. For example, lets take a look at a “Meet the Team” page from a totally-real-and-not-created-for-a-demo site.

Dynamic Listing Page with Meta Description shown in Inspector
Dynamic Listing Page with Meta Description shown in Inspector
Dynamic Page with same Meta Description from listing page shown in Inspector
Dynamic Page with same Meta Description from listing page shown in Inspector

As you can see, this page is served with the same Meta Description as our previous page. In theory, this seems like a great idea, as we don’t need to come up with one and instead can rely on Google to either use it or pull one from our text. In reality, we would probably want to control what Google would show or at least provide a better description for it.

Canonical URLs for listing pages

There are a lot of places to get information on how to go about setting up canonicals for listing pages (also known as paginated content). One source we are going reference for our implementations is from Search Engine Journal (SEJ) and their article SEO Friendly Pagination: A Complete Best Practices Guide.

For those not familiar with the canonical settings inside of HubSpot, you get the following options to choose from:

Canonical options in HubSpot's settings
Canonical options in HubSpot's settings

HubSpot hits the nail on the head in the Pages and Blog Posts section. However, the Blog Listing Pages area gives you two options, which according to SEJ, are options that you would not want to do especially since HubSpot makes use of the proper rel=next and rel=prev tags. We encourage you to read the article from SEJ about pagination and SEO, but if you’re like me and would rather have the cliff notes, here they are for the options shown above.

Set the blog listing page’s canonical URL to the first page in its series

This is a common mistake and if the site makes use of proper rel tags, it's unnecessary to do. This could lead to the search engine thinking you have only one page of search results. Then, Google wouldn't index pages further in the series or acknowledge signals from them.

Don’t add canonical URLs to any blog listing pages (Recommended)

While Google reference about Indicating paginated content to Google says one of things you can do is nothing, you would be playing a game of odds when doing this. In doing nothing, you are relying on Google to use the best judgement and simply crossing your fingers that Google will work it out on its own. When it comes to your SEO, wouldn’t you want to be on the safe side and know you are providing as much direction as you can to Google to aid in your SEO?!

How can we fix these issues?

While HubSpot may not have simple click and set options to go about fixing up these issues, but with the use of HubL, JavaScript, Custom Modules, and the power of Greyskull we can correct these issues. Now, one thing that may have seemed off was the use of the word JavaScript. Don’t worry, at first I was thinking to myself “this wont work” but as it turns out, Google can render JavaScript when crawling your pages (Source: Search Engine Land). Search Engine Land’s article goes over some JavaScript tests they ran with Googlebot (Googles crawler) and their conclusion was that Google can read meta tags and information inserted via JavaScript.

So with that, let’s begin our adventure into the HubSpot Design Manager and get cranking.

Fixing the Listing Pages

Once you’re in the design manager go into our blog template and expand the “Additional Markup” area located in the right-hand options pane. This should open up to a code editor view. In our code we are going to be using four variables that can be found inside of our Developer Info View along with one HubL filter, these items are:

Variables:

  • is_listing_view - checks if the page is a listing view such as blog listing page
  • canonical_url – gives you the absolute URL of the page you are on
  • current_page_number – when on a listing page, this is the current number of paginated view
  • content.meta_description – the current meta description for the page

Filter:

  • escapejs – escapes strings so they can be safely inserted in JavaScript

Don’t need a walkthrough of the code? Skip to the full code.

We’re going to begin by using an if statement coupled with the is_listing_view variable to make sure that our code gets placed on listing pages of our HubSpot Site.


<!-- `is_listing_view` is a HubL variable in the developer info pane that checks if the page is a listing view such as blog listing page -->
{% if is_listing_view %}

{% endif %}

Next, we are going to add in the canonical_url variable so we can make sure to set the canonical on each page. Remember, this variable is already populated by HubSpot inside of the developer info and currently doesn't show on listing pages per the recommended setting for the listing pages.


{% if is_listing_view %}

	<!-- Add Canonical to paginated pages, topics, authors, and main blog listing page -->
	<link rel="canonical" href="{{canonical_url}}">

{% endif %}

That takes care of our pages no longer having a canonical URL and we should begin to see the errors inside of Moz clear up during the next run of their scan. Let's continue on and take care of those SEMRush issues now. For this, we need a nested if statement that will check to make sure we are on a paginated page (such as page 2 or 3) of a listing using the current_page_number variable. We don't need to worry about accounting for page 1 as we already know page 1 will have the meta description and titles populated.


{% if is_listing_view %}

	<link rel="canonical" href="{{canonical_url}}">
	
	<!-- Nested IF statement. -->
 	{% if current_page_num > 1 %}

	{% endif %}
	<!-- /Nested IF Statement -->

{% endif %}

Our next step is make sure we are making the meta descriptions and titles unique as to avoid getting the duplicate errors in SEMRush. This is where we can rely on good ol' JavaScript to assist us along with using our current_page_number and content.meta_description variables plus our escapejs filter.


{% if is_listing_view %}

	<link rel="canonical" href="{{canonical_url}}">

 	{% if current_page_num > 1 %}
		<script>
	    //Append page num to title so you don't have duplicate title tags
	    document.title += " | Page {{current_page_num}}";
	    // Replace Current Meta Description with new one that appends page num before it.
	    document.querySelector('meta[name="description"]').setAttribute("content","Page {{current_page_num}} - {{content.meta_description|escapejs}}");
  		</script>

	{% endif %}

{% endif %}

Below is the full solution with commented code:


<!-- `is_listing_view` is a HubL variable in the developer info pane that checks if the page is a listing view such as blog listing page -->
{% if is_listing_view %}

	<!-- Add Canonical to paginated pages, topics, authors, and main blog listing page -->
	<link rel="canonical" href="{{canonical_url}}">

	<!-- Nested IF statement. -->
 	{% if current_page_num > 1 %}
		<script>
	    //Append page num to title so you don't have duplicate title tags
	    document.title += " | Page {{current_page_num}}";
	    // Replace Current Meta Description with new one that appends page num before it.
	    document.querySelector('meta[name="description"]').setAttribute("content","Page {{current_page_num}} - {{content.meta_description|escapejs}}");
    
  		</script>

	{% endif %}
	<!-- /Nested IF Statement -->

{% endif %}
<!-- /End listing view IF -->

You can take this one step further and make this into its own custom module. If you plan to go that route, make sure when referencing the module in the "Advanced Markup" area you add the no_wrapper=True parameter to the modules template tag or it will fail to load properly.

If you have any questions or comments, please feel free to drop them in the comments section below. We'd love to hear from you! Likewise, don't forget to join the HubSpot Developer Slack Group where things like this and more are discussed round the clock.

Photo by Webaroo.com.au on Unsplash