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

# Data access control

> Understand how AI agents access and use your data

AI agents offer flexible data access control to balance insights with privacy and security. By default, agents work with metadata only, but you can optionally enable data access for deeper analysis.

## Data access modes

**Metadata-only mode (default):**

* Agents can see your data structure, field names, and model definitions
* They can generate appropriate queries and visualizations
* No actual data values (except for one-row query results) are shared with the agent
* Perfect for exploring data structure and creating initial analyses

**Data access enabled:**

* Agents receive actual query results in addition to metadata
* Can provide specific insights, identify trends, and analyze patterns in your data
* Offers detailed summaries and data-driven recommendations
* Can search for actual field values to ensure accurate filters when building visualizations
* Only shares data when explicitly enabled per agent

<Info>
  Data access is optional and controlled per agent. When disabled, agents only
  work with your data model structure and cannot see actual data values. This
  ensures sensitive information is only shared when you explicitly choose to
  enable this capability.
</Info>

To enable data access, go to your agent settings and toggle the "Data Access" option.

<Frame>
  <img src="https://mintcdn.com/lightdash-mintlify-ca973f84/cHghj5I2wtqMZ-ik/images/guides/ai-agents/enable-data-access.png?fit=max&auto=format&n=cHghj5I2wtqMZ-ik&q=85&s=fb1d7da6fddf79cdc62da20279be695c" alt="How to enable data access for AI agents" width="2100" height="1584" data-path="images/guides/ai-agents/enable-data-access.png" />
</Frame>

## Limiting access to specific explores and fields

You can control which explores and fields your AI agent can access using tags. When you configure tags in your agent settings, the agent will only see explores and fields that have matching tags.

**Two tagging options:**

* **dbt tags** - Native dbt tags applied at the model level (using the `tags` property or `config.tags`). These control explore-level access
* **Lightdash metadata tags** - Tags defined in the Lightdash `meta` section, applied at the column level (individual metrics and dimensions). These control field-level access

**How tag matching works:**

* Add one or more tags to your agent settings
* Fields or explores with **any** of those tags will be accessible to the agent
* If no tags are configured, the agent can access everything
* As you add tags, you can interactively explore which explores and fields will be available in the agent settings interface

<Frame caption="Preview available explores and fields as you add tags">
  <img src="https://mintcdn.com/lightdash-mintlify-ca973f84/cHghj5I2wtqMZ-ik/images/guides/ai-agents/agent-tags-preview.gif?s=e4b1922b7676a94f45db6a0a3fad6474" alt="Interactive preview of explores and fields filtered by tags in agent settings" width="800" height="728" data-path="images/guides/ai-agents/agent-tags-preview.gif" />
</Frame>

**Two levels of tagging:**

1. **Explore-level tags** - Tag the model to control access to entire explores
2. **Field-level tags** - Tag individual metrics and dimensions for granular control

Watch this demo to see tag-based access control in action:

<Frame>
  <iframe width="100%" height="420" src="https://www.loom.com/embed/f38e27fee7784e7f95538613b3b77bb5?sid=a13feb5b-fef3-4f68-9fbf-e54f928c28e5" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen />
</Frame>

### How filtering works

The filtering behavior depends on how you've tagged your models:

**Explore visibility:**

* An explore is only visible if its **base table** has matching tags at either:
  * Explore level (model tags match agent tags), OR
  * Field level (at least one base table field has matching tags)
* If only joined tables have matching tags but the base table doesn't, the explore will be hidden

**Field visibility per table:**

Each table in an explore is filtered independently using one of two modes:

1. **Field-level mode** (when ANY field in the table has tags defined):
   * Only fields with matching tags are visible
   * Other fields are hidden, even if the explore is tagged
   * Note: An empty tags array (`tags: []`) activates field-level mode but matches nothing

2. **Explore-level mode** (when NO fields in the table have tags):
   * If explore tags match: ALL fields in the table are visible
   * If explore tags don't match: NO fields are visible

### Adding tags at the model level

Tag entire models to give your AI agent access to all metrics and dimensions within that explore:

<Accordion title="View code examples">
  <CodeGroup>
    ```yaml dbt 1.10+ theme={null}
    models:
      - name: marketing_campaigns
        config:
          tags: ["marketing", "ai"] #    <--------- dbt native tags (explore-level)
        columns:
          - name: campaign_name
            config:
              meta:
                dimension:
                  type: string
          - name: impressions
            config:
              meta:
                metrics:
                  total_impressions:
                    type: sum
    ```

    ```yaml dbt <=1.9 theme={null}
    models:
      - name: marketing_campaigns
        tags: ["marketing", "ai"] #    <--------- dbt native tags (explore-level)
        columns:
          - name: campaign_name
            meta:
              dimension:
                type: string
          - name: impressions
            meta:
              metrics:
                total_impressions:
                  type: sum
    ```
  </CodeGroup>
</Accordion>

### Adding tags to individual metrics & dimensions

For more granular control, tag specific metrics and dimensions:

<Accordion title="View code examples">
  <CodeGroup>
    ```yaml dbt 1.10+ theme={null}
    models:
      - name: orders
        columns:
          - name: status
            config:
              meta:
                dimension:
                  tags: ["ai", "sales"] # <--------- tagging the dimension
          - name: location
            config:
              meta:
                dimension:
                  tags: ["ai", "operations"] # <--------- tagging the dimension
          - name: amount
            description: Total amount of the order
            config:
              meta:
                metrics:
                  total_order_amount:
                    type: sum
                    format: usd
                    round: 2
                    tags: ["ai", "finance"] # <--------- tagging the metric
    ```

    ```yaml dbt <=1.9 theme={null}
    - name: orders
      columns:
        - name: status
          meta:
            dimension:
              tags: ['ai', 'sales'] #    <--------- tagging the dimension
         - name: location
          meta:
            dimension:
              tags: ['ai', 'operations'] #    <--------- tagging the dimension
        - name: amount
          description: Total amount of the order
          meta:
            metrics:
              total_order_amount:
                type: sum
                format: usd
                round: 2
                tags: ['ai', 'finance'] #    <--------- tagging the metric
    ```
  </CodeGroup>
</Accordion>

### Common scenarios

Here are some common tagging scenarios and their results:

**Scenario 1: Explore-level only (no field tags)**

```yaml theme={null}
models:
  - name: customers
    config:
      tags: ["ai-enabled"]
    columns:
      - name: customer_name
      - name: email
```

Result: If agent has `["ai-enabled"]` tag, ALL fields in the customers explore are visible.

**Scenario 2: Field-level only (no explore tags)**

```yaml theme={null}
models:
  - name: customers
    columns:
      - name: customer_name
        config:
          meta:
            dimension:
              tags: ["ai-enabled"]
      - name: email
        config:
          meta:
            dimension:
              tags: ["pii"]
```

Result: If agent has `["ai-enabled"]` tag, only `customer_name` is visible. The `email` field is hidden.

**Scenario 3: Mixed - explore tagged with fields that have different tags**

```yaml theme={null}
models:
  - name: orders
    config:
      tags: ["ai-enabled"]
    columns:
      - name: order_id
        config:
          meta:
            dimension:
              tags: ["pii"]
      - name: status
        config:
          meta:
            dimension:
              tags: ["internal"]
```

Result: If agent has `["ai-enabled"]` tag, NO fields are visible. Field-level mode is active (because fields have tags), and none of the field tags match "ai-enabled".

**Scenario 4: Mixed mode - base model with explore tags, joined model with field tags**

<Tabs>
  <Tab title="orders.yml (base model)">
    ```yaml theme={null}
    models:
      - name: orders
        config:
          tags: ["ai-enabled"]
          meta:
            joins:
              - join: customers
                sql_on: ${customers.customer_id} = ${orders.customer_id}
        columns:
          - name: order_id
          - name: status
          - name: customer_id
    ```
  </Tab>

  <Tab title="customers.yml (joined model)">
    ```yaml theme={null}
    models:
      - name: customers
        columns:
          - name: customer_id
          - name: email
            config:
              meta:
                dimension:
                  tags: ["ai-enabled"]
          - name: phone
            config:
              meta:
                dimension:
                  tags: ["pii"]
    ```
  </Tab>
</Tabs>

Result: If agent has `["ai-enabled"]` tag:

* `orders` table: ALL fields visible (explore-level mode - no field tags defined)
* `customers` table: Only `email` visible (field-level mode - has field tags, only `email` matches)

**Scenario 5: Only joined table has matching tags**

<Tabs>
  <Tab title="orders.yml (base model)">
    ```yaml theme={null}
    models:
      - name: orders
        config:
          meta:
            joins:
              - join: customers
                sql_on: ${customers.customer_id} = ${orders.customer_id}
        columns:
          - name: order_id # no tags
          - name: status # no tags
    ```
  </Tab>

  <Tab title="customers.yml (joined model)">
    ```yaml theme={null}
    models:
      - name: customers
        columns:
          - name: email
            config:
              meta:
                dimension:
                  tags: ["ai-enabled"]
    ```
  </Tab>
</Tabs>

Result: The entire explore is HIDDEN because the base table (`orders`) has no matching tags.

<Warning>
  An explore is only visible if the **base table** has matching tags (either at explore level or field level). Having matching tags only in joined tables is not enough.
</Warning>

## User attributes and permissions

AI agents automatically respect all data access controls configured through [user attributes](/references/workspace/user-attributes). This ensures that agents only access data that the user is authorized to see, maintaining your existing security policies.

### How user attributes flow through AI queries

When an AI agent generates and executes queries on behalf of a user, it inherits that user's attribute values and applies them to all data access:

**Row-level security:**

* Agents automatically apply `sql_filter` rules defined in your models
* Only rows matching the user's attribute values are included in query results
* Example: If a user has `sales_region: 'EMEA'`, the agent will only query data for that region

**Column-level security:**

* Agents respect `required_attributes` on dimensions
* Columns the user cannot access are invisible to the agent
* Metrics derived from restricted columns are also unavailable
* Example: If `salary` requires `is_admin: 'true'`, non-admin users' agents cannot query salary data

**Table-level security:**

* Agents respect `required_attributes` on models
* Tables the user cannot access are completely hidden from the agent
* The agent cannot reference or join restricted tables
* Example: If `payments` requires `is_admin: 'true'`, non-admin users' agents cannot query the payments table

### Default behavior

<Info>
  **In the Lightdash app:** AI agents automatically use the logged-in user's attributes for all queries.

  **In Slack:** By default, AI agents use the attributes of the user who created the agent. To have each Slack user's individual permissions respected, enable the **AI Agents OAuth requirement** toggle in your [Lightdash Slack settings](/references/integrations/slack-integration#ai-agents-configuration). When enabled, each Slack user must OAuth into Lightdash before using the agent, and their individual permissions are applied to all queries.
</Info>

### How this works behind the scenes

When an agent generates a query:

1. The agent receives the user's complete attribute profile (both direct user attributes and group attributes)
2. All `sql_filter` rules are automatically applied to the generated SQL
3. Dimensions and tables with `required_attributes` are filtered from the available schema
4. The agent only sees and can query data within the user's permissions

This happens transparently—the agent doesn't need special configuration. Your existing user attribute rules automatically protect AI-generated queries just like they protect manual queries.

### Example: Regional sales access

Consider this model configuration:

```yaml theme={null}
models:
  - name: sales
    meta:
      sql_filter: ${TABLE}.region IN (${lightdash.attributes.sales_region})
    columns:
      - name: revenue
      - name: customer_name
        meta:
          dimension:
            required_attributes:
              can_view_pii: "true"
```

For a user with `sales_region: 'EMEA'` and no `can_view_pii` attribute:

* The agent can query `revenue` data, but only for EMEA region
* The agent cannot see or query `customer_name` (PII restriction)
* If the agent tries to analyze customer names, it will fail with a permissions error
* All generated queries automatically include `WHERE region IN ('EMEA')`

### Security considerations

* **Metadata mode:** Even in metadata-only mode, agents respect user attributes when showing available fields
* **Data access mode:** When data access is enabled, query results are filtered by user attributes
* **Query generation:** Agents cannot generate queries that bypass user attribute restrictions
* **Error handling:** If an agent attempts to access restricted data, the query fails with a permissions error

<Warning>
  Custom SQL in table calculations or SQL Runner can potentially bypass user attribute filters. AI agents use the standard query interface and cannot bypass these restrictions.
</Warning>
