ConvertKit gives you two ways to track information about subscribers: custom fields and tags. Most operators pick one by habit or intuition, then run into performance problems, automation failures, or segmentation nightmares six months later.
The difference isn’t just semantic. Custom fields and tags work differently under the hood, cost differently at scale, and break in different ways when you push them too hard.
What custom fields actually store
Custom fields hold variable data—strings, numbers, dates—unique to each subscriber. Think first name, referral source, purchase count, or renewal date.
ConvertKit stores these as key-value pairs in your subscriber record. You can reference them in emails with liquid syntax ({{ first_name }}), filter segments by their values, and update them via API or form submission.
The gotcha: every custom field you create adds a column to every subscriber record, whether populated or not. An empty field still exists in the database. Add twenty fields and you’re carrying twenty columns per contact, even if nineteen are blank.
This doesn’t break anything immediately. But it slows segment queries, complicates exports, and makes your data harder to audit. I’ve seen accounts with forty-plus custom fields where only six held useful information. The rest were legacy experiments or half-finished automations.
What tags actually track
Tags are binary flags. A subscriber either has a tag or doesn’t. You can’t store a value in a tag—just presence or absence.
ConvertKit indexes tags separately from subscriber records. Adding a tag doesn’t expand the subscriber table. It creates a relationship record in a join table. That architecture scales better when you’re tracking dozens of attributes.
Tags also surface better in the UI. You can see all applied tags at a glance in the subscriber list. Custom field values require opening each record or exporting a CSV. For quick visual checks—who’s in the beta cohort, who opted into coaching—tags win.
The downside: tags can’t hold nuance. If you need to store when someone joined the beta or which tier they purchased, a tag won’t cut it. You’ll end up creating beta_joined_2026_01, beta_joined_2026_02, and so on—tag sprawl that’s worse than a single date field.
When to use custom fields
Reach for custom fields when you need to store or reference a specific value:
- Personalization tokens in email copy (first name, company, city)
- Numeric counters that increment (emails opened this month, courses completed)
- Dates for time-based logic (trial start date, last purchase, renewal window)
- External IDs for syncing with other tools (Stripe customer ID, WordPress user ID)
Custom fields also make sense when you need to filter segments by ranges or partial matches. “Purchase count greater than 3” or “City contains ‘New’” requires field-based logic. Tags can’t do that.
When to use tags
Use tags for binary states, audience segments, and behavioral flags:
- Lifecycle stages (subscriber, buyer, churned, reactivated)
- Interest categories (AI tools, WordPress, monetization)
- Engagement tiers (active, dormant, cold)
- Cohort membership (joined Q1 2026, beta tester, workshop attendee)
Tags scale better when you’re tracking many attributes that most subscribers won’t have. If only 8% of your list are buyers, a buyer tag is leaner than a is_buyer custom field sitting empty on 92% of records.
Tags also play nicer with automation branching. ConvertKit’s visual automations let you split paths based on tag presence with a single click. Doing the same with custom field values requires more setup and is harder to debug when it breaks.
The hidden cost of choosing wrong
I’ve worked with a SaaS newsletter operator who used custom fields for everything—including audience interests. They had fields like interested_in_AI, interested_in_SEO, and interested_in_monetization, each storing “yes” or blank.
Segmenting required filtering by six different field conditions. Automations couldn’t branch cleanly. Exports included twelve columns of “yes” and empty cells. Switching to tags cut segment load time from four seconds to under one and made the automation map readable again.
Conversely, I’ve seen operators try to use tags for dates. They’d create trial_started_2026_06_15, then realize a week later they couldn’t query “trial started more than 7 days ago” without manually adding 365 tags. A single trial_start_date custom field solved it.
One non-obvious tip
You can combine both. Use a custom field to store the precise value and a tag to mark the category.
Example: store last_purchase_date as a custom field (for time-based logic and reference), then apply a buyer tag (for quick filtering and automation branching). The field gives you precision; the tag gives you speed.
This hybrid approach works especially well for high-cardinality data—attributes that can take many values but where you still want fast segment access. Referral source is another good candidate: store the exact UTM in a field, apply a referral_traffic tag.
Before you create your next custom field or tag, ask: am I storing a value I need to reference, or am I marking a state I need to check? The answer tells you which to use.
Got a ConvertKit setup question? Reply to this email—I read every one, and reader questions become future articles.