Part 5: Productize
Goal: Build a dashboard to monitor your inspection system.
Skills: Creating Teleop workspaces, configuring dashboard widgets, writing MQL aggregation pipelines.
Time: ~10 min
What You’ll Build
You’ve built a working inspection system—but monitoring it requires navigating through the Viam app’s configuration and data tabs. In this section, you’ll create a dedicated dashboard that shows everything at a glance: live camera feeds and defect trends over time.
Viam’s Teleop interface lets you create custom monitoring dashboards. You’ll add widgets for camera streams and time series graphs that use MQL aggregation pipelines to analyze your detection data.
5.1 Create a Workspace
A workspace is a custom dashboard view for your machines.
- In the Viam app, go to Fleet → Teleop
- Click + Create workspace
- Replace the placeholder name with
inspection - In Select location, choose
Home(or your location name) - In Select machine, choose
inspection-station-1

You now have an empty workspace ready for widgets.
5.2 Add a camera stream widget
Add a live video feed from your inspection camera.
- Click + Add widget
- Select Camera stream
- Click the pencil icon to configure
- Set Camera name to
inspection-cam - Set Refresh type to
Live - Click Save
You should see the live feed from your inspection camera with cans passing on the conveyor belt.
5.3 Add a Defects Per Minute Widget
Now you’ll create a time series graph showing how many defective cans are detected per minute. This requires a custom MQL aggregation pipeline to filter for failures and count them in time buckets.
Recall the data structure from Part 4—each detection looks like:
{
"component_name": "inspector-service",
"time_received": "2026-02-02T02:23:27.326Z",
"data": {
"docommand_output": {
"label": "FAIL",
"confidence": 0.965815
}
}
}
You’ll write MQL stages that filter for FAIL labels and count them per minute.
Create the widget:
- Click + Add widget
- Select Time series
- Click the pencil icon to configure
- Set Title to
Defective cans per minute - Set Time range (min) to
60 - Set Refetch rate (sec) to
60 - Leave Y axis lower bound and Y axis upper bound as
auto
Configure the line:
- Set Resource name to
inspector-service - Set Capture method to
DoCommand - Set Title to
Defects - For Window method, select Custom query
Add the MQL stages:
The custom query method lets you write MongoDB aggregation pipeline stages. You need three stages: match, group, and project.
In Custom MQL Stages, add a
$matchstage to filter for failures only:{ "$match": { "data.docommand_output.label": "FAIL" } }Click + Add stage and add a
$groupstage to count failures per 60-second bucket:{ "$group": { "_id": { "$dateTrunc": { "date": "$time_received", "unit": "second", "binSize": 60 } }, "value": { "$sum": 1 } } }Click + Add stage and add a
$projectstage to format the output:{ "$project": { "time": "$_id", "value": true } }Click Save
The graph now shows the count of defective cans detected in each minute.
How the pipeline works
- $match filters to only FAIL detections
- $group buckets data into 60-second intervals and counts documents in each bucket
- $project renames
_idtotime(required format for the graph)
5.4 Add a Confidence Trend Widget
Add another time series showing the average confidence of failure detections over time. This helps you monitor model performance—if confidence drops, you may need to retrain.
- Click + Add widget
- Select Time series
- Click the pencil icon to configure
- Set Title to
Confidence - Set Time range (min) to
60 - Set Refetch rate (sec) to
60 - Set Y axis lower bound to
0 - Set Y axis upper bound to
1
Configure the line:
- Set Resource name to
inspector-service - Set Capture method to
DoCommand - Set Title to
FAIL confidence - For Window method, select Custom query
Add the MQL stages:
Add a
$matchstage:{ "$match": { "data.docommand_output.label": "FAIL" } }Click + Add stage and add a
$groupstage that averages confidence:{ "$group": { "_id": { "$dateTrunc": { "date": "$time_received", "unit": "second", "binSize": 60 } }, "value": { "$avg": { "$convert": { "input": "$data.docommand_output.confidence", "to": "double", "onError": "$data.docommand_output.confidence" } } } } }Click + Add stage and add a
$projectstage:{ "$project": { "time": "$_id", "value": true } }Click Save
The graph shows average confidence for failure detections over time.
Why use $convert?
The $convert operator ensures the confidence value is treated as a number for averaging. The onError fallback handles any edge cases where conversion fails.
5.5 Arrange Your Dashboard
Drag widgets to create a useful layout:
- Click and drag the grid icon in the top-left corner of each widget
- Position the camera stream on the right for real-time monitoring
- Stack the time series graphs on the left to compare defect counts and confidence trends
Your dashboard now provides a complete view of your inspection system:
- Live video showing the inspection in progress
- Defects per minute tracking production quality
- Confidence trend monitoring model performance

5.6 Summary
You’ve created a monitoring dashboard using MQL aggregation pipelines:
- Created a workspace for your inspection station
- Added a camera stream for live video monitoring
- Built a defects graph using $match → $group (count) → $project
- Built a confidence graph using $match → $group (average) → $project
The same MQL pipeline pattern—filter, aggregate, project—can be adapted for other metrics: pass rate, throughput, detection latency, or any data your system captures.
Going further
For fully custom dashboards with your own branding, you can build a custom app using the TypeScript, Flutter, Python, or Go SDK. The SDK provides access to the same data through tabularDataByMQL() and tabularDataBySQL() methods.
Congratulations
You’ve completed the tutorial. Here’s what you built:
- Vision Pipeline—Camera, ML model, and vision service detecting defects
- Data Capture—Automatic recording and cloud sync of images and detections
- Control Logic—Custom inspector module exposing detection through DoCommand
- Module Deployment—Packaged and deployed to run autonomously
- Productize—Monitoring dashboard with real-time analytics
You’ve gone from an empty machine to a production-ready inspection system with monitoring—patterns that apply to any Viam application.
← Back to Overview to review what you learned.
Was this page helpful?
Glad to hear it! If you have any other feedback please let us know:
We're sorry about that. To help us improve, please tell us what we can do better:
Thank you!