# Using JSON in segments

Attributes and event data can contain nested (JSON) values—arrays, objects, and arrays of objects. You can use these nested values to match people in segments, filters, and trigger criteria. If you’re not familiar with JSON, we provide some simple options to help you traverse nested attributes. If you *are* familiar with JSON, you can use JSON dot notation as you normally would.

 New to JSON?

JSON is a standard, simple way to organize and structure data. Check out our [introduction to JSON](/journeys/getting-started-with-json/) and learn how you can take advantage of JSON in Customer.io.

## How it works[](#how-it-works)

Attributes and events can contain nested JSON (JavaScript Object Notation) values, and you can evaluate these values when you build a [segmentA group of people who match a series of conditions. People enter and exit the segment automatically when they match or stop matching conditions.](/journeys/data-driven-segments/), filter, or trigger condition. If you’re not familiar with JSON, you might check out [our introduction to JSON](/journeys/getting-started-with-json)—but we’ll explain a bit about how it works on this page. Read on and you’ll be a pro in no time.

**If you’re new to JSON (nested attributes and values)**, or just want a simplified experience, you can use the *Has the property* or *Where at least one* selectors to build segments based on nested values. See the [If you’re new to JSON](#new-to-json) section below for more about these selectors.

[![use our simple editor to traverse json](https://docs.customer.io/images/segment-json-simple-example.png)](#b2d85e85945a9cee038ad4be1c3c23c9-lightbox)

**If you’re already familiar with JSON**, you can use dot notation to point to nested values. You might use the Advanced option to point right to the nested value you want to evaluate.

[![use our advanced editor to traverse json](https://docs.customer.io/images/segment-json-advanced-example.png)](#36c2fdb2f484c0b9c6787ce227ffc0f0-lightbox)

 You can only use JSON customer attributes and event properties in segment conditions

You can’t use nested [device attributes](/journeys/attributes/#standard-device-attributes), [collection properties](/collections/), or trigger properties (from an [incoming webhook](/webhook-triggered-campaigns/#create-a-data-campaign) or an [API-triggered broadcast](/broadcasts-in-customerio/#api-triggered-broadcasts)) in segment conditions.

### Example data[](#example-data)

On this page, we’ll consider the following sample JSON data representing a complex attribute or event data. We’ll use it to demonstrate segment matches on this page. In both cases, we’ll call it `shopper_history`.

```json
{
  "last_shopped": 1662587234,
  "location": {"city": "Montreal","province": "QC"},
  "purchases": [
    {
      "id": 123,
      "type": "computers",
      "name": "Monitor",
      "price": 25,
      "discount": 10,
      "shipping_address": {"city": "Calgary","province": "AB"},
      "coupons_applied": [
        {
          "coupon_code": "AXXXXX",
          "discount": "10%"
        },
        {
          "coupon_code": "BXXXXX",
          "discount": "15%"
        }
      ]
    },
    {
      "id": 456,
      "type": "computers",
      "name": "Mouse",
      "price": 15,
      "shipping_address": {"city": "Edmonton","province": "AB"}
    }
  ],
  "stores_visited": ["Winnipeg","Toronto","Vancouver"],
  "coupons_received": [5,10,20],
  "children_ages": [1654099180,1654099181,1654099182],
  "lottery_tickets":
     [
        [1,3,5,7,9],
        [1,2,3,5,8]
  ]
}
```

### If you’re new to JSON…[](#new-to-json)

We nest values under parents in two different formats: objects and arrays.

See the curly brackets surrounding the data above—the `{` on the first line and the `}` on the last line? That’s called an **object**. If we stored all of the data above in an attribute called *shopper\_history*, you could filter people who `last_shopped` with you using the *Has the property* selector—because `last_shopped` resides within the `shopper_history` attribute.

[![traverse an object with the has the property operator](https://docs.customer.io/images/segment-has-the-property.png)](#975b7630e6eae7aa4030e5acf258451a-lightbox)

See the square brackets surrounding the value after `stores_visited` above? That’s called an **array**. If we wanted to build a segment of all people who visited the Toronto store, we could build a segment of people with a *shopper\_history* attribute that has the property `stores_visited` where at least one value is `Toronto`.

[![find a value in an array with the where at least one operator](https://docs.customer.io/images/segment-where-at-least-one.png)](#f90a41f5aaf0f180e4ba1a55eecbe3ef-lightbox)

An array can also contain objects—that’s what’s going on with `purchases` above. If we wanted to find everybody who used a coupon on their purchase, we could set up a segment where: `shopper_history` has the property `purchases` where at least one property called `coupons_applied` exists.

[![use our simple editor to traverse json](https://docs.customer.io/images/segment-json-simple-example-coupon.png)](#a36d10b20cb498ee8b38b42d2b903330-lightbox)

## Nested properties in the basic segment builder[](#nested-properties-in-the-basic-segment-builder)

The segment builder has two selectors that help you traverse complex values:

*   **Has the property**: Checks for a child of an object.
*   **Where at least one**: Checks for a matching value in an array.

When working with complex attributes and event values, you might want to open a representative person in another browser window—someone with data that you can reference as you build your segment.

### Has the property (objects)[](#has-the-property)

The **has the property** selector lets you traverse objects. Using our example data, you could create a condition stating *Attribute `location` has the property `city` equal to `Montreal`*. This evaluates to true. When you use the *has the property* selector, we nest child values, helping show the parent-child relationships between nested attributes.

[![nested properties in a segment](https://docs.customer.io/images/segment-nested-property.png)](#29e0f8d17d1a0149c14860b03740e8c1-lightbox)

### At least one of (arrays)[](#at-least-one-of)

The **at least one of** selector matches an item in an array. When you use it, you select whether you want to match a *property* or *array value* in the array.

*   **property**: your array contains objects—like `purchases` in our example data, and you want to traverse that data to find a match.
*   **array value**: your array only contains values, like `stores_visited` in our example data. Use this to match literally to any value in the array.

For a simple array—a list of values in square brackets—simply use the `contains` or `equals` operators to match a value. Using the `stores_visited` array from our `shopper_history` example data, the following would evaluate to true.

`shopper_history.stores_visited contains Winnipeg` is true, and the person represented by the data above would join the segment.

You cannot specify a position or “index” when you use the segment builder this way. If you want to match a value at a specific index, you’ll need to use [JSON dot notation in the advanced editor](#dot-notation).

 *Equals* and *Contains* have some minor differences

The *equals* operator searches for a matching value, and *contains* searches for a match within a value in the array. See our [section below](#equals-vs-contains) for more information.

### Dot notation in the basic editor[](#simple-dot-notation)

You can use dot notation in the simplified, basic editor. However, you can’t specify an array index when you use the editor this way.

For example, if you wanted to filter or segment on a matching value in the `stores_visited` array, you could use *Attribute `shopper_history.stores_visited[]` is equal to `Winnipeg`*.

But you’d have to switch to [the advanced editor](#advanced-editor) if you only wanted to match the first item in the array—i.e. `shopper_history.stores_visited[0]`.

[![JSON dot notation in the segment builder](https://docs.customer.io/images/segment-json-example.png)](#2c2c6ab204d078e0d5f2433b435ab240-lightbox)

## The Advanced Editor[](#dot-notation)

You can click **Advanced** to switch to an expanded JSON dot notation editor.

If you don’t provide an array index when you use dot notation, we’ll match any item in the array (e.g. `array[]`). If you provide an index, we’ll match a specific position in an array. Arrays are zero-indexed—e.g. `array[0]` matches the first item in the array.

Using our `stores_visited` example:

*   `shopper_history.stores_visited[] contains Toronto` is true
*   `shopper_history.stores_visited[0] contains Toronto` is false

[![use an array in a segment condition](https://docs.customer.io/images/segment-array.png)](#56cdc8d3c53c54baa7bb0e2717e545a3-lightbox)

This works with nested arrays and arrays of objects as well. For example if we wanted to create a segment of people who used a specific coupon, we might use `shopper_history.purchases[].coupons_applied[].coupon_code`. This would search against every object within `purchases` for an array called `coupons_applied`, and then for the `coupon_code` for every object within `coupons_applied`.

[![use an array of objects in a segment condition](https://docs.customer.io/images/segment-array-of-objects.png)](#6d473cb87636f3491b4c8537ac0ba94d-lightbox)

 Empty brackets don’t work in Liquid

You can’t use our empty bracket array syntax (`array[]`) to match any item in an array using [liquidA syntax that supports variables, letting you personalize messages for your audience. For example, if you want to reference a person’s first name, you might use the variable `{{customer.first_name}}`.](/using-liquid). Instead, you’ll need to use a for loop or provide a specific index in the array.

### The `?` operator: for arrays or objects[](#question-mark-operator)

If you’re not sure whether an attribute is an object or an array, you can use the `?` operator in place of square brackets.

When you use a `?`, we’ll treat a value first as an array; if we don’t find a match, we’ll treat the value as an object. For example, if you wanted to access a key in purchases, but you weren’t sure if it was an object or an array of objects, you could use: `shopper_history.purchases?.type`.

If you use the *where at least one* property in the basic editor and then switch to *Advanced*, you’ll see that we use the `?` operator rather than square brackets, segments aren’t aware of your attribute and event data structure until you save conditions and we begin processing the segment.

## Traversing nested attributes[](#traverse-objects-arrays)

When you search within an object or an array, we’ll traverse the entire value until we find a match. For example, `purchases[].coupons_applied[].coupon_code` searches for the `coupon_code` key within any `coupons_applied` found in `purchases`.

However, if you know your coupon code values are unique, you could also simply search `purchases[]` for your coupon code value. We’ll automatically search for a matching value in any child property of the `purchases[]` array.

[![Look for a unique value from a top-level array](https://docs.customer.io/images/segment-array-traversal.png)](#7cf9f0266627eae1d70b8244235153e3-lightbox)

## Equals vs contains in an array[](#equals-vs-contains)

In most cases, the *equals* and *contains* conditions are functionally identical when you use the *at least one of* selector (e.g. you reference an array). But there is a minor difference: *Equals* searches for an exact match. *Contains* searches for a value containing a string value—so a partial string can match.

Using our `stores_visited` example data, these two statements are identical and true:

*   `stores_visited[] contains Toronto`
*   `stores_visited[] equals Toronto`

But these two statements are not identical:

*   `stores_visited[] contains Toro` is true
*   `stores_visited[] equals Toro` is false

If you don’t use array syntax—either the *where at least one* selector or `[]`—`contains` will work but `equals` will not. When you don’t use array syntax, we treat the value as a string; the stringified value of `stores_visited` contains `Toronto`, but it has more characters than just that word, so it can’t equal `Toronto`.

*   `stores_visited contains Toronto` is true
*   `stores_visited equals Toronto` is false

## Use *does not exist* instead of an empty string[](#empty-string)

In general, you shouldn’t send attributes or event data properties with empty strings. It’s not necessarily a problem if you do, but we don’t store customer [attributesA key-value pair that you associate with a person or an object—like a person’s name, the date they were created in your workspace, or a company’s billing date etc. Use attributes to target people and personalize messages.](/journeys/attributes/) with empty values, and you can’t save a segment or filter condition with an empty value.

But, if you do pass us attributes or properties with empty values—like in event data—you can segment or filter against these conditions using the *exists* or *does not exist* operators.

[![use the does not exist condition to check for an empty value](https://docs.customer.io/images/segment-array-exists.png)](#c91ba575cf273835946327ac06501d9f-lightbox)