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

# Managing dashboards with GraphQL

> Create dashboards and widgets, copy dashboards across models, and duplicate or delete line chart, statistic, and text widgets with the Arize GraphQL API.

Arize AX dashboards put your custom metrics, token usage, latency, error rates, and eval trends on one page, built from template layouts or from individual widgets you add yourself. See [Set Up Dashboards](/docs/ax/observe/dashboards) for the concepts (templates, widget types, global filters) behind what these mutations automate: creating dashboards, adding line chart, bar chart, statistic, text, pivot table, and experiment chart widgets, and copying, duplicating, or deleting any of them.

This guide assumes you already know how to [form a GraphQL call](/docs/ax/graphql-reference/overview/how-to-use-graphql/forming-calls) with an `x-api-key` header against `https://app.arize.com/graphql`.

## Find the IDs you need

Every dashboard mutation takes a space ID (to create a dashboard) or a dashboard ID (everything else), and every widget mutation also takes a model ID. Start from `viewer` to find your space, then the space's `dashboards` and `models` connections. See [Using global node IDs](/docs/ax/graphql-reference/overview/how-to-use-graphql/using-global-node-ids) for how these opaque IDs work.

<CodeGroup>
  ```graphql Query theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  query FindSpaceDashboardsAndModels($spaceSearch: String, $dashboardSearch: String, $modelSearch: String) {
    viewer {
      spaces(search: $spaceSearch, first: 5) {
        edges {
          node {
            id
            name
            dashboards(search: $dashboardSearch, first: 5) {
              edges {
                node {
                  id
                  name
                  status
                }
              }
            }
            models(search: $modelSearch, first: 5) {
              edges {
                node {
                  id
                  name
                }
              }
            }
          }
        }
      }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "spaceSearch": "LLM_test",
    "dashboardSearch": "Overview",
    "modelSearch": "support-agent"
  }
  ```
</CodeGroup>

Once you have a dashboard or widget ID, fetch it directly with `node(id: "<ID>") { ... on Dashboard { ... } }` (or `... on LineChartWidget`, `... on StatisticWidget`, and so on).

## List dashboards and their widgets in a space

Each widget type lives on its own connection off `Dashboard` (`lineChartWidgets`, `statisticWidgets`, `textWidgets`, `barChartWidgets`, `pivotTableWidgets`, `experimentChartWidgets`), so pull whichever ones you care about alongside the dashboard itself.

<CodeGroup>
  ```graphql Query theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  query DashboardsInSpace($spaceId: ID!) {
    node(id: $spaceId) {
      ... on Space {
        dashboards(first: 20) {
          edges {
            node {
              id
              name
              status
              lineChartWidgets {
                edges {
                  node {
                    id
                    title
                  }
                }
              }
              statisticWidgets {
                edges {
                  node {
                    id
                    title
                  }
                }
              }
              textWidgets {
                edges {
                  node {
                    id
                    title
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "spaceId": "<SPACE_ID>"
  }
  ```
</CodeGroup>

Reference: [`node` and object graph](/docs/ax/graphql-reference/queries/object-graph).

## Create a dashboard

An empty dashboard just needs a name and a space. You add widgets to it afterward with the widget mutations below.

<CodeGroup>
  ```graphql Mutation theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation CreateDashboard($input: CreateDashboardMutationInput!) {
    createDashboard(input: $input) {
      dashboard {
        id
        name
        status
      }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "name": "Support Agent Overview",
      "spaceId": "<SPACE_ID>"
    }
  }
  ```
</CodeGroup>

To rename it later or take it offline, `updateDashboardName` and `updateDashboardStatus` take the same `dashboardId` plus a `name` or `status` string, and both can run as two fields in one mutation request since they're independent fields on `Mutation`.

Reference: [`createDashboard`](/docs/ax/graphql-reference/mutations/dashboards#createdashboard), [`updateDashboardName`](/docs/ax/graphql-reference/mutations/dashboards#updatedashboardname), [`updateDashboardStatus`](/docs/ax/graphql-reference/mutations/dashboards#updatedashboardstatus).

## Create a line chart widget with one or more plots

A line chart widget holds one or more plots, each scoped to its own model, environment, and metric. The widget-level `timeSeriesMetricType` picks whether the metrics come from model inference data (`modelDataMetric`) or LLM evaluation runs (`evaluationMetric`); each plot then picks its own `metric` (`accuracy`, `count`, and so on), `modelEnvironmentName`, and an optional `dimension` when the metric is scoped to one feature or tag instead of the whole model.

<CodeGroup>
  ```graphql Mutation theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation CreateLineChartWidget($input: CreateLineChartWidgetMutationInput!) {
    createLineChartWidget(input: $input) {
      lineChartWidget {
        id
        title
      }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "title": "Accuracy by environment",
      "dashboardId": "<DASHBOARD_ID>",
      "timeSeriesMetricType": "modelDataMetric",
      "plots": [
        {
          "modelId": "<MODEL_ID>",
          "modelVersionIds": [],
          "modelEnvironmentName": "production",
          "metric": "accuracy",
          "title": "Production",
          "position": 0,
          "filters": []
        },
        {
          "modelId": "<MODEL_ID>",
          "modelVersionIds": [],
          "modelEnvironmentName": "validation",
          "metric": "accuracy",
          "title": "Validation",
          "position": 1,
          "filters": []
        }
      ]
    }
  }
  ```
</CodeGroup>

`modelVersionIds` and `filters` are required on every plot but accept an empty array (no version or filter restriction). Leave `gridPosition` off and Arize places the widget in the next open slot.

Reference: [`createLineChartWidget`](/docs/ax/graphql-reference/mutations/dashboards#createlinechartwidget).

## Create a statistic widget

A statistic widget shows a single number. Point it at a model and supply exactly one metric source: `performanceMetric`, `aggregation` (a data quality metric), or a saved `customMetric`.

<CodeGroup>
  ```graphql Mutation theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation CreateStatisticWidget($input: CreateStatisticWidgetMutationInput!) {
    createStatisticWidget(input: $input) {
      statisticWidget {
        id
        title
      }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "dashboardId": "<DASHBOARD_ID>",
      "title": "Overall accuracy",
      "timeSeriesMetricType": "modelDataMetric",
      "modelId": "<MODEL_ID>",
      "performanceMetric": "accuracy"
    }
  }
  ```
</CodeGroup>

Add `dimension` and `dimensionCategory` to scope the number to one feature or tag instead of the whole model.

Reference: [`createStatisticWidget`](/docs/ax/graphql-reference/mutations/dashboards#createstatisticwidget).

## Create a text widget

Text widgets add headings or notes between other widgets. Unlike the chart and statistic widgets, `gridPosition` and `creationStatus` are both required here, not defaulted.

<CodeGroup>
  ```graphql Mutation theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation CreateTextWidget($input: CreateTextWidgetMutationInput!) {
    createTextWidget(input: $input) {
      textWidget {
        id
        title
      }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "title": "Notes",
      "content": "Investigate the latency spike from Oct 3.",
      "gridPosition": [0, 0, 4, 2],
      "creationStatus": "published",
      "dashboardId": "<DASHBOARD_ID>"
    }
  }
  ```
</CodeGroup>

Reference: [`createTextWidget`](/docs/ax/graphql-reference/mutations/dashboards#createtextwidget).

## Recreate a dashboard for another model

`copyDashboard` clones a dashboard and its widgets as-is, pointed at the same models, in the same space:

<CodeGroup>
  ```graphql Mutation theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation CopyDashboard($input: CopyDashboardMutationInput!) {
    copyDashboard(input: $input) {
      dashboard {
        id
        name
      }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "dashboardId": "<DASHBOARD_ID>"
    }
  }
  ```
</CodeGroup>

To rebuild the same layout against a *different* model, `copyDashboard` won't help since it has no model argument. Use `createDashboardFromTemplate` with the original template and the new model's ID instead:

<CodeGroup>
  ```graphql Mutation theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation CreateDashboardFromTemplate($input: CreateDashboardFromTemplateMutationInput!) {
    createDashboardFromTemplate(input: $input) {
      dashboard {
        id
        name
      }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "name": "Support Agent Overview (model B)",
      "modelId": "<NEW_MODEL_ID>",
      "template": "generativeLlmModelV2"
    }
  }
  ```
</CodeGroup>

Reference: [`copyDashboard`](/docs/ax/graphql-reference/mutations/dashboards#copydashboard), [`createDashboardFromTemplate`](/docs/ax/graphql-reference/mutations/dashboards#createdashboardfromtemplate).

## Duplicate a widget

`duplicateWidget` works on any widget type. You pass the source widget's ID and a new grid position and title; the mutation looks up the widget's type itself, so you don't specify it.

<CodeGroup>
  ```graphql Mutation theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation DuplicateWidget($input: DuplicateWidgetMutationInput!) {
    duplicateWidget(input: $input) {
      lineChartWidget {
        id
        title
      }
      statisticWidget {
        id
        title
      }
      textWidget {
        id
        title
      }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "widgetId": "<WIDGET_ID>",
      "dashboardId": "<DASHBOARD_ID>",
      "gridPosition": [0, 2, 4, 2],
      "title": "Accuracy by environment (copy)"
    }
  }
  ```
</CodeGroup>

The payload has one nullable field per widget type; select every type you might duplicate and read whichever one comes back non-null.

Reference: [`duplicateWidget`](/docs/ax/graphql-reference/mutations/dashboards#duplicatewidget).

## Delete a widget

Each widget type has its own delete mutation, and each one returns the parent `dashboard` rather than a bare success flag, which is convenient for refreshing a cached widget list in the same request.

<CodeGroup>
  ```graphql Mutation theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation DeleteLineChartWidget($input: DeleteLineChartWidgetMutationInput!) {
    deleteLineChartWidget(input: $input) {
      dashboard {
        id
      }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "lineChartWidgetId": "<WIDGET_ID>"
    }
  }
  ```
</CodeGroup>

The other widget types follow the same `<type>WidgetId` shape, with one exception: [`deleteStatisticWidget`](/docs/ax/graphql-reference/mutations/dashboards#deletestatisticwidget) takes `statWidgetId`, not `statisticWidgetId`. See [`deleteBarChartWidget`](/docs/ax/graphql-reference/mutations/dashboards#deletebarchartwidget), [`deleteTextWidget`](/docs/ax/graphql-reference/mutations/dashboards#deletetextwidget), [`deletePivotTableWidget`](/docs/ax/graphql-reference/mutations/dashboards#deletepivottablewidget), and [`deleteExperimentChartWidget`](/docs/ax/graphql-reference/mutations/dashboards#deleteexperimentchartwidget) for the rest.

## Gotchas and behavior notes

<AccordionGroup>
  <Accordion title="deleteStatisticWidget's argument is statWidgetId, not statisticWidgetId">
    Every other delete mutation follows `<type>WidgetId` (`lineChartWidgetId`, `barChartWidgetId`, `textWidgetId`, `pivotTableWidgetId`, `experimentChartWidgetId`). `deleteStatisticWidget` breaks the pattern with `statWidgetId`.
  </Accordion>

  <Accordion title="needsInit is a frontend-only creationStatus value">
    The schema documents `needsInit` as "a widget that does not exist in the backend yet (this value should only be seen on the frontend)." Send `pending`, `created`, or `published` from the API instead. `unpublished` is also internal: it's how the UI "deletes" a widget during an edit session by cloning and unpublishing the old one rather than mutating it.
  </Accordion>

  <Accordion title="updateDashboardStatus's status argument is a plain String">
    `Dashboard.status` returns the `DashboardStatusType` enum (`active`, `inactive`, `deleted`), but `UpdateDashboardStatusMutationInput.status` is typed as a plain `String!`, not that enum. The schema won't validate the value for you, so send exactly `"active"`, `"inactive"`, or `"deleted"`.
  </Accordion>

  <Accordion title="copyDashboard doesn't retarget the model">
    `CopyDashboardMutationInput` only takes `dashboardId`. To put an equivalent dashboard on a different model, use `createDashboardFromTemplate` with the same `template` value and the new model's ID, as shown above.
  </Accordion>

  <Accordion title="Plot-level lists are required but can be empty">
    `LineChartPlotInputInput.modelVersionIds` and `.filters` are non-null lists (`[ID!]!`, `[LineChartFilterItemInputInput!]!`), so you must include the key, but `[]` is a valid value meaning "all versions" and "no filter."
  </Accordion>

  <Accordion title="positiveClass and customMetric.requiresPositiveClass travel together">
    `positiveClass` on a plot or widget only applies when the prediction value type is categorical and the metric needs a positive class (several field descriptions say "if timeseriesMetricType = 'evaluationMetrics'", which doesn't match the actual enum value `evaluationMetric` (singular); treat it as a documentation typo, not a separate value). `CustomMetricInput.requiresPositiveClass` flags the same dependency for custom metric formulas.
  </Accordion>
</AccordionGroup>

<CardGroup cols={2}>
  <Card title="Dashboard mutations reference" icon="book" href="/docs/ax/graphql-reference/mutations/dashboards">
    Full arguments, return types and minimal examples for every dashboard and widget mutation.
  </Card>

  <Card title="All mutations" icon="list" href="/docs/ax/graphql-reference/mutations">
    Browse mutations for every other domain: monitors, datasets, prompts and more.
  </Card>

  <Card title="API explorer" icon="terminal" href="/docs/ax/graphql-reference/overview/api-explorer">
    Run queries and mutations interactively against your own space.
  </Card>
</CardGroup>
