> ## Documentation Index
> Fetch the complete documentation index at: https://docs.omni.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Creating level of detail (LOD) fields

> Aggregate at a fixed granularity that persists regardless of the dimensions in your query.

export const CheckIcon = ({label}) => {
  return <span>
      <Icon icon="circle-check" iconType="solid" color="#26bd6c" />
      {label && ` ${label}`}
    </span>;
};

export const XCircleIcon = ({label}) => {
  return <span>
      <Icon icon="circle-xmark" iconType="solid" color="#ff2465" />
      {label && ` ${label}`}
    </span>;
};

export const MarkdownVariablesIcon = ({label}) => {
  return <span>
      <svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg" style={{
    display: "inline",
    verticalAlign: "middle"
  }}><path d="M3 12v-7a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-7"></path><path d="M3 10h18"></path><path d="M10 3v10"></path><path d="M2 17a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1v-4z"></path></svg>
    </span>;
};

export const DashboardIcon = ({label}) => {
  return <span>
      <svg fill="none" height="1em" strokeWidth="2" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg" style={{
    display: "inline",
    verticalAlign: "middle"
  }}><path d="M12.5625 3V21M12 9.75H3M21 15.375H12.5625M7 21H17C19.2091 21 21 19.2091 21 17V7C21 4.79086 19.2091 3 17 3H7C4.79086 3 3 4.79086 3 7V17C3 19.2091 4.79086 21 7 21Z" stroke="currentColor"></path></svg>
      {label && ` ${label}`}
    </span>;
};

export const WorkbookIcon = ({label}) => {
  return <span>
      <svg fill="none" height="1em" stroke-width="2" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg" style={{
    display: "inline",
    verticalAlign: "middle"
  }}><path d="M9.1875 3V15.375M21 15.375H3M7 21H17C19.2091 21 21 19.2091 21 17V7C21 4.79086 19.2091 3 17 3H7C4.79086 3 3 4.79086 3 7V17C3 19.2091 4.79086 21 7 21Z" stroke="currentColor"></path></svg>
      {label && ` ${label}`}
    </span>;
};

export const WorkbookNumberFormatIcon = ({label}) => {
  return <span>
      <svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 30 30" stroke-linecap="round" stroke-linejoin="round" height="1.75em" width="1.75em" xmlns="http://www.w3.org/2000/svg" style={{
    display: "inline",
    verticalAlign: "middle"
  }}><path d="M8 10v-7l-2 2"></path><path d="M6 16a2 2 0 1 1 4 0c0 .591 -.601 1.46 -1 2l-3 3h4"></path><path d="M15 14a2 2 0 1 0 2 -2a2 2 0 1 0 -2 -2"></path><path d="M6.5 10h3"></path></svg>
    </span>;
};

export const DashboardPreviewIcon = ({label}) => {
  return <span>
      <svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg" style={{
    display: "inline",
    verticalAlign: "middle"
  }}><path d="M3 16m0 1a1 1 0 0 1 1 -1h3a1 1 0 0 1 1 1v3a1 1 0 0 1 -1 1h-3a1 1 0 0 1 -1 -1z"></path><path d="M4 12v-6a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-6"></path><path d="M12 8h4v4"></path><path d="M16 8l-5 5"></path></svg>
    </span>;
};

export const DashboardCatalogIcon = ({label}) => {
  return <span>
      <svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg" style={{
    display: "inline",
    verticalAlign: "middle"
  }}><path d="M10 19h-6a1 1 0 0 1 -1 -1v-14a1 1 0 0 1 1 -1h6a2 2 0 0 1 2 2a2 2 0 0 1 2 -2h6a1 1 0 0 1 1 1v14a1 1 0 0 1 -1 1h-6a2 2 0 0 0 -2 2a2 2 0 0 0 -2 -2z"></path><path d="M12 5v16"></path><path d="M7 7h1"></path><path d="M7 11h1"></path><path d="M16 7h1"></path><path d="M16 11h1"></path><path d="M16 15h1"></path></svg>
      {label && ` ${label}`}
    </span>;
};

export const DashboardAddItemIcon = ({label}) => {
  return <span>
      <svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg" style={{
    display: "inline",
    verticalAlign: "middle"
  }}><path d="M4 4m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z"></path><path d="M4 14m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z"></path><path d="M14 14m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z"></path><path d="M14 7l6 0"></path><path d="M17 4l0 6"></path></svg>
      {label && ` ${label}`}
    </span>;
};

export const DashboardControlIcon = ({label}) => {
  return <span>
      <svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg" style={{
    display: "inline",
    verticalAlign: "middle"
  }}><path d="M3 3m0 3a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v12a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3z"></path><path d="M3 11l8 -8"></path><path d="M3 17l14 -14"></path></svg>
      {label && ` ${label}`}
    </span>;
};

export const DashboardChartIcon = ({label}) => {
  return <span>
      <svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg" style={{
    display: "inline",
    verticalAlign: "middle"
  }}><path d="M3 3v18h18"></path><path d="M20 18v3"></path><path d="M16 16v5"></path><path d="M12 13v8"></path><path d="M8 16v5"></path><path d="M3 11c6 0 5 -5 9 -5s3 5 9 5"></path></svg>
      {label && ` ${label}`}
    </span>;
};

export const DashboardPlaceholderIcon = ({label}) => {
  return <span>
      <svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg" style={{
    display: "inline",
    verticalAlign: "middle"
  }}><path d="M4 4m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z"></path><path d="M14 4m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z"></path><path d="M4 14m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z"></path><path d="M14 17h6m-3 -3v6"></path></svg>
      {label && ` ${label}`}
    </span>;
};

export const DashboardLayoutIcon = ({label}) => {
  return <span>
      <svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg" style={{
    display: "inline",
    verticalAlign: "middle"
  }}><path d="M4 7l16 0"></path><path d="M4 17l16 0"></path><path d="M7 4l0 16"></path><path d="M17 4l0 16"></path></svg>
      {label && ` ${label}`}
    </span>;
};

export const DashboardTextIcon = ({label}) => {
  return <span>
      <svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg" style={{
    display: "inline",
    verticalAlign: "middle"
  }}><path d="M4 20l3 0"></path><path d="M14 20l7 0"></path><path d="M6.9 15l6.9 0"></path><path d="M10.2 6.3l5.8 13.7"></path><path d="M5 20l6 -16l2 0l7 16"></path></svg>
      {label && ` ${label}`}
    </span>;
};

export const DashboardStackContainerIcon = ({label}) => {
  return <span>
      <svg width="1em" height="1em" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style={{
    display: "inline",
    verticalAlign: "middle"
  }}><path d="M4 5C4 4.73478 4.10536 4.48043 4.29289 4.29289C4.48043 4.10536 4.73478 4 5 4H19C19.2652 4 19.5196 4.10536 19.7071 4.29289C19.8946 4.48043 20 4.73478 20 5V9C20 9.26522 19.8946 9.51957 19.7071 9.70711C19.5196 9.89464 19.2652 10 19 10H5C4.73478 10 4.48043 9.89464 4.29289 9.70711C4.10536 9.51957 4 9.26522 4 9V5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path><path d="M4 15C4 14.7348 4.10536 14.4804 4.29289 14.2929C4.48043 14.1054 4.73478 14 5 14H12C12.2652 14 12.5196 14.1054 12.7071 14.2929C12.8946 14.4804 13 14.7348 13 15V19C13 19.2652 12.8946 19.5196 12.7071 19.7071C12.5196 19.8946 12.2652 20 12 20H5C4.73478 20 4.48043 19.8946 4.29289 19.7071C4.10536 19.5196 4 19.2652 4 19V15Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg>
      {label && ` ${label}`}
    </span>;
};

export const DashboardPageNavIcon = ({label}) => {
  return <span>
      <svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg" style={{
    display: "inline",
    verticalAlign: "middle"
  }}><path d="M4 8h16"></path><path d="M4 4m0 2a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2z"></path><path d="M8 4v4"></path></svg>
      {label && ` ${label}`}
    </span>;
};

export const IdeFileIcon = ({color = "#000000"}) => {
  return <span>
      <svg stroke={color} fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="file-type-icon" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg" style={{
    display: "inline",
    verticalAlign: "middle"
  }}><path d="M3 5a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-14z"></path><path d="M3 10h18"></path><path d="M10 3v18"></path></svg>
    </span>;
};

A level of detail (LOD) field calculates an aggregation at a granularity you specify, independent of the dimensions in the query. Use them when you need a value like "lifetime spend per customer" or "first order date" to stay attached to every row, even as you add or remove other dimensions.

## LOD basics

<AccordionGroup>
  <Accordion title="What's an LOD field?">
    In a standard query, an aggregation is computed at the granularity of whatever dimensions are in the `GROUP BY` clause. Add a dimension and the aggregation regroups; remove one and it regroups again.

    An LOD field opts out of that behavior. You define the granularity once — for example, "per user" or "across the whole dataset" — and the value persists regardless of the dimensions in the query.
  </Accordion>

  <Accordion title="Can you explain an LOD using SQL?">
    LODs can be mapped directly to a SQL equivalent.

    Consider the following example, a `max_age_in_country` LOD dimension that finds maximum user age within each country and attaches it to every user row.

    ```sql SQL theme={null}
    SELECT
      users.country AS "country",
      users.id AS "id",
      lod.max_age AS "max_age_in_country"
    FROM users
    INNER JOIN (
        SELECT country,
              MAX(age) AS max_age
          FROM users
      GROUP BY country
    ) lod ON users.country = lod.country
    ```

    The Omni definition for this LOD dimension would look like the following:

    ```yaml Omni model YAML theme={null}
    dimensions:
      max_age_in_country:
        sql: ${users.age}
        level_of_detail:
          aggregate_type: max
          fixed: [country]
    ```

    The `fixed: [country]` clause corresponds to the `GROUP BY country` in the inner query — one row per country, the level of detail. The join then carries that country-level value back to each user row, which is why the LOD behaves like a categorical dimension: every user in the same country shares the same `max_age_in_country` value.
  </Accordion>

  <Accordion title="Why are LOD fields useful?">
    LOD fields are useful any time you need a metric at a different grain than the rest of your analysis, for example:

    * A customer-level total used while breaking out by product category
    * A first-touch date used while analyzing activity over time
    * A grand total used while showing per-region values
  </Accordion>

  <Accordion title="Can LODs be created as dimensions?">
    Yes. When used as a dimension, an LoD produces a categorical value — one row per level of detail — which lets you perform an additional layer of aggregation (e.g., average customer lifetime spend).
  </Accordion>

  <Accordion title="Can LODs be created as measures?">
    Yes. When used as a measure, an LoD produces an aggregation of an aggregation, such as an average of averages or a percent of total.
  </Accordion>
</AccordionGroup>

## Requirements

To create an LOD field, you'll need **Querier**, **Modeler**, or **Connection Admin** permissions.

## Creating a level of detail field

You can create an LOD field directly from the field browser in a workbook or in the model IDE.

<AccordionGroup>
  <Accordion title="In the workbook" icon="book">
    <Steps>
      <Step title="Open the level of detail editor" noAnchor>
        1. In the field browser of a query tab, hover over a dimension and click the <Icon icon="ellipsis-vertical" type="solid" /> icon that appears.
        2. Select **Modeling > New level of detail field**.
        3. Enter a display name for the field in the **Field Label** field.
      </Step>

      <Step title="Set the aggregation" noAnchor>
        Use the **Aggregation** dropdown to choose an aggregate type, such as `Count distinct`.
      </Step>

      <Step title="Choose a grouping strategy" noAnchor>
        Use the **Level of Detail Grouping** and **Dimension(s)** fields to pick a strategy and the dimensions that define your level of detail. See [Grouping strategies](#grouping-strategies) below for more information.
      </Step>

      <Step title="Define optional fields" noAnchor>
        You can also add filters, define the field's scope, and add a  description and group label.
      </Step>

      <Step title="Save the field" noAnchor>
        Click **Add** to save the field. It appears in the field browser under your custom dimensions and behaves like any other field.
      </Step>
    </Steps>
  </Accordion>

  <Accordion title="In the IDE" icon="code">
    You can create LOD measures and dimensions in the model IDE with the `level_of_detail` parameter. For example:

    ```yaml LOD dimension definition theme={null}
    dimensions:
      max_age_in_country:
        sql: ${users.age}
        level_of_detail:
          aggregate_type: max
          fixed: [country]
    ```

    See the `level_of_detail` parameter references for [measures](/modeling/measures/parameters/level-of-detail) and [dimensions](/modeling/dimensions/parameters/level-of-detail) for the full list of supported parameters.
  </Accordion>
</AccordionGroup>

<Note>
  [Promote the LOD field to the shared model](/modeling/develop/promotion) to make it accessible in new and existing workbooks built on the model.
</Note>

## Grouping strategies

Three strategies control how the LOD field interacts with the dimensions in your query:

| Strategy    | What it does                                                                             | Use it when...                                                                                                                              |
| ----------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| **Fixed**   | Aggregates at the exact dimensions you list. Ignores every other dimension in the query. | You want the LOD value to stay constant no matter what's in the query, such as a customer's lifetime spend when you add a product dimension |
| **Include** | Aggregates at the dimensions in the query, plus the dimensions you specify.              | You want the LOD to follow the query but force additional dimensions into the grouping                                                      |
| **Exclude** | Aggregates at the dimensions in the query, minus the dimensions you specify.             | You want a "total" that ignores a specific dimension, such as a grand total that ignores region and is used to compute percent of total     |

## Common patterns

A few LOD patterns come up often enough that they're worth recognizing on sight. Each example below shows the same field built two ways — the workbook editor inputs and the equivalent YAML in the model IDE — so you can pick whichever surface you're working in.

<Tip>
  See the `level_of_detail` parameter references for [measures](/modeling/measures/parameters/level-of-detail) and [dimensions](/modeling/dimensions/parameters/level-of-detail) for additional examples.
</Tip>

### Customer lifetime spend

Calculate the total spend per customer so you can bucket customers (`$0–100`, `$100–500`, etc.) even while viewing orders by product category.

<Tabs>
  <Tab title="Workbook">
    The fields in the LOD editor would look like the following:

    * **Field to aggregate** - `Sale price`
    * **Aggregation** - `Sum`
    * **Level of Detail Grouping** - `Fixed`
    * **Fixed dimension(s)** - `User ID`
  </Tab>

  <Tab title="Omni YAML">
    The YAML definition of the LOD would look like the following:

    ```yaml theme={null}
    customer_lifetime_spend:
      sql: ${sale_price}
      level_of_detail:
        aggregate_type: sum
        fixed: [user_id]
    ```
  </Tab>
</Tabs>

### First-touch cohort date

Find each user's first order date so you can group users into acquisition cohorts.

<Tabs>
  <Tab title="Workbook">
    The fields in the LOD editor would look like the following:

    * **Field to aggregate** - `Order date`
    * **Aggregation** - `Min`
    * **Level of Detail Grouping** - `Fixed`
    * **Fixed dimension(s)** - `User ID`
  </Tab>

  <Tab title="Omni YAML">
    The YAML definition of the LOD would look like the following:

    ```yaml theme={null}
    first_order_date:
      sql: ${order_date}
      level_of_detail:
        aggregate_type: min
        fixed: [user_id]
    ```
  </Tab>
</Tabs>

For a full walkthrough of building cohorts on top of an LOD field, see [Build cohort analysis using level of detail](/guides/patterns/build-cohort-analysis-using-level-of-detail).

### Percent of total

Calculate the grand total of a metric so you can compare each row's value to the total — for example, what percentage of total sales each region represents. The result is the company-wide total attached to every row, ready to divide against.

<Tabs>
  <Tab title="Workbook">
    The fields in the LOD editor would look like the following:

    * **Field to aggregate** - `Sales`
    * **Aggregation** - `Sum`
    * **Level of Detail Grouping** - `Exclude`
    * **Fixed dimension(s)** - `Region`
  </Tab>

  <Tab title="Omni YAML">
    The YAML definition of the LOD would look like the following:

    ```yaml theme={null}
    total_sales_excluding_region:
      sql: ${sales}
      level_of_detail:
        aggregate_type: sum
        always_exclude: [region]
    ```
  </Tab>
</Tabs>

## Next steps

* [Build cohort analysis using level of detail](/guides/patterns/build-cohort-analysis-using-level-of-detail)
* [LOD fields vs. window functions vs. CTEs vs. Excel](/guides/patterns/level-of-detail-build-comparison)
* [`level_of_detail` parameter reference](/modeling/dimensions/parameters/level-of-detail)
* [Filtered measures](/analyze-explore/custom-fields/filtered-measures)
