> ## Documentation Index
> Fetch the complete documentation index at: https://lightdash-mintlify-9d6f9427.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# User attributes

> User attributes provide a way to customise Lightdash charts, dashboards, and other behaviour depending on the user that is logged in. For example, you could only show your sales team members data that are relevant to their region.

User attributes are defined for your whole Organization and can only be a text value (not a date or number). Some examples of user attributes are:

* Sales region
* Department
* Can view PII
* Can view financial data

To start user attributes you need to follow 2 steps:

1. Define the user attribute, users can only have user attributes that are explicitly created by admins
2. Set the user attribute value per user.

User attributes can only be managed by admins.

<iframe width="100%" height="420" src="https://www.youtube.com/embed/eSUULAeBZU8" title="How to create user attributes" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen />

## Managing user attributes

### Creating user attributes

User attributes can be created by navigating to **Organization Settings** > **User Attributes** and clicking on the**Add attribute** button. This will create a new user attribute but it will not be assigned to any user.

### Assigning user attributes to users and groups

User attributes can be assigned to users or [groups](/references/workspace/groups) by navigating to **Organization Settings** > **User Attributes** and clicking on the user attribute you'd like to assign. Select a user by email address, or a group by group name and set their value.

<Tip>
  Self-hosted Enterprise instances can declare user attributes and group-value mappings as instance config with the [`LD_SETUP_USER_ATTRIBUTES`](/self-host/customize-deployment/environment-variables#declare-user-attributes) environment variable, so they're reconciled on every deploy.
</Tip>

### Setting a default value for your user attribute

You can add a default attribute that will be applied to all users who don't have their own value defined in this user attribute.

<Frame>
  <img src="https://mintcdn.com/lightdash-mintlify-9d6f9427/u4PJkm0BuJuKtNvT/images/references/workspace/user-attribute-default-value-5618464d7ec3e8f71a78d0af4d409229.png?fit=max&auto=format&n=u4PJkm0BuJuKtNvT&q=85&s=3765e968c90539ac11e73311f0a614cb" alt="" width="633" height="421" data-path="images/references/workspace/user-attribute-default-value-5618464d7ec3e8f71a78d0af4d409229.png" />
</Frame>

If a user has an attribute defined, we will ignore the default for that user.

## Using user attributes in Lightdash

There are several places in Lightdash where you can customise behaviour based on user attributes.

### Where can I reference user attributes?

User attributes can be used in these specific contexts within the model.yaml file:

* `sql_filter:` - For row filtering at the model level
* `required_attributes:` - For column and table access control (AND logic - all conditions must match)
* `any_attributes:` - For column and table access control (OR logic - at least one condition must match)
* `sql_on:` - For filtering joins

User attributes can also be used in:

* **Chart and dashboard filter values** - Filter charts and dashboards dynamically based on the logged-in user

<Info>
  User attributes cannot currently be referenced inside`sql:` tags within the model YAML files.
</Info>

When referencing user attributes in SQL you can use the following [SQL variables](/references/sql-variables):

* `${lightdash.attributes.my_attr_1}` - a user attribute called `my_attr_1`
  * (optional) `ld` as an alias for `lightdash`
  * (optional) `attribute` or `attr` as an alias for `attributes`
* `${lightdash.user.<intrinsic_attribute>}` - reference an `intrinsic_attribute` of the current Lightdash user
  * (optional) `ld` as an alias for `lightdash`
  * available intrinsic user attributes:
    * `email`

<Info>
  **The user email attribute is only available when the email is verified.**

  This is a security measure to prevent users from creating/updating an account with any email they don't own and gain access to data they shouldn't see.

  If the user email is not verified you will get the following error:

  <Frame>
    <img src="https://mintcdn.com/lightdash-mintlify-9d6f9427/u4PJkm0BuJuKtNvT/images/references/workspace/user-attributes-info.png?fit=max&auto=format&n=u4PJkm0BuJuKtNvT&q=85&s=129af9223483cf0b181f4ca1595c9bc1" alt="" width="438" height="72" data-path="images/references/workspace/user-attributes-info.png" />
  </Frame>

  <Tabs>
    <Tab title="dbt v1.9 and earlier">
      ```yaml theme={null}
      models:
        - name: example
          meta:
            sql_filter: ${lightdash.user.email} = 'example@lightdash.com'
      ```
    </Tab>

    <Tab title="dbt v1.10+">
      ```yaml theme={null}
      models:
        - name: example
          config:
            meta:
              sql_filter: ${lightdash.user.email} = 'example@lightdash.com'
      ```
    </Tab>

    <Tab title="Lightdash YAML">
      ```yaml theme={null}
      type: model
      name: example

      sql_filter: ${lightdash.user.email} = 'example@lightdash.com'
      ```
    </Tab>
  </Tabs>

  If you are self hosting you can enable [SMTP](/self-host/customize-deployment/configure-smtp-for-lightdash-email-notifications) or [SSO](/self-host/customize-deployment/use-sso-login-for-self-hosted-lightdash) authentication to allow users to verify their email address.
</Info>

### Using user attributes in chart and dashboard filter values

You can reference user attributes directly in chart and dashboard filter values to create dynamic filters based on the logged-in user. This is useful for creating charts and dashboards that automatically filter to show only data relevant to the current user.

To use a user attribute in a filter value, enter one of the following references:

* `${lightdash.user.email}` - The logged-in user's email address
* `${lightdash.attribute.<attribute_name>}` - A custom user attribute value

For example, if you have a chart showing sales data and you want each user to only see their own records, you can add a filter where `sales_rep_email` is equal to `${lightdash.user.email}`. When the chart runs, the filter value will be replaced with the actual email of the logged-in user.

The same references work on dashboard filters, so a single dashboard can be shared with many users and each will only see the rows relevant to them.

<img src="https://mintcdn.com/lightdash-mintlify-9d6f9427/u4PJkm0BuJuKtNvT/images/references/workspace/user-attribute-dashboard-filter.png?fit=max&auto=format&n=u4PJkm0BuJuKtNvT&q=85&s=bcd25507b2b43ba30fd5aaea9a401ebe" alt="Dashboard filter using a user attribute as its value" width="440" height="315" data-path="images/references/workspace/user-attribute-dashboard-filter.png" />

Similarly, you can use custom attributes like `${lightdash.attribute.country}` to filter data based on a user's assigned region or department.

<Info>
  If a user attribute referenced in a filter value is not set for the current user, the query will return a `Forbidden` error.
</Info>

<Warning>
  Chart and dashboard filters are **not a security boundary**. Any user with edit access to the chart or dashboard can remove or change the filter and see the underlying rows. If you need to actually restrict which rows a user can query, use [row filtering with `sql_filter`](#row-filtering-with-sql%5Ffilter) in your dbt model — that runs on the warehouse and cannot be bypassed from the UI.
</Warning>

### Row filtering with `sql_filter`

Row-level security (RLS) in Lightdash is implemented using the `sql_filter` property combined with user attributes. This allows you to restrict which rows each user can see based on their attributes.

To reference a user attribute in your sql, use the special lightdash reference`${lightdash.attributes.<attribute_name> }`. You should use the `IN` operator since the attribute might have multiple values.

For example, if you have a user attribute called `sales_region` you can use it in your sql like this:

<Tabs>
  <Tab title="dbt v1.9 and earlier">
    ```yaml theme={null}
    models:
      - name: my_model
        meta:
          sql_filter: ${TABLE}.sales_region IN (${lightdash.attributes.sales_region})
    ```
  </Tab>

  <Tab title="dbt v1.10+">
    ```yaml theme={null}
    models:
      - name: my_model
        config:
          meta:
            sql_filter: ${TABLE}.sales_region IN (${lightdash.attributes.sales_region})
    ```
  </Tab>

  <Tab title="Lightdash YAML">
    ```yaml theme={null}
    type: model
    name: my_model

    sql_filter: ${TABLE}.sales_region IN (${lightdash.attributes.sales_region})
    ```
  </Tab>
</Tabs>

### Column filtering with `required_attributes`

You can use `user attributes` to limit some dimensions to some users.

<Info>
  Users without access to this dimension will not see it, as well as the **metrics derived from it**. .
</Info>

In the example below, only users with `is_admin` attribute `true` can use the `salary` dimension on `user` table.

<Tabs>
  <Tab title="dbt v1.9 and earlier">
    ```yaml theme={null}
    columns:
      - name: user
        description: User name
      - name: salary
        description: User salary
        meta:
          dimension:
            required_attributes:
              is_admin: "true"
    ```
  </Tab>

  <Tab title="dbt v1.10+">
    ```yaml theme={null}
    columns:
      - name: user
        description: User name
      - name: salary
        description: User salary
        config:
          meta:
            dimension:
              required_attributes:
                is_admin: "true"
    ```
  </Tab>

  <Tab title="Lightdash YAML">
    ```yaml theme={null}
    type: model
    name: users

    dimensions:
      - name: user
        description: User name
      - name: salary
        description: User salary
        required_attributes:
          is_admin: "true"
    ```
  </Tab>
</Tabs>

If a user without access to this dimension runs a query that contains this dimension, they will get a `Forbidden` error. Also, if the user runs a query that contains a metric derived from this dimension, they won't see the metric on the explore page and won't be able to query from it.

You can add multiple attributes for a single dimension. There are two ways to do this:

1. **`Multiple attributes joined with AND.`** In the example below, only users with `is_admin: "true" AND team_name: "HR"` have access to the `salary` dimension in Lightdash.

<Tabs>
  <Tab title="dbt v1.9 and earlier">
    ```yaml theme={null}
    columns:
      - name: user
        description: User name
      - name: salary
        description: User salary
        meta:
          dimension:
            required_attributes:
              is_admin: 'true'
              team_name: 'HR'
    ```
  </Tab>

  <Tab title="dbt v1.10+">
    ```yaml theme={null}
    columns:
      - name: user
        description: User name
      - name: salary
        description: User salary
        config:
          meta:
            dimension:
              required_attributes:
                is_admin: 'true'
                team_name: 'HR'
    ```
  </Tab>

  <Tab title="Lightdash YAML">
    ```yaml theme={null}
    type: model
    name: users

    dimensions:
      - name: user
        description: User name
      - name: salary
        description: User salary
        required_attributes:
          is_admin: 'true'
          team_name: 'HR'
    ```
  </Tab>
</Tabs>

2. **`Multiple attribute values joined with OR.`** In the example below, users with `team_name = 'HR' OR team_name = 'C-Suite'` have access to the `salary` dimension in Lightdash.

<Tabs>
  <Tab title="dbt v1.9 and earlier">
    ```yaml theme={null}
    columns:
      - name: user
        description: User name
      - name: salary
        description: User salary
        meta:
          dimension:
            required_attributes:
              team_name: ['HR', 'C-Suite']
    ```
  </Tab>

  <Tab title="dbt v1.10+">
    ```yaml theme={null}
    columns:
      - name: user
        description: User name
      - name: salary
        description: User salary
        config:
          meta:
            dimension:
              required_attributes:
                team_name: ['HR', 'C-Suite']
    ```
  </Tab>

  <Tab title="Lightdash YAML">
    ```yaml theme={null}
    type: model
    name: users

    dimensions:
      - name: user
        description: User name
      - name: salary
        description: User salary
        required_attributes:
          team_name: ['HR', 'C-Suite']
    ```
  </Tab>
</Tabs>

<Info>
  Column filtering using `required_attributes` does not take into account intrinsic attributes of a user - `email`.
</Info>

### Column filtering with `any_attributes`

While `required_attributes` uses AND logic (all conditions must match), `any_attributes` uses OR logic — a user only needs to match **at least one** of the conditions to access the dimension.

In the example below, users with `department = "sales"` **OR** `department = "finance"` **OR** `role = "analyst"` can see the `revenue` dimension.

<Tabs>
  <Tab title="dbt v1.9 and earlier">
    ```yaml theme={null}
    columns:
      - name: revenue
        description: Total revenue
        meta:
          dimension:
            any_attributes:
              department: ["sales", "finance"]
              role: "analyst"
    ```
  </Tab>

  <Tab title="dbt v1.10+">
    ```yaml theme={null}
    columns:
      - name: revenue
        description: Total revenue
        config:
          meta:
            dimension:
              any_attributes:
                department: ["sales", "finance"]
                role: "analyst"
    ```
  </Tab>

  <Tab title="Lightdash YAML">
    ```yaml theme={null}
    type: model
    name: orders

    dimensions:
      - name: revenue
        description: Total revenue
        any_attributes:
          department: ["sales", "finance"]
          role: "analyst"
    ```
  </Tab>
</Tabs>

Each entry in `any_attributes` is a separate condition. The user needs to satisfy **any one** of them. Array values on a single key (like `["sales", "finance"]`) mean any of those values is accepted for that key.

### Combining `required_attributes` and `any_attributes`

You can use both `required_attributes` and `any_attributes` together. When both are set, **both** checks must pass:

1. All conditions in `required_attributes` must match (AND)
2. At least one condition in `any_attributes` must match (OR)

In the example below, a user must have `access_level = "2"` **AND** (`department = "sales"` **OR** `department = "finance"`).

<Tabs>
  <Tab title="dbt v1.9 and earlier">
    ```yaml theme={null}
    columns:
      - name: revenue
        description: Total revenue
        meta:
          dimension:
            required_attributes:
              access_level: "2"
            any_attributes:
              department: ["sales", "finance"]
    ```
  </Tab>

  <Tab title="dbt v1.10+">
    ```yaml theme={null}
    columns:
      - name: revenue
        description: Total revenue
        config:
          meta:
            dimension:
              required_attributes:
                access_level: "2"
              any_attributes:
                department: ["sales", "finance"]
    ```
  </Tab>

  <Tab title="Lightdash YAML">
    ```yaml theme={null}
    type: model
    name: orders

    dimensions:
      - name: revenue
        description: Total revenue
        required_attributes:
          access_level: "2"
        any_attributes:
          department: ["sales", "finance"]
    ```
  </Tab>
</Tabs>

<Info>
  Column filtering using `any_attributes` does not take into account intrinsic attributes of a user - `email`.
</Info>

### Table filtering with `required_attributes`

You can use `user attributes` to limit some tables to some users.

In the example below, only users with `is_admin` attribute `true` can use the `payments` table. Users without access to this table will not see it on the `tables page` or the `explore page` when joined to other tables.

<Tabs>
  <Tab title="dbt v1.9 and earlier">
    ```yaml theme={null}
    models:
      - name: payments
        meta:
          required_attributes:
            is_admin: "true"
    ```
  </Tab>

  <Tab title="dbt v1.10+">
    ```yaml theme={null}
    models:
      - name: payments
        config:
          meta:
            required_attributes:
              is_admin: "true"
    ```
  </Tab>

  <Tab title="Lightdash YAML">
    ```yaml theme={null}
    type: model
    name: payments

    required_attributes:
      is_admin: "true"
    ```
  </Tab>
</Tabs>

Similar to [columns filtering](#column-filtering-with-required%5Fattributes), you can add multiple attributes for a single table.

<Info>
  Table filtering using `required_attributes` does not take into account intrinsic attributes of a user - `email`.
</Info>

### Table filtering with `any_attributes`

You can also use `any_attributes` at the table level with OR logic. In the example below, users with `department = "sales"` **OR** `department = "finance"` **OR** `role = "analyst"` can access the `payments` table.

<Tabs>
  <Tab title="dbt v1.9 and earlier">
    ```yaml theme={null}
    models:
      - name: payments
        meta:
          any_attributes:
            department: ["sales", "finance"]
            role: "analyst"
    ```
  </Tab>

  <Tab title="dbt v1.10+">
    ```yaml theme={null}
    models:
      - name: payments
        config:
          meta:
            any_attributes:
              department: ["sales", "finance"]
              role: "analyst"
    ```
  </Tab>

  <Tab title="Lightdash YAML">
    ```yaml theme={null}
    type: model
    name: payments

    any_attributes:
      department: ["sales", "finance"]
      role: "analyst"
    ```
  </Tab>
</Tabs>

You can combine `required_attributes` and `any_attributes` on the same table. Both checks must pass — see [combining required and any attributes](#combining-required_attributes-and-any_attributes) for details.

<Info>
  Table filtering using `any_attributes` does not take into account intrinsic attributes of a user - `email`.
</Info>

### Filtering joins with `sql_on`

If you're joining a table, you can also customise the rows that are returned

You can use user attributes to filter the rows returned by a join. This is useful if you want to restrict the data returned from the joined table. To reference a user attribute in your sql, use the special lightdash reference`${ lightdash.attributes.<attribute_name> }`. For example, if you have a user attribute called `sales_region` you can use it in your sql like this:

<Tabs>
  <Tab title="dbt v1.9 and earlier">
    ```yaml theme={null}
    models:
      - name: base
        meta:
          joins:
            - join: joined
              sql_on: >
                ${base}.id = ${joined}.id
                AND ${joined}.sales_region = ${lightdash.attributes.sales_region}
    ```
  </Tab>

  <Tab title="dbt v1.10+">
    ```yaml theme={null}
    models:
      - name: base
        config:
          meta:
            joins:
              - join: joined
                sql_on: >
                  ${base}.id = ${joined}.id
                  AND ${joined}.sales_region = ${lightdash.attributes.sales_region}
    ```
  </Tab>

  <Tab title="Lightdash YAML">
    ```yaml theme={null}
    type: model
    name: base

    joins:
      - join: joined
        sql_on: >
          ${base}.id = ${joined}.id
          AND ${joined}.sales_region = ${lightdash.attributes.sales_region}
    ```
  </Tab>
</Tabs>

## Current limitations

Lightdash dimensions and custom metrics are protected by this feature, however, it is possible to write custom SQL to bypass this filter, for example:

* Developers and admins running SQL queries on SQL runner.
* Custom SQL or subqueries on `table calculations`

<Info>
  Scheduler deliveries will run against the user who created the scheduled delivery, be careful when sharing required attributes with other users.
</Info>

## Demo: filtering a chart based on user attributes

The following video gives you a full demo for how to use user attributes to filter chart results.

<iframe width="100%" height="420" src="https://www.youtube.com/embed/t6QS0rr0PDQ" title="Customizing Lightdash with User Attributes" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen />

## How user and group attribute values interact

Users can be assigned attributes, but you can also assign groups attributes. So, if a user is assigned an attribute value, but they're also part of a group that's been assigned a value for the same attribute, what happens?

### Column filtering

If the required attributes match ***any*** of the user's group or user attribute values, then the user has access to the column.

For example, if a user is part of a group with the attribute value `kiwi`, another group with the attribute value `orange`, and they've also been assigned as a user to the attribute value `coconut`.

<Tabs>
  <Tab title="dbt v1.9 and earlier">
    ```yaml theme={null}
    columns:
      - name: tropical_fruits_column
        meta:
          dimension:
            required_attributes:
              fruits: 'coconut'
    ```
  </Tab>

  <Tab title="dbt v1.10+">
    ```yaml theme={null}
    columns:
      - name: tropical_fruits_column
        config:
          meta:
            dimension:
              required_attributes:
                fruits: 'coconut'
    ```
  </Tab>

  <Tab title="Lightdash YAML">
    ```yaml theme={null}
    type: model
    name: fruits

    dimensions:
      - name: tropical_fruits_column
        required_attributes:
          fruits: 'coconut'
    ```
  </Tab>
</Tabs>

In this example, the `tropical_fruits_column` will be visible to them because `coconut` is listed in their attribute values `['kiwi','orange', 'coconut']`.

### Row filtering

The template reference will be replaced by an array of the user's group or user attribute values.

Let's walk through an example:

<Tabs>
  <Tab title="dbt v1.9 and earlier">
    ```yaml theme={null}
    models:
      - name: my_model
        meta:
          sql_filter: ${TABLE}.fruit IN (${lightdash.attributes.fruit})
    ```
  </Tab>

  <Tab title="dbt v1.10+">
    ```yaml theme={null}
    models:
      - name: my_model
        config:
          meta:
            sql_filter: ${TABLE}.fruit IN (${lightdash.attributes.fruit})
    ```
  </Tab>

  <Tab title="Lightdash YAML">
    ```yaml theme={null}
    type: model
    name: my_model

    sql_filter: ${TABLE}.fruit IN (${lightdash.attributes.fruit})
    ```
  </Tab>
</Tabs>

In this example, the `${lightdash.attributes.fruit}` will be replaced with `'kiwi','orange','coconut'`. The final SQL will be `my_model.fruit IN ('kiwi','orange','coconut)`
