message.comDevelopers

Custom attributes Live

Attach arbitrary key-value attributes to visitors, conversations, and tickets. Strings, numbers, booleans, and dates. Display in the agent sidebar, filter saved views, ground AI replies, and drive routing rules. The flexible escape hatch for anything our schema does not explicitly model.

Custom attributes are the glue between your systems and the workspace. Anything you would normally put in a CRM custom field can live here.

Supported types

Each attribute is typed when first written. Type is sticky per key per workspace; subsequent writes are coerced or rejected accordingly.

  • string. Up to 1024 characters.
  • number. IEEE 754 double precision.
  • boolean. true or false.
  • date. Unix seconds or ISO 8601. Stored as Postgres timestamptz.
  • array of string. Up to 50 entries, useful for tag-style fields.

Visitor attributes

The most common pattern. Push from the widget after sign-in or via REST from your backend.

Browser, via widget
// Browser, via the widget
Message.identify({
  email: "[email protected]",
  userId: "crm-4567",
  // Arbitrary attributes follow
  plan: "pro",                // string
  mrr: 99,                    // number
  trialEndsAt: 1717200000,    // unix seconds, date
  isPaid: true,               // boolean
});
Server-side via REST
// Server-side via REST
curl -X PATCH 'https://app.message.com/api/v1/visitors/uuid' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "attributes": {
      "lifetimeValue": 2400,
      "lastOrderAt": "2026-05-10",
      "tier": "gold"
    }
  }'

Conversation attributes

For attributes that change with each conversation (the page the visitor was on, an experiment variant, the cart total at the time of message), attach them to the conversation rather than the visitor. Use Message.update() from the widget, or PATCH the conversation.

Conversation context
// Per-conversation context (e.g., the page they were on)
Message.update({
  page: "/checkout/payment",
  cartTotal: 89.50,
  experiment: "checkout_v2"
});

AI grounding

The AI reads visitor attributes when drafting replies. A pro-plan customer with $5,000 lifetime value asking for a refund gets a different draft than an anonymous trial user. We do not let the model see attributes you mark as private; toggle in Settings → AI → Attribute access.

Agent display

Attributes appear in the right-rail sidebar on every conversation. You can pin specific attributes to always show; the rest collapse behind a toggle. Configure the layout in Settings → Workspace → Visitor profile layout.

Filters and routing

Saved views can filter on attributes. Routing rules can target by attribute (route VIPs to a dedicated department; route anonymous trial users to the general queue). Combine with saved views for power-user workflows.

Naming conventions

Use camelCase keys. Avoid spaces, special characters, and the reserved prefixes __ and msg_. Keys are case-sensitive; plan and Plan are different attributes (do not do this to yourself).

Limits

  • Up to 100 distinct attribute keys per resource.
  • Up to 1024 characters per string value.
  • Up to 50 entries in a string array.
  • No nested objects. Flatten before sending.

Common pitfalls

  • Hardcoded date strings. Pass unix seconds or ISO 8601 with a timezone. Bare "2026-05-13" is interpreted UTC; if you meant local, you will be eight hours off.
  • Type drift. Writing plan: 99 then later plan: "pro" fails the second write. Pick a type and stick to it.
  • Storing secrets in attributes. Do not. Attributes are not encrypted at the field level; they are visible to every agent.