HubSpot's Undocumented Image Resizing API
Tags: hubspot, nuxt, imageoptimization, problemsolving
Published: 2020-11-19 17:34:22

**TL;DR:** Resize your HubSpot-hosted images by using URLs of the form `https://f.hubspotusercontent40.net/hub/${PORTAL_ID}/hubfs/${IMG_NAME}.jpg&width=400&name=${IMG_NAME}.jpg`. Your mileage may vary, read the post for more info!

If you are looking for **image optimization on HubSpot CMS templates only, HubSpot supports that [by default](https://knowledge.hubspot.com/cos-general/can-i-disable-automatic-image-resizing).** You can stop reading here 🙂

This article is about requesting resized versions of images that are hosted on HubSpot, but *from a non-HubSpot site*. You might be in this situation when you're getting HubSpot-hosted image URLs through the HubSpot CMS Blog API, CMS Files API or CMS HubDb API (possibly others too). 

Note: this blog post was a learning from a project at [Columbia Road](https://www.columbiaroad.com/), an updated version can be found on the company site: [Tech logs: HubSpot's Undocumented Image Resizing API](https://www.columbiaroad.com/blog/tech-logs-hubspots-undocumented-image-resizing-api)

------

Nowadays, responsive images are not a gimmick anymore. With a web that has [an equal share](https://gs.statcounter.com/platform-market-share/desktop-mobile-tablet) of mobile and desktop users, responsive images are a must if you don't want a user to bounce on a slow-loading, image-heavy web page.

Modern browsers widely support the HTML `srcset` attribute that enables responsive images ([MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-srcset), [CanIUse](https://caniuse.com/srcset)) and its CSS `background-image` equivalent `image-set()` ([CanIUse](https://caniuse.com/css-image-set)). But automatically creating responsive image sets is not trivial. You usually use a specialized media hosting service or Digital Asset Manager for that (e.g. Cloudinary or Contentful). HubSpot also provides this service, but it is somewhat hidden. Read on to learn how it works.

# Problem: no documented HubSpot Image API

In a project at [Columbia Road](https://www.columbiaroad.com/) we recently became stewards of a site driven by Nuxt.js. Large images on the site were causing long loading times. Many of these images came from HubSpot: the Nuxt.js site used the [HubSpot Blog API](https://developers.hubspot.com/docs/api/cms/blog-post) to generate a listing of blog posts, and these blog posts had featured images that were hosted on HubSpot.

To reduce the loading time we needed to implement responsive images, but while HubSpot [magically supports responsive images and on-demand image resizing](https://knowledge.hubspot.com/cos-general/can-i-disable-automatic-image-resizing) in its own HubSpot CMS template pages, it did not expose a documented API for doing that externally on a non-HubSpot page.

# Solution: an undocumented API

Here's how we did get access to an API anyway. Since HubSpot has an internal mechanism for generating responsive `srcset` attributes and specifying a certain image `width`, we could figure out if we could somehow influence that mechanism from the outside. A starting point was by looking at the output of responsive images generated by HubSpot.

### Modifying the image size

To inspect the output of HubSpot's responsive image resizing mechanism, we made a test Coded HubSpot CMS Blog Page Template in HubL. We included the following source code that handles the featured blog image, as suggested by the [image resizing documentation](https://knowledge.hubspot.com/cos-general/can-i-disable-automatic-image-resizing) for HubL pages:

```django
{# Note: this is an excerpt of a Coded HubSpot Blog Template to use as an illustration, it's not a fully working template #}
<img width="200px" src="{{ content.post_list_summary_featured_image }}" />
<img width="600px" src="{{ content.post_list_summary_featured_image }}" />
```

When looking at a preview of a blog post with the above template, the corresponding HTML output was generated for the images (see this by inspecting the HTML of the preview page):

```html
<!-- Variable Portal ID and image title are omitted for the privacy of our client -->
<img width="200" src="https://f.hubspotusercontent40.net/hub/${PORTAL_ID}/hubfs/${IMG_NAME}.jpg&width=400&name=${IMG_NAME}.jpg">
<img width="600" src="https://f.hubspotusercontent40.net/hub/${PORTAL_ID}/hubfs/${IMG_NAME}.jpg&width=600&name=${IMG_NAME}.jpg">
```
We see here that the `<img>` tag that got a `width="400px"` attribute in a Coded HubSpot Blog Template now has a corresponding URL `?width=400` query parameter related to image resizing. **This starts to reveal a solution to our problem: we can modify this parameter to request a different size of the image.**

But we're not ready yet. How do we generate these image URLs ourselves? 

### Transforming a generic image URL into responsive URLs

Let's consider our original input in Nuxt.js, which we got from the Blog API data: in the response of the official Blog API, we found that the HubSpot Blog API gave us generic image URLs in the following basic formats:

```bash
# URL type 1 - for featured images
https://cdn2.hubspot.net/hubfs/${PORTAL_ID}/${IMG_NAME}.jpg

# URL type 2 - for featured images
https://f.hubspotusercontent40.net/hubfs/${PORTAL_ID}/${IMG_NAME}.jpg

# NOTE: this might vary on your portal.
# The HubSpot File Manager suggest that you can also use branded domain name from the site for these two types
https://brand.com/hubfs/${PORTAL_ID}/${IMG_NAME}.jpg
# A third image type for author icons also exists, but won't be covered here as they are already small thumbnails.
```

Here I should note that these input URLs might vary based on your Portal and the source of the URLs. Check the API response you're looking at or HubSpot's media manager to find your input URLs. The output URLs might also vary. If you don't know what they are, replicate the template test I did in the previous section.

For the URL types 1 and 2 that we encountered it was possible to extract the  `PORTAL_ID` and  `IMG_NAME` from the Blog API responses with a regular expression, and then reconstruct a URL of the output form which we saw in the last section. The resulting transformed URL succeeds in loading images of the requested size: mission accomplished.

The following function on CodePen implements this transformation. Feel free to adapt it to your needs!

{% codepen https://codepen.io/th0rgall/pen/OJXYxdm default-tab=js%}

# Caveats

There are some caveats to mention:

1. '**Undocumented' probably also means 'unsupported'.** If HubSpot would break or change this functionality, and you can not respond quickly to revert the image URLs to their original form, images on your site could break without warning. See [Alternatives & Improvements](#alternatives-amp-improvements) on how to mitigate this situation.
2. **Give it some time.** For some images it took some time (tens of seconds to minutes) from the first requested resized image in order for the actual resized image to appear. This could be due to scheduled resizing processes or variable time in CDN distribution at HubSpot's side.
3. **No complete support.** For some reason unknown to us this resizing only works for ~90% of the images where we tried it on. For some images the original resolution is returned, no matter what size parameters we give it.
4. **Only width & height controls.** Other Image optimization APIs pformat format (e.g. WebP) and quality parameters. This API doesn't clearly expose those. Note: it seems that HubSpot is serving WebP by default when using these resizing options APIs.

# Alternatives & improvements

One important improvement on the above code would be to load images via JavaScript. In such a case, you could detect potential 400 or 500 error codes when HubSpot changed this API's functionality or signature, and you could automatically insert the original URL instead. 

Another sure-fire approach to the whole problem would be to implement a microservice that scrapes the images from the HubSpot Blog API and uploads them to Contentful on a regular basis. This would protect you from API changes. However, this approach also has disadvantages. One, it's more costly to architect & develop. Two, it's more costly to operate because you need to manage an extra service. Still, it could be a solution if you need a massive number of HubSpot-sourced images on an external web page and you have a very low fault tolerance. At least one person on the internet has done [something similar](https://www.impactplus.com/blog/why-developers-love-hubspot).

And with that thought put out there, this post is a wrap! I hope it can help someone who - like me - Googled for a solution to this problem unsuccessfully. It *is* pretty annoying that HubSpot does not have a documented API for resizing images.