HubSpot CRM property audit — 2026-04-01

Location: knowledge/operations/sales/ — GTM / RevOps HubSpot material under operations.

How this was produced

  • Source: HubSpot CRM Properties API via tools/hubspot-api-service (npm run audit-properties -- --json).
  • Scope: contacts, companies, deals — active properties only (not archived).
  • Credential: Private app token from 1Password (Platform Team Hubspot Service Key); do not commit tokens or paste them here.

Actions executed (API) — 2026-04-01

Script: tools/hubspot-api-service/scripts/apply-hubspot-audit-cleanup.ts — run with HUBSPOT_ACCESS_TOKEN set:

cd tools/hubspot-api-service
export HUBSPOT_ACCESS_TOKEN="$(op read 'op://Brainforge AI Team/Platform Team Hubspot Service Key/notesPlain')"
npx tsx scripts/apply-hubspot-audit-cleanup.ts

Completed via API

ActionResult
Deal labelsdeal_source → “Deal source”; service_interest / subservice_type → title case; all partner_* and partnership_* deal fields → Partner … style labels; partner_current_week → “Partner current week” (+ description).
Company labelis_updated → “Firmographic / ICP review complete” (+ description).
TCV groupdeals.tcv__total_contract_value_ moved to property group dealinformation (resolves single-field deal_revenue group clutter).
Company billing/contract duplicatesArchived on companies (deal is SoT): billing_frequency, contract_start_date, contract_end_date, next_invoice_date, payment_terms.
Koalify cleanupArchived on all three objects: koalify_duplicate_properties, koalify_is_primary_duplicate, koalify_main_duplicate, koalify_number_of_duplicates (where present).

Blocked — manual follow-up

ItemReasonWhat to do
koalify_duplicate_rules (companies, contacts, deals)HubSpot: property in use by lists (INBOUNDDB_LISTS IDs 136–148 depending on object).In HubSpot: Lists that reference Koalify duplicate rules — remove the filter column or delete obsolete lists, then re-run npx tsx scripts/apply-hubspot-audit-cleanup.ts or archive the three properties in Settings → Properties.
Zoom initial_zoom_webinar_attendance_average_durationRead-only integration property; API archive returns 400.Settings → Properties → Contacts and/or Zoom integration; HubSpot Support if needed.
Company capability text → selectsNeeds per-field design (options, backfill).Not automated; convert properties one-by-one when you need reporting filters.

After lists are fixed

Re-run the cleanup script (it is idempotent for labels and skips missing properties):

cd tools/hubspot-api-service
export HUBSPOT_ACCESS_TOKEN="$(op read 'op://Brainforge AI Team/Platform Team Hubspot Service Key/notesPlain')"
npx tsx scripts/apply-hubspot-audit-cleanup.ts

RevOps reminder

  • Deal is now the place for contract/billing fields; company copies above are archived — update workflows, forms, and reports that still pointed at company properties.
  • Disconnect Koalify under Settings → Integrations if you no longer use it, so it does not recreate properties.

Executive summary

MetricCount
Total property definitions (3 objects)1,114
Custom (non–HubSpot-defined), active137
Custom on companies34
Custom on contacts35
Custom on deals68

The portal is not overloaded with custom fields: most volume is HubSpot standard. Cleanup value is mostly naming consistency, grouping, retiring integrations, and clarifying duplicates between company vs deal.

Automated checks (what the data showed)

Duplicate labels (same object, same display label)

Only two pairs (both involve HubSpot-defined semantics — do not delete via custom-property archive):

  1. Companies — “Target account”hs_is_target_account vs hs_target_account (standard behavior; use HubSpot docs to decide how reps should use each).
  2. Contacts — “Email hard bounce reason”hs_email_hard_bounce_reason vs hs_email_hard_bounce_reason_enum (platform fields).

Implication: No quick win from “merge duplicate labels” among custom fields; focus elsewhere.

Custom fields sharing the same internal name across objects

These are intentionally parallel in many orgs (company-level vs deal-level). Confirm whether you want both populated or a single source of truth (usually deal for revenue terms, company for account-level contract):

Internal nameObjects
billing_frequencycompanies, deals
contract_end_datecompanies, deals
contract_start_datecompanies, deals
next_invoice_datecompanies, deals
payment_termscompanies, deals
source_namecontacts, deals

Recommendation: Document in RevOps onboarding: which object is authoritative for billing/contract dates and when to sync vs leave blank.

Koalify (koalify_*)

  • 15 custom properties use the koalify_ prefix; 5 per object live in group koalify_duplicates on companies, contacts, and deals.
  • Recommendation: If Koalify is still in use, keep and treat as a closed set. If not, plan an archive after exports and workflow removal (use archive-crm-properties dry-run → --apply only with schema write on the token).

Integration-specific clusters (keep or retire consciously)

ClusterNotes
HeyReach (heyreach*, contacts)Four fields; keep if outbound still flows through HeyReach; otherwise deprecate after data export.
Zoom (contacts / zoom)Two “attendance duration” style metrics plus registration/join link fields.
Nudge (deals / nudge_tracking)Three fields; aligns with internal automation; keep unless product is retired.

Zoom: consolidation / UX

  • Similar labels: “Total attendance duration percentage before Attendance API migration” vs “Average Zoom webinar attendance duration” — same object (contacts), stem overlap in analytics.
  • Recommendation: If the migration is done, hide or archive the legacy initial_zoom_webinar_attendance_average_duration after confirming no reports depend on it. The legacy field is hidden today (hidden: true), which is good; next step is archive when safe.

Partner vs partnership naming (deals)

  • Mix of partner_* and partnership_* prefixes on the same motion (e.g. partner_type / partnership_relationship).
  • Recommendation: Pick one prefix convention for new fields; optionally rename labels (not internal names) for clarity in UI — internal renames are disruptive; prefer label + description cleanup.

Deal groups

GroupCustom count
dealinformation56
koalify_duplicates5
deal_activity3
nudge_tracking3
deal_revenue1 (tcv__total_contract_value_)

Recommendation: Move TCV into dealinformation or rename group deal_revenue → something broader if you add more revenue fields — avoids a one-field group.

Company “capability” free-text grid

Many short text fields on companies (data_warehouse, llm, cdp, orchestration, etc.) — useful for notes but weak for reporting and filtering.

Recommendation: For properties you filter on in lists, consider enumeration or multi-select; keep text for long-tail “other.”

Label / naming hygiene (quick wins)

  • Inconsistent casing: e.g. deal source vs “Deal Source” style elsewhere; service_interest / subservice_type internal-style labels.
  • Recommendation: Standardize labels in HubSpot settings (no API required for label-only) for rep-facing consistency.
  • is_updated (companies): Label is vague — rename to something actionable (e.g. “ICP / firmographic review completed”) or remove if unused.

Type hygiene

  • work_start_to_live_date (deals): string — if values are dates, consider date type in a future migration (requires new property + backfill, non-trivial).

Suggested priority order

  1. Document company vs deal authority for shared contract/billing fields (RevOps doc, not necessarily schema change).
  2. Label cleanup on deals/contacts (low risk): deal source, service_interest, subservice_type, is_updated.
  3. Partner/partnership label + description pass; optional new fields follow one prefix.
  4. Koalify — confirm still needed; if not, archive bundle with a written backup.
  5. Zoom legacy field — confirm reporting; then archive initial_zoom_webinar_attendance_average_duration if unused.
  6. TCV group — merge visually into dealinformation or expand deal_revenue.
  7. Company capability fields — only convert to picklists where you need reporting.

Re-running the audit

cd tools/hubspot-api-service
export HUBSPOT_ACCESS_TOKEN="$(op read 'op://Brainforge AI Team/Platform Team Hubspot Service Key/notesPlain')"
npm run audit-properties -- --custom-only --csv > hubspot-custom-properties.csv

Dry-run archive (example):

npm run archive-properties -- --object-type=deals --from-file=props-to-archive.txt

See knowledge/platform/integrations/hubspot/hubspot-api-setup.md for required schema write scopes before --apply.

Appendix: custom property inventory by group

The full machine-readable breakdown (object / group / name / label / type) was generated from the same JSON export on 2026-04-01. To regenerate, run the audit command above and pipe through your own grouping script, or ask the agent to reproduce the “by group” table from a fresh export.


Next review: After major RevOps changes (new tools, partner motion, or retiring Koalify/HeyReach), re-run audit and bump the date in the filename.