Back to The Times of Claw

DenchClaw Widget Mode: At-a-Glance Metrics

How DenchClaw's widget mode turns your custom apps into compact dashboard cards showing live CRM metrics at a glance.

Mark Rachapoom
Mark Rachapoom
·6 min read
DenchClaw Widget Mode: At-a-Glance Metrics

DenchClaw Widget Mode: At-a-Glance Metrics

DenchClaw's widget mode lets any Dench App run as a compact, auto-refreshing card in your workspace dashboard. Instead of opening a full app to check your pipeline status, today's tasks, or key metrics, you see them at a glance — always current, always visible, no click required.

What Is a Widget?#

A widget is a Dench App running in compact mode — a fixed-size card embedded in your DenchClaw dashboard. Widgets:

  • Auto-refresh at a configurable interval (every 30 seconds, every 5 minutes, etc.)
  • Show a summary view of the app's data — designed to be read at a glance
  • Can be expanded to the full app with a click
  • Support grid-based layout — arrange multiple widgets side by side
  • Live-query your DuckDB data on every refresh

The dashboard page in DenchClaw is a grid of widgets. Think macOS menu bar apps, but for your CRM data.

Configuring Widget Mode#

Any Dench App becomes a widget by setting display: widget in its .dench.yaml manifest:

# pipeline-summary.dench.app/.dench.yaml
name: Pipeline Summary
slug: pipeline-summary
icon: trending-up
version: 1.0.0
 
display: widget
widget:
  width: 2      # Grid columns (1-4)
  height: 2     # Grid rows (1-4)
  refreshMs: 60000   # Auto-refresh every 60 seconds
  expandable: true   # Click to open full app
 
permissions:
  db: read

Grid units: the dashboard uses a 4-column grid. A widget with width: 2 takes 2 of 4 columns (half the width). Height units are based on a standard row height (~150px per unit).

Building a Widget#

The index.html for a widget needs to render content that fits in the widget's dimensions. Unlike a full-app index.html, a widget should show summary information only.

Here's a simple pipeline summary widget:

<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      font-family: system-ui;
      padding: 12px;
      background: var(--surface);
      color: var(--text);
    }
    .metric {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 4px 0;
      border-bottom: 1px solid var(--border);
    }
    .metric-value {
      font-size: 20px;
      font-weight: 700;
      color: var(--accent);
    }
    .title {
      font-size: 13px;
      font-weight: 600;
      margin-bottom: 8px;
      color: var(--text-muted);
    }
  </style>
</head>
<body>
  <div class="title">Pipeline Summary</div>
  <div id="metrics"></div>
 
  <script>
    async function load() {
      const stages = await dench.db.query(`
        SELECT "Stage", COUNT(*) as count, SUM(CAST("Deal Value" AS FLOAT)) as total
        FROM v_deals
        WHERE "Status" NOT IN ('Closed Won', 'Closed Lost')
        GROUP BY "Stage"
        ORDER BY total DESC
      `);
 
      const container = document.getElementById('metrics');
      container.innerHTML = stages.map(s => `
        <div class="metric">
          <span>${s.Stage}</span>
          <span class="metric-value">$${Math.round(s.total / 1000)}K</span>
        </div>
      `).join('');
    }
 
    load();
    // dench.widget.onRefresh(load);  // Called on each auto-refresh
  </script>
</body>
</html>

This widget shows your deal pipeline value by stage, refreshed every minute.

Widget CSS Variables#

Widgets receive theme CSS variables from the workspace so they automatically match dark/light mode:

var(--background)    /* Main background */
var(--surface)       /* Card/panel background */
var(--text)          /* Primary text */
var(--text-muted)    /* Secondary/muted text */
var(--accent)        /* Accent color */
var(--border)        /* Border color */
var(--success)       /* Green */
var(--warning)       /* Amber */
var(--error)         /* Red */

Using these variables means your widget looks correct in both light and dark mode without additional work.

Dashboard Layout#

The dashboard page shows a draggable grid of widgets. To configure your dashboard:

  1. Navigate to Dashboard in the DenchClaw sidebar (or press G then H)
  2. Widgets are arranged in a 4-column grid
  3. Drag to reorder
  4. Click the gear icon on any widget to configure refresh rate or remove it
  5. Click "+ Add Widget" to add a new app as a widget

Dashboard layout is saved to ~/.openclaw-dench/workspace/dashboard.yaml:

layout:
  - slug: pipeline-summary
    position: { col: 0, row: 0 }
    width: 2
    height: 2
  - slug: tasks-today
    position: { col: 2, row: 0 }
    width: 2
    height: 2
  - slug: upcoming-renewals
    position: { col: 0, row: 2 }
    width: 4
    height: 1

Useful Widget Ideas#

Here are widgets worth building for a sales CRM:

Pipeline Value by Stage (2×2)

  • Total open pipeline value
  • Deal count per stage
  • Biggest deal in each stage

Today's Tasks (2×2)

  • List of tasks due today
  • Overdue task count
  • Click to expand full task list

Follow-up Queue (2×1)

  • Count of contacts last-touched >14 days ago
  • Quick link to the filtered view

Closing This Month (2×2)

  • Deals closing this month
  • Total potential close value
  • Win rate this month vs. last

Recent Activity (4×1)

  • Last 5 CRM events (entries created, stages changed)
  • Timestamp for each

Widget Refresh and Performance#

The refreshMs setting controls how often the widget re-queries DuckDB and re-renders. Guidelines:

  • 30 seconds: For widgets showing real-time data (active subagent status, incoming messages)
  • 5 minutes: For most metric widgets (pipeline, tasks, follow-ups)
  • 30 minutes: For slowly-changing summaries (monthly totals, quarterly trends)
  • Manual: Set refreshMs: 0 for widgets that only refresh on user interaction

DuckDB queries are fast (milliseconds for typical CRM data volumes), so frequent refresh doesn't impact performance.

See also: DenchClaw App Builder for the full app development API, and DenchClaw Event System for real-time widget updates driven by CRM events.

Frequently Asked Questions#

Can a widget open a modal or take user input?#

Yes, within limits. Widgets can render buttons and input fields. Clicking a button can trigger a DuchDB write, call the AI, or emit an event. For complex interactions, configure the widget as expandable so users can open the full app.

How many widgets can I have on my dashboard?#

No fixed limit. Performance degrades gracefully if you have many widgets all refreshing frequently. In practice, 6-10 widgets with 5-minute refresh intervals are imperceptible to system performance.

Can a widget display a chart?#

Yes. Include Chart.js or any other charting library in your widget's HTML. Render the chart in a canvas element sized to fit the widget dimensions. Charts in widgets look identical to charts in full-screen apps.

What's the difference between a widget and a full app?#

A full app is a standalone window/tab with full screen space. A widget is a compact card in the dashboard grid. Most apps should be both: configure display: widget in .dench.yaml and design the index.html to be responsive — showing summary view at widget dimensions and full detail when expanded.

Do widgets work offline?#

Widgets query DuckDB, which is fully local. Widgets work offline as long as the DenchClaw server is running. Any widget feature that requires an internet connection (like an AI query or external API fetch) will fail gracefully with an error state when offline.

Ready to try DenchClaw? Install in one command: npx denchclaw. Full setup guide →

Mark Rachapoom

Written by

Mark Rachapoom

Building the future of AI CRM software.

Continue reading

DENCH

© 2026 DenchHQ · San Francisco, CA