> 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.md).

# Member Custom Attributes

How to add, update, and remove member custom attributes in bulk using a CSV file in Open Loyalty.

Use the member custom attributes import to add, update, or remove custom attributes on many members at once. Custom attributes are simple key–value pairs (for example, `city: Warsaw`). This import is useful when you need to tag members with data from an external system, run a one-off backfill, or clean up an attribute across your member base.

**File format:** CSV

#### Prerequisites

{% hint style="warning" %}
**By default, one attribute per file.** Each file can contain the `memberId` column plus **one** attribute column. To update several attributes, import one file per attribute, or contact support to raise the column limit for your environment.
{% endhint %}

#### Choosing a member identifier

During import, you select which type of identifier your CSV 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 data in your file.

{% hint style="info" %}
**The first column header is always `memberId`**, regardless of which identifier type you use. The system matches members based on the identifier type you select during import, not the header name.
{% endhint %}

#### CSV file structure

| Column                | Required | Description                                                                                             |
| --------------------- | -------- | ------------------------------------------------------------------------------------------------------- |
| **`memberId`**        | **Yes**  | The member identifier (email, phone, loyalty card number, or UUID — matching your import selection).    |
| **`<attribute key>`** | **Yes**  | One column per attribute. The **column header is the attribute key**; each cell is that member's value. |

#### How cell values are handled

| Cell value                        | Result                                                                     |
| --------------------------------- | -------------------------------------------------------------------------- |
| Any value (e.g. `Warsaw`)         | Adds the attribute if the member doesn't have it; overwrites it if they do |
| `null` (any case: `NULL`, `Null`) | Removes the attribute from the member                                      |
| Empty cell                        | Ignored — the member's existing attribute stays unchanged                  |

A few details worth knowing:

* `null` on an attribute the member doesn't have is not an error — the row succeeds and nothing changes.
* Only the exact word `null` removes an attribute. A value that merely contains it (e.g. `nullable`) is saved as normal text.
* A cell containing only a space is saved as a value — it is not treated as empty.

#### Sample files

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

{% tabs %}
{% tab title="Using email" %}
{% code title="member-custom-attributes-by-email.csv" %}

```csv
memberId,city
john.doe@example.com,Warsaw
jane.smith@example.com,Krakow
alex.jones@example.com,null
```

{% endcode %}

In this file, `john.doe` and `jane.smith` get `city` set (added or overwritten), and `alex.jones` has `city` removed.
{% endtab %}

{% tab title="Using loyalty card" %}
{% code title="member-custom-attributes-by-card.csv" %}

```csv
memberId,preferred_store
CARD-00001,Warsaw Centrum
CARD-00002,Gdansk Oliwa
CARD-00003,Poznan Stary Rynek
```

{% endcode %}
{% endtab %}

{% tab title="Using UUID" %}
{% code title="member-custom-attributes-by-uuid.csv" %}

```csv
memberId,segment_source
e82c96cf-32a3-43bd-9034-4df343e5fd93,crm_q3_campaign
a1b2c3d4-e5f6-7890-abcd-ef1234567890,crm_q3_campaign
```

{% endcode %}
{% endtab %}
{% endtabs %}

#### Format rules

* The first column header must be `memberId`
* Every other column header is used as the attribute key
* At least one attribute column is required
* Attribute keys and values can be **up to 255 characters** each
* Use only **one type** of identifier throughout the file
* Save as `.csv` with UTF-8 encoding and a comma (`,`) separator

#### Limits and row processing

* **Each row is processed as a whole.** If anything in a row is invalid (member not found, value too long, too many columns), the entire row fails and none of its attributes are saved. Other rows are not affected.
* **Attribute limit per member.** If a row would push a member over the maximum number of custom attributes allowed on your environment, the whole row fails.
* Members are matched only within the tenant you are importing into.

#### Step by step

{% stepper %}
{% step %}
**Prepare your CSV**

Create a file with `memberId` as the first column and the attribute key as the next column header. Fill in one row per member. Use `null` in a cell to remove that attribute from the member.
{% endstep %}

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

Go to **Imports & Exports → Imports** and select **Import member custom attributes**. You can also start the same import from **Members → Add member → Import member custom attributes**.
{% endstep %}

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

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

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

The import appears in the imports list with the type **Member custom attributes**. Open it to see the outcome of each row — the matched member, the attributes applied, and the status. Fix any failed rows and re-import only those.
{% endstep %}
{% endstepper %}

#### Common mistakes

| Mistake                                           | Fix                                                                                           |
| ------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| Adding several attribute columns                  | With the default limit, use one attribute column per file — or ask support to raise the limit |
| Leaving a cell empty to delete an attribute       | Empty cells are ignored. Write `null` to remove an attribute                                  |
| Renaming the first column (e.g. `email`)          | The first header must be `memberId`, even when your file contains email addresses             |
| Selecting the wrong identifier type during import | The dropdown must match what's in your CSV (e.g. select "Email" if your file contains emails) |
| Mixing identifier types in one file               | Use one type per file — all emails, all phone numbers, all card numbers, or all UUIDs         |
| Keys or values longer than 255 characters         | Shorten them — the whole row fails otherwise                                                  |


---

# 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.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.
