Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.elasticfunnels.io/llms.txt

Use this file to discover all available pages before exploring further.

The CRM module lets you define custom entity types, fields, pipelines, and stages — then store structured data entries linked to any record in the system. Think of it as both a customer relations management tool and a general-purpose data platform (like Webflow CMS Collections). You can create traditional pipeline-based entities (deals, contacts) or standalone data collections (properties, inventory, cities).

How entries attach to records

Each CRM entry is linked to a record in your funnel or store through two values:
FieldDescription
reference_typeThe type of record (e.g. customer, order, lead)
reference_idThe ID of that record
This pattern lets you attach structured data to customers, orders, or custom reference types you define.

Concepts

Entries vs. Fields: An entry is a single record or document stored in the CRM (like a row in a database, representing e.g. a specific check-in for a customer). A field is a specific piece of data that lives inside an entry (like a column, e.g. “current_weight” or “deal_value”).

Entity Modes

Entities operate in one of two modes:
ModeDescription
CRM (default)Traditional pipeline-based entity with stages, suitable for deals, leads, contacts
DataStandalone data collection without pipelines — ideal for storing structured records like properties, inventory items, cities, products
When creating an entity, choose “Data Collection” to skip pipelines entirely. Data-mode entities focus purely on fields and entries.

Entities

An entity defines a type of CRM record (e.g. “Deals”, “Contacts”, “Properties”). Each entity has:
  • A name and slug (machine-readable identifier)
  • An entity mode (crm or data)
  • Fields that define the data structure
  • Pipelines with stages for workflow tracking (CRM mode only)

Fields

Fields define what data can be stored on entries. Each field has:
PropertyDescription
labelHuman-readable label
keyMachine-readable key (used in API and templates)
typeSee supported types below
ui_editableWhether this field can be edited in the admin UI (default true)
reporting_configOptional analytics metadata for CRM reports

Supported field types

TypeRenders asNotes
textText inputDefault type
textareaMulti-line text
rich_text, wysiwygRich textFormatted content stored as HTML
emailEmail inputRendered as mailto link
phonePhone inputRendered as tel link
urlURL inputRendered as clickable link
numberNumeric inputStored as double
dateDate pickerISO 8601 string
datetimeDate+time pickerISO 8601 string
booleanToggle switchtrue/false
selectDropdownRequires options array
multiselectMulti-select tagsRequires options array
colorColor pickerHex color code
imageImage URL / uploaderRenders as thumbnail
fileFile URL / uploaderRenders as download link
jsonJSON editorRenders as collapsible tree
referenceEntity referenceLinks to single entry in another entity
multi_referenceMulti-referenceLinks to multiple entries in another entity
The type in CRM settings controls how the field appears and behaves in the admin UI. It does not change what you pass from code: setCrmField always sends a JavaScript value — a string, number, boolean, or a JSON object. For fields configured as date in the CRM, pass a date-time string from scripts, typically ISO 8601 (e.g. new Date().toISOString() or '2026-03-15').

UI-editable fields

Set ui_editable: false on fields that should only be updated programmatically (via backend scripts). These fields display with a lock icon in the admin UI and cannot be inline-edited. Use reporting_config to mark fields as reportable and suggest how the Reports tab should aggregate and chart them. Supported values include reportable, aggregation_type (numeric, categorical, date, boolean), baseline (min/max), bucket_size, and preferred_chart (kpi, histogram, pie, bar, line).

Relations

Relations link entries across entities. A field of type reference or multi_reference creates a relation between the current entity and a target entity. Relations are stored in Elasticsearch alongside the entry data.

Configuring reference fields

When creating a reference field, specify:
  • Target entity: Which entity the reference points to
  • Display field: Which field from the target entity to show as the label (defaults to title)

Working with relations programmatically

Use SetCrmRelation and RemoveCrmRelation to manage relations from backend scripts:
SetCrmRelation({
  slug: 'properties',
  relationKey: 'city',
  targetEntryId: 'abc123'
});

RemoveCrmRelation({
  slug: 'properties',
  relationKey: 'city',
  targetEntryId: 'abc123'
});

Pipelines & Stages

Pipelines represent workflows (CRM mode only). Each pipeline contains ordered stages with optional colors and semantic statuses (e.g. won, lost, active). Entries move through stages as they progress.

Customer CRM Data

The most common pattern is linking CRM entries to customers. When a customer visits a page, their session supplies the customer context so CRM defaults attach to the right person (creating the customer record when needed).

Example: Weight Loss Tracker

  1. Create a CRM entity called “Weight Tracker” with slug weight-tracker and fields like current_weight, goal_weight, last_checkin
  2. Create a pipeline “Progress” with stages “Starting”, “In Progress”, “Goal Reached”
  3. Store data via backend scripts or the template engine:
setCrmFields({
  slug: 'weight-tracker',
  fields: [
    { fieldKey: 'current_weight', value: 185 },
    { fieldKey: 'goal_weight', value: 165 },
    { fieldKey: 'last_checkin', value: '2026-03-15' }
  ]
});
slug identifies the CRM entity (board/type). referenceType / referenceId default to the current customer when omitted. For another record: setCrmField({ slug: 'weight-tracker', referenceType: 'order', referenceId: '12345', fieldKey: 'status', value: 'shipped' }). See Data Functions.
  1. Read it back on any page:
var weight = getCrmField({ slug: 'weight-tracker', fieldKey: 'current_weight' });
var goal = getCrmField({ slug: 'weight-tracker', fieldKey: 'goal_weight' });
if (weight && goal && Number(weight) <= Number(goal)) {
  setVariable('show_congrats', true);
}

Viewing Customer CRM Data

Customer CRM entries are visible in the Customer Details page under the CRM tab. This shows all CRM entries linked to that customer across all entity types.

Functions

The following functions are available in both the template engine and backend scripts. Write functions accept an optional async parameter (default false). When true, the write runs in the background for faster response times. Read functions are always synchronous.
FunctionDescription
EnsureCrmEntity({ slug, ... })Idempotently create an entity with fields (returns { id, slug, created, fields_added })
CreateCrmEntry({ slug, title?, values?, ... })Create a new entry and return its ID
getCrmEntries({ slug, ... })Fetch all entries for one entity slug + reference
getCrmField({ slug, fieldKey, ... })Get one field value (slug + fieldKey required)
getCrmFields({ slug, fieldKeys, ... })Get multiple field values (slug + fieldKeys required)
setCrmField({ slug, fieldKey, value, ... })Set one field value — upserts a single value per key
setCrmFields({ slug, fields, ... })Set multiple field values in one read/write cycle
addCrmFieldValue({ slug, fieldKey, value, ... })Append a new entry with a field value — enables multiple values per key
getCrmFieldValues({ slug, fieldKey, ... })Get all values for a field key across entries (returns array)
clearCrmEntries({ slug, ... })Delete all entries for an entity slug + reference
SetCrmRelation({ slug, relationKey, targetEntryId, ... })Add a relation from entry to another entry
RemoveCrmRelation({ slug, relationKey, targetEntryId, ... })Remove a specific relation
moveCrmLead({ slug, pipelineId/pipelineSlug, stageId/stageSlug, ... })Move entry to a specific pipeline + stage
moveCrmToStage({ slug, stageId/stageSlug, ... })Move entry to a stage (pipeline resolved from stage)
moveCrmToPipeline({ slug, pipelineId/pipelineSlug, ... })Move entry to a pipeline (lands on first stage)
moveCrmToEntity({ fromSlug, toSlug, fieldMap, ... })Copy mapped fields across entity types
slug is always required (the entity’s slug from CRM settings). Reference defaults: customer + session customer id.

Common options

Every CRM function accepts these optional properties:
PropertyTypeDefaultDescription
referenceTypestring'customer'Linked record type
referenceIdstringsession customer_idLinked record id
Write functions also accept:
PropertyTypeDefaultDescription
asyncbooleanfalseWhen true, writes run in the background — faster but eventual consistency

Single-value fields

Use setCrmField / getCrmField for fields that hold one value per key (e.g. weight, goal, last check-in date):
setCrmField({ slug: 'weight-tracker', fieldKey: 'current_weight', value: 182 });
var weight = getCrmField({ slug: 'weight-tracker', fieldKey: 'current_weight' });
When you need to read multiple fields at once, use getCrmFields and pass an array of fieldKeys:
var fields = getCrmFields({ slug: 'weight-tracker', fieldKeys: ['current_weight', 'goal_weight'] });
var weight = fields.current_weight;
var goal = fields.goal_weight;
When writing multiple fields in one script, prefer setCrmFields so all values are merged in one read/write cycle:
setCrmFields({
  slug: 'weight-tracker',
  fields: [
    { fieldKey: 'current_weight', value: 182 },
    { fieldKey: 'goal_weight', value: 165 },
    { fieldKey: 'last_checkin', value: today }
  ]
});
If you need to keep separate setCrmField calls, pass force: true to skip the per-key scan and merge directly into the newest entry — much faster for sequential writes:
setCrmField({ slug: 'weight-tracker', fieldKey: 'current_weight', value: 182, force: true });
setCrmField({ slug: 'weight-tracker', fieldKey: 'goal_weight', value: 165, force: true });
setCrmField({ slug: 'weight-tracker', fieldKey: 'last_checkin', value: today, force: true });

Multi-value fields

Use addCrmFieldValue / getCrmFieldValues when a key can have multiple values over time (e.g. weigh-in history). Each addCrmFieldValue call creates a separate CRM entry:
addCrmFieldValue({
  slug: 'weight-tracker',
  fieldKey: 'weighin_history',
  value: { date: '2026-03-31', weight: 182, notes: 'post-workout' }
});

var history = getCrmFieldValues({ slug: 'weight-tracker', fieldKey: 'weighin_history', limit: 10 });
// Returns an array of values, newest first

Clearing entries

Use clearCrmEntries to delete all entries for an entity + reference:
var result = clearCrmEntries({ slug: 'weight-tracker' });
// { ok: true, deleted: 3 }

Pipeline and stage movement

Use moveCrmLead to move a CRM entry to a specific pipeline and stage by id or slug:
// By slug (recommended — works across environments)
moveCrmLead({ slug: 'deals', pipelineSlug: 'sales', stageSlug: 'qualified' });

// By id
moveCrmLead({ slug: 'deals', pipelineId: 3, stageId: 12 });
Returns { ok, moved, totalMatched, pipeline_id, stage_id }. moved is the number of entries updated (1 unless allEntries: true). Use moveCrmToStage when you only know the stage — the pipeline is resolved automatically:
moveCrmToStage({ slug: 'deals', stageSlug: 'won' });
Use moveCrmToPipeline to move an entry into a pipeline; it lands on the first stage:
moveCrmToPipeline({ slug: 'deals', pipelineSlug: 'onboarding' });
Use moveCrmToEntity to copy field values from one entity type to another (e.g. promoting a lead to a deal):
moveCrmToEntity({
  fromSlug: 'leads',
  toSlug: 'deals',
  fieldMap: { lead_score: 'initial_score', source: 'lead_source' },
  pipelineSlug: 'sales',
  stageSlug: 'new',
  removeFromOld: false  // set true to delete source entries after copy
});
Returns { ok, moved, removed_from_old }. Pass allEntries: true to any move function to update all matching entries instead of just the newest one.

Ensuring entities programmatically

Use EnsureCrmEntity at the top of a backend script to idempotently provision an entity. Re-runs never overwrite admin edits — only missing fields are added.
EnsureCrmEntity({
  slug: 'properties',
  name: 'Properties',
  singularName: 'Property',
  pluralName: 'Properties',
  entityMode: 'data',  // 'crm' (default) or 'data'
  icon: 'building',
  fields: [
    { key: 'address', label: 'Address', type: 'text' },
    { key: 'price', label: 'Price', type: 'number' },
    { key: 'bedrooms', label: 'Bedrooms', type: 'number' },
    { key: 'photo', label: 'Photo', type: 'image', ui_editable: false },
    { key: 'city', label: 'City', type: 'reference', options: { target_entity_id: 5 } },
    { key: 'status', label: 'Status', type: 'select', options: ['available', 'sold', 'pending'] },
    {
      key: 'listing_date',
      label: 'Listing Date',
      type: 'date',
      reportingConfig: { reportable: true, aggregationType: 'date' }
    }
  ]
});

Creating entries

Use CreateCrmEntry to create a new entry and get back its ID (useful for setting relations):
var result = CreateCrmEntry({
  slug: 'properties',
  title: '123 Main St',
  values: {
    address: '123 Main Street, Springfield',
    price: 450000,
    bedrooms: 3,
    status: 'available'
  }
});
// result = { ok: true, id: 'abc123' }

Managing relations

Use SetCrmRelation to link entries:
// Link a property to a city
SetCrmRelation({
  slug: 'properties',
  relationKey: 'city',
  targetEntryId: 'city-entry-id-here'
});
Use RemoveCrmRelation to unlink:
RemoveCrmRelation({
  slug: 'properties',
  relationKey: 'city',
  targetEntryId: 'city-entry-id-here'
});

Async writes

For non-critical writes where you don’t need immediate consistency, pass async: true so the write runs in the background:
setCrmField({ slug: 'weight-tracker', fieldKey: 'last_page_view', value: today, async: true });
setCrmFields({ slug: 'weight-tracker', fields: [{ fieldKey: 'current_weight', value: 182 }, { fieldKey: 'last_checkin', value: today }], async: true });
addCrmFieldValue({ slug: 'weight-tracker', fieldKey: 'page_views', value: { url: '/dashboard', ts: today }, async: true });
moveCrmLead({ slug: 'deals', pipelineSlug: 'sales', stageSlug: 'contacted', async: true });
See Data Functions for full parameter details and examples.