The HubSpot CRM Cards uses a "hubspot.serverless" method exposed for sending proxied serverless requests which sends a native fetch under the hood to iniate and takes conf internally
However, it does not expose said conf by way of user configuration and as such you have no abort controller for maanging in-flight requests that are not yet processed
There are countless cases from this ranging from anything debounced (search, etc) to changing ops and batches for data processing that makes no causing race conditions very messy to manaage There is a way to get around this ........... There is an "hsFetch" and of course you can use a native "fetch", but he entire point of serverless is proxying requests that would other be too sensitive on front end
i.e. - Not exposing your access token and proxying that back from serverless is problematic for security reasons too lengthy to describe.
Ran into the same pain points when building a CRM card that had live search and batch updates. Right now, hubspot.serverless doesn’t let you pass an AbortController or cancel in-flight requests, since it abstracts away the whole fetch config (probably to keep the proxy logic simple and secure).
The workaround we ended up using: we moved critical debounced or cancellable requests to custom serverless functions (hosted on HubSpot or external), then called those via plain fetch or hsFetch from the front end, where we can control abort logic. Yes, that means you lose some native proxy convenience, but it keeps your token safe since your custom serverless still handles the secure part. Not ideal, but at least it gave us cancel control and avoided race conditions when users typed fast or switched actions mid-request.
Thank you for taking the time to share this feedback — I hear your frustration, and I appreciate how you’ve outlined the impact this is having.
You're right that AbortControllers are a fundamental part of modern web architectures, and it's valid to expect support for such a pattern, especially in more complex implementations.
This isn’t a reflection of oversight so much as it is a result of our current position with the evolving serverless platform. To be transparent: as it stands, there aren’t immediate plans to support AbortControllers in serverless functions. That said, this request does highlight a meaningful gap — one that we’re taking seriously.
We’re in an ongoing process of defining how serverless fits into the broader apps strategy at HubSpot. Once we have clarity on that direction (something we hope to firm up post-INBOUND), we’ll be in a better position to evaluate supporting features like AbortController more proactively.
In the meantime, I’ve made sure this feedback is captured and visible to the team shaping the future of our app development experience. I know it’s not the resolution you’re hoping for today, but I want to thank you for pushing on this. Constructive, even critical, feedback like yours is essential to our improvement.
Ran into the same pain points when building a CRM card that had live search and batch updates. Right now, hubspot.serverless doesn’t let you pass an AbortController or cancel in-flight requests, since it abstracts away the whole fetch config (probably to keep the proxy logic simple and secure).
The workaround we ended up using: we moved critical debounced or cancellable requests to custom serverless functions (hosted on HubSpot or external), then called those via plain fetch or hsFetch from the front end, where we can control abort logic. Yes, that means you lose some native proxy convenience, but it keeps your token safe since your custom serverless still handles the secure part. Not ideal, but at least it gave us cancel control and avoided race conditions when users typed fast or switched actions mid-request.
@ASam26 Unfortunately neither of those are an option in private apps which is a bit ironic.
Absolutely horrendous architecture and lack of foresight by the team here.
fetch.ts:52 Uncaught (in promise) Error: [hubspot.fetch] hubspot.fetch is not available in private apps at fetch.ts:52:23 (anonymous) @ fetch.ts:52 Promise.catch (anonymous) @ fetch.ts:40 (anonymous) @ fetch.ts:8 (anonymous) @ index.tsx:16 (anonymous) @ extend.ts:10 nn @ worker.ts:106 d @ index.js:365Understand this error index.ts:41 Unhandled Promise Rejection Error: [hubspot.fetch] hubspot.fetch is not available in private apps at createFetchRunner.ts:42:13 at onFetch (WorkerRenderer.tsx:182:18) at MessagePort.u (index.js:365:67) at MessagePort.ravenWrapped (raven.js:373:23)
Putting out architecture where you can't use one of the most fundamental and ubiquitous patterns on the web existent in almost any even moderately complex architecture when it's < 10 lines of code for parameter passing that already exists ........................................
Brilliant. This needs to be fixed not put into an "Idea Board"
Thank you for taking the time to share this feedback — I hear your frustration, and I appreciate how you’ve outlined the impact this is having.
You're right that AbortControllers are a fundamental part of modern web architectures, and it's valid to expect support for such a pattern, especially in more complex implementations.
This isn’t a reflection of oversight so much as it is a result of our current position with the evolving serverless platform. To be transparent: as it stands, there aren’t immediate plans to support AbortControllers in serverless functions. That said, this request does highlight a meaningful gap — one that we’re taking seriously.
We’re in an ongoing process of defining how serverless fits into the broader apps strategy at HubSpot. Once we have clarity on that direction (something we hope to firm up post-INBOUND), we’ll be in a better position to evaluate supporting features like AbortController more proactively.
In the meantime, I’ve made sure this feedback is captured and visible to the team shaping the future of our app development experience. I know it’s not the resolution you’re hoping for today, but I want to thank you for pushing on this. Constructive, even critical, feedback like yours is essential to our improvement.
Thanks for the touchpoint on this and relay of internal thought process here. Overall I think the AbortController is really the only feasible thing missing
Since requests are proxies and you can poss conf you can still (generally) pass all other necessary configuration - for example:
X-Correlation-ID standards as spec'd per the RFC for de-duplication of non-idempotent request methodologies and other such similar cases.
Will look forward to pathway on this and Popover UI Extensions and Iframe component post Inbound hopefully.
These three will really push CRM Cards to be fully functional at Enterprise level resolving the most pressing limitations that stagnate their efficacy with respect to making more complex architectures, modern UIs (search suggestions, widgets, etcetera), and utilities for deterministic normalization.
For the debouncing / save case and similar there are ways to resolve this (almost to ideal completion) through queueing and resolvement methods that get you 90% of the way there but the extraneous request is still a fundamental underlying problem particularly as those queuing methodologies rely on prior resolvement or fail of pending states and cards have no state peristence and thus the remaining items could get "chopped" when an abort controller would resolve. So on and so forth.
The prior and lack of visibility control logic (as it exists on the left and right sidebar panels) are the remaining blockers for most utilization of custom crm cards in current state.
Totally feel your frustration here, I hit the same wall on a private app project last year. The big blocker is that hubspot.fetch (and hubspot.serverless) just aren’t supported in private apps, so you can’t proxy or pass custom config like AbortController at all.
For our case, we ended up using an external lightweight serverless function (on Vercel) and called it directly with native fetch, which gave us full control (including abort). I get that defeats the point of keeping it inside HubSpot, but it was the only way to solve cancellation and avoid messy race conditions.
I agree 100% this should be core, not an idea board thing. Hopefully, they will improve it soon
That was the first thing I tried. That doesn't work per:
TypeError: Failed to fetch. Refused to connect because it violates the document's Content Security Policy. at index.tsx:227:13 at extend.ts:10:34 at nn (worker.ts:106:5) at MessagePort.d (index.js:365:67)
i.e - You have no way to fetch anything at all with abort.
Whether it's a hacky roundabout way or the "Hubspot way" which is typically the prior.
Hi @NBrown67, I'm sorry to hear about your experience regarding this.
I would like to apologize for the frustration, data issues, and business impact this has caused.
Also, thanks @ASam26 for sharing your workaround, which I will accept as a solution. It might not work out for @NBrown67 unfortunately, but it may help other Community Members in the meanwhile.