Dynamic Dropdowns: Clean Up Messy Text Properties in HubSpot
How I built a HubSpot app that scans free-text properties, deduplicates messy values, and converts them into clean dropdown properties - and got my first install within hours of launch.
Built at Daeda Tech - This project was developed as part of Daeda Technologies.
Key Metrics
| Metric | Value |
|---|---|
| Installs | 7 |
| Time to First Install | < 24 hours |
| Records Scanned | Up to 10,000 |
| Auto-Sync Check Interval | Every 15 minutes |
The Launch
Dynamic Dropdowns launched on Sunday 22nd February 2026. By 2am that same night, it had its first install! A second install came the next day. This had never happened to me before - the HubSpot app I built before this, Clean Dial took months of marketing on linkedin, reddit, community forums, slack channels, sales outreach to get just 3 installs! Dynamic Dropdowns got traction in hours.
The first installer hit an issue and raised a support request. I jumped on it, improved the system, and fixed the error. He was pretty happy with the response. This was my 1st ever support request for an app, and it’s a great feedback loop - install, support, quick fix, satisfied user.
Now at 7 installs and after a week of being out there my app’s HubSpot Marketplace application is submitted and under review.
The Problem
HubSpot text properties accumulate messy, inconsistent freeform values. Over time, a field like “State” ends up containing “California”, “CA”, “Calif.”, “california”, and “CALIFORNIA” - all meaning the same thing, all living as separate values across thousands of records. There’s no native way to audit what’s in a free-text property, deduplicate the variants, and convert it into a clean dropdown while keeping everything your team has already entered. You’d have to trawl through records manually.
This is a gap that grows worse the longer a portal has been in use. Older portals with large contact databases are sitting on years of inconsistent data entry with no clean path to standardisation.
The Solution
Dynamic Dropdowns scans up to 10,000 records, discovers every unique value in a text property, automatically merges casing and punctuation variants, lets you curate the final list, and then creates a clean enumeration property from those values.
To set it up: select a text property, run a scan, review and curate the deduplicated value list, then create the new dropdown. From then on you have a clean select property built from the real data your team has already entered.
Technical Architecture
Building this on top of HubSpot’s API surfaced several challenges that didn’t show up in staging.
UI Extension Fetch Proxy Timeout
HubSpot’s UI extension fetch proxy has a 15-second limit. Dynamic Dropdowns is a settings page app, and large portal scans were exceeding that limit - the scan would be mid-run when HubSpot’s proxy cut the connection. The fix was to immediately return an accepted response and poll for completion in the background, rather than holding the connection open for the duration of the scan.
Rate Limiting and Retry
The HubSpot Search API has strict rate limits, and under real usage the app started hitting them. The fix was a Bottleneck rate limiter capped at ~4.16 requests per second on all outbound calls, with linear backoff retry (1s, 2s) on 429 responses up to 3 attempts - so requests get throttled and retried rather than hammering the endpoint and failing outright.
Live Streaming Scan Results
The polling architecture doesn’t just return results when a scan finishes - it updates the in-memory scan job on every page of results, so the frontend polling every 2 seconds shows values populating live as the scan progresses. A scan across 10,000 records feels responsive rather than frozen.
Normalization Matches HubSpot’s Own Algorithm
The deduplication logic uses the same normalization HubSpot applies internally: lowercase, strip special characters, spaces to underscores. This means variants like “Calif.” and “Calif” are merged before the API call, rather than discovered as a collision error after submission. Pre-empting the platform’s own validation is more robust than catching the error after the fact.
Cross-Object Creation
The object to scan and the object to create the dropdown on are separate fields. You can scan Contact values and create the dropdown on Companies, or scan Deals and create on Tickets. This required an explicit schema decision to keep scan context and creation context decoupled - useful when teams want to standardise a property across multiple object types.
Scan Store TTL Cleanup
Scan jobs are held in memory during processing. Completed jobs are cleaned up after 5 minutes via a TTL cleanup pass. Without this, a long-running process would accumulate completed scan objects indefinitely - a small but deliberate production durability detail.
Auto-Sync Engine - Architecture
My Auto-sync engine lets portals keep their dropdown mappings up to date automatically.
My first implementation (all local) had a straightforward problem: a single setInterval batch-synced all enabled mappings at the same time, causing a burst of API calls on a fixed schedule, with no relation to when each user actually enabled auto-sync.
A portal that had just manually synced would get synced again unnecessarily. And there was no guard against a manual sync and an auto-sync running concurrently on the same mapping.
The Redesign - Ready for Production MVP
The setInterval now runs every 15 minutes just to check which syncs are due. Each portal’s sync is processed sequentially to respect HubSpot rate limits. A “due” filter compares each mapping’s last_synced_at timestamp to a 6-hour threshold - only stale mappings run. Fresh portals are skipped entirely. To prevent concurrent syncs on the same mapping, a lock system was added.
”Sync Already In Progress” Feedback
When a user clicks “Sync Now” while an auto-sync is already running on the same mapping, the route detects { skipped: true } and surfaces an info alert rather than silently reloading. Small, but it prevents the confusion of clicking sync and nothing visibly happening.
Future Improvements
Once on the marketplace I plan to switch to a webhook structure with cronjob fallback.
Marketplace & Tooling
Listing Automation
Submitting to the HubSpot Marketplace involves a lot of manual form-filling - listing fields, screenshots, assets, categorisation. I used Claude + Playwright MCP + Remotion to automate most of it - generating the images and videos as well as filling out the listing. Filling out the Dynamic Dropdowns listing was the first round to figure out all the needed steps in the flow and i’m currently putting together an automated flow/TUI tool for all future listings.
Forms - Future Feature Decision
HubSpot forms are sticky - when a dropdown property updates, forms don’t reflect the new values quickly. A forms feature is on the roadmap: sending a patch to force forms to sync when Dynamic Dropdowns updates a property, so the form stays current without waiting on HubSpot’s cache. The plan is to add it once the app is approved on the marketplace, since the additional OAuth scopes required would add scrutiny to the initial review.
Clean Dial vs Dynamic Dropdowns: A Lesson in Product-Market Fit
The contrast between these two apps has been eye-opening for me!
Clean Dial solves a (I think) real but niche problem - phone number formatting and live/reachability checks. It’s useful, but it’s a vitamin. People don’t go searching for it unless they already know they have a data quality problem. Getting installs has been a slow grind over several months.
Dynamic Dropdowns solves a problem people actively complain about in forums. Inconsistent free-text data is a gap that every HubSpot team hits eventually. It’s closer to a painkiller - people know they need it and go looking for a solution.
The difference in traction is night and day. Same distribution channels but it seems the product that scratches a more obvious itch wins on adoption speed every time.
What I Learned
- Solve problems people are already searching for. Dynamic Dropdowns took off because it addresses a known gap. The demand was already there - I just needed to build the supply.
- Fast support builds trust fast. Fixing the first installer’s issue quickly turned a potential churn into a happy user. In the early days, every install matters and every support interaction is a chance to build reputation.
- Launch timing doesn’t matter as much as problem-market fit. I launched on a Sunday evening thinking it wouldn’t get loads of interaction, I just wanted to get it out there, but it’s been one of my best performing linkedin posts. When the problem is real enough, people find the solution regardless of when you ship it.
Learn More
Questions I Had to Figure Out
How is Dynamic Dropdowns different from just creating a HubSpot enumeration property manually?
Dynamic Dropdowns scans your existing free-text property data — up to 10,000 records — automatically merges inconsistent variants like 'California', 'california', and 'CALIFORNIA.', lets you curate the final list, then creates the clean dropdown from what's actually in your CRM. Manual creation requires you to know all the values in advance and doesn't handle deduplication.
How does Dynamic Dropdowns handle HubSpot API rate limits?
It uses a Bottleneck rate limiter capped at around 4.16 requests per second on all outbound calls, with linear backoff retry (1s, 2s) on 429 responses up to 3 attempts. Requests are throttled and retried automatically rather than failing.
Can Dynamic Dropdowns scan one HubSpot object and create the dropdown on a different object?
Yes. The scan object and the creation object are decoupled fields. You can scan Contact values and create the dropdown on Companies, or scan Deals and create on Tickets.
Want more build logs & tech experiments?
Follow my journey on Substack