<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Smuves</title>
    <description>The latest articles on DEV Community by Smuves (@smuves).</description>
    <link>https://dev.to/smuves</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3760959%2Fcbed3c17-5b5e-4586-bde8-8994ff1d7002.jpeg</url>
      <title>DEV Community: Smuves</title>
      <link>https://dev.to/smuves</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/smuves"/>
    <language>en</language>
    <item>
      <title>How We Built a Module Audit Script for a 166-Component HubSpot Site</title>
      <dc:creator>Smuves</dc:creator>
      <pubDate>Thu, 16 Apr 2026 04:25:01 +0000</pubDate>
      <link>https://dev.to/smuves/how-we-built-a-module-audit-script-for-a-166-component-hubspot-site-4p5j</link>
      <guid>https://dev.to/smuves/how-we-built-a-module-audit-script-for-a-166-component-hubspot-site-4p5j</guid>
      <description>&lt;p&gt;When a team tells you their HubSpot site has about 40 modules, and the actual count turns out to be 166, the first problem is not cleaning it up. The first problem is just figuring out what is there.&lt;/p&gt;

&lt;p&gt;This post is about the audit script we built to answer that question. Not a polished product. Just a script that ran against the HubSpot Design Manager and the CMS API and spit out a CSV we could actually work from.&lt;/p&gt;

&lt;p&gt;If you are staring at a HubSpot portal that has accumulated years of components and nobody on the current team remembers what half of them do, this is the approach that got us to a consolidation map.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Design Manager UI is not enough
&lt;/h2&gt;

&lt;p&gt;HubSpot's Design Manager shows you a list of modules. You can click into each one, see the fields, see the template that renders it, and get a sense of what it was built for.&lt;/p&gt;

&lt;p&gt;What it does not show you is usage. There is no native "where is this module referenced" view. If you want to know whether a module is live on any page or if it is just sitting in the library unused, you have to cross-reference against every page, every blog post, every email template, and every landing page that could possibly use it.&lt;/p&gt;

&lt;p&gt;For 40 modules that is annoying. For 166 modules it is a week of work.&lt;/p&gt;

&lt;p&gt;That is the gap the script filled. Pull the full module list via the API, pull the full page list, cross-reference them, and output a single file that tells you which modules are actually in use and which are orphaned.&lt;/p&gt;

&lt;p&gt;We wrote about why this kind of sprawl happens in the first place in &lt;a href="https://www.smuves.com/blog/the-cms-nobody-owns" rel="noopener noreferrer"&gt;this breakdown of CMS governance gaps&lt;/a&gt;. The short version is that nobody owns the component library in most companies, so new modules get added faster than old ones get retired. Over a few years you end up with five banner variants that do the same thing.&lt;/p&gt;

&lt;p&gt;The script does not solve that problem. It just makes the mess visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step one: Pulling the module list
&lt;/h2&gt;

&lt;p&gt;The HubSpot CMS API has an endpoint for design manager assets. You hit &lt;code&gt;/cms/v3/source-code/published/content&lt;/code&gt; with the right scope and you get back the module definitions, including the HubL name, the fields, the created date, and the last modified date.&lt;/p&gt;

&lt;p&gt;The pagination is standard. Page through until you get an empty response. Dump everything into a list of dicts, one per module.&lt;/p&gt;

&lt;p&gt;A few things to extract for each module:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The HubL name (this is the identifier you will use to grep against page source)&lt;/li&gt;
&lt;li&gt;The module label (what shows up in the Design Manager UI)&lt;/li&gt;
&lt;li&gt;The field list (what inputs the module accepts)&lt;/li&gt;
&lt;li&gt;The template path&lt;/li&gt;
&lt;li&gt;The created and last modified timestamps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one is more useful than it sounds. A module that has not been modified in four years and was built by a developer who no longer works at the company is a very different candidate for consolidation than one that was updated last quarter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step two: Pulling the page and post inventory
&lt;/h2&gt;

&lt;p&gt;You need the full list of anywhere a module could be used. For a typical HubSpot portal that means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Site pages&lt;/li&gt;
&lt;li&gt;Landing pages&lt;/li&gt;
&lt;li&gt;Blog posts&lt;/li&gt;
&lt;li&gt;Email templates&lt;/li&gt;
&lt;li&gt;Drag-and-drop templates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Pages API and the Blog Posts API both return the serialized layout data for each page. Inside that layout data are module references, usually by HubL name. This is the thing you want to grep against.&lt;/p&gt;

&lt;p&gt;Pull everything, paginate through it, and dump the layout JSON for each page into a local store. For large portals this takes a while. The portal we audited had around 32,000 pages, so we ran this in batches and cached aggressively.&lt;/p&gt;

&lt;p&gt;One gotcha. Some pages reference modules inline via HubL in custom templates, not through the drag-and-drop layout. If you only look at the layout JSON you will miss those. You also need to pull the template source and grep for module tags there. Something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;

&lt;span class="n"&gt;HUBL_MODULE_PATTERN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{%\s*module\s+[\'&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;]?([a-zA-Z0-9_\-]+)[\'&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;]?&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IGNORECASE&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;extract_module_refs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template_source&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HUBL_MODULE_PATTERN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template_source&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That regex is not bulletproof but it caught enough of the inline references to be worth including.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step three: Cross-referencing
&lt;/h2&gt;

&lt;p&gt;Now you have two things. A list of modules that exist. And a list of pages, posts, and templates with the modules they reference.&lt;/p&gt;

&lt;p&gt;The cross-reference is just a lookup. For every module in the library, check whether its HubL name appears in any page layout or template source. Build a usage map.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;defaultdict&lt;/span&gt;

&lt;span class="n"&gt;usage_map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defaultdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;all_pages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;module_ref&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;module_refs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;usage_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;module_ref&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;page_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;page_url&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;page_type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;all_modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hubl_name&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;usage_map&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;orphaned&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usage_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hubl_name&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;single_use&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;active&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three buckets. Orphaned (not referenced anywhere, deletion candidate). Single-use (referenced on exactly one page, probably consolidation candidate). Active (referenced on multiple pages, needs more careful review).&lt;/p&gt;

&lt;p&gt;For the 166-module portal, the breakdown was rough as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;58 orphaned modules (not referenced anywhere in the current site)&lt;/li&gt;
&lt;li&gt;31 single-use modules (most were custom builds for specific landing pages)&lt;/li&gt;
&lt;li&gt;77 active modules (referenced across multiple pages)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That 58 number was the first real "oh" moment. A third of the library was dead code. Nobody had known because nobody had looked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step four: Similarity detection
&lt;/h2&gt;

&lt;p&gt;The harder question is not which modules are unused. It is which modules are duplicative.&lt;/p&gt;

&lt;p&gt;This is where the field list comparison becomes useful. If two modules have near-identical field schemas (same field names, same types, same structure), they are probably doing the same thing even if they have different names.&lt;/p&gt;

&lt;p&gt;The approach we used was a simple Jaccard similarity on field signatures.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;field_signature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;frozenset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;jaccard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;similarity_pairs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mod_a&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;mod_b&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]:&lt;/span&gt;
        &lt;span class="n"&gt;sig_a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;field_signature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mod_a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sig_b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;field_signature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mod_b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;jaccard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sig_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sig_b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;similarity_pairs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;mod_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mod_b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any pair with a similarity score above 0.8 is worth a human review. The script does not decide they are duplicates. It flags them for a person to look at.&lt;/p&gt;

&lt;p&gt;When we ran this against the 166-module portal, we got 43 similarity pairs above the threshold. After manual review, 31 of those pairs turned out to be true duplicates that could be consolidated. The rest were intentional variants with meaningful differences.&lt;/p&gt;

&lt;p&gt;This is where automation stops being useful. A script can tell you two modules have the same field schema. It cannot tell you whether one renders a rounded button and the other renders a square button, or whether one has a max-width constraint and the other does not. That review has to happen in a browser with a real human looking at the output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step five: The consolidation map
&lt;/h2&gt;

&lt;p&gt;The output of all this is a single CSV with one row per module. Columns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Module name&lt;/li&gt;
&lt;li&gt;Usage status (orphaned, single_use, active)&lt;/li&gt;
&lt;li&gt;Usage count&lt;/li&gt;
&lt;li&gt;List of pages where it is referenced&lt;/li&gt;
&lt;li&gt;Similar modules flagged for review&lt;/li&gt;
&lt;li&gt;Consolidation recommendation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last column is the one that actually drives decisions. For each module, a human reviews the data and marks it as one of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep (this is a canonical version, keep it as-is)&lt;/li&gt;
&lt;li&gt;Merge into X (this is duplicative of module X, migrate all references and delete)&lt;/li&gt;
&lt;li&gt;Delete (orphaned or deprecated, safe to remove)&lt;/li&gt;
&lt;li&gt;Review (unclear, needs more investigation)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the 166-module portal, the final breakdown was 40 keeps, 78 merges, 35 deletes, and 13 reviews that got resolved in follow-up discussions. 166 modules became 40. Same rendered output on every live page.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the script cannot do
&lt;/h2&gt;

&lt;p&gt;The audit script is a discovery tool, not a decision tool. It tells you what is there. It does not tell you what should be there.&lt;/p&gt;

&lt;p&gt;The consolidation decisions still require human judgment. Is this module still needed for campaigns that happen twice a year? Does the marketing team have plans to use it in Q4? Is the styling intentional or is it drift?&lt;/p&gt;

&lt;p&gt;The script also does not handle the actual migration. Once you decide module A should be merged into module B, you still have to update every page that references A, swap it for B, and test that the page renders correctly. That is a separate piece of tooling.&lt;/p&gt;

&lt;p&gt;What the script does is shrink the decision space. Instead of staring at 166 modules and trying to figure out where to start, you have a ranked list of candidates with usage data attached. You can work through it systematically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Would we open source it?
&lt;/h2&gt;

&lt;p&gt;Probably not. The script is too tightly coupled to the specific project we built it for, and rewriting it to be generically useful would take more effort than the value justifies for a standalone tool.&lt;/p&gt;

&lt;p&gt;But the approach is the important part, not the code. If you are facing a similar audit, the steps are straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pull the full module inventory via the API&lt;/li&gt;
&lt;li&gt;Pull the full page and template inventory via the API&lt;/li&gt;
&lt;li&gt;Cross-reference to build a usage map&lt;/li&gt;
&lt;li&gt;Run similarity detection on field signatures&lt;/li&gt;
&lt;li&gt;Export the result as a flat CSV&lt;/li&gt;
&lt;li&gt;Review the CSV with a human who knows the site&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That process is what we are productizing at &lt;a href="https://www.smuves.com/blog/the-cms-nobody-owns" rel="noopener noreferrer"&gt;Smuves&lt;/a&gt; as part of our migration tooling. The goal is to make this kind of audit something a marketing ops person can run in an afternoon, not something that requires writing a custom script every time.&lt;/p&gt;

&lt;p&gt;The underlying problem is not hard. It just requires someone to actually look at the library.&lt;/p&gt;

</description>
      <category>hubspot</category>
      <category>webdev</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Nobody Governs the Components. That Is the Problem.</title>
      <dc:creator>Smuves</dc:creator>
      <pubDate>Tue, 14 Apr 2026 10:37:02 +0000</pubDate>
      <link>https://dev.to/smuves/nobody-governs-the-components-that-is-the-problem-2p0m</link>
      <guid>https://dev.to/smuves/nobody-governs-the-components-that-is-the-problem-2p0m</guid>
      <description>&lt;p&gt;Here is something that does not show up in any sprint review or quarterly roadmap: the slow accumulation of duplicate components on a website that has been running for more than three years.&lt;/p&gt;

&lt;p&gt;It starts innocently. A developer builds a banner module in 2019 for a campaign landing page. It works, it ships, everyone moves on. The next year, a different developer joins the team and needs a banner for a product page. They do not know the 2019 banner exists, or they find it but it does not support the CTA button they need. So they build a new one. By 2022, a third developer creates "Banner v3" because the first two do not handle responsive images the way the new design system requires.&lt;/p&gt;

&lt;p&gt;Nobody is doing anything wrong. Each decision makes sense in isolation. But zoom out and look at the full module inventory three years later, and the picture is different.&lt;/p&gt;

&lt;p&gt;This is component sprawl. And in CMS platforms like HubSpot, it is almost invisible until something forces you to look at the whole system at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why CMS platforms make this worse
&lt;/h2&gt;

&lt;p&gt;Traditional web applications have build systems, component libraries, design systems, linting rules, and import patterns that naturally surface duplication. If two React components do the same thing, there is a decent chance someone will notice during a code review or a dependency audit.&lt;/p&gt;

&lt;p&gt;CMS platforms work differently. Modules in HubSpot are created through the Design Manager or the CLI, and they live in a flat list. There is no built-in dependency graph. There is no tool that says "this module is functionally identical to that one." There is no component registry that developers check before building something new.&lt;/p&gt;

&lt;p&gt;The result is predictable. A site that has been actively maintained for four or five years ends up with three different accordion modules, four hero sections, five banner variants, and two footer components that produce identical output.&lt;/p&gt;

&lt;p&gt;We have seen this firsthand. During &lt;a href="https://www.smuves.com/blog/what-a-cms-audit-actually-reveals-before-you-migrate-a-single-page" rel="noopener noreferrer"&gt;a recent content architecture audit&lt;/a&gt;, a large enterprise HubSpot site turned out to have 166 modules. The team responsible for the site estimated they had about 40. That is not a rounding error. That is a four-to-one gap between perception and reality.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trigger that makes it visible
&lt;/h2&gt;

&lt;p&gt;In daily operations, module sprawl causes no immediate symptoms. Pages render. Content editors can still publish. The design looks right to visitors. Nobody has a reason to count the modules.&lt;/p&gt;

&lt;p&gt;The trigger is almost always a migration or a major redesign. The moment someone needs to map every component from the old system to a new one, the sprawl becomes a blocking problem.&lt;/p&gt;

&lt;p&gt;Each duplicate module is a mapping decision. Each variant needs to be evaluated: is this meaningfully different, or is it the same thing with a slightly different field structure? Can three accordion components be consolidated into one configurable component, or do they serve genuinely different purposes?&lt;/p&gt;

&lt;p&gt;This is architecture work that teams expect to take days but ends up taking weeks, entirely because nobody maintained a clean inventory along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  What governance actually looks like
&lt;/h2&gt;

&lt;p&gt;Component governance does not require complex tooling. It requires a process and a habit.&lt;/p&gt;

&lt;p&gt;At minimum, it means maintaining a living inventory of every module in your CMS. Not in someone's head. Not in a wiki that was last updated eighteen months ago. An actual, current list that developers reference before building anything new.&lt;/p&gt;

&lt;p&gt;It means having a rule: before creating a new module, check the existing inventory. If something similar exists, extend it. If the existing module cannot handle the new use case, document why a new one is needed and who approved the decision.&lt;/p&gt;

&lt;p&gt;It means running periodic audits. Not waiting until migration day to discover you have five banners. Running a quarterly check that counts components, flags duplicates, and consolidates anything that has drifted.&lt;/p&gt;

&lt;p&gt;For HubSpot sites specifically, this is harder than it should be. HubSpot does not provide a single view of all modules with their usage data out of the box. Building that visibility usually requires pulling the data through the API or using a tool that can surface the full inventory.&lt;/p&gt;

&lt;p&gt;We wrote about the broader architecture problem, including how a 166-module site got consolidated down to 40 during a migration, on &lt;a href="https://www.smuves.com/blog/the-cms-nobody-owns" rel="noopener noreferrer"&gt;the Smuves blog&lt;/a&gt;. The consolidation process is worth understanding if you are working on a site that has been around long enough to accumulate this kind of debt.&lt;/p&gt;

&lt;h2&gt;
  
  
  The developer takeaway
&lt;/h2&gt;

&lt;p&gt;If you work on a CMS that has been in production for more than two years, assume you have more components than you think. Run the count. If the number surprises you, that is the signal to start governance now rather than during a future migration.&lt;/p&gt;

&lt;p&gt;The cost of counting and consolidating proactively is a fraction of the cost of discovering the sprawl when you are already committed to a migration timeline and budget.&lt;/p&gt;

&lt;p&gt;Component sprawl is a governance problem, not a technology problem. And governance problems only get solved when someone decides to start tracking.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>hubspot</category>
    </item>
    <item>
      <title>Your CMS Does Not Have a Spreadsheet View. Here Is Why That Matters.</title>
      <dc:creator>Smuves</dc:creator>
      <pubDate>Tue, 07 Apr 2026 04:02:02 +0000</pubDate>
      <link>https://dev.to/smuves/your-cms-does-not-have-a-spreadsheet-view-here-is-why-that-matters-2o8f</link>
      <guid>https://dev.to/smuves/your-cms-does-not-have-a-spreadsheet-view-here-is-why-that-matters-2o8f</guid>
      <description>&lt;p&gt;Open your CRM. Salesforce, HubSpot, Zoho .. it does not matter which one. You see rows, columns, filters. You can select 500 contacts and update a field in one click.&lt;/p&gt;

&lt;p&gt;Open your analytics dashboard. Whether it is GA4 or Mixpanel or Amplitude, you get tables, exports, and bulk selections. Every data point in front of you at once.&lt;/p&gt;

&lt;p&gt;Open your database client. Whether it is pgAdmin or TablePlus or any SQL tool, you can query, filter, and update thousands of records in a single statement.&lt;/p&gt;

&lt;p&gt;Now open your CMS.&lt;/p&gt;

&lt;p&gt;Want to see all your page titles in one place? You cannot. Want to update meta descriptions across 200 blog posts? Click into post one. Scroll down to the settings panel. Edit. Save. Click back. Click into post two. Repeat 200 times.&lt;/p&gt;

&lt;p&gt;This is not an exaggeration. This is Tuesday afternoon for most content teams.&lt;/p&gt;

&lt;p&gt;The gap nobody talks about&lt;br&gt;
Every data discipline has a spreadsheet view. It is so fundamental that nobody even thinks about it. When a sales ops person needs to clean up 1,000 contact records, they open a list, filter it, and edit in place. The tooling assumes bulk operations are a normal part of the job.&lt;/p&gt;

&lt;p&gt;CMS platforms do not make this assumption. They were built for one thing .. creating and editing individual pages. The entire interface is optimized for a single page at a time. Headings, body text, images, modules, settings. All scoped to one URL.&lt;/p&gt;

&lt;p&gt;That design works fine when you are building a five-page marketing site. It falls apart the moment you are managing a 200-page blog, a 50-page resource library, or a multi-language site with thousands of entries.&lt;/p&gt;

&lt;p&gt;The problem is not that the page editor is bad. It is that the page editor is the only tool you get.&lt;/p&gt;

&lt;p&gt;What a spreadsheet view actually means for content teams&lt;br&gt;
When we talk about a spreadsheet view for CMS content, we are not talking about exporting a CSV and reimporting it. That workflow exists, and it is painful. You lose formatting. You break relationships between content types. You introduce errors on reimport that take hours to debug.&lt;/p&gt;

&lt;p&gt;A real spreadsheet view means pulling your live CMS data into rows and columns where you can filter, sort, and edit ... then push changes back without the export-import dance.&lt;/p&gt;

&lt;p&gt;Imagine this workflow instead. You connect your HubSpot portal. You select "blog posts" as your content type. Every post appears as a row. Title, URL, meta description, featured image alt text, publish date, author,  all visible as columns. You spot 47 posts with missing meta descriptions. You write them directly in the cells. You push the updates back to HubSpot. Done.&lt;/p&gt;

&lt;p&gt;That is what we built at Smuves. A Google Sheets integration that treats your HubSpot CMS content like structured data instead of individual pages locked behind an editor.&lt;/p&gt;

&lt;p&gt;The find-and-replace problem makes this worse&lt;br&gt;
If you cannot see all your content in one view, you definitely cannot search across it. HubSpot has had an open community feature request for sitewide find-and-replace since 2017. Nearly a decade of users asking for the same thing. The official response has consistently been that this is not something the team is currently planning to build.&lt;/p&gt;

&lt;p&gt;Think about what that means for a content team going through a rebrand. You changed your product name. Or your company name. Or a partner brand name. You need to find every instance across every page, every blog post, every landing page, and replace it.&lt;/p&gt;

&lt;p&gt;Without a spreadsheet view, you are opening pages one at a time and using Ctrl+F inside each page editor. Without site wide find-and-replace, you do not even know which pages contain the old name until you manually check.&lt;/p&gt;

&lt;p&gt;We wrote about this exact problem in more detail in our breakdown of why CMS platforms still lack find-and-replace. The short version, it is a category problem, not a feature gap.&lt;/p&gt;

&lt;p&gt;Why CRM tooling evolved and CMS tooling did not&lt;br&gt;
CRM platforms figured this out early. The entire value proposition of a CRM is managing data at scale. Bulk actions, list views, filtered segments, mass updates, these were table stakes from day one.&lt;/p&gt;

&lt;p&gt;CMS platforms took a different path. They evolved from publishing tools. WordPress started as a blogging engine. HubSpot CMS grew out of a marketing platform. The mental model was always "create a page, publish a page." Maintenance at scale was never part of the original design.&lt;/p&gt;

&lt;p&gt;The result is a tooling gap that grows wider as your website grows larger. A 10-page site does not feel the pain. A 100-page site starts to feel it. A 1,000-page site is drowning in it.&lt;/p&gt;

&lt;p&gt;Content teams end up doing one of three things. They build internal scripts to interact with the CMS API (expensive and fragile). They hire freelancers to do the manual clicking (slow and error-prone). Or they just do not maintain their content. Pages accumulate outdated metadata. Alt text goes missing, Redirects pile up unmanaged.&lt;/p&gt;

&lt;p&gt;That third option is the most common. And it is how websites slowly decay without anyone noticing. We covered this pattern in our website hygiene playbook the slow accumulation of small problems that compound into real damage over time.&lt;/p&gt;

&lt;p&gt;The spreadsheet view as a content operations layer&lt;br&gt;
Here is where the thinking shifts. A spreadsheet view is not just a convenience feature. It is a content operations layer.&lt;/p&gt;

&lt;p&gt;When content lives in rows and columns, you can do things that are impossible in a page editor. You can sort all blog posts by publish date and spot gaps in your publishing cadence. You can filter by author and see who owns which content. You can compare meta descriptions side by side and catch duplicates instantly. You can run formulas to flag titles over 60 characters or descriptions under 120 characters.&lt;/p&gt;

&lt;p&gt;This is the same kind of data hygiene that every other team takes for granted. Sales ops cleans CRM data weekly. Analytics teams validate tracking parameters. Database administrators run integrity checks.&lt;/p&gt;

&lt;p&gt;Content teams deserve the same tooling. Not because they are technical, but because managing a website at scale is a data problem whether you call it that or not.&lt;/p&gt;

&lt;p&gt;What we are building at Smuves&lt;br&gt;
Smuves started because our founder was tired of editing HubSpot pages one at a time during a large website project. She built a Google Apps Script that pulled CMS content into a spreadsheet. It saved weeks of work.&lt;/p&gt;

&lt;p&gt;That script became a product. The product now handles bulk editing for pages, blog posts, redirects, tags, authors, and HubDB tables in HubSpot. Every edit is logged. Every change is reversible.&lt;/p&gt;

&lt;p&gt;The free tier lets you inspect and export your content. The Pro tier gives you full bulk editing and push-back capability. If you are managing more than 50 pages in HubSpot and you have never seen your content in a spreadsheet view, it is worth trying.&lt;/p&gt;

</description>
      <category>hubspot</category>
      <category>cms</category>
      <category>webdev</category>
      <category>bulkediting</category>
    </item>
    <item>
      <title>What a CMS Migration Audit Actually Revealed (32,000 Pages, 166 Modules, 57 Content Types)</title>
      <dc:creator>Smuves</dc:creator>
      <pubDate>Thu, 02 Apr 2026 04:05:18 +0000</pubDate>
      <link>https://dev.to/smuves/what-a-cms-migration-audit-actually-revealed-32000-pages-166-modules-57-content-types-5fbl</link>
      <guid>https://dev.to/smuves/what-a-cms-migration-audit-actually-revealed-32000-pages-166-modules-57-content-types-5fbl</guid>
      <description>&lt;p&gt;Most CMS migrations do not fail because of bad code. They fail because nobody looked at what was on the website before the project started.&lt;/p&gt;

&lt;p&gt;The team picks a new platform. They scope the work based on what they think exists. They write a statement of work, set a budget, hire developers, and begin building. Three weeks later, someone discovers the site has four times as many content types as the documentation said. Modules nobody knew existed. A localization structure that completely changes the architecture requirements.&lt;/p&gt;

&lt;p&gt;At that point, the budget is wrong. The timeline is wrong. The content model decisions made in week one are wrong. Everything built so far needs rework.&lt;/p&gt;

&lt;p&gt;This is not a rare scenario. It is the most common way CMS migrations go sideways. And the fix is straightforward: audit before you touch a single file.&lt;/p&gt;

&lt;p&gt;What "Auditing first" actually means&lt;br&gt;
A CMS audit before migration is not a content quality review. You are not checking whether your blog posts are well-written or whether your landing page copy converts.&lt;/p&gt;

&lt;p&gt;You are answering four structural questions:&lt;/p&gt;

&lt;p&gt;What content types actually exist on the site?&lt;br&gt;
What components and modules does the site use to display content?&lt;br&gt;
How does the site handle multiple languages, regions, or variations?&lt;br&gt;
What percentage of the content can be migrated programmatically versus what requires manual decisions?&lt;br&gt;
The answers to these questions determine the project scope, the architecture of the destination platform, the migration strategy, and the actual cost. Without them, you are quoting a project you do not understand.&lt;/p&gt;

&lt;p&gt;The gap between what teams think they have and what is actually there&lt;br&gt;
We ran a full audit on a 32,000-page HubSpot site before writing a single line of migration code. The team told us they had 12 content types and roughly 40 modules.&lt;/p&gt;

&lt;p&gt;The actual count: 57 content types and 166 modules.&lt;/p&gt;

&lt;p&gt;11 languages. 48 HubDB tables powering dynamic content. 5 different banner modules doing the same job. 4 hero sections. Three CTA components that were functionally identical.&lt;/p&gt;

&lt;p&gt;The team was not wrong because they were careless. They were wrong because nobody had ever looked at the full picture. Content was built by different developers over different years with no central inventory. The CMS became a reflection of every contractor, agency, and sprint that touched it, without anyone tracking what accumulated.&lt;/p&gt;

&lt;p&gt;That gap ... 12 content types in the documentation versus 57 in reality ... is not unusual. It is the norm on any site older than three years with more than one person touching the CMS.&lt;/p&gt;

&lt;p&gt;Why the audit changes everything downstream&lt;br&gt;
Once you have an accurate inventory, several things become possible that were not before.&lt;/p&gt;

&lt;p&gt;First, you can consolidate before you migrate. Those 166 modules became 40 after consolidation. Same functionality. Cleaner architecture. The destination platform was not burdened with four decades of accumulated technical debt from the source.&lt;/p&gt;

&lt;p&gt;Second, you can quantify the automation opportunity. Of the 31,000+ content entries on that site, 42% were fully automatable. No manual review needed. No decisions to make. They could be pulled from HubSpot, transformed to fit the new content model, and loaded into ContentStack programmatically.&lt;/p&gt;

&lt;p&gt;Without the audit, nobody knows that number. Teams either over-engineer everything (treating all content as if it needs manual attention) or miss the scope of what actually requires human decisions. The 42% automation finding cut the migration timeline significantly. That finding was only possible because of the audit.&lt;/p&gt;

&lt;p&gt;Third, the architecture decision becomes data-driven instead of opinionated. The question of whether to lift-and-shift or redesign the content model is not a philosophical one. The audit answers it. If you have 166 modules, 57 content types, and 11 languages, a lift-and-shift carries years of technical debt directly into your new platform. The data tells you to consolidate first.&lt;/p&gt;

&lt;p&gt;This is the same discipline that content teams need when managing websites at scale day-to-day ... not just during migrations. If you have ever tried to update metadata across hundreds of pages or find where a specific word appears across your entire HubSpot site, you understand the value of having full visibility into your content layer. We wrote about this in our piece on what bulk editing actually requires across a large HubSpot site, and the same principle applies: you cannot manage what you cannot see.&lt;/p&gt;

&lt;p&gt;The four steps of a pre-migration audit&lt;br&gt;
Here is the framework we use before any migration project starts.&lt;/p&gt;

&lt;p&gt;Step 1: Content inventory - Export every page, post, template, and content entry in the source CMS. Count them. Categorize them. Map them to content types. The number will surprise you.&lt;/p&gt;

&lt;p&gt;On HubSpot specifically, this means exporting pages, blog posts, landing pages, HubDB tables, and any custom objects. Do not assume the platform's own reporting gives you an accurate count. It often does not surface the full picture when content spans multiple hubs or was imported from external systems.&lt;/p&gt;

&lt;p&gt;Step 2: Module and component mapping - Document every module and component used to render content on the site. Note which ones are duplicates or near-duplicates. A banner module and a "feature banner" module that produce identical output are one component, not two.&lt;/p&gt;

&lt;p&gt;This step is the one teams most commonly skip because it feels like designer work rather than migration work. It is not. The component inventory determines how many content types you need in the destination platform and how complex the migration transforms will be.&lt;/p&gt;

&lt;p&gt;Step 3: Localization audit - If the site serves multiple languages or regions, map how the source CMS handles them versus how the destination CMS handles them. HubSpot, for example, treats each language variant as a separate page. ContentStack uses locale fallbacks. That is not a minor implementation detail. It is a fundamental architecture difference that changes the content model.&lt;/p&gt;

&lt;p&gt;Missing this in discovery means discovering it after you have started building. That is an expensive time to find an architecture problem.&lt;/p&gt;

&lt;p&gt;Step 4: Automation assessment - Once the inventory is complete, classify entries by migration complexity. Fully automatable: structured content, no manual review needed, can be scripted. Requires human review: content that does not map cleanly to the new model, pages with custom layouts, anything that requires a judgment call.&lt;/p&gt;

&lt;p&gt;The ratio between these two buckets determines the human hours required for the migration. Without this classification, every hour estimate is a guess.&lt;/p&gt;

&lt;p&gt;The cost of skipping the audit&lt;br&gt;
Skipping the audit feels like saving time at the start of a project. It is not. It is borrowing time from the middle of the project, at a much higher interest rate.&lt;/p&gt;

&lt;p&gt;Discovery gaps found in week three cost more to fix than discovery gaps found in week zero. The architecture decisions made without complete information need to be reversed. The content that was scoped incorrectly needs to be rescoped. The developers who built for 12 content types need to rebuild for 57.&lt;/p&gt;

&lt;p&gt;None of that is recoverable from a budget or timeline perspective without pain. The audit is not a nice-to-have step at the front of the project. It is the project. Everything else depends on what it reveals.&lt;/p&gt;

&lt;p&gt;Website hygiene, content visibility, and knowing what is actually on your site matter beyond migration projects too. We cover the ongoing side of this in our website hygiene playbook for HubSpot marketers, which gets into the day-to-day equivalent of this kind of structured audit work.&lt;/p&gt;

&lt;p&gt;One note on tooling&lt;/p&gt;

&lt;p&gt;Running a full content audit manually on a large HubSpot site is technically possible and extremely slow. You are exporting CSVs, cross-referencing template reports, pulling HubDB table lists from the API, and manually categorizing thousands of entries in a spreadsheet.&lt;/p&gt;

&lt;p&gt;The same problem shows up in day-to-day website management: HubSpot does not have bulk visibility tools built in. You cannot see all your metadata gaps at once. You cannot search across the full site for a specific string. You cannot pull a structured view of all your modules and which pages they appear on.&lt;/p&gt;

&lt;p&gt;This is a known gap. The HubSpot community has had an open feature request for sitewide find-and-replace since 2017. The bulk editing challenges that make content teams slow are the same ones that make audits hard.&lt;/p&gt;

&lt;p&gt;That is the gap we are working on at Smuves. Start with the free tier if you want to see what your content inventory actually looks like before committing to anything.&lt;/p&gt;

</description>
      <category>hubspot</category>
      <category>webdev</category>
      <category>migration</category>
      <category>cms</category>
    </item>
    <item>
      <title>Your Rebrand Took Four Weeks. The CMS Updates Took Three Months. Here Is Why.</title>
      <dc:creator>Smuves</dc:creator>
      <pubDate>Mon, 30 Mar 2026 01:11:52 +0000</pubDate>
      <link>https://dev.to/smuves/the-multi-portal-mess-how-hubspot-agencies-lose-hours-to-portal-switching-1foh</link>
      <guid>https://dev.to/smuves/the-multi-portal-mess-how-hubspot-agencies-lose-hours-to-portal-switching-1foh</guid>
      <description>&lt;p&gt;The rebrand was supposed to take six weeks. New logo, new color palette, new messaging framework, new domain. The design team finished in four. The copywriters delivered the new voice guide in three. The developers rebuilt the header and footer components in five days.&lt;/p&gt;

&lt;p&gt;Then someone opened HubSpot and asked: "So how do we update the meta descriptions on all 340 pages?"&lt;/p&gt;

&lt;p&gt;That is where the project stalled. Not for a day. For three weeks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rebrand checklist nobody warns you about
&lt;/h2&gt;

&lt;p&gt;Most rebrand planning documents focus on the creative deliverables. Logo files. Brand guidelines. Tone of voice documents. Maybe a new tagline. These are the visible outputs that stakeholders review in meetings and approve with enthusiasm.&lt;/p&gt;

&lt;p&gt;What rarely appears in the plan is the CMS execution checklist. And it is long.&lt;/p&gt;

&lt;p&gt;For a typical HubSpot website with 200 to 500 pages, a rebrand touches all of the following: meta titles that reference the old brand name, meta descriptions that use old messaging or taglines, Open Graph images that show the old logo, featured images with old branding burned into them, alt text that references the old company name, CTAs with old colors and copy, footer content across every page, internal links pointing to renamed or restructured pages, URL slugs that contain the old brand name, and redirects from old slugs to new ones.&lt;/p&gt;

&lt;p&gt;Each of these is a per-page operation in HubSpot. There is no native way to select all pages and batch-update their meta descriptions. There is no bulk find-and-replace for CTA text across your site. There is no "swap all OG images" function.&lt;/p&gt;

&lt;p&gt;You open a page. You click into settings. You update the field. You save. You publish. You move to the next page.&lt;/p&gt;

&lt;p&gt;For 340 pages, that is 340 repetitions of the same workflow. Per field. If you are updating meta titles, meta descriptions, and OG images, you are looking at over a thousand individual edit-save-publish cycles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why HubSpot's rebrand guide does not solve this
&lt;/h2&gt;

&lt;p&gt;HubSpot does have an official knowledge base article on preparing assets for a company rebrand. It walks through updating connected domains, branding settings, email templates, and social defaults. It is a useful checklist for the platform-level settings that exist in one place.&lt;/p&gt;

&lt;p&gt;But it does not address the page-level grunt work, because HubSpot does not have native tooling for it. The guide tells you what to update. It does not tell you how to update 340 pages without losing your mind.&lt;/p&gt;

&lt;p&gt;The gap between "here is what needs to change" and "here is how to change it at scale" is where every rebrand project bleeds time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The math that kills the timeline
&lt;/h2&gt;

&lt;p&gt;Let me walk through a realistic estimate.&lt;/p&gt;

&lt;p&gt;Assume a 300-page HubSpot site. During a rebrand, you need to update at minimum: meta titles (300 edits), meta descriptions (300 edits), OG images (300 edits), and footer CTAs (300 edits if not globally templated). That is 1,200 individual page edits.&lt;/p&gt;

&lt;p&gt;At an optimistic three minutes per edit (open page, find the settings panel, make the change, save, publish), that is 3,600 minutes. Sixty hours. A full week and a half of one person doing nothing but clicking through HubSpot page settings.&lt;/p&gt;

&lt;p&gt;Now add the QA pass. Someone needs to verify that every page actually shows the new metadata. That is another round of 300 page checks. Add redirect setup for any renamed URLs. Add time for the mistakes that inevitably happen when someone is on their 200th consecutive page edit and accidentally pastes the wrong description.&lt;/p&gt;

&lt;p&gt;The realistic total for the CMS execution phase of a rebrand lands somewhere between 80 and 120 hours for a mid-sized site. That is two to three full work weeks. For a task that could be done in an afternoon with the right tooling.&lt;/p&gt;

&lt;h2&gt;
  
  
  The workflow that actually works
&lt;/h2&gt;

&lt;p&gt;After watching this play out on two separate rebrand projects, I changed the approach entirely.&lt;/p&gt;

&lt;p&gt;The workflow I use now has three phases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase one:&lt;/strong&gt; Export everything. Pull all page metadata into a single spreadsheet. Titles, descriptions, URLs, OG image paths, alt text, CTA copy. Every field that needs updating should be visible in rows and columns, not hidden behind individual page settings panels. Tools like &lt;a href="https://www.smuves.com/documentation" rel="noopener noreferrer"&gt;Smuves&lt;/a&gt; make this a one-click operation. Connect your HubSpot portal, select the content type, and export to Google Sheets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase two:&lt;/strong&gt; Edit in the spreadsheet. This is where the speed comes from. In a spreadsheet, you can use find-and-replace to swap the old brand name for the new one across every meta title in seconds. You can write a formula to regenerate meta descriptions from a template. You can paste new OG image URLs in bulk. You can have multiple team members editing different columns simultaneously. A rebrand that touches 300 pages worth of metadata can be edited in a spreadsheet in two to four hours.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase three:&lt;/strong&gt; Push it back. Import the updated spreadsheet back into HubSpot. The &lt;a href="https://www.smuves.com/blog/anatomy-good-page-metadata" rel="noopener noreferrer"&gt;Smuves activity logs&lt;/a&gt; track every change with before-and-after values, so you have a clear audit trail of what was updated. Run your QA pass against the log instead of spot-checking individual pages.&lt;/p&gt;

&lt;p&gt;Total time for the CMS execution phase: one day instead of three weeks.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this looks like in practice
&lt;/h2&gt;

&lt;p&gt;On the last rebrand I worked on, the site had 280 pages and 140 blog posts. The creative phase took four weeks. The CMS execution phase, using the export-edit-import workflow, took six hours.&lt;/p&gt;

&lt;p&gt;Six hours. For 420 content items across two content types. With a complete audit trail showing every field that changed.&lt;/p&gt;

&lt;p&gt;The project manager nearly fell out of her chair when I told her we were done. She had blocked two full weeks on the timeline for CMS updates based on the previous rebrand experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters beyond the timeline
&lt;/h2&gt;

&lt;p&gt;The time savings are obvious. But there is a second benefit that matters just as much: accuracy.&lt;/p&gt;

&lt;p&gt;When a human manually edits 300 pages one at a time, errors are inevitable. A typo in a meta description. A missed page that still shows the old tagline. An OG image that was not swapped because someone lost their place in the list.&lt;/p&gt;

&lt;p&gt;These errors persist quietly until someone notices them. A client Googles themselves and sees the old brand name in a search result. A prospect shares a link on LinkedIn and the old logo appears in the preview card. An investor visits the about page and finds a footer that still says the old company name.&lt;/p&gt;

&lt;p&gt;In a spreadsheet, you can use formulas and filters to verify that every single row has been updated. You can sort by the "brand name" column and instantly see if any old references remain. The verification is structural, not manual.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;If you are planning or budgeting a rebrand, add a line item for CMS execution. It is not a footnote. On most HubSpot sites, it is the longest phase of the project unless you plan for it.&lt;/p&gt;

&lt;p&gt;Do not assume page-by-page editing is the only option. Export your metadata to a spreadsheet, make your changes there, and push them back. The workflow exists. The tooling exists. The only thing missing from most rebrand plans is the awareness that this approach is possible.&lt;/p&gt;

&lt;p&gt;Measure the CMS execution phase separately from the creative phase. If your rebrand took eight weeks but the creative work was done in four, you have a four-week CMS problem that will repeat itself next time unless you fix the process.&lt;/p&gt;

</description>
      <category>management</category>
      <category>marketing</category>
      <category>productivity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I Wrote a Script to Switch Between 12 HubSpot Portals. Then I Stopped.</title>
      <dc:creator>Smuves</dc:creator>
      <pubDate>Fri, 27 Mar 2026 05:30:28 +0000</pubDate>
      <link>https://dev.to/smuves/i-wrote-a-script-to-switch-between-12-hubspot-portals-then-i-stopped-2ga2</link>
      <guid>https://dev.to/smuves/i-wrote-a-script-to-switch-between-12-hubspot-portals-then-i-stopped-2ga2</guid>
      <description>&lt;p&gt;If you have ever managed more than three HubSpot portals for agency clients, you already know the drill. Log in. Click around. Find the page you need. Make the edit. Log out. Log in to the next one. Repeat until your afternoon disappears.&lt;/p&gt;

&lt;p&gt;I spent the better part of 2024 building internal tooling to make this less painful. Browser profiles for each client. A Tampermonkey script that auto-detected which portal I was in and color-coded the nav bar so I would stop accidentally editing the wrong site. A shared Notion doc where our team tracked which portals needed what updates each week.&lt;/p&gt;

&lt;p&gt;It worked, kind of. But it was duct tape on a structural problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Issue: HubSpot Portals Are Islands
&lt;/h2&gt;

&lt;p&gt;HubSpot was not designed for people who need to operate across multiple portals simultaneously. Every portal is its own universe. Its own login context. Its own set of pages, blog posts, redirects, and settings. There is no native way to view content across portals, compare settings between them, or perform the same action in multiple portals without doing it manually each time.&lt;/p&gt;

&lt;p&gt;For a single brand, this is fine. For an agency running content operations across a dozen clients, it creates a workflow that looks more like a context-switching penalty than a content management system.&lt;/p&gt;

&lt;p&gt;Here is what the actual day looks like. You get a Slack message from a client asking you to update meta descriptions across 40 blog posts. You log into their portal. You open the first post. You click into settings. You change the meta description. You save. You go back to the list. You open the next one. Forty times.&lt;/p&gt;

&lt;p&gt;Then another client pings you with the same request. New portal. Same tedious process. Different set of 40 posts.&lt;/p&gt;

&lt;p&gt;And that is just metadata. When a client asks you to do a find-and-replace across their blog (say, swapping out an old product name for a new one), you are looking at the same page-by-page grind. There is no built-in find-and-replace for HubSpot CMS content. The Ideas forum has had this request open for years. The community workaround is either "do it manually" or "use the API."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Math Nobody Talks About
&lt;/h2&gt;

&lt;p&gt;Let us say you manage 10 client portals. Each client has a website with somewhere between 50 and 500 pages. Every quarter, you run a hygiene pass: checking metadata, fixing broken redirects, updating alt text, cleaning up outdated content.&lt;/p&gt;

&lt;p&gt;If each portal takes you four hours of manual editing per quarter (and that is conservative for a 200-plus page site), you are looking at 40 hours. That is a full work week, every quarter, just on maintenance.&lt;/p&gt;

&lt;p&gt;Now multiply that by the number of people on your team who touch CMS content. The hours compound fast.&lt;/p&gt;

&lt;p&gt;The frustrating part is not the work itself. It is the fact that you are doing the same type of work, in the same type of interface, across portals that do not talk to each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Actually Needed
&lt;/h2&gt;

&lt;p&gt;When I stepped back and looked at what I was really trying to solve, it came down to three things.&lt;/p&gt;

&lt;p&gt;First, I needed a way to see and edit content across multiple portals without logging in and out. Not a dashboard that shows me analytics. An actual editing interface where I could make changes.&lt;/p&gt;

&lt;p&gt;Second, I needed bulk operations. Not the "select five pages and archive them" kind that HubSpot offers natively. Real bulk editing. Change 200 meta descriptions at once. Find and replace a URL across every blog post on a client site. Update alt text in a single pass.&lt;/p&gt;

&lt;p&gt;Third, I needed an audit trail. When you are making changes across client sites at scale, you need to know what changed, when it changed, and who changed it. HubSpot does not give you that level of visibility for CMS content changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tooling Gap
&lt;/h2&gt;

&lt;p&gt;I looked at the HubSpot API. You can absolutely build something that hits the CMS endpoints and modifies content programmatically. I did this for a while. But writing and maintaining custom scripts for every type of bulk operation, across every client portal, is its own full-time job. Every time HubSpot updates their API, something breaks. Every time a client has a unique content structure, you need a new script variant.&lt;/p&gt;

&lt;p&gt;I also looked at the HubSpot Ideas forum. The request for bulk metadata editing has been open for years. Hundreds of upvotes. Comments from people managing 500-plus page sites saying they are spending weeks on tasks that should take minutes. HubSpot has not shipped a native solution.&lt;/p&gt;

&lt;p&gt;The community responses are revealing. One agency user wrote that they can export all their titles and descriptions instantly but importing them back is "one huge grind for the team." Another said it could "save weeks of internal work for mid to large sites." These are not edge cases. These are the daily reality for anyone managing client websites at scale.&lt;/p&gt;

&lt;p&gt;This is the gap where tools like &lt;a href="https://www.smuves.com/features" rel="noopener noreferrer"&gt;Smuves&lt;/a&gt; exist. It is a bulk CMS editor built specifically for HubSpot that lets you connect multiple portals from a single dashboard, edit content in bulk, and push changes back with activity logging. The kind of thing I was trying to duct-tape together with scripts and browser profiles.&lt;/p&gt;

&lt;p&gt;Their &lt;a href="https://www.smuves.com/blog/the-ultimate-guide-to-bulk-editing-in-hubspot" rel="noopener noreferrer"&gt;bulk editing guide&lt;/a&gt; walks through the actual workflow: export content to Google Sheets, make your changes in a familiar spreadsheet environment, and push updates back to HubSpot. For agencies, the multi-portal piece means you do not need to juggle logins or maintain separate editing processes for each client.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned From Building (and Abandoning) My Own Solution
&lt;/h2&gt;

&lt;p&gt;The biggest lesson was not technical. It was operational.&lt;/p&gt;

&lt;p&gt;Custom tooling only makes sense when the problem is unique to you. The multi-portal editing problem is not unique. Every HubSpot agency deals with it. The fact that so many agencies build their own workarounds (browser profiles, API scripts, elaborate Notion trackers) tells you that the native tooling has a blind spot.&lt;/p&gt;

&lt;p&gt;The second lesson was about context switching. Every time you log into a different portal, your brain has to re-orient. Which client is this? What are their brand guidelines? Where did we leave off last time? That cognitive overhead is invisible in time tracking but very real in output quality.&lt;/p&gt;

&lt;p&gt;The third lesson was about risk. When you are manually editing pages one at a time across multiple portals, mistakes happen. You paste the wrong meta description. You update the wrong redirect. You accidentally publish a draft. Without proper logging, you might not catch it until a client calls you.&lt;/p&gt;

&lt;h2&gt;
  
  
  For Other Agency Devs
&lt;/h2&gt;

&lt;p&gt;If you are still in the "build it yourself" phase, here is my honest take. Spend the time on tooling that is specific to your agency's unique value proposition. The CMS bulk editing problem has been solved by people who focus on it full time. Your energy is better spent on the things that actually differentiate your agency.&lt;/p&gt;

&lt;p&gt;And if you are an agency ops person who keeps hearing "we will just use the API" from your dev team, push back. Ask them how many hours they spent last quarter maintaining those scripts versus the hours they could have spent on client-facing work. The answer is usually sobering.&lt;/p&gt;

&lt;p&gt;The portal-switching tax is real. Most agencies just never put a number on it.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Your Content Strategist Is Debugging Redirects. That Is the Problem.</title>
      <dc:creator>Smuves</dc:creator>
      <pubDate>Mon, 23 Mar 2026 05:27:21 +0000</pubDate>
      <link>https://dev.to/smuves/your-content-strategist-is-debugging-redirects-that-is-the-problem-238a</link>
      <guid>https://dev.to/smuves/your-content-strategist-is-debugging-redirects-that-is-the-problem-238a</guid>
      <description>&lt;p&gt;I want to describe a hiring pattern I have seen play out at least a dozen times in the last few years. A company decides they need to level up their content. They write a job description for a "Content Strategist." The listing talks about editorial vision, audience research, content calendars, SEO strategy, and thought leadership. They hire someone smart. Someone with a portfolio full of campaigns that drove real results.&lt;/p&gt;

&lt;p&gt;Then, on day three, someone asks them to fix 47 broken redirects.&lt;/p&gt;

&lt;p&gt;By week two, they are updating meta descriptions on old blog posts. By month two, they are exporting HubSpot data into spreadsheets, cleaning up author tags, and trying to figure out why half the landing pages still reference a product name that changed in 2023.&lt;/p&gt;

&lt;p&gt;This is not content strategy. This is content operations. And the failure to distinguish between the two is costing companies real money and burning out talented people.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Two Jobs Living Inside One Title
&lt;/h3&gt;

&lt;p&gt;Content strategy is about decisions. What topics should we cover? Who are we writing for? What does our brand sound like? How does content support the sales pipeline? Where should we be publishing? These are high-level questions that require research, judgment, and time to think.&lt;/p&gt;

&lt;p&gt;Content operations is about execution at scale. How do we update 200 page titles without breaking anything? How do we manage redirects when we retire old campaign pages? How do we keep metadata consistent across a site that has grown to 500 pages over four years? Who tracks what changed and when?&lt;/p&gt;

&lt;p&gt;Both are essential. Neither is optional. But they require completely different skill sets, completely different tools, and completely different mindsets.&lt;/p&gt;

&lt;p&gt;The problem is that most companies hire for strategy and then hand over operations. Not because they are cheap or clueless, but because they do not realize how much operational work their website actually requires until someone is sitting in the seat.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why CMS Tooling Creates This Problem
&lt;/h3&gt;

&lt;p&gt;Here is the thing most people miss. The reason content operations work consumes so much time is not because the tasks are complex. It is because the tools make simple tasks slow.&lt;/p&gt;

&lt;p&gt;Take HubSpot as an example. If you need to update a meta description on one page, it takes about two minutes. Click into the page editor, find the settings tab, make the edit, save, publish. Fine.&lt;/p&gt;

&lt;p&gt;Now multiply that by 150 pages. Suddenly you are looking at five hours of clicking through the same interface, doing the same two-minute task over and over. That is a full day of work that requires zero strategic thinking and maximum tolerance for repetition.&lt;/p&gt;

&lt;p&gt;Redirects are even worse. HubSpot lets you manage them, but doing it one at a time when you have hundreds to review is the kind of work that makes people question their career choices.&lt;/p&gt;

&lt;p&gt;The CMS was not built for bulk operations. It was built for creating and editing individual pages. So anyone responsible for site-wide maintenance is stuck working against the tool instead of with it.&lt;/p&gt;

&lt;p&gt;This is exactly why tools focused on bulk operations exist. Smuves, for example, has been shipping features specifically designed to eliminate the repetitive CMS work that eats up content team hours. The &lt;a href="https://www.smuves.com/product-updates" rel="noopener noreferrer"&gt;product updates&lt;/a&gt; page shows a clear focus on this: in-app bulk editing, find and replace across entire sites, advanced filters, and activity logging. These are operations features, not strategy features. And that distinction matters.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Real Cost of Role Confusion
&lt;/h3&gt;

&lt;p&gt;When you collapse strategy and operations into one role, three things happen.&lt;/p&gt;

&lt;p&gt;First, strategic work does not get done. The person you hired to think about audience segmentation and content differentiation is instead spending their afternoons in a spreadsheet updating alt text. The strategic thinking you are paying for never actually happens because the operational backlog always feels more urgent.&lt;/p&gt;

&lt;p&gt;Second, operational work gets done badly. A strategist doing operations work is like a software architect doing QA testing. They can do it, but it is not their strength, they do not enjoy it, and they will cut corners to get back to the work they were actually hired for.&lt;/p&gt;

&lt;p&gt;Third, the person burns out and leaves. I have seen this pattern repeat consistently. Someone takes a content strategist role, discovers that 70% of the job is CMS maintenance, spends six months trying to push through it, and then quietly starts interviewing elsewhere. The company loses the person and the institutional knowledge, then posts the same job listing and starts the cycle again.&lt;/p&gt;

&lt;h3&gt;
  
  
  What the Fix Actually Looks Like
&lt;/h3&gt;

&lt;p&gt;The fix is not complicated, but it does require admitting that content operations is a real discipline that deserves its own resources.&lt;/p&gt;

&lt;p&gt;Step one: audit how your content team actually spends their time. Not how you think they spend it. How they actually spend it. Track it for two weeks. You will almost certainly find that operational tasks (metadata updates, redirect management, broken link fixes, CMS cleanup) consume 50% or more of what was supposed to be a strategy role.&lt;/p&gt;

&lt;p&gt;Step two: separate the responsibilities. You do not necessarily need to hire a full-time content operations person. But you do need to explicitly name the operational tasks, assign them, and give whoever owns them the right tools. A detailed guide like &lt;a href="https://www.smuves.com/blog/the-ultimate-guide-to-bulk-editing-in-hubspot" rel="noopener noreferrer"&gt;The Ultimate Guide to Bulk Editing Your Website in HubSpot&lt;/a&gt; lays out the specific workflows and pain points that fall under operations, not strategy.&lt;/p&gt;

&lt;p&gt;Step three: invest in tooling that eliminates the repetition. The reason operations work takes so long is not that there is too much of it. It is that the tools require manual, page-by-page work for tasks that should be bulk operations. Fix the tooling layer and you can compress what used to take days into what takes an hour.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Quick Checklist: Is Your Strategist Actually Doing Ops?
&lt;/h3&gt;

&lt;p&gt;If the person in your content strategist role regularly does any of the following, they are doing operations work:&lt;/p&gt;

&lt;p&gt;Updating meta titles or descriptions across multiple pages. Managing URL redirects (creating, reviewing, or cleaning up redirect chains). Fixing broken internal links. Editing author profiles, tags, or categories in the CMS. Exporting CMS data to spreadsheets for bulk review. Re-publishing pages after making settings-level changes. Auditing alt text on images across the blog.&lt;/p&gt;

&lt;p&gt;None of these tasks require strategic thinking. All of them require time. And all of them are things that a proper operations setup, backed by the right tools, can handle far more efficiently than a person clicking through a CMS one page at a time.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Takeaway for Technical Teams
&lt;/h3&gt;

&lt;p&gt;If you work in engineering or DevOps, think about it this way. You would never ask a solutions architect to also handle ticket triage, server monitoring, and patch management full-time. You understand that architecture and operations require different tools, different workflows, and different people (or at least different time blocks).&lt;/p&gt;

&lt;p&gt;Content teams deserve the same respect. Strategy and operations are both essential. But they are not the same job. And the longer companies pretend they are, the more strategic talent they will burn through doing work that a better tooling setup could handle in a fraction of the time.&lt;/p&gt;

&lt;p&gt;The next time someone on your team says "our content is not where it should be," ask the follow-up question: is that because the strategy is wrong, or because the person responsible for strategy is spending their days fixing redirects?&lt;/p&gt;

&lt;p&gt;The answer will tell you everything about where to invest next.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>hubspot</category>
    </item>
    <item>
      <title>Your AI Writes 10x Faster. Your CMS Still Deploys at 1x. Here is the Fix.</title>
      <dc:creator>Smuves</dc:creator>
      <pubDate>Mon, 16 Mar 2026 11:52:47 +0000</pubDate>
      <link>https://dev.to/smuves/your-ai-writes-10x-faster-your-cms-still-deploys-at-1x-here-is-the-fix-dod</link>
      <guid>https://dev.to/smuves/your-ai-writes-10x-faster-your-cms-still-deploys-at-1x-here-is-the-fix-dod</guid>
      <description>&lt;p&gt;I spent last Tuesday morning watching our content lead generate eight blog post drafts in about forty minutes using a combination of Claude and HubSpot Breeze. Titles, outlines, body copy, meta descriptions. All done before lunch.&lt;/p&gt;

&lt;p&gt;Then I watched her spend the rest of the day manually entering those drafts into HubSpot CMS. One page at a time. Copying meta descriptions into individual page settings. Uploading featured images and writing alt text in separate fields. Setting canonical URLs. Configuring Open Graph tags. Clicking publish, then moving to the next one.&lt;/p&gt;

&lt;p&gt;Eight posts. Roughly six hours of CMS busywork after forty minutes of creation.&lt;/p&gt;

&lt;p&gt;That ratio is broken. And if you are running content operations on HubSpot, you have probably felt it too.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Bottleneck Has Moved
&lt;/h3&gt;

&lt;p&gt;For years, the slowest part of content operations was creation. Research, drafting, editing, approval. That pipeline could take days or weeks per piece. The CMS deployment step was a minor footnote because you were only publishing a handful of pieces per week anyway.&lt;/p&gt;

&lt;p&gt;AI changed that equation overnight. Tools like HubSpot Breeze Remix, Jasper, and various LLM-powered workflows have compressed creation timelines from days to hours. Some teams are producing ten or twenty pieces of content per week where they used to produce three or four.&lt;/p&gt;

&lt;p&gt;But here is the thing nobody is talking about. The CMS did not get faster. HubSpot still expects you to open each page individually, fill out metadata fields one by one, configure settings manually, and click through confirmation dialogs. The deployment interface was designed for an era when you published two blog posts a week. Not twenty.&lt;/p&gt;

&lt;p&gt;The bottleneck has shifted from creation to deployment. And most teams have not noticed because they are too busy clicking through page editors.&lt;/p&gt;

&lt;h3&gt;
  
  
  What "Deployment" Actually Involves
&lt;/h3&gt;

&lt;p&gt;If you are a developer or technical marketer, you know the publishing step is not just "paste content and hit publish." For every piece of content going live on a HubSpot site, the deployment checklist looks something like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Page title and H1 alignment&lt;/li&gt;
&lt;li&gt;Meta description (unique, under 160 characters)&lt;/li&gt;
&lt;li&gt;URL slug configuration&lt;/li&gt;
&lt;li&gt;Canonical URL setting&lt;/li&gt;
&lt;li&gt;Featured image upload with descriptive alt text&lt;/li&gt;
&lt;li&gt;Open Graph title, description, and image&lt;/li&gt;
&lt;li&gt;Twitter Card configuration&lt;/li&gt;
&lt;li&gt;Blog author assignment&lt;/li&gt;
&lt;li&gt;Tag and category assignment&lt;/li&gt;
&lt;li&gt;Internal linking verification&lt;/li&gt;
&lt;li&gt;Schema markup validation&lt;/li&gt;
&lt;li&gt;301 redirect setup (if replacing or consolidating old content)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is twelve distinct configuration steps per page, most of which happen outside the content editor in HubSpot page settings panels. Multiply that by ten or twenty pieces of content per week and you have a serious operational problem.&lt;/p&gt;

&lt;p&gt;None of these steps require creative thinking. They are mechanical, repetitive, and error-prone when done manually at volume. They are exactly the kind of work that should be handled in bulk.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why HubSpot Does Not Solve This Natively
&lt;/h3&gt;

&lt;p&gt;HubSpot has invested heavily in AI-powered content creation. Breeze Content Agent generates drafts. Breeze Remix repurposes a single asset across channels. These are legitimate productivity multipliers on the creation side.&lt;/p&gt;

&lt;p&gt;But on the deployment side, HubSpot CMS still operates with the same one-page-at-a-time editing model it has had for years. There is no native interface for bulk-updating meta descriptions across fifty pages. No spreadsheet view for reviewing and editing alt text across your entire blog. No way to batch-configure Open Graph tags for a set of newly created posts.&lt;/p&gt;

&lt;p&gt;The HubSpot Community forums have hundreds of upvoted requests for bulk metadata editing going back years. Users describe updating 500 or 600 page titles manually as "not a great way to spend time." That thread has been active since at least 2019 and the core limitation remains.&lt;/p&gt;

&lt;p&gt;This is a design asymmetry. HubSpot accelerated the input side of content operations with AI but left the output side essentially unchanged.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Spreadsheet Escape Hatch
&lt;/h3&gt;

&lt;p&gt;The most practical workaround I have found involves treating your CMS data like a dataset rather than a series of individual pages. Export your page metadata into a spreadsheet environment, make bulk edits using familiar tools like formulas, find-and-replace, and column operations, then push the changes back to HubSpot in one operation.&lt;/p&gt;

&lt;p&gt;This is the approach that tools like &lt;a href="https://www.smuves.com/features" rel="noopener noreferrer"&gt;Smuves&lt;/a&gt; are built around. Instead of clicking through individual page editors, you pull your HubSpot CMS data into Google Sheets, edit hundreds of rows of metadata simultaneously, and sync the changes back with activity logs tracking every modification. It turns a six-hour clicking marathon into a thirty-minute spreadsheet session.&lt;/p&gt;

&lt;p&gt;The workflow looks like this in practice:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Export all blog posts (or pages, or redirects) from HubSpot into a sheet&lt;/li&gt;
&lt;li&gt;Review and edit meta descriptions, titles, alt text, and URLs in bulk&lt;/li&gt;
&lt;li&gt;Use spreadsheet formulas to enforce consistency (character limits, keyword inclusion, formatting rules)&lt;/li&gt;
&lt;li&gt;Push updates back to HubSpot with one click&lt;/li&gt;
&lt;li&gt;Review activity logs to confirm what changed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a technical team, this is the obvious approach. You would never manually edit 200 database records one at a time through a GUI. You would query them, transform them in bulk, and write them back. CMS content metadata deserves the same treatment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the Post-AI Deployment Workflow
&lt;/h3&gt;

&lt;p&gt;If your team has already adopted AI for content creation, the next efficiency gain is not another AI tool. It is fixing the deployment pipeline. Here is a practical framework:&lt;/p&gt;

&lt;p&gt;Batch your AI-generated content. Do not publish each piece as it comes out of the AI tool. Accumulate a batch, then deploy them together. This turns twelve individual deployment sessions into one bulk operation.&lt;/p&gt;

&lt;p&gt;Standardize your metadata templates. Create formulas or templates for meta descriptions, OG tags, and alt text patterns. When you are editing in a spreadsheet, you can apply these templates across an entire column instantly.&lt;/p&gt;

&lt;p&gt;Audit before you publish. When you can see all your pending content in a single spreadsheet view, inconsistencies become obvious. Duplicate meta descriptions, missing alt text, broken URL patterns. These are invisible when you are editing pages one at a time but immediately apparent in a tabular view.&lt;/p&gt;

&lt;p&gt;If you are looking for a deeper walkthrough on managing HubSpot content in bulk, the &lt;a href="https://www.smuves.com/blog/the-ultimate-guide-to-bulk-editing-in-hubspot" rel="noopener noreferrer"&gt;Smuves guide to bulk editing in HubSpot&lt;/a&gt; covers the specific mechanics of exporting, editing, and re-importing CMS data.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Math That Should Worry You
&lt;/h3&gt;

&lt;p&gt;Here is a rough calculation. If your team publishes 15 pieces of content per week and each piece takes 25 minutes of CMS configuration work, that is over six hours per week spent on mechanical deployment tasks. Over a year, that is roughly 325 hours. A full two months of a content team member doing nothing but clicking through page settings.&lt;/p&gt;

&lt;p&gt;AI made your content creation ten times faster. But if your deployment process still runs at the old speed, you have not actually gained that time. You have just moved the line where people sit and wait.&lt;/p&gt;

&lt;p&gt;The teams that figure this out first will be the ones shipping content at the speed their AI tools actually enable. Everyone else will be stuck in page editors, wondering why their AI investment has not translated into more published content.&lt;/p&gt;

&lt;p&gt;The bottleneck is not your writers anymore. It is your CMS.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I Stopped Fighting HubSpot CMS and Started Managing It From Google Sheets</title>
      <dc:creator>Smuves</dc:creator>
      <pubDate>Tue, 10 Mar 2026 05:21:37 +0000</pubDate>
      <link>https://dev.to/smuves/i-stopped-fighting-hubspot-cms-and-started-managing-it-from-google-sheets-305d</link>
      <guid>https://dev.to/smuves/i-stopped-fighting-hubspot-cms-and-started-managing-it-from-google-sheets-305d</guid>
      <description>&lt;p&gt;There is a moment that every HubSpot CMS user hits eventually. You need to update meta descriptions across 150 blog posts. Maybe it is a rebrand. Maybe someone finally ran a Screaming Frog audit and the results were ugly. Whatever the reason, you open HubSpot, click into the first post, scroll to the settings panel, make the edit, save, go back to the list, and click into the next one.&lt;/p&gt;

&lt;p&gt;By post number twelve, you are already doing the math on how long this is going to take.&lt;/p&gt;

&lt;p&gt;I spent the better part of two years managing content operations inside HubSpot CMS, and I can tell you the platform is genuinely excellent at a lot of things. Building pages, managing contacts, running automation workflows. But there is one thing it has never been good at: letting you see and edit your content at scale.&lt;br&gt;
The CMS editor is built for single-page work. That is fine when you are publishing a new landing page. It is not fine when you need to fix a broken URL pattern across your entire blog archive, or swap out a phone number that appears in the footer module of 200 pages, or update Open Graph images before a product launch.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem Is Not HubSpot. The Problem Is the Interface Paradigm.
&lt;/h3&gt;

&lt;p&gt;HubSpot CMS treats every piece of content as an individual record that you access through a form-based editor. Click in, scroll, edit, save, go back. That is a fine pattern for creating content. It is a terrible pattern for maintaining content.&lt;/p&gt;

&lt;p&gt;Content maintenance is fundamentally a tabular operation. You want to see rows of pages. You want columns of fields. You want to sort by last updated date, filter by content type, and scan for patterns. You want to select a range and apply a change. This is spreadsheet thinking, and it is how every content operations team I have ever worked with actually processes information.&lt;/p&gt;

&lt;p&gt;The disconnect between how content teams think (rows and columns) and how HubSpot CMS works (forms and single-page editors) is the root of almost every CMS workflow frustration I have encountered.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Google Sheets Works as a CMS Control Panel
&lt;/h3&gt;

&lt;p&gt;Google Sheets is not a CMS. Nobody is claiming it should be one. But as a read-write interface for CMS data, it has properties that the HubSpot editor simply does not offer.&lt;/p&gt;

&lt;p&gt;First, visibility: A spreadsheet shows you hundreds of records at once. You can scan a column of meta descriptions in seconds and spot the ones that are too long, duplicated, or missing entirely. Try doing that inside HubSpot, where you have to click into each page individually to see its metadata.&lt;/p&gt;

&lt;p&gt;Second, formulas: Need to append a brand name to every title tag? That is a CONCATENATE function and a drag operation. Need to truncate descriptions to 155 characters? That is a LEFT function. Need to find and replace a domain across all your canonical URLs? CTRL+H. These are operations that take seconds in a spreadsheet and hours in a CMS editor.&lt;/p&gt;

&lt;p&gt;Third, collaboration: Google Sheets has real-time multi-user editing, commenting, version history, and sharing controls built in. Your SEO specialist can review metadata in the same sheet where your content manager is updating page titles, while your dev lead checks redirect mappings in another tab. In HubSpot, everyone is editing through the same single-page interface, one person at a time.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Missing Piece: Getting Data In and Out
&lt;/h3&gt;

&lt;p&gt;Here is where things used to fall apart. HubSpot does not have a native "export all my CMS content to a spreadsheet and let me push changes back" feature. The CRM side has decent import/export for contacts and deals. The CMS side? Not so much.&lt;/p&gt;

&lt;p&gt;The traditional workarounds were painful. You could use the HubSpot CMS API to pull data programmatically, but that meant writing scripts, handling pagination, managing authentication tokens, and building your own import logic. I have seen teams burn entire sprints on custom API integrations that did nothing more than get their page data into a spreadsheet.&lt;/p&gt;

&lt;p&gt;Some teams tried Zapier or Make workflows, but those tools are designed for event-driven automation, not bulk data operations. They work great for "when a form is submitted, create a row." They do not work well for "give me all 800 blog posts with their metadata so I can fix them."&lt;/p&gt;

&lt;p&gt;This gap is exactly what tools like &lt;a href="https://www.smuves.com/integrations" rel="noopener noreferrer"&gt;Smuves&lt;/a&gt; were built to close. The concept is straightforward: connect to your HubSpot portal, export your CMS content to Google Sheets, edit in the spreadsheet environment, and push the changes back with logging and error tracking. No API scripts. No Zapier chains. Just a direct bridge between where your data lives and where you actually want to work with it.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Practical Workflow That Actually Scales
&lt;/h3&gt;

&lt;p&gt;Here is what a realistic content operations workflow looks like when you treat Google Sheets as your CMS control panel.&lt;br&gt;
Step one: export. Pull your target content type out of HubSpot and into a sheet. Pages, blog posts, redirects, HubDB rows, whatever you need. Each row is a record. Each column is a field.&lt;/p&gt;

&lt;p&gt;Step two: audit. This is where spreadsheets shine. Sort by publish date to find stale content. Filter for pages with empty meta descriptions. Use conditional formatting to highlight titles over 60 characters. You can build an audit template once and reuse it every quarter.&lt;/p&gt;

&lt;p&gt;Step three: edit. Make your changes directly in the cells. Use formulas for batch operations. Use find-and-replace for string swaps. Collaborate with your team in real time.&lt;/p&gt;

&lt;p&gt;Step four: push. Import the updated data back to HubSpot. A good integration tool will give you detailed logs showing what changed, what succeeded, and what failed. This is critical for accountability, especially when multiple people are making changes.&lt;/p&gt;

&lt;p&gt;Step five: verify. Spot-check a few records in HubSpot to confirm the changes landed correctly. Run your Screaming Frog audit again if you were fixing SEO issues.&lt;/p&gt;

&lt;p&gt;The entire cycle for a 200-page metadata update can take under an hour. In the native HubSpot editor, the same task could easily consume an entire day.&lt;/p&gt;

&lt;h3&gt;
  
  
  When This Approach Breaks Down
&lt;/h3&gt;

&lt;p&gt;I want to be honest about the limitations. Google Sheets as a CMS control panel is not a replacement for the HubSpot editor. It is a complement.&lt;/p&gt;

&lt;p&gt;You still need the native editor for visual layout work, drag-and-drop module placement, and design changes. The spreadsheet workflow is specifically for field-level data: titles, descriptions, URLs, redirects, tags, author attributions, alt text, canonical URLs, Open Graph properties, and similar structured content.&lt;/p&gt;

&lt;p&gt;If you are editing rich text body content, you are probably better off working inside HubSpot or a dedicated writing tool. The spreadsheet approach is most powerful for the operational metadata layer that wraps around your content.&lt;/p&gt;

&lt;p&gt;The other limitation is trust. When you are pushing bulk changes back to a live CMS, you need confidence that the tool handling the sync is reliable. This is why activity logs matter so much. The ability to see exactly what changed, when, and whether it succeeded is the difference between a bulk edit tool you use once and one you build your entire workflow around.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Bigger Point
&lt;/h3&gt;

&lt;p&gt;HubSpot is a great platform. But the CMS editing experience was designed for content creators, not content operators. As your site grows past a few dozen pages, the gap between what the editor offers and what your team needs becomes impossible to ignore.&lt;/p&gt;

&lt;p&gt;Google Sheets fills that gap because it was already built for the kind of work content operations teams do: scanning, filtering, batch editing, collaborating, and auditing data at scale. The challenge has always been connecting the spreadsheet to the CMS in a way that is reliable, logged, and safe.&lt;/p&gt;

&lt;p&gt;That &lt;a href="https://www.smuves.com/blog/top-5-challenges-in-editing-hubspot-websites-in-bulk-and-how-smuves-solves-them" rel="noopener noreferrer"&gt;challenge is solvable now&lt;/a&gt;. And once you start managing your HubSpot CMS from a spreadsheet, you will wonder how you ever did it any other way.&lt;/p&gt;

</description>
      <category>hubspot</category>
      <category>bulkediting</category>
      <category>ai</category>
    </item>
    <item>
      <title>The Post-Migration Metadata Disaster Nobody Plans For (And How to Fix It Without Losing Your Mind)</title>
      <dc:creator>Smuves</dc:creator>
      <pubDate>Thu, 05 Mar 2026 04:40:30 +0000</pubDate>
      <link>https://dev.to/smuves/the-post-migration-metadata-disaster-nobody-plans-for-and-how-to-fix-it-without-losing-your-mind-1n72</link>
      <guid>https://dev.to/smuves/the-post-migration-metadata-disaster-nobody-plans-for-and-how-to-fix-it-without-losing-your-mind-1n72</guid>
      <description>&lt;p&gt;You just finished migrating 300 pages from WordPress to HubSpot. The DNS is updated. The 301 redirects are mapped. The staging site looked clean. Your project manager sent the "we are live" Slack message and everyone reacted with party emojis.&lt;/p&gt;

&lt;p&gt;Then you open Google Search Console four days later.&lt;/p&gt;

&lt;p&gt;Half your blog posts have duplicate meta descriptions pulled from template defaults. Ninety-something pages lost their featured image alt text entirely. The Open Graph tags on your entire /resources section are either blank or pointing to the old domain. And someone on the team quietly admits they forgot about canonical URLs on the landing pages.&lt;/p&gt;

&lt;p&gt;Welcome to the part of CMS migration that nobody puts in the project plan.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why the migration itself is never the problem
&lt;/h3&gt;

&lt;p&gt;I have been through three HubSpot CMS migrations in the past four years. Every single time, the actual migration went fine. The data transferred. Pages loaded. Redirects fired correctly. The technical move is well-documented and, honestly, pretty straightforward if you follow the standard checklist.&lt;/p&gt;

&lt;p&gt;The disaster is always what comes after.&lt;/p&gt;

&lt;p&gt;Every CMS stores and renders metadata differently. WordPress might auto-generate your og:description from the first 160 characters of your post body. HubSpot expects you to set it manually in the page settings. Drupal handles canonical URLs one way. Webflow handles them another.&lt;/p&gt;

&lt;p&gt;The result is that your content technically migrated, but the metadata layer that search engines and social platforms rely on is either missing, duplicated, or just plain wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I typically find during a post-migration audit
&lt;/h3&gt;

&lt;p&gt;After every migration, there is a phase I call "the spreadsheet phase." This is where someone (usually me) exports every page and blog post into a spreadsheet and manually audits the metadata field by field, row by row.&lt;/p&gt;

&lt;p&gt;Here is what consistently shows up:&lt;/p&gt;

&lt;p&gt;Title tags that are blank or populated with template defaults like "New Page" or the CMS placeholder text. Meta descriptions that were pulled from the wrong field during import, so they are either truncated gibberish or identical across dozens of pages. URL slugs that gained extra characters or lost hyphens during the conversion process. Internal links still pointing to old URL structures that somehow bypassed the redirect map. Featured image alt text that vanished completely during the transfer.&lt;/p&gt;

&lt;p&gt;For a 200-page site, the audit alone takes about three full days of focused work. For a 500-page site with an active blog, you are looking at a week or more.&lt;/p&gt;

&lt;p&gt;And this is just the audit. Fixing everything takes even longer.&lt;/p&gt;

&lt;h3&gt;
  
  
  The real bottleneck is not finding the problems
&lt;/h3&gt;

&lt;p&gt;Finding metadata issues is tedious but manageable. Screaming Frog, Sitebulb, or even a simple crawl export will surface most of them. The real bottleneck is fixing them inside HubSpot.&lt;/p&gt;

&lt;p&gt;HubSpot does not offer native bulk editing for page metadata. You cannot export all your meta titles and descriptions to a CSV, fix them in a spreadsheet, and re-import. The official workflow is: open a page, click into settings, update the field, save, publish, go back to the page list, find the next page, and repeat.&lt;/p&gt;

&lt;p&gt;For 300 pages, that is roughly 300 individual editing sessions. Each one requires multiple clicks, a page load, and a publish confirmation. The HubSpot community forums have threads going back years asking for bulk metadata editing, and the feature requests have hundreds of upvotes with no native solution in sight.&lt;/p&gt;

&lt;p&gt;This is where the gap between "migration complete" and "migration actually done" becomes painfully obvious.&lt;/p&gt;

&lt;h3&gt;
  
  
  A better post-migration audit workflow
&lt;/h3&gt;

&lt;p&gt;Over the past few migrations, I have built a workflow that cuts the post-migration cleanup time significantly. Here is the general approach:&lt;/p&gt;

&lt;p&gt;First, crawl the migrated site immediately, before Google has fully re-indexed everything. Export the full crawl data including titles, meta descriptions, H1 tags, canonical URLs, alt text counts, and status codes.&lt;/p&gt;

&lt;p&gt;Second, build your audit spreadsheet. Map every URL against the pre-migration data you should have captured during the planning phase. Flag discrepancies in a dedicated column. Prioritize by traffic. Your top 50 organic pages should be audited first because those are the ones where metadata errors will cost you the most.&lt;/p&gt;

&lt;p&gt;Third, fix in bulk. This is the step where most teams burn out because they try to do it inside HubSpot one page at a time. Tools like &lt;a href="https://www.smuves.com/features" rel="noopener noreferrer"&gt;Smuves&lt;/a&gt; exist specifically for this problem. You can pull your HubSpot CMS content into a spreadsheet-style interface, edit metadata fields across hundreds of pages at once, and push the changes back. The activity logs give you a clear audit trail of what changed, when, and by whom, which matters a lot when multiple people are touching pages during a migration cleanup.&lt;/p&gt;

&lt;p&gt;Fourth, re-crawl and validate. After bulk fixes, run another crawl to confirm everything stuck. Compare against your pre-migration baseline. Check Google Search Console for any new crawl errors that appeared.&lt;/p&gt;

&lt;h3&gt;
  
  
  The alt text problem nobody talks about
&lt;/h3&gt;

&lt;p&gt;One metadata field that consistently gets destroyed during migrations is featured image alt text. Most migration tools focus on transferring the image file itself but ignore the alt text attribute. The result is hundreds of pages with images that have no alt text, which hurts both accessibility and image search visibility.&lt;/p&gt;

&lt;p&gt;This is one of those issues that is invisible until someone audits for it specifically. If you are doing a post-migration audit, add an alt text column to your spreadsheet and flag every page where the featured image alt text is empty or generic. The &lt;a href="https://www.smuves.com/blog/most-overlooked-website-hygiene-item-featured-image-alt-text" rel="noopener noreferrer"&gt;Smuves blog has a solid breakdown&lt;/a&gt; of why this specific field gets overlooked and how to approach fixing it at scale.&lt;/p&gt;

&lt;h3&gt;
  
  
  What should be in every migration project plan
&lt;/h3&gt;

&lt;p&gt;If I could add one section to every CMS migration project plan, it would be a dedicated "Post-Launch Metadata Audit" phase with its own timeline and resource allocation. Not a bullet point under "QA." An actual phase with assigned owners and deadlines.&lt;/p&gt;

&lt;p&gt;Here is what that section should include: a pre-migration metadata export as a baseline, a crawler setup ready to run on launch day, a prioritized audit checklist sorted by organic traffic, a bulk editing tool or workflow for fixing issues without the one-page-at-a-time grind, and a 30-day monitoring plan covering Search Console, analytics, and social sharing previews.&lt;/p&gt;

&lt;p&gt;The migration is not done when the site goes live. It is done when the metadata is clean. Every team that learns this the hard way wishes someone had told them sooner.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>hubspot</category>
    </item>
    <item>
      <title>I Used AI to Generate 300 Meta Descriptions. Then I Spent Two Days Uploading Them to HubSpot One by One.</title>
      <dc:creator>Smuves</dc:creator>
      <pubDate>Tue, 24 Feb 2026 06:31:13 +0000</pubDate>
      <link>https://dev.to/smuves/i-used-ai-to-generate-300-meta-descriptions-then-i-spent-two-days-uploading-them-to-hubspot-one-by-1gb2</link>
      <guid>https://dev.to/smuves/i-used-ai-to-generate-300-meta-descriptions-then-i-spent-two-days-uploading-them-to-hubspot-one-by-1gb2</guid>
      <description>&lt;p&gt;Let me walk you through the most frustrating workflow I have encountered this year.&lt;/p&gt;

&lt;p&gt;A client handed me a HubSpot site with 312 blog posts. Most had either blank meta descriptions or auto-generated ones that said something like "Read this blog post to learn more about..." which is basically the same as having nothing at all.&lt;/p&gt;

&lt;p&gt;So I did what any reasonable person would do in 2026. I pulled all 312 URLs into a spreadsheet, ran them through an AI tool, and generated fresh meta descriptions in about 40 minutes. Each one was tailored to the page content, included relevant keywords, and stayed under 155 characters.&lt;/p&gt;

&lt;p&gt;That was the easy part.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Part Nobody Talks About
&lt;/h3&gt;

&lt;p&gt;Here is where the workflow completely falls apart. HubSpot does not have a bulk import for meta descriptions. There is no CSV upload for page metadata. There is no multi-select editing for SEO fields.&lt;/p&gt;

&lt;p&gt;The HubSpot Community thread requesting this feature has been open for years. Hundreds of upvotes. Comments from agency owners, SEO managers, and content leads all saying the same thing. One person wrote that they had a 500-page site and could export all titles and descriptions instantly using any crawling tool, but importing them back was a grind that ate their entire week.&lt;/p&gt;

&lt;p&gt;I sat there clicking into each blog post, navigating to settings, pasting the meta description, clicking save, and moving on to the next one. For 312 posts.&lt;br&gt;
The AI took 40 minutes. The manual upload took roughly 14 hours across two days.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why This Gap Exists
&lt;/h3&gt;

&lt;p&gt;Most CMS platforms were built before AI content generation was a realistic workflow. The assumption was always that you would write one page at a time, set its metadata, publish, and move on. Nobody designed for the scenario where a team could produce 300 pieces of optimized metadata in an afternoon and need to deploy them all at once.&lt;/p&gt;

&lt;p&gt;HubSpot specifically treats page settings as individual records. You open a page, you edit its settings, you save. There is no spreadsheet view. There is no API-friendly batch endpoint for CMS page metadata that normal marketing teams can use without developer support.&lt;br&gt;
The ironic part is that HubSpot actually has solid bulk editing for CRM records. You can filter contacts, select hundreds, and update properties in bulk. But that same capability does not extend to CMS content like blog posts, landing pages, or website pages.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Spreadsheet Bridge Pattern
&lt;/h3&gt;

&lt;p&gt;After that painful experience, I started looking for better workflows. The pattern that actually works looks like this.&lt;br&gt;
First, export all your HubSpot CMS content to a Google Sheet. This gives you a working spreadsheet with page titles, URLs, current meta descriptions, alt text fields, and other metadata all visible in columns.&lt;/p&gt;

&lt;p&gt;Second, use AI tools directly inside the spreadsheet. Google Sheets supports extensions and scripts that can call AI APIs. You can generate meta descriptions, rewrite title tags, or create alt text right there in the cells next to the original content. You can review everything before anything touches your live site.&lt;/p&gt;

&lt;p&gt;Third, import the edited spreadsheet back into HubSpot in bulk.&lt;/p&gt;

&lt;p&gt;That third step is the one that used to be impossible. Tools like Smuves have started solving this exact problem by connecting Google Sheets directly to HubSpot CMS. You edit in the spreadsheet and push changes back without clicking into 312 individual page settings.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Practical Workflow for AI-Generated Metadata
&lt;/h3&gt;

&lt;p&gt;Here is what the actual process looks like when the tooling works properly.&lt;/p&gt;

&lt;p&gt;Step one. Connect your HubSpot portal to a bulk editing tool and export your CMS content. You want every blog post, landing page, and website page in a single sheet with their current metadata.&lt;/p&gt;

&lt;p&gt;Step two. Identify the gaps. Filter for blank meta descriptions, duplicate title tags, missing alt text. This is your hit list.&lt;/p&gt;

&lt;p&gt;Step three. Run AI generation on the flagged items. Whether you use ChatGPT, Claude, or a Sheets-native AI extension, the goal is the same. Generate optimized content for each empty or weak field.&lt;/p&gt;

&lt;p&gt;Step four. Review in the spreadsheet. This is critical. AI output needs human review. Check for accuracy, tone, and keyword alignment. Fix anything that sounds generic or misses the point of the page.&lt;/p&gt;

&lt;p&gt;Step five. Import the updated sheet back into HubSpot. With a tool that supports &lt;a href="https://www.smuves.com/features" rel="noopener noreferrer"&gt;bulk CMS editing and Google Sheets sync&lt;/a&gt;, this step takes minutes instead of days.&lt;/p&gt;

&lt;h3&gt;
  
  
  What About Find and Replace?
&lt;/h3&gt;

&lt;p&gt;There is another scenario where this gap hurts. Say you rebrand and need to update your company name across 400 pages. Or you change a product name and it appears in meta descriptions, title tags, and body content everywhere.&lt;/p&gt;

&lt;p&gt;HubSpot does not have a global find-and-replace for CMS content. You either write a custom script using the API or you open every single page.&lt;/p&gt;

&lt;p&gt;Bulk editing tools with find-and-replace functionality can scan all your HubSpot content, show you every instance of the old text, let you preview the replacement, and execute across all pages at once. That is the kind of operation that should take five minutes, not five days.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Real Bottleneck in AI Content Workflows
&lt;/h3&gt;

&lt;p&gt;I keep seeing articles about how AI is transforming content marketing. And it is. The generation side is genuinely impressive. But the deployment side, the actual process of getting AI-generated content live on your CMS, has not kept up.&lt;/p&gt;

&lt;p&gt;The bottleneck is not creation anymore. It is implementation.&lt;br&gt;
If you are running a HubSpot site with more than 100 pages, you need a bulk operations layer between your AI tools and your CMS. Otherwise you are generating content at machine speed and deploying it at human speed, which defeats the entire purpose.&lt;/p&gt;

&lt;p&gt;The teams that figure out this middle layer are going to move significantly faster than everyone else. Not because their AI is better, but because their operational workflow does not have a two-day manual bottleneck sitting in the middle of it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Takeaways
&lt;/h3&gt;

&lt;p&gt;The AI-to-CMS pipeline is broken for most HubSpot users. The fix is not better AI. It is better bulk editing infrastructure.&lt;/p&gt;

&lt;p&gt;If you are generating metadata, alt text, or content updates with AI, build your workflow around spreadsheets as the bridge layer. Generate in sheets, review in sheets, push to CMS in bulk.&lt;/p&gt;

&lt;p&gt;And if you are evaluating tools for this, look for Google Sheets integration, bulk import and export for CMS fields, find-and-replace across all content types, and activity logs that track what changed. That combination closes the gap between AI generation and CMS deployment.&lt;/p&gt;

</description>
      <category>hubspot</category>
      <category>ai</category>
      <category>bulkediting</category>
    </item>
    <item>
      <title>How to Actually Fix Your HubSpot SEO Audit (Without Losing Your Mind)</title>
      <dc:creator>Smuves</dc:creator>
      <pubDate>Wed, 18 Feb 2026 05:06:04 +0000</pubDate>
      <link>https://dev.to/smuves/how-to-actually-fix-your-hubspot-seo-audit-without-losing-your-mind-2kme</link>
      <guid>https://dev.to/smuves/how-to-actually-fix-your-hubspot-seo-audit-without-losing-your-mind-2kme</guid>
      <description>&lt;p&gt;You ran the audit. Good job. Now you are staring at 340 pages with missing meta descriptions, 180 blog posts with no alt text on the featured image, and a spreadsheet someone started two quarters ago that nobody finished.&lt;/p&gt;

&lt;p&gt;This is the moment most HubSpot teams quietly close the tab and go do something else.&lt;/p&gt;

&lt;p&gt;It is not laziness. The audit itself is easy. What comes after is the part nobody warns you about. HubSpot's native editor was not built for fixing things at scale. Every fix is one page at a time, one settings panel at a time, one save button at a time.&lt;/p&gt;

&lt;p&gt;Here is what a realistic remediation workflow looks like, and where the actual bottleneck lives.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Your Audit Actually Surfaces
&lt;/h3&gt;

&lt;p&gt;Whether you are using Screaming Frog, Semrush, Ahrefs, or HubSpot's own SEO recommendations tool, a typical audit on a mid-size HubSpot site returns roughly the same categories of issues.&lt;/p&gt;

&lt;p&gt;Missing or duplicate page title tags. HubSpot will let you publish a page without a custom title. That means your page title defaults to whatever the internal page name is, which is often something like "LP - Q3 Offer - FINAL v2". Not great for a SERP.&lt;/p&gt;

&lt;p&gt;Missing or thin meta descriptions. Google does not always use your meta description, but it does read it. Social previews pull from it directly. A missing meta description on a shared blog post means the platform grabs the first sentence of body text, which sometimes starts with "In this article, we will cover..." Not exactly a compelling click.&lt;/p&gt;

&lt;p&gt;Featured image alt text missing across the blog. This one is easy to overlook because it does not fail a page load. It just quietly hurts accessibility, image search visibility, and how AI systems read your content. There is a solid breakdown of why this matters more than most people think at the &lt;a href="https://www.smuves.com/blog/most-overlooked-website-hygiene-item-featured-image-alt-text" rel="noopener noreferrer"&gt;Smuves post on featured image alt text&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Duplicate title tags across similar posts. Topic clusters in HubSpot tend to breed duplicate or near-duplicate titles if you built them fast and planned to optimize later.&lt;/p&gt;

&lt;p&gt;A 300-page site with moderate hygiene debt will typically surface 80 to 150 actionable issues. That sounds manageable until you open HubSpot and realize there is no "fix all" button anywhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  The HubSpot Editing Problem
&lt;/h3&gt;

&lt;p&gt;Here is the specific friction. HubSpot's content editor is a per-page interface. To update metadata on a blog post, you go into the post, click Settings, update the title, update the meta description, save, publish. Then you go to the next post.&lt;/p&gt;

&lt;p&gt;That workflow is fine for one post. It is not fine for 140 posts.&lt;/p&gt;

&lt;p&gt;There is no native CSV import for metadata. There is no multi-select-and-edit for SEO fields. There is no global find-and-replace for title tag patterns. The HubSpot Community thread requesting bulk metadata editing has been open for years and has hundreds of upvotes. As of mid-2025, someone posted: "500 page site. We can export all the titles and descriptions using any old tool in an instant, but importing them back in is one huge grind for the team."&lt;/p&gt;

&lt;p&gt;That is the real problem. The audit is not the hard part. The remediation is the hard part, because the tooling was not built for it.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Practical Remediation Workflow
&lt;/h3&gt;

&lt;p&gt;Here is how teams actually get through this without spending weeks on it.&lt;/p&gt;

&lt;p&gt;Step 1: Export your audit data into a working spreadsheet.&lt;br&gt;
Pull your flagged URLs, current titles, current meta descriptions, and alt text fields into a Google Sheet. If you are using Screaming Frog, export to CSV. If you are using Semrush's Site Audit, export the specific issue report. Your goal is a sheet where each row is a page and the relevant SEO fields are columns you can edit directly.&lt;/p&gt;

&lt;p&gt;Step 2: Fix metadata in bulk inside the spreadsheet.&lt;br&gt;
This is the part most people do not realize they can do efficiently. With all your titles and descriptions visible in one place, you can sort by character count to catch titles over 60 characters, use formulas to flag duplicates instantly, and write new titles and descriptions right in the cells without switching tabs between 140 browser windows.&lt;/p&gt;

&lt;p&gt;For alt text specifically, add a column for the generated description and batch-write them based on what each image actually shows. Good alt text for a featured image should describe what the image communicates in context, not just what it literally depicts. The anatomy of good page metadata post from Smuves goes deep on what "good" actually looks like across title tags, meta descriptions, and OG tags.&lt;/p&gt;

&lt;p&gt;Step 3: Push the changes back into HubSpot.&lt;br&gt;
This is where native HubSpot tooling falls flat. The spreadsheet is great for editing. Getting edits back into HubSpot without a tool like Smuves means either copy-pasting every field manually or writing an API script to handle it. Smuves handles this loop directly: pull HubSpot CMS content to Google Sheets, edit in the sheet, push updates back. No API knowledge required, no per-page clicking.&lt;/p&gt;

&lt;p&gt;Step 4: Prioritize by traffic, not by page count.&lt;br&gt;
Do not try to fix everything at once. Sort your audit data by organic sessions and fix the top 20% of pages first. Those fixes will have the most immediate SEO impact. The remaining 80% can be scheduled in batches over a sprint or two.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Gets Better When You Actually Do This
&lt;/h3&gt;

&lt;p&gt;After a metadata remediation pass on a site with 150-plus blog posts, the most common improvements are:&lt;/p&gt;

&lt;p&gt;Click-through rate from organic search goes up. Better titles and descriptions are a direct lever on CTR, which feeds back into rankings over time.&lt;/p&gt;

&lt;p&gt;Social sharing looks more intentional. OG titles and descriptions stop defaulting to internal draft names.&lt;/p&gt;

&lt;p&gt;AI search visibility improves. Language models that scan your site now have clean, descriptive signals to work with instead of blank fields.&lt;/p&gt;

&lt;p&gt;The next audit is significantly faster. Once your hygiene baseline is clean, ongoing maintenance is much lighter.&lt;/p&gt;

&lt;p&gt;The audit you have been sitting on is not the obstacle. The page-by-page editing interface is the obstacle. Once you remove that friction, the whole backlog becomes a few hours of focused spreadsheet work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick Checklist Before You Start
&lt;/h3&gt;

&lt;p&gt;Before you touch a single page, make sure your spreadsheet has these columns ready:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Page URL&lt;/li&gt;
&lt;li&gt;Current title tag with character count&lt;/li&gt;
&lt;li&gt;Current meta description with character count&lt;/li&gt;
&lt;li&gt;Featured image alt text (blank means missing)&lt;/li&gt;
&lt;li&gt;Organic traffic from the last 90 days&lt;/li&gt;
&lt;li&gt;Priority tier based on traffic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sort by priority. Work top to bottom. Batch the pushes back into HubSpot. Do not try to perfect every row before you start pushing updates. Progress beats perfection here.&lt;/p&gt;

&lt;p&gt;The audit does not have to sit in a folder. It just needs a workflow that matches the actual scale of the problem.&lt;/p&gt;

</description>
      <category>hubspot</category>
      <category>bulkediting</category>
    </item>
  </channel>
</rss>
