Recount
Node.js

Groups

Bundle related Node.js trace steps - tables, charts and other spans - into a named, collapsible section with recount.addGroup.

A group span bundles related child spans into a named, collapsible section in the trace view. Use groups when you want to display multiple tables, charts, or other spans together under a single heading.

Basic usage

recount.addGroup('Energy plan comparison', (g) => {
  g.span('table', 'Current plan', {
    output: recount.tableFromObject({
      data: { plan: 'Standard', rate: '$0.28/kWh', dailySupply: '$1.10' }
    })
  });

  g.span('table', 'Recommended plan', {
    output: recount.tableFromObject({
      data: { plan: 'GreenSaver', rate: '$0.24/kWh', dailySupply: '$0.95' }
    })
  });
});

The group renders as a collapsible accordion with its child spans indented inside. The group itself does not count against your span quota - only its child spans do.


recount.addGroup(name, builder, options?)

Creates a group span on the active trace. Must be called inside a startTrace callback.

ParameterTypeDescription
namestringDisplay name for the group
builder(g: SpanGroup) => voidCallback to add child spans to the group
optionsGroupSpanOptionsOptional group-level options

Options

OptionTypeDescription
descriptionstringShort description shown when the group is expanded in the dashboard (max 1,000 chars)
limitnumberKeep only the first N child spans
samplenumberRandomly sample down to N child spans (reservoir sampling, preserves relative order)
sampleThresholdnumberOnly apply sample if the child count exceeds this value. Defaults to sample

limit and sample are mutually exclusive - if both are set, sample takes precedence.

Limiting child spans

Use limit to keep only the first N child spans. Useful when iterating over a list but only the leading results matter.

recount.addGroup(
  'Search results',
  (g) => {
    for (const result of results) {
      g.span('json', result.title, { output: result });
    }
  },
  { limit: 10 }
);

Sampling child spans

Use sample to keep a random subset of N child spans. Selected spans preserve their original relative order.

recount.addGroup(
  'Processed items',
  (g) => {
    for (const item of items) {
      g.span('json', item.id, { output: item });
    }
  },
  { sample: 20 }
);

Use sampleThreshold to only apply sampling when the child count exceeds a given value - useful when the list size varies and you only want to cut down large batches.

// Sample to 20 only if more than 100 items - otherwise keep all
recount.addGroup(
  'Processed items',
  (g) => {
    for (const item of items) {
      g.span('json', item.id, { output: item });
    }
  },
  { sample: 20, sampleThreshold: 100 }
);

SpanGroup

The g object passed to the builder callback is a SpanGroup. It exposes the same span(), addMessage(), and alert() methods as the top-level trace - except you cannot nest groups within groups.

g.span(type, name, options?)

Add a child span to the group. Supports all non-group span types.

recount.addGroup('LLM pipeline', (g) => {
  g.span('llm', 'Classify intent', {
    input: { messages: [{ role: 'user', content: 'My bill seems too high' }] },
    output: { response: 'billing_query' }
  });

  g.span('db', 'Fetch account history', {
    metadata: { table: 'transactions', queryType: 'sql' },
    input: {
      query: 'SELECT * FROM transactions WHERE account_id = $1',
      params: [42]
    }
  });

  g.span('json', 'Build response', {
    output: { recommendation: 'Switch to GreenSaver', savings: '$18.40/mo' }
  });
});

g.addMessage(name, text?, opts?)

Shorthand for adding a message child span.

recount.addGroup('Validation', (g) => {
  g.addMessage('Policy check', 'Policy is active and in-force');
  g.addMessage('Coverage check', 'Comprehensive cover confirmed');
  g.addMessage('Excess check', 'Excess of $500 applies', { level: 'warn' });
});

g.alert(label, level, options?)

Flags the most recently added child span with a warn or error badge. See Alerts for the full API.

recount.addGroup('Risk checks', (g) => {
  g.span('json', 'Credit check', { output: { score: 610 } });
  if (creditScore < 650) {
    g.alert('Below minimum credit score', 'error', {
      checks: [{ value: 610 }]
    });
  }
});

Using the SpanGroup class directly

If you need to pass the group builder around or construct it separately, import SpanGroup:

import recount, { SpanGroup } from '@refactorlabs/recount';

function buildComparisonGroup(g: SpanGroup, plans: Plan[]) {
  for (const plan of plans) {
    g.span('table', plan.name, {
      output: recount.tableFromObject({ data: plan })
    });
  }
}

await recount.startTrace('Compare plans', async () => {
  recount.addGroup('Plan options', (g) => buildComparisonGroup(g, plans));
});

On this page