HubSpot
Feb 2026
HubSpot Enrich Contact: how we built it
Context
Enriching a HubSpot contact sounds simple until you want it to be free, let users bring their own API keys, stay secure, and still feel effortless in the CRM.
This project is our answer: a HubSpot tool that orchestrates multiple enrichment providers in cascade while keeping the UX straightforward and the sensitive parts locked down.
Tech: what you need
Auto-deployed HubSpot project
CRM Card + Settings page (React + TypeScript)
Cascading enrichment services (Full Enrich → Zeliq → Kaspr), with added complexity when results come back via webhook
Context
The challenge was to ship a free HubSpot tool that allows users to plug in their own API keys for multiple enrichment services while keeping the experience simple and the implementation secure.
The hardest part was chaining providers based on what’s configured and available, without exposing complexity to the user who triggers the enrichment request.

How to built it
HubSpot project & auto-deploy
We built the HubSpot app using HubSpot’s most up-to-date, declarative app system. The project is defined in a JSON file stored on GitHub and auto-deployed to HubSpot whenever updates are made. This gives us automation for configuration, plus traceability and reproducibility: every action is recorded and historized, which reduces human error and improves collaboration.
The app also uses HubSpot’s newer capabilities, including a fully custom Settings page. That’s where users can enter the API keys for the enrichment services they want to use, and see them displayed in an obfuscated way (fetched from our own database).
CRM Card & Settings in React / TypeScript
Using HubSpot’s environment, we built both:
the CRM Card (shown on the contact page), and
the Settings page, in React + TypeScript.
React handles UI state and interactions, while TypeScript reduces developer errors by enforcing correctness. HubSpot runs this UI code in a dedicated, isolated environment: we only access the interface and a limited set of contact-related data. This setup helps keep the user experience highly custom while staying safe.
This architecture also makes it straightforward to interface with our own database through secure APIs while benefiting from HubSpot’s additional isolation layer.

Backend: from n8n-first to a dedicated NodeJS service
We initially considered handling everything in n8n, but the tool’s requirements quickly made that approach harder to evolve. We needed, among other things:
HubSpot call validation: HubSpot includes a cryptographic signature on each call. We validate it to ensure requests genuinely come from HubSpot. This is critical to prevent malicious access to sensitive data, and it also helps identify which HubSpot instance is calling us (so we can decode the right API keys).
HubSpot authentication workflow: required when connecting the app to a new HubSpot instance, and used to apply changes back into HubSpot (for example, writing phone/email found by enrichment).
API key encryption: since we store per-instance keys, they’re stored encrypted in MongoDB under AES-256.
Cascading enrichment orchestration: covered in the next section.
Because of this, we implemented a dedicated NodeJS service to handle the full backend scope without over-engineering. In n8n, this would have been possible, but it would have required multiple workflows sharing functions and logic, making it less maintainable and harder to test over time.
Cascading enrichment services
Chaining enrichment providers introduces a few key challenges: deciding which services are available, handling provider-specific errors, and dealing with responses that may be asynchronous. For example, Full Enrich may not respond immediately; instead, it calls back later via webhook once results are ready.
To manage this, we treat each enrichment request as a flow with:
a progress stage,
which service was used,
what response was received,
and what the next step should be.
When a provider returns a result, it includes a “signature” that lets us map it back to the correct flow so we can either continue to the next service (if needed) or update HubSpot if the result is good.
On the UI side, the CRM card periodically asks for the flow status and updates automatically as soon as a valid response arrives. It also shows which provider produced the result.
The final outcome
A free HubSpot tool that lets users plug in their own API keys to run contact enrichment securely. This project provides a simple, “one-click” enrichment experience inside the CRM while hiding all the hard parts behind a clean architecture: a React/TypeScript CRM card and Settings page on the front end, and a dedicated NodeJS service on the back end to validate HubSpot signatures, handle OAuth, encrypt keys (AES-256), and orchestrate the enrichment cascade.

