Case study · HubSpot · UI extensions and Cloudflare Workers
One-click tags on HubSpot contacts and companies
HubSpot has no manual tags on contacts or companies, and people have asked for them since 2017. We built a free app that adds a Tags card to the record and a settings page to rename, merge and delete tags across every record. It is our own product, built and shipped by our team.
Find or add a tag
- Churn risk
- Key account
- Newsletter
- Partner
- Referral
- Trade show 2026
The problem
No tags where people want them most
There is no tag field you can add to a HubSpot contact or company by hand. The request in HubSpot's ideas forum has 488 votes, and HubSpot marked it Not Currently Planned in May 2020. HubSpot's colour-coded object tags cover deals, tickets and some other objects, but not contacts or companies. They are set by rules, not by hand, and need a paid plan.
The usual workaround is a multiple-checkbox property used as a tag field. Every new tag is a property option, so a user without permission to edit property settings has to ask an admin. Merging two tags means a filter, two bulk edits and deleting an option by hand. On the free CRM, each such property uses one of only 10 custom properties.
What we built
A card, a settings page and a small backend
The Tags card sits on contact, company and deal records and shows the record's tags as coloured chips. Tick to add, untick to remove, or type a name to create a new tag. The settings page lets admins add, rename, recolour, merge and delete tags, or point the app at an existing multiple-checkbox property. Because tags live in that property, views, segments, workflows and reports all work with them.
A normal HubSpot property
Tags are saved on the records, in the customer's own account. Our backend keeps no record data.
Create as you type
Anyone who can see the card can add a new tag on the spot. Admins can switch that off so only they add tags.
Rename, merge, delete
Changes run across every record that carries the tag, in steps, with progress shown on the settings page.
Every plan
Works on the free CRM and every paid plan, using one custom property per object.
Engineering
The hard parts, and how we solved them
- Why it needed a backend. HubSpot's own serverless functions can only be installed by Enterprise accounts, and they aren't available to apps distributed through the Marketplace. A free app for every plan still needs a place for its OAuth tokens. We used a Cloudflare Worker with a D1 database that stores only the encrypted tokens, each tag's colour and two settings.
- OAuth and trust. The Worker exchanges the install code for tokens, encrypts them with AES-GCM bound to the account id, and after install redirects only to HubSpot addresses. Every call from the card or settings page must carry a valid HubSpot signature and exactly one account id and user id, so a request can't point at another account. Every change on the settings page needs a Super Admin, which the Worker checks with HubSpot.
- Two people tagging the same record. Adds use HubSpot's append syntax, so two people adding tags at once don't overwrite each other. Changes to the list of tags take a short lock and re-check the list right before the write.
- Rename and merge across many records. Merge and delete run in steps of up to 500 records, with a lock on the object held across steps so two admins can't run conflicting jobs. Each page re-reads current values with a batch read, because search results can lag, and re-reads the tag list so a tag created meanwhile isn't stripped. At the end, a final pass and one last search confirm that no record still carries the old tag before the option is removed.
- Staying inside the limits. Cloudflare caps the outbound calls one Worker request can make. Each step tracks its HubSpot call budget, caps retries, times out a call after 15 seconds and hands back a cursor before it runs out, and the settings page keeps calling until the job is finished. HubSpot replays a card's request to the backend if it fails with a server error, so the Worker reports HubSpot outages as client errors, to avoid repeated writes.
- HubSpot's own rules. A multiple-checkbox property can't exist without options, so the property is created with the first tag, and the last tag can't be deleted. When an account uninstalls, an hourly job notices the revoked token, deletes it, and purges the colours and settings 30 days later unless the account installs again.
Result
Where it is now
The first build was live-tested on 1 October 2026 in a HubSpot test account: the card on a contact, a company and a deal, and every settings action, from rename and merge to switching to an existing property. Two rounds of internal code review followed. The second, four separate passes over backend security, data handling, the interface and the docs, found no critical or high-severity issues, and every finding from both rounds was fixed with a test. The code has 102 automated tests covering the card, the settings page and the backend.
The backend is deployed and the app is available on request. It is not on the HubSpot Marketplace yet. HubSpot requires three active installs from unrelated accounts, and an app card review, before a new listing can be submitted.