Skip to content

Live Widgets

Live widgets let you push real-time values into the desktop app instead of just log lines. A single card showing the current step of a batch job, a progress bar, a table of results, a chart of throughput — all driven by regular SDK calls, no dashboard config required.

Think of it as a lightweight console.log for numbers and progress that you actually want to watch update live: the progress of a batch job, live metrics during a load test, a counter ticking up during a migration.

The Live page showing a progress bar, a value card, a job-queues table, and a latency chart updating in real time

Requires @gunsole/core >= 0.3.0.

import { createGunsoleClient } from "@gunsole/core";
const gunsole = createGunsoleClient({ projectId: "my-app", mode: "desktop" });
for (let i = 0; i <= items.length; i++) {
gunsole.liveProgress("import-job", {
label: "Importing",
current: i,
total: items.length,
});
gunsole.liveChart("import-job", {
label: "Throughput",
y: itemsPerSecond,
});
// ... process items[i]
}

Every widget is identified by a liveId — a string you choose. Multiple SDK calls sharing the same liveId and widget type update the same widget in the desktop app. Widgets show up on the project’s Live Widgets page, and a summary also appears as a stat card on the project dashboard.

A single-value card — a number, a status string, whatever you want to keep an eye on.

gunsole.liveCard("active-workers", "12");
gunsole.liveCard("active-workers", "8", { tags: { region: "us-east" } });
gunsole.liveCard(liveId: string, text: string, options?: LiveLogOptions): void

A progress bar with a current/total count and an optional label.

gunsole.liveProgress("import-job", {
label: "Importing users",
current: 42,
total: 500,
});
gunsole.liveProgress(
liveId: string,
data: { label?: string; current: number; total: number },
options?: LiveLogOptions
): void

A table of rows — useful for showing a snapshot of top errors, slowest endpoints, worker status, and the like.

gunsole.liveTable("worker-status", {
title: "Workers",
columns: ["id", "status", "processed"],
rows: [
["worker-1", "running", "1204"],
["worker-2", "idle", "980"],
],
});
gunsole.liveTable(
liveId: string,
data: { title?: string; columns: string[]; rows: string[][] },
options?: LiveLogOptions
): void

A chart that appends a data point on every call — great for throughput, latency, or any metric you want to watch trend over time.

gunsole.liveChart("throughput", {
label: "Requests/sec",
y: currentRps,
});
// Multiple series
gunsole.liveChart("latency", {
chartType: "line",
series: "p99",
y: p99Latency,
});
// Reset the series and start over
gunsole.liveChart("throughput", { y: 0, reset: true });
gunsole.liveChart(
liveId: string,
data: {
chartType?: "line" | "bar" | "area";
label?: string;
x?: number | string;
y: number;
series?: string;
maxPoints?: number;
reset?: boolean;
},
options?: LiveLogOptions
): void

Defaults: x is the current timestamp, series is "value", chartType is "line", maxPoints is 500 (oldest points are dropped once exceeded). Pass reset: true to clear the series before appending the new point — handy at the start of a new run.

The four widget types don’t all behave the same way when called repeatedly with the same liveId:

  • liveCard, liveProgress, liveTable — coalesce. These represent a single current value. If you call them multiple times before the SDK’s next batch flush, only the latest call wins — the pending value is simply replaced. This makes it cheap to call liveProgress in a tight loop; you’re not paying for every single call, just for what actually gets flushed. Coalescing replacements also bypass the SDK’s rate limiter, since they don’t add new entries to the queue.
  • liveChart — appends. Every call adds a new data point to the series. Nothing is coalesced, since each point is meaningful on its own (that’s what makes it a chart). Chart calls do pay the normal rate-limit cost, so avoid calling liveChart at a rate higher than your maxLogRate allows if you want every point to land.

In short: update liveCard/liveProgress/liveTable as often as you want, but treat liveChart calls like any other rate-limited log call.

Live widgets appear on the project’s Live Widgets page, with a stat card summarizing them on the project dashboard. Widgets can be reordered, deleted, and cleared from the UI.

All four methods accept an optional LiveLogOptions as the last argument:

OptionTypeDefaultDescription
bucketstring"live"Bucket the widget’s underlying entries are grouped under
levelstring"info"Log level for the underlying entries
tagsRecord<string, string>Tags merged into the underlying entries
contextRecord<string, unknown>Extra context attached to the underlying entries