Docs menuAnthropic

Docs Integrations

Anthropic

Wrap the Anthropic client, in TypeScript or Python, to record every Messages call your agent makes. About five 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). Python 3.9 or later (python3 --version).
  • An Anthropic API key.

Steps

  1. Install the SDK and the Anthropic client

    terminalShell
    npm install @runback/sdk @anthropic-ai/sdk
    terminalShell
    pip install "runback-sdk[anthropic]"
    Expected output
    The install finishes without errors.
  2. Set your keys

    Runback reads its key from RUNBACK_API_KEY; the model client reads its own.

    terminalShell
    export RUNBACK_API_KEY="<RUNBACK_API_KEY>"
    export ANTHROPIC_API_KEY="sk-ant-..."
    Expected output
    Nothing is printed. echo $RUNBACK_API_KEY should print your key.
  3. Wrap the client and run it

    Wrap your existing client once; every messages.create and messages.stream call through it is recorded. Save this as agent.mjs and run node agent.mjsagent.py and run python agent.py.

    agent.mjsJavaScript
    // agent.mjs: npm install @runback/sdk @anthropic-ai/sdk
    import Anthropic from "@anthropic-ai/sdk";
    import { startRun } from "@runback/sdk/core";
    import { wrapAnthropic } from "@runback/sdk/anthropic";
    
    const task = "Say hello in three words.";
    const run = startRun({ runName: "support-agent", input: task });
    const claude = wrapAnthropic(new Anthropic(), run); // messages.create and messages.stream
    
    const msg = await claude.messages.create({
      model: "claude-sonnet-4-6",
      max_tokens: 256,
      messages: [{ role: "user", content: task }],
    });
    const answer = msg.content.map((b) => (b.type === "text" ? b.text : "")).join("");
    
    await run.finish({ output: answer, status: "success" });
    console.log(answer);
    agent.pyPython
    # agent.py: pip install "runback-sdk[anthropic]"
    import anthropic
    from runback import Collector
    from runback.anthropic import wrap_anthropic
    
    task = "Say hello in three words."
    run = Collector(run_name="support-agent", input=task)
    claude = wrap_anthropic(anthropic.Anthropic(), run)  # or anthropic.AsyncAnthropic()
    
    msg = claude.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=256,
        messages=[{"role": "user", "content": task}],
    )
    answer = "".join(b.text for b in msg.content if b.type == "text")
    
    run.finish(output=answer)
    print(answer)
    Expected output
    Your agent's normal output and 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 support-agent. Open it to step through what the agent did.

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.
Error: Could not resolve authentication method. Expected one of apiKey, authToken, …ANTHROPIC_API_KEY is not set.Run the agent with the key set, e.g. ANTHROPIC_API_KEY=sk-ant-... node agent.mjs.
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.

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.
ModuleNotFoundError: No module named 'runback'The package went into a different Python environment.Activate the virtual environment you installed into, or install with the same python you run the agent with: python -m pip install ….
TypeError: "Could not resolve authentication method. Expected one of api_key, auth_token, …ANTHROPIC_API_KEY is not set.Run the agent with the key set, e.g. ANTHROPIC_API_KEY=sk-ant-... python agent.py.
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

Per call: messages, system prompt, tool definitions, parameters, response text, tool use, stop reason, tokens and latency, for messages.create and messages.stream. Tool results you send back become tool steps paired with the model's call.

wrap_anthropic on anthropic.Anthropic(), messages, scripted model. 5 events, captured 9 Oct 2026.

  1. Runstart · py-anthropic
    {
      "error": null,
      "input": "for [redacted:email]",
      "metadata": {},
      "name": "py-anthropic",
      "output": null,
      "parent_span_id": null,
      "phase": "start",
      "run_id": "01M4G4WC0QX80S2SNE1RJH1KG5",
      "schema_version": 1,
      "seq": 0,
      "span_id": "01M4G4WC0QX80S2SNE1RJH1KG6",
      "status": "running",
      "ts_end": null,
      "ts_start": "2026-10-09T10:55:57.463Z",
      "type": "run"
    }
  2. Modelclaude-mock-1 → get_weather17 tokens · 55 ms · called a tool
    {
      "error": null,
      "latency_ms": 55,
      "metadata": {
        "framework": "anthropic"
      },
      "model": {
        "model_id": "claude-mock-1",
        "provider": "anthropic"
      },
      "parent_span_id": "01M4G4WC0QX80S2SNE1RJH1KG6",
      "request": {
        "messages": [
          {
            "content": "Weather in Paris? cc [redacted:email]",
            "role": "user"
          }
        ],
        "params": {
          "max_output_tokens": 256
        },
        "system": "You are a weather bot.",
        "tools": [
          {
            "description": "Weather for a city",
            "name": "get_weather",
            "parameters": {
              "properties": {
                "city": {
                  "type": "string"
                }
              },
              "required": [
                "city"
              ],
              "type": "object"
            }
          }
        ]
      },
      "response": {
        "finish_reason": "tool_use",
        "reasoning": null,
        "text": null,
        "tool_calls": [
          {
            "input": {
              "city": "Paris"
            },
            "tool_call_id": "toolu_1",
            "tool_name": "get_weather"
          }
        ]
      },
      "run_id": "01M4G4WC0QX80S2SNE1RJH1KG5",
      "schema_version": 1,
      "seq": 1,
      "span_id": "01M4G4WECN5KHERP8QJ5AEWW7D",
      "ts_end": "2026-10-09T10:55:59.893Z",
      "ts_start": "2026-10-09T10:55:59.838Z",
      "type": "llm",
      "usage": {
        "input_tokens": 12,
        "output_tokens": 5,
        "total_tokens": 17
      }
    }
  3. Toolget_weather
    {
      "error": null,
      "input": {
        "city": "Paris"
      },
      "latency_ms": null,
      "output": {
        "forecast": "sunny"
      },
      "parent_span_id": "01M4G4WECN5KHERP8QJ5AEWW7D",
      "run_id": "01M4G4WC0QX80S2SNE1RJH1KG5",
      "schema_version": 1,
      "seq": 2,
      "span_id": "01M4G4WEDHWTQG91S7PBGMJDSR",
      "tool_call_id": "toolu_1",
      "tool_name": "get_weather",
      "ts_end": "2026-10-09T10:55:59.921Z",
      "ts_start": "2026-10-09T10:55:59.920Z",
      "type": "tool"
    }
  4. Modelclaude-mock-128 tokens · 2 ms · finished
    {
      "error": null,
      "latency_ms": 2,
      "metadata": {
        "framework": "anthropic"
      },
      "model": {
        "model_id": "claude-mock-1",
        "provider": "anthropic"
      },
      "parent_span_id": "01M4G4WC0QX80S2SNE1RJH1KG6",
      "request": {
        "messages": [
          {
            "content": "Weather in Paris? cc [redacted:email]",
            "role": "user"
          },
          {
            "content": [
              {
                "caller": null,
                "id": "toolu_1",
                "input": {
                  "city": "Paris"
                },
                "name": "get_weather",
                "toolset_name": null,
                "type": "tool_use"
              }
            ],
            "role": "assistant"
          },
          {
            "content": [
              {
                "content": "{\"forecast\": \"sunny\"}",
                "tool_use_id": "toolu_1",
                "type": "tool_result"
              }
            ],
            "role": "tool"
          }
        ],
        "params": {
          "max_output_tokens": 256
        },
        "system": null,
        "tools": [
          {
            "description": "Weather for a city",
            "name": "get_weather",
            "parameters": {
              "properties": {
                "city": {
                  "type": "string"
                }
              },
              "required": [
                "city"
              ],
              "type": "object"
            }
          }
        ]
      },
      "response": {
        "finish_reason": "end_turn",
        "reasoning": null,
        "text": "It is sunny in Paris.",
        "tool_calls": []
      },
      "run_id": "01M4G4WC0QX80S2SNE1RJH1KG5",
      "schema_version": 1,
      "seq": 3,
      "span_id": "01M4G4WEDMBHJ5EAAR2YQXVJZB",
      "ts_end": "2026-10-09T10:55:59.924Z",
      "ts_start": "2026-10-09T10:55:59.921Z",
      "type": "llm",
      "usage": {
        "input_tokens": 20,
        "output_tokens": 8,
        "total_tokens": 28
      }
    }
  5. Runend · py-anthropicsucceeded
    {
      "error": null,
      "input": null,
      "metadata": {
        "cassette_digest": "9b16481ca418ca70cb443a6ff46d9e989c8c76b3ad10943b1d43d8c7a8891c3b",
        "cassette_entries": 3,
        "redaction_by_type": {
          "email": 3
        },
        "redaction_count": 3
      },
      "name": "py-anthropic",
      "output": "It is sunny in Paris.",
      "parent_span_id": "01M4G4WC0QX80S2SNE1RJH1KG6",
      "phase": "end",
      "run_id": "01M4G4WC0QX80S2SNE1RJH1KG5",
      "schema_version": 1,
      "seq": 4,
      "span_id": "01M4G4WEDMBHJ5EAAR2YQXVJZC",
      "status": "success",
      "ts_end": "2026-10-09T10:55:59.924Z",
      "ts_start": "2026-10-09T10:55:59.924Z",
      "type": "run"
    }

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.

wrapAnthropic on new Anthropic(), messages, scripted model. 5 events, captured 2 Nov 2026.

  1. Runstart · support-agent
    {
      "schema_version": 1,
      "run_id": "01M6DEG69TBA43RR308GZ88XHZ",
      "span_id": "01M6DEG69T6QHFHJT5THBCT9MT",
      "parent_span_id": null,
      "seq": 0,
      "ts_start": "2026-11-02T06:17:44.506Z",
      "ts_end": null,
      "type": "run",
      "phase": "start",
      "name": "support-agent",
      "input": "Weather in Paris? cc [redacted:email]",
      "output": null,
      "status": "running",
      "error": null,
      "metadata": {}
    }
  2. Modelclaude-sonnet-4-6 → get_weather17 tokens · 3 ms · called a tool
    {
      "ts_start": "2026-11-02T06:17:44.507Z",
      "ts_end": "2026-11-02T06:17:44.510Z",
      "model": {
        "provider": "anthropic",
        "model_id": "claude-sonnet-4-6"
      },
      "request": {
        "system": null,
        "messages": [
          {
            "role": "user",
            "content": "Weather in Paris? cc [redacted:email]"
          }
        ],
        "tools": [
          {
            "name": "get_weather",
            "description": "Weather for a city",
            "parameters": {
              "type": "object",
              "properties": {
                "city": {
                  "type": "string"
                }
              },
              "required": [
                "city"
              ]
            }
          }
        ],
        "params": {
          "max_output_tokens": 256
        }
      },
      "response": {
        "text": null,
        "reasoning": null,
        "finish_reason": "tool_use",
        "tool_calls": [
          {
            "tool_call_id": "toolu_1",
            "tool_name": "get_weather",
            "input": {
              "city": "Paris"
            }
          }
        ]
      },
      "usage": {
        "input_tokens": 12,
        "output_tokens": 5,
        "total_tokens": 17
      },
      "latency_ms": 3,
      "error": null,
      "metadata": {
        "framework": "anthropic"
      },
      "schema_version": 1,
      "run_id": "01M6DEG69TBA43RR308GZ88XHZ",
      "span_id": "01M6DEG69Y1A4RFNPQ2RVQ84ER",
      "parent_span_id": "01M6DEG69T6QHFHJT5THBCT9MT",
      "seq": 1,
      "type": "llm"
    }
  3. Toolget_weather
    {
      "schema_version": 1,
      "run_id": "01M6DEG69TBA43RR308GZ88XHZ",
      "span_id": "01M6DEG69YHFTKF1831ZMEJ612",
      "parent_span_id": "01M6DEG69Y1A4RFNPQ2RVQ84ER",
      "seq": 2,
      "ts_start": "2026-11-02T06:17:44.510Z",
      "ts_end": "2026-11-02T06:17:44.510Z",
      "type": "tool",
      "tool_name": "get_weather",
      "tool_call_id": "toolu_1",
      "input": {
        "city": "Paris"
      },
      "output": {
        "city": "Paris",
        "forecast": "sunny"
      },
      "latency_ms": null,
      "error": null
    }
  4. Modelclaude-sonnet-4-628 tokens · finished
    {
      "ts_start": "2026-11-02T06:17:44.510Z",
      "ts_end": "2026-11-02T06:17:44.510Z",
      "model": {
        "provider": "anthropic",
        "model_id": "claude-sonnet-4-6"
      },
      "request": {
        "system": null,
        "messages": [
          {
            "role": "user",
            "content": "Weather in Paris? cc [redacted:email]"
          },
          {
            "role": "assistant",
            "content": [
              {
                "type": "tool_use",
                "id": "toolu_1",
                "name": "get_weather",
                "input": {
                  "city": "Paris"
                }
              }
            ]
          },
          {
            "role": "tool",
            "content": [
              {
                "type": "tool_result",
                "tool_use_id": "toolu_1",
                "content": "{\"city\":\"Paris\",\"forecast\":\"sunny\"}"
              }
            ]
          }
        ],
        "tools": [
          {
            "name": "get_weather",
            "description": "Weather for a city",
            "parameters": {
              "type": "object",
              "properties": {
                "city": {
                  "type": "string"
                }
              },
              "required": [
                "city"
              ]
            }
          }
        ],
        "params": {
          "max_output_tokens": 256
        }
      },
      "response": {
        "text": "It is sunny in Paris.",
        "reasoning": null,
        "finish_reason": "end_turn",
        "tool_calls": []
      },
      "usage": {
        "input_tokens": 20,
        "output_tokens": 8,
        "total_tokens": 28
      },
      "latency_ms": 0,
      "error": null,
      "metadata": {
        "framework": "anthropic"
      },
      "schema_version": 1,
      "run_id": "01M6DEG69TBA43RR308GZ88XHZ",
      "span_id": "01M6DEG69YE9044BMNEH111V8G",
      "parent_span_id": "01M6DEG69T6QHFHJT5THBCT9MT",
      "seq": 3,
      "type": "llm"
    }
  5. Runend · support-agentsucceeded
    {
      "schema_version": 1,
      "run_id": "01M6DEG69TBA43RR308GZ88XHZ",
      "span_id": "01M6DEG69Z0MA8DZTMCSNFF717",
      "parent_span_id": "01M6DEG69T6QHFHJT5THBCT9MT",
      "seq": 4,
      "ts_start": "2026-11-02T06:17:44.511Z",
      "ts_end": "2026-11-02T06:17:44.511Z",
      "type": "run",
      "phase": "end",
      "name": "support-agent",
      "input": null,
      "output": "It is sunny in Paris.",
      "status": "success",
      "error": null,
      "metadata": {
        "cassette_digest": "4cc37c883ae9a5cf9270fd004f7a51d55dc6761a590bedb095795ddba4d789aa",
        "cassette_entries": 3,
        "redaction_count": 3,
        "redaction_by_type": {
          "email": 3
        },
        "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

Anthropic, Python wrapper

QuestionAnswerWhy
ContextFullEvery messages call, streamed or not, with tools and tokens.
Tool stepsInferredRead from the tool result in the next request, so a tool's latency isn't known.
RedactionIn your processOn by default.
Stop before it runsNoThe client never runs your tools, so there is no hook to block in.
ReplayRe-issue onlyA model step can be re-sent to a live model. The whole run can't be re-run with the same tool results: they aren't kept.
Signed recordYesEach run is hash-chained and can be exported as a signed record.

Next steps

  • See what a run holds: Capture.
  • Stop a risky tool call before it runs: Control.
Last updated 2 Nov 2026.