---
title: Create custom widgets for streaming dashboards
source: https://docs.newrelic.com/docs/streaming-video-&-ads/custom-widget-support
---

Custom widgets let you extend the Media Streaming dashboard with chart visualizations built from your own NRQL queries. Use them when the built-in quality metrics don't cover a specific data point your team needs to monitor.

> #### ⚠️ IMPORTANT
>
> Each account supports a soft limit of **50 custom widgets per dashboard context** — 50 for **Video quality metrics** and 50 for **Ad quality metrics**, counted separately. If you reach the limit, delete an existing custom widget before adding a new one. Your existing widgets continue to function normally.

## Before you begin [#prereqs]

You need the following before creating a custom widget:

-   Access to a New Relic account with the Streaming Video & Ads agent installed. See [Install the Streaming Video & Ads agent](https://docs.newrelic.com/docs/streaming-video-&-ads/installation/install-the-streaming-video-&-ads-agent) if you haven't set it up yet.
-   The **+ Add Custom Widget** button visible in the [Quality Metrics section](https://docs.newrelic.com/docs/streaming-video-&-ads/view-data-in-newrelic/streaming-video-&-ads-features). If it isn't, contact your New Relic account team to request access.

## Write your NRQL query [#writing-queries]

The NRQL editor supports any valid NRQL query. For an introduction to NRQL syntax, see [Introduction to NRQL](https://docs.newrelic.com/docs/nrql/get-started/introduction-nrql-how-nrql-works).

### Query requirements [#query-requirements]

Custom widget queries have two additional requirements beyond standard NRQL:

-   Don't write a `SINCE` or `UNTIL` clause directly in your query. The dashboard time picker adds the time range automatically when the query runs.
-   To respond to dashboard-level filter bar selections, include a [filter placeholder](#placeholders) in your query.

### Filter placeholders [#placeholders]

The dashboard applies global filters when a query runs. If you write a plain `WHERE` clause directly in your query, the dashboard can't inject user-selected filter conditions into it. Filter placeholders are special NRQL comments that get replaced with the active filter conditions when the query runs.

| Placeholder                     | Replaced with       | When to use                                                                                                                           |
| ------------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `/* {whereClause} */`           | `WHERE [filters]`   | Query has no existing `WHERE` clause                                                                                                  |
| `/* {andWhereClause} */`        | `AND [filters]`     | Query already has a `WHERE` clause — appends filters to it                                                                            |
| `/* {aggregatorWhereClause} */` | `, WHERE [filters]` | Query uses a `filter()` aggregator with no existing inner `WHERE` clause — the `filter()` wrapper is removed when no filter is active |

**Example — no existing WHERE clause:**

```sql
SELECT count(*) FROM VideoAction /* {whereClause} */
```

With filter `City = Ashburn` applied:

```sql
SELECT count(*) FROM VideoAction WHERE city = 'Ashburn' SINCE 30 minutes ago UNTIL now
```

**Example — existing WHERE clause:**

```sql
SELECT count(*) FROM VideoAction
WHERE actionName = 'QOE_AGGREGATE' /* {andWhereClause} */
```

With filter `City = Ashburn` applied:

```sql
SELECT count(*) FROM VideoAction
WHERE actionName = 'QOE_AGGREGATE' AND city = 'Ashburn' SINCE 30 minutes ago UNTIL now
```

**Example — ratio query with mixed aggregators:**

```sql
FROM VideoAction
SELECT filter(sum(elapsedTime), WHERE actionName = 'CONTENT_HEARTBEAT' /* {andWhereClause} */)
     / filter(uniqueCount(viewId) /* {aggregatorWhereClause} */)
  AS 'avgWatchTime'
TIMESERIES
```

With filter `City = Ashburn` applied:

```sql
FROM VideoAction
SELECT filter(sum(elapsedTime), WHERE actionName = 'CONTENT_HEARTBEAT' AND city = 'Ashburn')
     / filter(uniqueCount(viewId), WHERE city = 'Ashburn')
  AS 'avgWatchTime'
TIMESERIES SINCE 30 minutes ago UNTIL now
```

Without any active filter:

```sql
FROM VideoAction
SELECT filter(sum(elapsedTime), WHERE actionName = 'CONTENT_HEARTBEAT')
     / uniqueCount(viewId)
  AS 'avgWatchTime'
TIMESERIES SINCE 30 minutes ago UNTIL now
```

> #### 💡 TIP
>
> Placeholders are valid NRQL comments — clicking **Run Query** works even when no filters are active in the dashboard.

### Blocked keywords and characters [#blocked]

To prevent accidental data modification, the NRQL editor rejects queries that contain:

-   The keywords `DROP`, `DELETE`, `INSERT`, `UPDATE`, `CREATE`, or `ALTER`
-   Semicolons (`;`), which would allow query chaining

Queries containing any of these fail validation and can't be saved or previewed.

### Sample queries [#sample-queries]

The following examples show common query patterns for video and ad monitoring. Each uses the appropriate filter placeholder for its query structure.

**Basic timeseries — total video starts:**

```sql
SELECT count(*) AS 'Video Starts'
FROM VideoAction
WHERE actionName = 'CONTENT_START' /* {andWhereClause} */
TIMESERIES
```

**Unique viewer count with filter integration:**

```sql
SELECT uniqueCount(viewId) AS 'Unique Viewers'
FROM VideoAction /* {whereClause} */
TIMESERIES
```

**Error rate across event types:**

```sql
SELECT count(*) AS 'Error Count'
FROM VideoErrorAction, VideoAction
WHERE actionName = 'CONTENT_ERROR' /* {andWhereClause} */
TIMESERIES
```

**Average watch time (ratio with nested aggregators):**

```sql
FROM VideoAction
SELECT filter(sum(elapsedTime), WHERE actionName = 'CONTENT_HEARTBEAT' /* {andWhereClause} */)
     / filter(uniqueCount(viewId) /* {aggregatorWhereClause} */)
  AS 'avgWatchTime'
TIMESERIES
```

### Limitations [#known-limitations]

Some NRQL query patterns have limited or untested support when global filters are active. See [Limitations for Streaming Video & Ads](https://docs.newrelic.com/docs/streaming-video-&-ads/limitations#nrql-patterns) for the full list.

## Create a custom widget [#create]

To create a custom widget:

1.  Go to **[one.newrelic.com](https://one.newrelic.com) > All Capabilities > Streaming Video & Ads**, then select **Video Overview** or **Ads Overview**.
2.  Scroll down to the **Video Quality Metrics** or **Ad Quality Metrics** section.
3.  Click **+ Add Custom Widget** in the section header.
4.  Enter a unique title for the widget.
5.  Write your NRQL query in the NRQL editor. See [Write your NRQL query](#writing-queries) above for guidance on syntax, filter placeholders, and examples.
6.  Click Run Query to preview results against live data. This doesn't save the widget. Use the preview to confirm the chart renders the data you expect, verify filter placeholders resolve correctly when a filter is active, and catch any syntax or logic errors before saving.
7.  When the preview loads, the chart type picker appears. The default is Line—select a different type if needed. Some chart types may appear grayed out if they aren't recommended for your query results, but you can still select any of them: **Billboard**, **Line**, **Area**, **Bar**, **Table**, or **Pie**.
8.  Click **Save**. New Relic adds the widget to the **Custom Metrics** section of the metric selector dropdown and renders it at the top of the quality metrics grid. Widgets persist across sessions.

> #### 💡 TIP
>
> Widget availability depends on the view you create them in:
>
> -   **All-platform view** (Video Overview or Ads Overview): Widgets are visible to all users on the account.
> -   **Single-application view** (a specific application's page): Widgets are specific to that application.
>
>     The chart type is not view-dependent — the chart type you set applies to all viewers regardless of which view they use.

## Edit a custom widget [#edit]

To edit a custom widget:

1.  In the **Quality Metrics** section, locate the custom widget you want to change.
2.  Click the pencil  icon on the widget card. The editor opens with your existing title and query pre-populated.
3.  Make your changes, click **Run Query** to verify, then click **Save**.

When saved:

-   Your original creation date and widget identity are preserved.
-   The widget immediately re-renders with the updated query.
-   If you changed the title, it updates in the metric selector dropdown.

## Delete a custom widget [#delete]

To delete a custom widget:

1.  In the **Quality Metrics** section, click the  icon on the widget card.
2.  Select **Delete**.
3.  Confirm in the prompt: _"Are you sure you want to delete '[Widget Title]'? This action cannot be undone."_

When deleted:

-   New Relic permanently deletes the widget.
-   The dashboard immediately removes the widget card.
-   The metric selector dropdown removes the title entry.
-   If the widget was selected, the dashboard deselects it automatically.

> #### ⚠️ CAUTION
>
> Deletion is permanent. Copy your NRQL query before deleting a widget if you may need it later.

## Troubleshoot [#troubleshoot]

Find your symptom below. Issues are ordered from most to least common.

### Widget doesn't update when I apply a dashboard filter [#widget-not-responding-to-filters]

Your query is missing a filter placeholder. Without `/* {whereClause} */`, `/* {andWhereClause} */`, or `/* {aggregatorWhereClause} */`, the widget always runs the query as written and ignores dashboard filter bar selections. See [Filter placeholders](#placeholders) to choose the right one for your query structure.

### Filters apply but the query returns an error or no data [#wrong-placeholder]

You may have used the wrong placeholder type. Check:

-   If your query has no `WHERE` clause, use `/* {whereClause} */`.
-   If your query already has a `WHERE` clause at the query level, use `/* {andWhereClause} */`.
-   If the placeholder is inside a `filter()` aggregator with no existing inner `WHERE`, use `/* {aggregatorWhereClause} */`.

The wrong placeholder produces invalid NRQL when the query runs, causing it to fail.

### My query fails validation or won't save [#query-blocked]

Check whether your query contains a [blocked keyword or character](#blocked), such as `DROP`, `DELETE`, or a semicolon. Also check that the query meets these requirements:

-   The query contains both `SELECT` and `FROM` clauses.
-   There are no syntax errors flagged by the editor's inline validation.

### Widget won't save — title already exists [#duplicate-title]

If a widget with the same title already exists in the same dashboard context (Video or Ad quality metrics), saving fails with a toast notification:

-   **Title:** Failed to save widget
-   **Description:** A widget with this name already exists

Title matching is case-insensitive — `My Widget` and `MY WIDGET` are treated as the same title. Choose a distinct title or rename the existing widget first.

### Widget saves but disappears after a page refresh [#widget-not-saving]

This may indicate a save failure. Check for a toast notification that appeared at save time — it will indicate whether the save failed due to a network error. Retry saving, or contact your New Relic account team if the issue persists.

### I can't add a new widget [#limit-reached]

You've reached the 50-widget soft limit for this dashboard context (Video or Ad quality metrics). Delete at least one existing custom widget, then try adding a new one.

### + Add Custom Widget button is not visible [#button-not-visible]

New Relic controls access to this feature. Contact your New Relic account team to request access.
