User attributes
Customize what charts and dashboards show based on attributes of the logged-in user
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:
- Define the user attribute, users can only have user attributes that are explicitly created by admins
- Set the user attribute value per user.
User attributes can only be managed by admins.
Managing user attributes
Creating user attributes
User attributes can be created by navigating to Organization Settings > User Attributes and clicking on theAdd 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 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.
Each user, group, and default supports multiple values. When you reference the attribute in SQL or required_attributes / any_attributes, Qyra treats all assigned values as a set — see How user and group attribute values interact.
Self-hosted Enterprise instances can declare user attributes and group-value mappings as instance config with the LD_SETUP_USER_ATTRIBUTES environment variable, so they're reconciled on every deploy.
Setting a default value for your user attribute
You can add one or more default values that will be applied to all users who don't have their own value defined in this user attribute.

If a user has an attribute defined, we will ignore the default for that user.
Using user attributes in Qyra
There are several places in Qyra 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 levelrequired_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
User attributes cannot currently be referenced insidesql: tags within the model YAML files.
When referencing user attributes in SQL you can use the following SQL variables:
${qyra.attributes.my_attr_1}- a user attribute calledmy_attr_1- (optional)
ldas an alias forqyra - (optional)
attributeorattras an alias forattributes
- (optional)
${"{"{"}"}qyra.user.<intrinsic_attribute>{"}"}- reference anintrinsic_attributeof the current Qyra user- (optional)
ldas an alias forqyra - available intrinsic user attributes:
email
- (optional)
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:

models:
- name: example
meta:
sql_filter: ${qyra.user.email} = 'example@qyraflow.com'models:
- name: example
config:
meta:
sql_filter: ${qyra.user.email} = 'example@qyraflow.com'type: model
name: example
sql_filter: ${qyra.user.email} = 'example@qyraflow.com'If you are self hosting you can enable SMTP or SSO authentication to allow users to verify their email address.
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:
${qyra.user.email}- The logged-in user's email address${"{"{"}"}qyra.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 ${qyra.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.
If a referenced attribute is not set for the current user, the query returns a Forbidden error.

Similarly, you can use custom attributes like ${qyra.attribute.country} to filter data based on a user's assigned region or department.
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 in your dbt model — that runs on the warehouse and cannot be bypassed from the UI.
Row filtering with sql_filter
Row-level security (RLS) in Qyra 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 qyra reference${"{"{"}"}qyra.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:
models:
- name: my_model
config:
meta:
sql_filter: ${TABLE}.sales_region IN (${qyra.attributes.sales_region})models:
- name: my_model
meta:
sql_filter: ${TABLE}.sales_region IN (${qyra.attributes.sales_region})type: model
name: my_model
sql_filter: ${TABLE}.sales_region IN (${qyra.attributes.sales_region})Column filtering with required_attributes
You can use user attributes to limit some dimensions to some users.
Users without access to this dimension will not see it, as well as the metrics derived from it. .
In the example below, only users with is_admin attribute true can use the salary dimension on user table.
columns:
- name: user
description: User name
- name: salary
description: User salary
config:
meta:
dimension:
required_attributes:
is_admin: "true"columns:
- name: user
description: User name
- name: salary
description: User salary
meta:
dimension:
required_attributes:
is_admin: "true"type: model
name: users
dimensions:
- name: user
description: User name
- name: salary
description: User salary
required_attributes:
is_admin: "true"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:
Multiple attributes joined with AND.In the example below, only users withis_admin: "true" AND team_name: "HR"have access to thesalarydimension in Qyra.
columns:
- name: user
description: User name
- name: salary
description: User salary
config:
meta:
dimension:
required_attributes:
is_admin: 'true'
team_name: 'HR'columns:
- name: user
description: User name
- name: salary
description: User salary
meta:
dimension:
required_attributes:
is_admin: 'true'
team_name: 'HR'type: model
name: users
dimensions:
- name: user
description: User name
- name: salary
description: User salary
required_attributes:
is_admin: 'true'
team_name: 'HR'Multiple attribute values joined with OR.In the example below, users withteam_name = 'HR' OR team_name = 'C-Suite'have access to thesalarydimension in Qyra.
columns:
- name: user
description: User name
- name: salary
description: User salary
config:
meta:
dimension:
required_attributes:
team_name: ['HR', 'C-Suite']columns:
- name: user
description: User name
- name: salary
description: User salary
meta:
dimension:
required_attributes:
team_name: ['HR', 'C-Suite']type: model
name: users
dimensions:
- name: user
description: User name
- name: salary
description: User salary
required_attributes:
team_name: ['HR', 'C-Suite']Column filtering using required_attributes does not take into account intrinsic attributes of a user - email.
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.
columns:
- name: revenue
description: Total revenue
config:
meta:
dimension:
any_attributes:
department: ["sales", "finance"]
role: "analyst"columns:
- name: revenue
description: Total revenue
meta:
dimension:
any_attributes:
department: ["sales", "finance"]
role: "analyst"type: model
name: orders
dimensions:
- name: revenue
description: Total revenue
any_attributes:
department: ["sales", "finance"]
role: "analyst"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:
- All conditions in
required_attributesmust match (AND) - At least one condition in
any_attributesmust match (OR)
In the example below, a user must have access_level = "2" AND (department = "sales" OR department = "finance").
columns:
- name: revenue
description: Total revenue
config:
meta:
dimension:
required_attributes:
access_level: "2"
any_attributes:
department: ["sales", "finance"]columns:
- name: revenue
description: Total revenue
meta:
dimension:
required_attributes:
access_level: "2"
any_attributes:
department: ["sales", "finance"]type: model
name: orders
dimensions:
- name: revenue
description: Total revenue
required_attributes:
access_level: "2"
any_attributes:
department: ["sales", "finance"]Column filtering using any_attributes does not take into account intrinsic attributes of a user - email.
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.
models:
- name: payments
config:
meta:
required_attributes:
is_admin: "true"models:
- name: payments
meta:
required_attributes:
is_admin: "true"type: model
name: payments
required_attributes:
is_admin: "true"Similar to columns filtering, you can add multiple attributes for a single table.
Table filtering using required_attributes does not take into account intrinsic attributes of a user - email.
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.
models:
- name: payments
config:
meta:
any_attributes:
department: ["sales", "finance"]
role: "analyst"models:
- name: payments
meta:
any_attributes:
department: ["sales", "finance"]
role: "analyst"type: model
name: payments
any_attributes:
department: ["sales", "finance"]
role: "analyst"You can combine required_attributes and any_attributes on the same table. Both checks must pass — see combining required and any attributes for details.
Table filtering using any_attributes does not take into account intrinsic attributes of a user - email.
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 qyra reference${"{"{"}"} qyra.attributes.<attribute_name> {"}"}. For example, if you have a user attribute called sales_region you can use it in your sql like this:
models:
- name: base
config:
meta:
joins:
- join: joined
sql_on: >
${base}.id = ${joined}.id
AND ${joined}.sales_region = ${qyra.attributes.sales_region}models:
- name: base
meta:
joins:
- join: joined
sql_on: >
${base}.id = ${joined}.id
AND ${joined}.sales_region = ${qyra.attributes.sales_region}type: model
name: base
joins:
- join: joined
sql_on: >
${base}.id = ${joined}.id
AND ${joined}.sales_region = ${qyra.attributes.sales_region}Current limitations
Qyra 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
Scheduler deliveries will run against the user who created the scheduled delivery, be careful when sharing required attributes with other users.
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.
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.
columns:
- name: tropical_fruits_column
config:
meta:
dimension:
required_attributes:
fruits: 'coconut'columns:
- name: tropical_fruits_column
meta:
dimension:
required_attributes:
fruits: 'coconut'type: model
name: fruits
dimensions:
- name: tropical_fruits_column
required_attributes:
fruits: 'coconut'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:
models:
- name: my_model
config:
meta:
sql_filter: ${TABLE}.fruit IN (${qyra.attributes.fruit})models:
- name: my_model
meta:
sql_filter: ${TABLE}.fruit IN (${qyra.attributes.fruit})type: model
name: my_model
sql_filter: ${TABLE}.fruit IN (${qyra.attributes.fruit})In this example, the ${qyra.attributes.fruit} will be replaced with 'kiwi','orange','coconut'. The final SQL will be my_model.fruit IN ('kiwi','orange','coconut)