Recount
Python

Groups

Bundle related Python trace steps - tables, charts and other spans - into a named, collapsible section with recount.add_group.

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

def build_group(g):
    g.span("table", "Current plan", {
        "output": recount.table_from_object(
            {"plan": "Standard", "rate": "$0.28/kWh", "dailySupply": "$1.10"}
        ),
    })

    g.span("table", "Recommended plan", {
        "output": recount.table_from_object(
            {"plan": "GreenSaver", "rate": "$0.24/kWh", "dailySupply": "$0.95"}
        ),
    })


recount.add_group("Energy plan comparison", build_group)

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.add_group(name, builder, options=None)

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

ParameterTypeDescription
namestrDisplay name for the group
builderCallable[[SpanGroup], None]Callback to add child spans to the group
optionsGroupSpanOptionsOptional group-level options

A builder that raises still flushes whatever spans it buffered before the error - the exception itself is swallowed.

Options

OptionTypeDescription
descriptionstrShort description shown when the group is expanded in the dashboard (max 1,000 chars)
limitintKeep only the first N child spans
sampleintRandomly sample down to N child spans (reservoir sampling, preserves relative order)
sampleThresholdintOnly 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.

def build_group(g):
    for result in results:
        g.span("json", result["title"], {"output": result})


recount.add_group("Search results", build_group, {"limit": 10})

Sampling child spans

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

def build_group(g):
    for item in items:
        g.span("json", item["id"], {"output": item})


recount.add_group("Processed items", build_group, {"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.add_group(
    "Processed items",
    build_group,
    {"sample": 20, "sampleThreshold": 100},
)

SpanGroup

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

g.span(type_, name, options=None)

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

def build_group(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"},
    })


recount.add_group("LLM pipeline", build_group)

g.add_message(name, text=None, opts=None)

Shorthand for adding a message child span.

def build_group(g):
    g.add_message("Policy check", "Policy is active and in-force")
    g.add_message("Coverage check", "Comprehensive cover confirmed")
    g.add_message("Excess check", "Excess of $500 applies", {"level": "warn"})


recount.add_group("Validation", build_group)

g.alert(label, level, options=None)

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

def build_group(g):
    g.span("json", "Credit check", {"output": {"score": 610}})
    if credit_score < 650:
        g.alert("Below minimum credit score", "error", {"checks": [{"value": 610}]})


recount.add_group("Risk checks", build_group)

Using the SpanGroup class directly

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

from recount import SpanGroup


def build_comparison_group(g: SpanGroup, plans: list[dict]) -> None:
    for plan in plans:
        g.span("table", plan["name"], {"output": recount.table_from_object(plan)})


async def trace_fn():
    recount.add_group("Plan options", lambda g: build_comparison_group(g, plans))


await recount.start_trace("Compare plans", trace_fn)

On this page