AttributesUpdated 03/01/2019


You can use Processor or Incoming Webhooks to create or update attributes using the the following code conventions.


Users and Accounts can have attributes to describe them. These are synonymous with properties, fields, and traits in other tools.

Attributes have three types:

  • Reserved attributes are set by Hull (e.g. user.name, user.email)
  • Grouped attributes show attributes from the same source (e.g. Salesforce) or a group you have defined. Use grouped attributes to organize your data
  • Ungrouped attributes that do not have a particular attribute group. These will appear in a default group called "traits".

Updating attributes with the Processor or Incoming Webhooks connector

You can use Processor or Incoming Webhooks to create or update attributes using the the following code conventions.

Warnings & Best Practices

  • Use snake_case rather than camelCase to name your Attributes (you can convert strings with _.snakeCase('Foo Bar');
  • Write human-readable keys for attributes. lead_score is better than ls
  • Pass the correct value type. Once an Attribute is cast (when it is created for the first time, it cannot be changed. (e.g. Don't pass an integer value as "1234")
  • Do NOT create dynamic keys for Attributes.
  • Do NOT write large arrays (keep to <50 values)
  • Do NOT create infinite loops - these will count towards your billable quota

Updating Ungrouped User Attributes

You can create and update ungrouped one or more attributes with a hull.traits() call as follows:

hull.traits({ ATTRIBUTE_NAME: <value>, ATTRIBUTE2_NAME: <value> })

Updating Grouped User Attributes

You can create and update grouped attributes with a hull.traits() call that passes a source in a second object.

  hull.traits({ ATTRIBUTE_NAME: <value> }, { source: "string" })

Updating Attributes with dates

Use _at or _date as suffix to your Attribute names to recognize the values as valid dates.

You can pass valid:

  • Unix timestamp in seconds or milliseconds
  • String formatted according to ISO-8601

Incrementing & decrementing Attribute values (atomic operations)

Since Processor code may run multiple times in parallel, incrementing values like this will not be reliable:

hull.traits({ coconuts: user.coconuts+1 });

To reliable increment and decrement values, you need to use atomic operations as so:

hull.traits({ coconuts: { operation: 'inc', value: 1 } })

Where:

  • operation
  • inc, dec, or setIfNull
  • value
  • The value to increment, decrement, or set if nothing else was set before

Associating data with User Profiles

Data from Incoming Webhooks will need to be associated with a User (or Account) profile. You will need to pass either an email, anonymous_id or external_id.

Warning Read and understand Hull's identity resolution strategy before customizing how data is associated.

You can write this as follows:

// Associate with a User and write an attribute
hull.traits ({ email: <email> }).traits({ ATTRIBUTE_NAME: <value> }, { source: "string" })

Updating Account Attributes

You can create and update Account attributes with a hull.account() call.

If the User is not associated with an Account or if you need to explicitly address the account, you can use the chained function hull.account.traits() call.

Warning: Read about Hull's identity resolution strategy before customizing linking between Users and Accounts.

You cannot created grouped account attributes.

Here's an example writing an Account Attribute:

hull.account().traits({ ATTRIBUTE_NAME: <value>, ATTRIBUTE2_NAME: <value> })

Warning: Beware of writing User Attributes to Account Attributes. It is possible multiple Users associated with an Account may have different versions of data - this can create a billable infinite loop as the Account Attribute is continuously updated between the two versions.

You can prevent infinite loops with a setIfNull operation on the Account, or evaluate the changes object (in Processor), or rely on a User Event to then update an Attribute.

// Update Account attribute when an event is tracked
events.map(event => {
  if (event.event === "MRR Changed") {
    hull.account().traits({ mrr: event.properties.mrr });
  }
});

Deleting an attribute

To delete an attribute, make a hull.traits() call and set the value to null

hull.traits({ ATTRIBUTE_NAME: null })