Skip to content

Custom fields

LeadHunter ships with the obvious fields — name, website, phone, address, status — but every business tracks attributes specific to its market. Custom fields let you define those once, attach them to every account in your company, and reference them everywhere you can reference a built-in field: account forms, saved filters, campaign bulk-add, the scoring prompt.

Custom fields are scoped to a Company — a bike-shop CRM’s fleet_size is invisible to a podcast directory in another Company; neither company’s schema pollutes the other’s data.

TypeWhat it storesExample
textShort single-line stringLicense number
textareaLong multi-line stringNotes about the location
numberInteger or decimalNumber of franchises
dateYYYY-MM-DDContract renewal date
booleantrue / falseHas loyalty program?
selectOne value from a listTier: Gold / Silver / Bronze
multiselectMany values from a listLanguages spoken
urlValidated URLReviews page

A quick decision guide for which type to reach for:

You want to capture…Use
One label from a finite list (Gold / Silver / Bronze)select
Many labels from a finite list (multi-tag)multiselect
A yes/no flagboolean
A count you’ll want to filter or sort bynumber
A specific datedate
A clickable URLurl
A short opaque string (license number, account ref)text
A long free-form blobtextarea (but consider: would notes on the Account itself do?)

Picking the most-restrictive type that fits makes the field usable in saved filters with the right operators. text is the catch-all, but a select would let you filter cleanly while text only supports substring matching.

From Settings → Custom fields → Add field, each definition carries:

PropertyWhat it does
KeyMachine name. Lowercase, snake_case, starts with a letter (regex ^[a-z][a-z0-9_]{0,79}$). Shows up in filter expressions as cf.<key>.
LabelHuman-readable name shown on account forms (e.g. “Fleet size”).
TypeOne of the eight above.
OptionsRequired for select / multiselect. The exact strings counted as valid values.
Help textOne-line hint shown next to the input on the account form.
RequiredWhen on, account create / edit forms reject submissions that don’t fill this field. Partial updates skip the check, so a re-import that omits the field doesn’t fail.
OrderDisplay position on account forms. Lower numbers appear first.

The schema is per-Company, not global. A field defined under Bike Shop CRM doesn’t show up under Radio Stations — each tenant’s fields are isolated.

Two paths an operator can use:

  1. The account form — every defined field shows up in the Custom fields section of the new-account and edit-account screens, in the order you set. Validates on save against the declared type.
  2. CSV / XLSX import — map a column to a custom field key in the import wizard’s column-mapping step. The static-values trick from Import accounts also works here: set a batch-wide custom-field value (e.g. every row in this file is cf.source_list = "Trade show 2026") without needing a column for it.

Auto-enrichment doesn’t fill custom fields. The discover-website + scrape + language-detect pipeline only populates the standard fields (website, website_content, language). If you need a custom field populated automatically, fill it on import or on the account form.

Every value you put in a custom field is part of the prompt the scoring model reads when ranking the account against the Product’s ICP. So a thoughtfully-defined custom field is one of the easiest ways to inject business context into scoring without re-writing the ICP.

A bike-shop CRM with cf.fleet_size, cf.brands_carried, and cf.service_offered on every row gives the model concrete numerical and categorical signals it can use directly. The same accounts without those custom fields force the model to guess from the website alone.

This is the difference between custom fields and the notes field on the Account, which is operator-only and isn’t read by the scoring prompt. See Account → Notes are operator-only.

Reference custom fields in saved filters with the cf. prefix:

match: all
conditions:
country = Spain
cf.tier in [Gold, Platinum]
cf.contract_renewal_date lt 2026-06-30

Custom fields support the same operators as built-ins, modulo the field type — gt / lt apply only to numbers and dates; is_true / is_false only to booleans; contains differs between text (substring) and multiselect (array membership). See Build a saved filter for the full operator matrix and worked examples.

When two accounts merge, custom fields are unioned:

  • text / textarea / number / date / url / select / boolean — if only one row has a value, that value sticks; if both have values, the survivor’s wins but the absorbed row’s value is recorded in merge_history so you can read what was overridden.
  • multiselectunion of both arrays. No loss.

Nothing is silently dropped, even on a conflict.

ActionEffect
Add a fieldInstant. Existing accounts immediately gain the field with a null value; new accounts pick it up on the next form load.
Rename label or help textInstant. Filters and forms keep working — they reference the key, not the label.
Rename a keyNot safe. References in saved filters and import mappings break silently. Prefer creating a new field with the new key, backfilling values, then deleting the old one.
Delete a fieldRemoves it from the schema (stops showing in forms; rejected by the import wizard). The values stay on existing accounts in the underlying JSON blob — they just become invisible. Cheap to re-add; expensive to recover deleted history. If you’re sure you want the values gone too, ask support for a one-off cleanup.
  • Personal data on individual people — names, emails, phone numbers of specific contacts. Those belong on the Contact model, not on the Account’s custom fields.
  • High-cardinality free text you never plan to filter on. A 10KB description of every account belongs in notes, not in a textarea custom field — custom fields are meant to be queryable, and JSON-indexed long text doesn’t query efficiently.
  • Anything that’s the same for every account — that’s a company-level setting, not a field on each row.
  • Anything you’ll want to aggregate across the whole database — define a custom field that filters cleanly (number, date, select) and use saved filters for the aggregation; the saved-filter reach estimator is the closest thing to a count-by query in LeadHunter today.

For a Company running outbound to bike shops, useful custom fields might be:

FieldTypeWhy
fleet_sizenumberTarget by store size. “Shops with ≥20 bikes in stock” is a meaningful audience.
brands_carriedmultiselect, options = the brands you care about”Shops that carry Trek but not Specialized” is a meaningful slice.
service_offeredbooleanSome products only fit shops with a workshop.
contract_renewal_datedateFor existing customers — filter for “renewing in the next 90 days”.
loyalty_program_urlurlUseful for partnership campaigns; one click from the row.

A saved filter combining country = Spain + cf.fleet_size gte 20 + cf.brands_carried contains Trek + status = prospect gives you the audience for next quarter’s premium-Trek-dealer campaign.

Worked example 2 — a podcast / radio-station directory

Section titled “Worked example 2 — a podcast / radio-station directory”

A Company running outbound to media outlets might define:

FieldTypeWhy
formatselect, options = news, music, talk, mixedThe Product description and ICP are different per format.
weekly_audiencenumberReach the model can compare directly against the ICP’s audience floor.
genresmultiselect, options = the music genres you care about”Rock and electronic, but not classical” is a real targeting move.
accepts_sponsorshipbooleanHard prerequisite — set it after the first conversation.
frequency_mhznumberGeographic + technical filter for FM-only campaigns.

The product description on a “podcast advertising platform for music shows” product references cf.genres and cf.weekly_audience directly, so the model has structured signals to score against — not just whatever it can extract from the station’s website.

  • Build a saved filter — every saved filter speaks the same cf.<key> syntax.
  • Import accounts — map CSV columns to custom fields, or set batch-wide static values.
  • Account — the row your custom fields hang off.
  • ICP and scoring — how custom field values become part of the scoring prompt.