このページでは

For AI agents: a documentation index is available at /docs/llms.txt. Append .md to any page URL for markdown, or send Accept: text/markdown.

Render agent artifacts

このページはまだあなたの言語に翻訳されていません。 現在取り組んでいますので、後でもう一度確認してください。

An artifact is a small, versioned JSON envelope your agent attaches to a tool call or AI response to describe a visual it showed a user. Agent Analytics validates the envelope and redraws that visual as a card in the session view, so a reviewer sees what the user saw instead of the JSON behind it. Amplitude draws the card with built-in renderers that follow the viewer's theme, so you never ship UI code and Amplitude never executes yours.

Emit artifacts when the visual was the answer and the raw payload doesn't tell you whether the answer was any good, such as a chart your agent generated or a set of choices it offered. If you only need the underlying numbers for analysis, you don't need artifacts: tool content already lands as event properties you can query in charts and cohorts.

Agent Analytics renders valid $agent_artifact envelopes automatically for every organization.

How it works

  1. Your agent produces a visual for its user, as it does today.
  2. Alongside it, your code attaches an artifact envelope to the tool call's input or output, or to an AI response attachment for a direct answer.
  3. Agent Analytics recognizes the envelope, validates it, and renders a card in both the conversation view and the trace panel.
  4. The original tool payload or response text stays visible next to the card. Amplitude never replaces or hides it.

If a payload doesn't validate, Agent Analytics shows a short reason next to the raw output instead of a card. It never guesses at your data or renders a partial result.

Instrument artifacts with your coding agent

Use your coding agent to add artifact serializers where your application produces visuals. Open the repository in your coding agent, then copy and run this prompt. If your application doesn't send sessions to Agent Analytics yet, set up instrumentation first.

text
Add artifact instrumentation to this application's existing Amplitude
Agent Analytics integration.

Read the artifact contract:
https://amplitude.com/docs/amplitude-ai/agent-analytics/render-artifacts
Also read the instrumentation guide for the SDK or ingest path this
repository uses. If you can't access the documentation, ask me for it
before implementing the contract. Identify the existing content-capture
and redaction settings for the installed SDK or exporter. HTTP, OTLP,
and imported data do not inherit AI SDK settings.

1. Find the code that produces charts, summaries, tables, choices, or
   static HTML shown to users. Trace each visual to its tool call and
   existing instrumentation. Don't infer a displayed visual from arbitrary
   JSON. Find the actual data used to render each visual; a chart ID, URL,
   or configuration without values isn't a data snapshot. Preserve the
   displayed filters, time range, timezone, and transformations. If that
   data or an editable emission point is unavailable, report the gap.
   Prefer capturing that data where the application produces the visual,
   before truncation, then attaching it through existing instrumentation.
   Avoid fetching it again just for analytics. If a reference needs a new
   read, preserve resource permissions, bound the total work, and disclose
   that the snapshot may differ from what the user originally saw.

2. Write reusable serializer functions in the project's language that
   return a root-level $agent_artifact envelope with v: 1, the appropriate
   type, and its required fields. Prefer chart, summary, table, or options.
   If those types would lose meaningful content, implement a static html
   fallback when feasible. Examples include choices with descriptions,
   tables with semantic highlights, and reports containing several visuals.
   Generate self-contained HTML/CSS/inline SVG from the actual source data,
   escaping dynamic text. Follow the documented HTML restrictions and
   per-type size limits. The result captures what was shown; controls stay
   inert. For script-dependent visuals, generate a faithful static snapshot
   from their data rather than simply removing scripts. Before skipping a
   visual, evaluate both structured types and static html. If neither fits,
   explain what content or meaning would be lost or what data is missing.

3. Derive labels, values, units, ordering, and scope from the application
   code. Ask me about ambiguous mappings, such as cents versus dollars or
   missing values. Don't invent values, silently truncate data, or change
   the meaning of the visual to make an envelope validate.

4. Attach the envelope to the corresponding tool output, or tool input
   for an input-side artifact such as a choice prompt. For a direct final-answer
   visual, use an explicit artifact attachment on the existing AI response.
   Follow the existing SDK, HTTP, or OTLP path and its serialization rules. Reuse session,
   trace, and tool or message identifiers. Preserve application behavior and existing
   payload fields, and avoid recording the same tool call or response twice.
   Account for every visual the tool or final answer produces. For multiple visuals, evaluate one
   static html report that preserves all meaningful content within the
   documented limits. If that isn't feasible and no structured type fits,
   explain the limitation and ask me how to proceed. Don't silently select
   one visual or invent a multi-artifact envelope. Keep snapshot-only
   failures from failing the underlying tool or response. Preserve request
   cancellation and existing background persistence; don't add a storage
   wait solely to capture data already available at the producer.

5. Preserve content-capture, exclusion, and redaction settings. Don't enable
   capture to bypass metadata-only mode. The producer owns the content it
   sends, including raw HTML, attributes, CSS, and inline SVG. Select only
   source data approved for analytics capture. Use the existing SDK redaction
   path without private helpers or an additional redaction pass. For HTTP,
   OTLP, and imports, apply the source pipeline's policy before export.
   Ordinary string redaction is best-effort; it doesn't interpret rendered
   HTML or guarantee detection of values split across markup or encoded in
   styles. Don't build a rendered-HTML PII detector, or omit HTML solely
   because redaction is enabled. Viewer sanitization protects rendering,
   not sensitive data at ingestion. Use synthetic fixtures for tests.

6. Add focused tests for representative inputs, optional or missing
   fields, and invalid or oversized data. Validate the artifact envelope
   and the complete serialized content field, including sibling fields,
   against artifact and transport limits. Report an oversized snapshot
   without truncating it or dropping the underlying event. Verify capture
   exclusions, configured redaction, and the actual outbound payload.
   Redaction can change markup or serialized JSON; check that the resulting
   envelope remains parseable and represents the approved content faithfully.
   Show the changed files, mapping assumptions, test results, and a
   representative emitted envelope. Test slow or failed snapshot work and
   cancellation. Record fixed omission reasons, such as missing data,
   unsupported representation, size limit, or timeout, using existing span
   identifiers. Don't log source content or exception bodies. Distinguish
   expected capture exclusions from failures and ordinary nonvisual output.
   Explain how to verify the artifact in
   an Agent Analytics test session. Distinguish local serializer/contract
   checks from live ingestion and visual verification; report which checks
   you actually performed. For HTML fallbacks, verify that meaningful
   content remains visible under the documented rendering restrictions.

7. Finish with an instrumented / skipped / needs a decision checklist.
   For each visual path, name its source and emission point, coverage,
   representation, and any limitation or unanswered mapping question. For
   skipped visuals, explain why neither a structured type nor static html
   works. Don't claim full coverage based on one successful example.

Review the generated changes and coverage checklist, especially skipped visuals, units, and field mappings, before using them. After running the tests, send a test session and confirm the artifact matches the visual your agent showed. If Agent Analytics reports Artifact not rendered, use the validation reason to correct the serializer.

To implement the serializer yourself, use the envelope, artifact types, and tool-call examples.

The envelope

Every artifact is a JSON object under a single reserved key. The key is deliberately vendor-neutral and nothing in the payload grammar is Amplitude-specific, so the same builder can emit to another platform that adopts this shape. You change the key, not your code.

json
{
  "$agent_artifact": {
    "v": 1,
    "spec": "https://amplitude.com/docs/amplitude-ai/agent-analytics/render-artifacts",
    "type": "chart",
    "title": "Monthly payouts",
    "caption": "August was the highest month.",
    "scope": { "label": "Aug 2026" },
    "locale": "en-IN",
    "payload": {}
  }
}

Two conventions apply everywhere:

  • unit is a display string, not a concept. Send "INR", "%", "ms", "req/s", or anything else. Amplitude appends it to values as-is and never interprets it. Number formatting comes from locale.
  • Colors are semantic, never literal. Send primary, success, or danger and Amplitude maps them to theme colors that work in light and dark mode, and that stay distinguishable for color-blind readers. Hex values, fonts, and sizes aren't part of the contract.

Attach the envelope to a tool call

Artifacts travel on the tool call that produced them. Pass the envelope as the tool's output, or as input when the artifact is the input, as with a question you asked the user.

const artifact = {
  $agent_artifact: {
    v: 1,
    type: "chart",
    title: "Monthly payouts",
    payload: {
      shape: "categorical",
      kind: "bar",
      unit: "INR",
      items: [
        { label: "Aug 2026", value: 37279.7, color: "danger" },
        { label: "Jul 2026", value: 23925, color: "primary" },
      ],
    },
  },
};

session.trackToolCall("render_payouts_chart", latencyMs, true, {
  input: JSON.stringify({ range: "last-3-months" }),
  output: JSON.stringify(artifact),
});

Tool content comes from the input and output options. Amplitude ignores other spellings without an error, so your artifact never arrives. That includes toolInput and toolOutput, which are the names of the resulting event properties. If you rely on patch() for zero-code instrumentation, note that auto-extracted tool calls carry no input or output, so artifacts need an explicit trackToolCall. Refer to Track tool calls in the SDK reference.

Attach a direct-answer artifact to an AI response

When your application displays a visual directly in an assistant answer, attach its envelope to that existing AI response. Use the same v: 1 envelope and artifact types as tool artifacts. Each attachment has type: "artifact" and a root-level $agent_artifact field.

The Python SDK accepts the attachment as a dictionary and handles serialization:

python
agent = ai.agent(
    "Your agent",
    user_id=user_id,
    session_id=session_id,
    trace_id=trace_id,
)
agent.track_ai_message(
    content=response_text,
    model=model,
    provider=provider,
    latency_ms=latency_ms,
    message_id=message_id,
    attachments=[{
        "type": "artifact",
        "$agent_artifact": {
            "v": 1,
            "type": "table",
            "title": "Sessions by region",
            "payload": {
                "columns": ["Region", "Sessions"],
                "rows": [["Alpha", 12], ["Beta", 18]],
            },
        },
    }],
)

For HTTP ingestion, serialize the attachment list as the [Agent] Attachments event property on the existing [Agent] AI Response event. Keep the response text and session, trace, and message identifiers. Don't emit a second response or a synthetic tool call for the same answer. Add attachments only after the application accepts the final answer; intermediate drafts aren't final-answer snapshots.

Agent Analytics renders artifact attachments in list order in both the conversation and trace views, including responses without text. It recognizes only explicit type: "artifact" attachments in this channel. It doesn't infer visuals from response text or fetch attachment URLs.

The attachment list supports up to 32 entries and 256 KB of serialized data, including other attachment types. Each artifact also follows its per-type limits. Your SDK or ingest path can impose a smaller limit; check its serialized output and reject an oversized snapshot instead of truncating it. For several visuals that form one report, prefer one static html artifact that preserves the complete report.

SDK attachments follow the SDK's content-capture and redaction settings. metadata_only mode omits attachment bodies, so artifact cards don't render. For direct HTTP, apply your source pipeline's privacy policy before exporting the attachment list.

Emit from any ingest path

The envelope is the same on every path. What changes is only where you put it: artifacts ride the tool call's existing content fields, so any path that carries tool content carries artifacts.

AI SDK

Pass the envelope as the output (or input) option, as in the examples above. Amplitude serializes it into the [Agent] Tool Output property.

HTTP API or a standard Amplitude SDK

Set the [Agent] Tool Output property directly on an [Agent] Tool Call event. Refer to Set up Agent Analytics for the full event contract and the ID fields every event needs.

bash
curl -X POST https://api2.amplitude.com/2/httpapi \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "YOUR_API_KEY",
    "events": [{
      "event_type": "[Agent] Tool Call",
      "user_id": "user-123",
      "event_properties": {
        "[Agent] Session ID": "ticket-42",
        "[Agent] Turn ID": 2,
        "[Agent] Trace ID": "trace-abc",
        "[Agent] Agent ID": "support-bot",
        "[Agent] Tool Name": "render_refund_summary",
        "[Agent] Tool Success": true,
        "[Agent] Tool Input": "{\"order_id\":\"A-1\"}",
        "[Agent] Tool Output": "{\"$agent_artifact\":{\"v\":1,\"type\":\"summary\",\"title\":\"Refund total\",\"payload\":{\"headline\":{\"value\":42.5,\"label\":\"Refunded\",\"unit\":\"USD\"}}}}"
      }
    }]
  }'

Both properties take a JSON string, so serialize the envelope before assigning it.

OTLP

Put the envelope in whichever result attribute your instrumentation already uses on the tool span. Amplitude reads the first one present, in this order:

Tool input follows the same pattern, from gen_ai.tool.call.arguments or input.value. The tool name comes from gen_ai.tool.name or tool.name. Refer to Set up Agent Analytics for the OTLP endpoint and headers.

Artifact types

chart

Describe a chart by its data shape, which Amplitude validates, plus an optional kind that hints at the picture you drew.

kind is a free string: bar, column, pie, donut, line, area, or anything else you call your chart. Amplitude draws a kind that has its own renderer that way. Anything else renders as the shape's default presentation with a visible note saying so, so a reviewer always knows they're looking at a substitute. Shapes that have no dedicated renderer yet (steps, points, matrix) render as a labeled table and carry the same note.

Optional chart fields: unit, xLabel, yLabel, and highlightedIndex (for categorical, to emphasize one item).

json
{
  "$agent_artifact": {
    "v": 1,
    "type": "chart",
    "title": "Monthly cash flow",
    "locale": "en-IN",
    "payload": {
      "shape": "series",
      "kind": "line",
      "unit": "INR",
      "xLabel": "Month",
      "yLabel": "Amount",
      "series": [
        {
          "label": "Cash-in",
          "color": "success",
          "points": [
            { "x": "Apr 2026", "y": 222389 },
            { "x": "May 2026", "y": 42810 }
          ]
        },
        {
          "label": "Cash-out",
          "color": "danger",
          "points": [
            { "x": "Apr 2026", "y": 61453 },
            { "x": "May 2026", "y": 32580 }
          ]
        }
      ]
    }
  }
}

summary

One number card at whatever density you need: a bare headline, a headline with a comparison, or a full overview with supporting metrics and facts. Send a headline; every other field is optional.

json
{
  "$agent_artifact": {
    "v": 1,
    "type": "summary",
    "title": "Net cash flow",
    "scope": { "label": "Sep 2026" },
    "payload": {
      "headline": {
        "value": 25008,
        "label": "Net cash flow",
        "unit": "SAR",
        "tone": "positive"
      },
      "delta": { "value": 80192, "direction": "up", "comparedTo": "vs August" },
      "metrics": [{ "label": "Entries", "value": 41, "tone": "neutral" }],
      "facts": [
        { "label": "All-time balance", "value": 918220, "tone": "positive" }
      ],
      "suggestions": ["Show entries for this month"]
    }
  }
}

tone is positive, negative, or neutral. It carries direction, not judgment. suggestions are the follow-ups your agent offered; they render as labels, because the session view is a record of what happened, not a place to continue the conversation.

options

A choice you presented to the user. Because the user has already answered by the time anyone reviews the session, the choices render as labels.

json
{
  "$agent_artifact": {
    "v": 1,
    "type": "options",
    "payload": {
      "question": "Which quarter should I show?",
      "options": [
        { "id": "2026-q1", "label": "Jan – Mar 2026" },
        { "id": "2026-q2", "label": "Apr – Jun 2026" }
      ],
      "reason": "too_many_results"
    }
  }
}

Attach this one to the tool's input, since the question is what your tool received. reason is your own short code for why the agent asked; it's stored for analysis and not rendered.

table

json
{
  "$agent_artifact": {
    "v": 1,
    "type": "table",
    "title": "Spend by region",
    "payload": {
      "columns": ["Region", "Sessions", "Spend"],
      "rows": [
        ["EU", 1200, 4517.5],
        ["US", 880, 91000]
      ]
    }
  }
}

Cells are strings or numbers; numbers format by locale and align right. Every row needs exactly one cell per column. Amplitude rejects a row of any other length instead of padding it, because padding would misstate your data.

html

For a visual the other types can't express, send self-contained markup.

json
{
  "$agent_artifact": {
    "v": 1,
    "type": "html",
    "title": "Custom SLA gauge",
    "payload": {
      "html": "<html><head><style>…</style></head><body>…</body></html>"
    }
  }
}

Amplitude enforces all of these:

  • Static markup only: Amplitude rejects script tags, and the rendering frame can't execute scripts at all. Interactivity belongs in the declarative types.
  • Fully self-contained: inline your CSS and data. Amplitude blocks images (including data: images) and external requests for fonts, stylesheets, and APIs. Use HTML, CSS, or inline SVG for visuals.
  • No navigation: Amplitude removes link destinations, so links display as content without navigating when clicked.
  • Bring your own styling: the frame isolates your document, so Amplitude's theme doesn't reach inside it.
  • 100,000 characters maximum.

Amplitude shows an html artifact collapsed, with a button to render it, then draws it in a sealed frame that can't reach the surrounding page.

Prefer a declarative type wherever one fits: those cards follow the viewer's theme, work with screen readers, and appear in exports. html trades all of that for freedom of layout.

Limits

The Agent Analytics viewer rejects oversized artifact payloads instead of rendering partial data. Your SDK or exporter can impose smaller limits or truncate content before ingestion. Check the complete serialized content field, including the envelope, escaping, and sibling fields. If a snapshot exceeds a limit, report the failure and preserve the underlying event without the oversized snapshot. Don't truncate the snapshot to make it fit.

Privacy

You control what artifact content you send to Amplitude, including raw HTML, attributes, CSS, and inline SVG. Select source data approved for analytics capture and preserve your application's resource permissions and exclusions. Viewer validation and sandboxing protect rendering; they don't remove sensitive data before ingestion.

AI SDKs

Artifact envelopes use the same content-capture and redaction settings as other tool content and message attachments. Use the existing tracking methods and configured redaction pipeline. Don't call private SDK helpers or add a second redaction pass. Modes such as metadata_only and customer_enriched omit content bodies, so artifacts don't render.

SDK redaction applies configured patterns and callbacks to strings. It's best-effort and doesn't interpret browser rendering. For example, an email split across HTML elements or encoded in CSS may remain in the payload. Sending an HTML artifact doesn't establish that its contents are free of sensitive data. Redaction settings don't add an HTML-specific omission policy.

Configured redactors can also change markup or serialized JSON. Use synthetic fixtures to check the actual outbound envelope for parseability and fidelity. Select or mask excluded source values before constructing HTML, while preserving the normal SDK redaction configuration. No artifact-specific HTML preparation API is required. Check your installed SDK's tracking methods and transport limits.

HTTP, OTLP, and imports

HTTP, OTLP, Batch, S3, and warehouse imports don't inherit AI SDK privacy settings. Apply your source pipeline's capture, exclusion, and redaction policy before data leaves the source. Follow the non-SDK privacy guide and the procedure for your integration.

Raw HTML has the same producer-owned content boundary on every path. An external pipeline doesn't need an artifact-specific SDK helper. Existing source redactors still apply, with the same limits of string matching. A successful event-schema or artifact validation check doesn't prove that the payload contains no sensitive data. Verify your policy against the final exported content, including other attributes and error text.

Troubleshooting

これは役に立ちましたか?