> For the complete documentation index, see [llms.txt](https://help.openloyalty.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.openloyalty.io/implementation-guide/integrations-and-data-exchange/imports-exports/imports/sample-import-files/member-custom-attributes-1.md).

# Member Custom Fields

How to set, update, and clear member custom field values in bulk using a JSON file in Open Loyalty.

Use the member custom fields import to set or update custom field values for many members at once. Custom fields are structured fields defined in your custom fields schema and organized into groups (for example, a `driving` group with `score` and `level` fields). This import is useful for backfilling data from an external system or bulk-updating values after a schema change.

**File format:** JSON

{% hint style="info" %}
**Custom fields vs. custom attributes.** Custom fields follow a schema you define (groups, field types, validation). Custom attributes are free-form key–value pairs. If you want to import simple key–value data, see Member Custom Attributes.
{% endhint %}

#### Prerequisites

{% hint style="danger" %}
**The schema must exist before you import.** Every group and field in your file must already be defined in your custom fields schema, using exactly the same keys. Values are validated against the field types in the schema — a group or field that doesn't exist, or a value of the wrong type, causes the row to fail.
{% endhint %}

#### Choosing a member identifier

During import, you select which type of identifier your file contains. The supported options are:

* **Email address**
* **Phone number**
* **Loyalty card number**
* **Member UUID** (the internal Open Loyalty identifier) You must use **one identifier type per file**. The identifier you choose in the import dropdown must match the `identifier` values in your file.

#### JSON file structure

The file is a JSON **array**. Each item in the array represents one member:

| Key                | Required | Description                                                                                          |
| ------------------ | -------- | ---------------------------------------------------------------------------------------------------- |
| **`identifier`**   | **Yes**  | The member identifier (email, phone, loyalty card number, or UUID — matching your import selection). |
| **`customFields`** | **Yes**  | An object of groups, each containing field values: `{ "group": { "field": value } }`.                |

The `customFields` object uses the same structure as when you edit a member's custom fields through the API.

**Sample File:**

{% file src="/files/pegQOX5YN86H7VBfT9eZ" %}

#### How values are handled

The import **merges** values into the member's existing custom fields — it works like a partial update:

| In your file                                 | Result                                                                 |
| -------------------------------------------- | ---------------------------------------------------------------------- |
| A field with a value                         | Sets or overwrites that field                                          |
| A field set to `null`                        | Clears that field                                                      |
| A field left out of the file                 | Left unchanged                                                         |
| A subgroup (list of objects) with a new list | Replaces the whole list — to remove one item, send the list without it |
| A subgroup set to `null`                     | Clears the whole list                                                  |

{% hint style="warning" %}
**You can't clear a whole group with `null`.** A group must always be an object. To clear a group, set each of its fields to `null`.
{% endhint %}

#### Sample file

{% code title="member-custom-fields-by-email.json" %}

```json
[
  {
    "identifier": "john.doe@example.com",
    "customFields": {
      "driving": { "score": 90, "level": "advanced", "last_trip_date": "2026-09-15" },
      "preferences": { "interests": ["sport", "travel"] }
    }
  },
  {
    "identifier": "jane.smith@example.com",
    "customFields": {
      "driving": { "score": 75, "level": null }
    }
  },
  {
    "identifier": "alex.jones@example.com",
    "customFields": {
      "activatedoffers": {
        "reward": [
          { "rewardid": "OFFER-1-SUMMER", "activatedon": "2026-06-04" },
          { "rewardid": "OFFER-4-AUTUMN", "activatedon": "2026-09-11" }
        ]
      }
    }
  }
]
```

{% endcode %}

In this file:

* `john.doe` gets three `driving` fields and a multi-select `interests` value.
* `jane.smith` gets a new `score`, has `level` cleared, and keeps every other field as it was.
* `alex.jones` gets the full list of activated offers in the `reward` subgroup.

#### Value formats

| Field type    | Format in JSON                      | Example                                                    |
| ------------- | ----------------------------------- | ---------------------------------------------------------- |
| String        | Text in quotes                      | `"advanced"`                                               |
| Number        | Number without quotes               | `90` or `4.5`                                              |
| Date          | `YYYY-MM-DD` in quotes              | `"2026-09-15"`                                             |
| Single select | One value from the collection       | `"gold"`                                                   |
| Multi select  | Array of values from the collection | `["sport", "travel"]`                                      |
| Subgroup      | Array of objects                    | `[{ "rewardid": "OFFER-1", "activatedon": "2026-06-04" }]` |

#### Format rules

* The file must be a valid JSON **array**, even if it contains only one member
* Each item must include `identifier` and `customFields`
* Group and field keys must match your schema exactly
* Use only **one type** of identifier throughout the file
* Save as `.json` with UTF-8 encoding

#### Row processing

* **Each member is processed as a whole.** If any value for a member fails validation, none of that member's changes are saved. Other members in the file are not affected.
* Members are matched only within the store you are importing into.

#### Step by step

{% stepper %}
{% step %}
**Check your schema**

Make sure every group and field you plan to import exists in your custom fields schema, and note each field's type.
{% endstep %}

{% step %}
**Prepare your JSON file**

Create an array with one object per member. Add the member's `identifier` and the `customFields` you want to set, update, or clear.
{% endstep %}

{% step %}
**Open the import**

Go to **Imports & Exports → Imports** and select **Member custom fields**. You can also start the same import from the import menu on the **Members** list.
{% endstep %}

{% step %}
**Choose the identifier and upload**

Select the **identifier type** that matches your file (email, phone, loyalty card number, or UUID), upload your JSON file, and confirm.
{% endstep %}

{% step %}
**Review the results**

The import appears in the imports list. Open it to see the outcome for each member, fix any failed entries, and re-import only those.
{% endstep %}
{% endstepper %}

#### Common mistakes

| Mistake                                           | Fix                                                                    |
| ------------------------------------------------- | ---------------------------------------------------------------------- |
| Uploading a CSV file                              | This import accepts JSON only                                          |
| Group or field not defined in the schema          | Add it to the schema first, or check the key spelling and letter case  |
| Wrong value type (e.g. `"90"` for a number field) | Send numbers without quotes and dates as `YYYY-MM-DD`                  |
| Setting a whole group to `null`                   | Groups can't be `null` — set each field in the group to `null` instead |
| Sending one subgroup item to "add" it to the list | The list is replaced — send the complete list you want to keep         |
| File is a single object instead of an array       | Wrap the content in `[ ]`, even for one member                         |
| Selecting the wrong identifier type during import | The dropdown must match the `identifier` values in your file           |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://help.openloyalty.io/implementation-guide/integrations-and-data-exchange/imports-exports/imports/sample-import-files/member-custom-attributes-1.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `build a script that syncs our docs to a CMS` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
