Segments: Build Smart Contact Segments

Build smart subsets of your contact list with Keila using contact metadata or custom data.These subsets are called Segments.

You can either use the visual editor to combine conditions, or build more complex segments with the query editor.

Screenshot of editing a contact segment in Keila

Keila Query Language

The Keila Query Language is inspired by MongoDB’s Query Documents and is fully valid JSON.

The following operators are supported:

match

The simplest operator is the match operator. It matches either exact values or exact elements in an array.

Examples

Match an exact value:

{ "email": "joe@example.com" }
{ "data.age": 30 }

Match an array that contains an exact value:

{ "data.tags": "rocket-scientist" }

$and

The $and operator allows the combination of multiple conditions with a logical AND. This means that all conditions need to be true in order to have a match.

Example

Match contacts that have both the rocket-scientist and book-enthusiast tag. Contacts that have only one of the two are not matched.

{
  "$and": [
    { "data.tags": "rocket-scientist" },
    { "data.tags": "book-enthusiast" }
  ]
}

$or

The $or operator allows the combination of multiple conditions with a logical OR. This means that at least one condition needs to be true in order to have a match.

Example

Match contacts that have at least one of the rocket-scientist and book-enthusiast tags. Contacts that have both tags are also matched.

{
  "$or": [
    { "data.tags": "rocket-scientist" },
    { "data.tags": "book-enthusiast" }
  ]
}

$not

The $not operator allows the negation of a conditoin.

Example

Match contacts that don’t have the rocket-scientist tag.

{
  "$not": { "data.tags": "rocket-scientist" }
}

$like

The $like operator is similar to the match operator but allows the use of % as a wildcard.

Examples

Match all contacts with an email address that ends in @keila.io:

{ "email": { "$like": "%@keila.io" } }

Match all contacts with a first name that contains the letter a:

{ "first_name": { "$like": "%a%" } }

$lt, $lte, $gt, $gte

$lt (lesser than), $lte (lesser than or equal to), $gt (greater than), and $gte (greater than or equal to) are relative comparison operators.

Example

Match all contacts that were added before January 1 2022:

{ "inserted_at": { "$lt": "2022-01-01T00:00:00Z" } }

$empty

The $empty operator checks if a field is empty. The following values are considered empty:

  • null
  • empty string ("")
  • empty list ([])
  • empty object ({}).
  • unset values are also considered empty.

Examples

Match all contacts that don’t have a first name:

{ "first_name": { "$empty": true } }

Match all contacts that have a custom field:

{ "data.custom_field": { "$empty": false } }

Message-based Segmentation

You can create segments based on how contacts interact with your campaigns using the messages field. This allows you to target contacts who have received, opened, or clicked specific campaigns.

The following filters are available for the messages field:

  • campaign_id: The ID of the campaign. If omitted, the contact will be included in the segment if any campaign matches the other criteria.
  • opened_at: The date and time the contact opened the campaign.
  • clicked_at: The date and time the contact clicked a link in the campaign.
  • bounced_at: The date and time the contact bounced the campaign.
  • complaint_received_at: The date and time a complaint was received about the campaign.
  • unsubscribed_at: The date and time a contact unsubscribed from the campaign.

Examples

Match contacts who received a specific campaign:

{ "messages": { "campaign_id": "your-campaign-id" } }

Match contacts who opened a campaign:

{
  "messages": {
    "campaign_id": "your-campaign-id",
    "opened_at": { "$empty": false }
  }
}

Match contacts who clicked a link in a campaign:

{
  "messages": {
    "campaign_id": "your-campaign-id",
    "clicked_at": { "$empty": false }
  }
}

Matching contacts who have not interacted with campaigns

If you want to match all contacts who have not interacted with a campaign, including those who have not received it, use the $not operator:

{
  "$not": {
    "messages": {
      "campaign_id": "your-campaign-id",
      "opened_at": { "$empty": false }
    }
  }
}

If you only want to match contacts who haven’t interacted but did receive the campaign, the $empty operator is sufficient:

{
  "messages": {
    "campaign_id": "your-campaign-id",
    "opened_at": { "$empty": true }
  }
}