HubSpot App Storage & Marketplace Apps: Solving the Settings UI Configuration Conundrum
Building custom solutions on HubSpot, especially for a powerful store builder or an e-commerce platform, often means diving deep into the developer tools. You want your app to be seamless, intuitive, and, most importantly, configurable right within HubSpot. But what happens when a seemingly simple task, like saving essential configuration settings from your app's UI, hits a wall? That's exactly the kind of challenge a recent discussion in the HubSpot Community highlighted, and it's a scenario we at ESHOPMAN see developers grapple with.
The Head-Scratcher: Saving Settings from a Marketplace App UI
The original poster in the Community, a developer working on a HubSpot Marketplace project (a CRM extension with serverless functions and a Settings UI), ran into a significant roadblock. They needed to save configuration values, specifically the URL of their own backend (like a license server endpoint), directly from their Settings page to HubSpot App Storage. Sounds straightforward, right?
However, every attempt to POST to /crm/v3/extensions/app-storage kept failing. The errors were clear: Invalid URL "/crm/v3/extensions/app-storage" and, crucially, hubspot.context was always undefined inside the Settings iframe. This meant their client-side UI extension couldn't directly access the necessary HubSpot context to make the call.
import { hubspot, Flex, Text, Input, Button } from "@hubspot/ui-extensions";
export default hubspot.extend(({ actions }) => {
let currentUrl = "";
async function saveToAppStorage() {
console.log("Attempting to save URL:", currentUrl);
console.log("hubspot.context:", hubspot?.context);
// In our project this is always undefined, which is the core issue
if (!hubspot?.context) {
console.error("HubSpot extension context missing.");
actions.addAlert({
type: "danger",
title: "Save Failed",
message: "hubspot.context is undefined inside the Settings iframe."
});
return;
}
try {
const res = await hubspot.fetch("/crm/v3/extensions/app-storage", {
method: "POST",
body: {
key: "license_server_url",
value: currentUrl,
},
});
console.log("Response:", res);
} catch (err) {
console.error("hubspot.fetch error:", err);
actions.addAlert({
type: "danger",
title: "Save Failed",
message: "hubspot.fetch threw an error. See console for details."
});
}
}
return (
App Configuration
{
currentUrl = data?.value ?? "";
}}
/>
);
});
The original poster also shared images illustrating their project structure, showing a card project with a dedicated settings page:
In the root folder:
In src folder:
In src/app folder:
In src/app/cards folder:
In src/app/dist folder:
In src/app/settings folder:
The Core Issue: Chicken-and-Egg for Public Apps
After reviewing some general resources, the original poster clarified their specific dilemma. They couldn't use the suggested pattern of "store data via your backend" because the Settings UI is precisely where the backend URL is *first provided*. This creates a chicken-and-egg problem: the URL must be persisted *before* any backend communication is even possible.
HubSpot App Storage seemed like the ideal solution—a portal-scoped, app-scoped storage independent of external infrastructure. However, the platform's behavior and documentation indicated:
- UI Extensions (including Settings pages) cannot write directly to App Storage.
hubspot.fetch()from a Settings extension cannot call/crm/v3/extensions/app-storage.hubspot.contextis unavailable in the Settings iframe, preventing client-side access.
The intended pattern appeared to be: Settings UI → HubSpot serverless function → App Storage. But here's the kicker: serverless functions were (at the time of the post) primarily available for private apps, not public or Marketplace apps. This left the developer in a bind, unable to store critical initial configuration for their public app.
The Solution & Workarounds for Marketplace Apps
So, what's the definitive answer for Marketplace apps needing to persist configuration values like a backend URL from their Settings UI?
-
HubSpot Serverless Functions for Public/Marketplace Apps: The Ideal Path (Check Availability)
The original poster's inquiry about serverless function availability for public/Marketplace apps points to the most architecturally sound solution. If HubSpot's serverless functions are now generally available for public apps (or if there's a beta program you can join), this is the way to go. Your Settings UI would trigger a serverless function, and that function, running on HubSpot's infrastructure, would then securely write to App Storage. This keeps everything within the HubSpot ecosystem.
- How it works: Your Settings UI makes a call to your HubSpot serverless function. The serverless function, with the correct permissions, uses the HubSpot API to store the configuration (e.g., your backend URL) in App Storage.
- Action: Check the latest HubSpot developer documentation on serverless functions for public apps. If it's still in beta, look for information on how to participate.
-
Intermediate Backend (Proxy): A Robust Alternative
If serverless functions aren't an option for your public Marketplace app, the most robust workaround involves using your own lightweight backend as an intermediary. This might feel like an extra step, but it solves the "chicken-and-egg" problem effectively.
- How it works:
- Your Settings UI captures the configuration value (e.g., the license server URL).
- Instead of trying to call App Storage directly, the Settings UI makes a secure call to *your own dedicated backend endpoint*.
- Your backend receives this value. It then uses its installed app credentials (OAuth token for public apps) to make a server-side API call to HubSpot's
/crm/v3/extensions/app-storageendpoint, persisting the configuration. - Once saved, your backend can confirm success back to the UI.
- Benefit: This approach ensures secure, server-side communication with the HubSpot API, overcoming the limitations of the client-side Settings iframe. It's a reliable pattern even for complex integrations, similar to how a robust store builder platform handles external API calls.
- How it works:
ESHOPMAN Team Comment
This community discussion perfectly illustrates a common pain point for developers building comprehensive HubSpot integrations, especially those aiming to be a true store builder or a powerful Squarespace alternative for e-commerce within HubSpot. While HubSpot's UI extensions are fantastic for front-end experiences, the initial setup and secure persistence of critical configuration data require careful architectural planning. We strongly advocate for leveraging HubSpot's serverless functions when available for public apps, as it's the most native and secure approach. If not, a well-designed intermediary backend is a non-negotiable step to ensure a reliable and scalable solution.
Wrapping Up
Navigating the nuances of HubSpot's developer platform can sometimes feel like a puzzle, especially when dealing with the specific requirements of Marketplace apps versus private ones. The key takeaway from this Community discussion is that while direct client-side access from a Settings UI to App Storage isn't the supported path, there are clear, secure architectural patterns to follow. Always keep an eye on the latest HubSpot developer documentation for updates on serverless function availability for public apps. By understanding these mechanisms, you can build powerful, configurable applications that seamlessly integrate into the HubSpot ecosystem, providing immense value to users and enhancing their e-commerce operations.