Docs menuManual recording

Docs Integrations

Manual recording

Record model and tool calls yourself, from any agent loop no integration fits: start a run, record each call, then finish it. About ten minutes.

Before you begin

  • A Runback account and a Send only key. In the app, open Settings › Keys and access › API key, keep Send only selected, select Generate API key and copy it (it is shown once and starts rb_cloud_). The quickstart walks through it.
  • Node.js 20 or later (node --version). @runback/sdk/core needs no AI SDK and no model client.

Steps

  1. Install the SDK

    terminalShell
    npm install @runback/sdk
    Expected output
    npm finishes without errors.
  2. Set your key

    terminalShell
    export RUNBACK_API_KEY="<RUNBACK_API_KEY>"
    Expected output
    Nothing is printed. echo $RUNBACK_API_KEY should print your key.
  3. Record your agent's steps

    run.llm and run.tool are plain function calls. Call them from your framework's own hooks, or straight after a raw model API call. Redaction runs on what you hand them, in your process, before anything is sent. This example records one model call and one tool call; save it as agent.mjs and run node agent.mjs.

    agent.mjsJavaScript
    // agent.mjs: npm install @runback/sdk (nothing else: @runback/sdk/core needs no AI SDK)
    import { startRun } from "@runback/sdk/core";
    
    const run = startRun({ runName: "loan-agent", input: "Application A-1042" });
    
    // Call these from your framework's own hooks, at the point each call happens.
    run.llm({
      model: { provider: "anthropic", model_id: "claude-sonnet-4-6" },
      request: { messages: [{ role: "user", content: "Assess application A-1042" }] },
      response: {
        text: null,
        tool_calls: [{ tool_call_id: "t1", tool_name: "credit_check", input: { applicant: "A-1042" } }],
        finish_reason: "tool_use",
      },
      usage: { input_tokens: 140, output_tokens: 22, total_tokens: 162 },
      latencyMs: 640,
    });
    run.tool({ toolName: "credit_check", toolCallId: "t1", input: { applicant: "A-1042" }, output: { score: 712 }, latencyMs: 85 });
    
    await run.finish({ output: "approved", status: "success" });
    Expected output
    No [runback] line. A [runback] line means the run was not sent; see Troubleshooting.
  4. Check the run arrived

    Open Runs in the app. Your run is at the top, named loan-agent.

Troubleshooting

You seeWhat it meansFix
[runback] no RUNBACK_API_KEY set — dropped 3 eventsThe key is not set in the terminal you ran the agent from.Export RUNBACK_API_KEY in the same terminal (a new tab starts without it), then run the agent again.
[runback] ingest failed 401 {"error":"Invalid API key"}Runback rejected the key: mistyped, revoked or expired.Copy the whole key again, or create a new one in Settings › Keys and access › API key.
Failed to load the ES module (Node 22+) or Cannot use import statement outside a module (Node 20)The file is not treated as an ES module.Name it .mjs, or add "type": "module" to package.json.
The agent ran, but the run is not in RunsThe key belongs to a different workspace, or you are looking at the shared demo.Check the workspace name in the top right of the app is the one the key came from.

Your agent never fails because of Runback: if recording fails, the model call still returns and Runback prints one [runback] line saying why.

What Runback records

startRun from @runback/sdk/core, recorded by hand. 4 events, captured 19 Oct 2026.

  1. Runstart · loan-agent
    {
      "schema_version": 1,
      "run_id": "01M59REJ9CTQ7A14RRY8KJG374",
      "span_id": "01M59REJ9CW3C6M1MBGXWG3T9S",
      "parent_span_id": null,
      "seq": 0,
      "ts_start": "2026-10-19T09:38:57.452Z",
      "ts_end": null,
      "type": "run",
      "phase": "start",
      "name": "loan-agent",
      "input": "Application from [redacted:email]",
      "output": null,
      "status": "running",
      "error": null,
      "metadata": {}
    }
  2. Modelclaude-sonnet-4-6 → credit_check162 tokens · 640 ms · called a tool
    {
      "ts_start": "2026-10-19T09:38:57.453Z",
      "ts_end": "2026-10-19T09:38:57.453Z",
      "model": {
        "provider": "anthropic",
        "model_id": "claude-sonnet-4-6"
      },
      "request": {
        "system": null,
        "messages": [
          {
            "role": "user",
            "content": "Assess the application from [redacted:email]"
          }
        ],
        "tools": [],
        "params": {}
      },
      "response": {
        "text": null,
        "reasoning": null,
        "finish_reason": "tool_use",
        "tool_calls": [
          {
            "tool_call_id": "t1",
            "tool_name": "credit_check",
            "input": {
              "applicant": "A-1042"
            }
          }
        ]
      },
      "usage": {
        "input_tokens": 140,
        "output_tokens": 22,
        "total_tokens": 162
      },
      "latency_ms": 640,
      "error": null,
      "schema_version": 1,
      "run_id": "01M59REJ9CTQ7A14RRY8KJG374",
      "span_id": "01M59REJ9DP86N5V6KG7CE6G9Q",
      "parent_span_id": "01M59REJ9CW3C6M1MBGXWG3T9S",
      "seq": 1,
      "type": "llm"
    }
  3. Toolcredit_check85 ms
    {
      "schema_version": 1,
      "run_id": "01M59REJ9CTQ7A14RRY8KJG374",
      "span_id": "01M59REJ9D5MMBRRYM0CEWW7XC",
      "parent_span_id": "01M59REJ9DP86N5V6KG7CE6G9Q",
      "seq": 2,
      "ts_start": "2026-10-19T09:38:57.453Z",
      "ts_end": "2026-10-19T09:38:57.453Z",
      "type": "tool",
      "tool_name": "credit_check",
      "tool_call_id": "t1",
      "input": {
        "applicant": "A-1042"
      },
      "output": {
        "score": 712
      },
      "latency_ms": 85,
      "error": null
    }
  4. Runend · loan-agentsucceeded
    {
      "schema_version": 1,
      "run_id": "01M59REJ9CTQ7A14RRY8KJG374",
      "span_id": "01M59REJ9D4F81EA8M9RMAZ3WE",
      "parent_span_id": "01M59REJ9CW3C6M1MBGXWG3T9S",
      "seq": 3,
      "ts_start": "2026-10-19T09:38:57.453Z",
      "ts_end": "2026-10-19T09:38:57.453Z",
      "type": "run",
      "phase": "end",
      "name": "loan-agent",
      "input": null,
      "output": "approved",
      "status": "success",
      "error": null,
      "metadata": {
        "cassette_digest": "767663abb6d237e19a94322f081310dd9f4de9cfc0bbe9e4da2978a677672ae9",
        "cassette_entries": 2,
        "redaction_count": 2,
        "redaction_by_type": {
          "email": 2
        },
        "truncated_fields": 0
      }
    }

The events this integration really sent, redacted in its own process, from a run in Runback's test suite. The model is scripted, so its name and its answers are the test's. The suite re-checks them on every change.

What it can and cannot do

Manual recording

QuestionAnswerWhy
Code changesOne call per stepYou call run.llm and run.tool yourself, from your own loop or your framework's hooks.
ContextWhat you passRunback records the request, response, tokens and latency you hand it. Nothing is read from your model client.
RedactionIn your processOn by default, before anything is buffered or sent. Pass redact: false to startRun to turn it off.
Stop before it runsYes, if you askStart the run with decide: true (or local enforce rules), then await run.decide(toolName, input) before the tool and run it only when .allowed is true.
Signed recordYesEach run is hash-chained and can be exported as a signed record.

Without the SDK

POST the same events to /api/ingest with your key as a bearer token. The Start page's test run does exactly that, and the event fields are in Events. In Go, the Go SDK records the same way, by hand from your own loop.

Last updated 2 Nov 2026.