{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-@l10n/es-ES/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["tabs","tab"]},"type":"markdown"},"seo":{"title":"Track and Measure Agent Behavior on the XRP Ledger","siteUrl":"https://xrpl.org/","llmstxt":{"hide":false,"title":"XRPL Developer Portal & Documentation","description":"Explore XRP Ledger documentation, blogs, and other blockchain developer resources needed to start building and integrating with the ledger.","details":{"content":"XRP Ledger concepts, use cases, tutorials, references, and other blockchain developer resources. Also, stay up to date with release announcements and more through the XRPL Blog."},"sections":[{"title":"Introduction","description":"A high-level introduction to the XRP Ledger.","includeFiles":["docs/introduction/**/*.*","about/faq.md"],"excludeFiles":["docs/introduction/index.md"]},{"title":"Use Cases","description":"Real-world applications and business scenarios for the XRP Ledger.","includeFiles":["docs/use-cases/**/*.*"],"excludeFiles":["docs/use-cases/index.md","docs/use-cases/defi/index.md"]},{"title":"Agentic Transactions","description":"XRPL AI Starter Kit to help autonomous agents discover, set up, and execute agentic transactions on the XRP Ledger.","includeFiles":["docs/agents/**/*.*"],"excludeFiles":[]},{"title":"Concepts","description":"Core concepts including accounts, tokens, transactions, consensus, and more.","includeFiles":["docs/concepts/**/*.*"],"excludeFiles":["docs/concepts/index.md","docs/concepts/decentralized-storage/index.md","docs/concepts/payment-types/index.md"]},{"title":"Tutorials","description":"Step-by-step guides for building on the XRP Ledger in JavaScript, Python, Go, and more.","includeFiles":["docs/tutorials/**/*.*"],"excludeFiles":[]},{"title":"References","description":"Protocol specification, transaction types, ledger entries, and API methods.","includeFiles":["docs/references/**/*.*"],"excludeFiles":["docs/references/xrp-api.md","docs/references/data-api.md","docs/references/protocol/index.md","docs/references/protocol/ledger-data/ledger-entry-types/index.md","docs/references/protocol/transactions/index.md","docs/references/protocol/transactions/types/index.md","docs/references/http-websocket-apis/api-conventions/index.md","docs/references/http-websocket-apis/public-api-methods/*/index.md","docs/references/http-websocket-apis/admin-api-methods/*/index.md"]},{"title":"Infrastructure","description":"Install, configure, and troubleshoot rippled and Clio servers.","includeFiles":["docs/infrastructure/**/*.*"],"excludeFiles":["docs/infrastructure/index.md","docs/infrastructure/*/index.md","docs/infrastructure/installation/build-run-rippled-in-reporting-mode.md","docs/infrastructure/configuration/data-retention/index.md","docs/infrastructure/configuration/server-modes/index.md"]},{"title":"Blog (2023+)","description":"Recent XRPL Blog posts (showing 2023 and newer).","includeFiles":["blog/2023/**/*.*","blog/2024/**/*.*","blog/2025/**/*.*","blog/2026/**/*.*"],"excludeFiles":[]},{"title":"Resources","description":"Developer resources and contribution guidelines.","includeFiles":["resources/**/*.*"],"excludeFiles":["resources/index.md"]}],"excludeFiles":[]},"description":"Use SourceTag, Memos, and WebSocket monitoring to attribute, audit, and react to agent-generated transactions on the XRP Ledger. Applies to all XRPL agentic workflows — payments, trading, escrow, and more.\n"},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"track-and-measure-agent-behavior","__idx":0},"children":["Track and Measure Agent Behavior"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When an agent transacts on the XRP Ledger, its activity is permanently recorded"," ","on a public ledger. That is a feature, not a side effect — but only if you"," ","design for it. Without attribution, an agent's transactions are indistinguishable"," ","from human-initiated ones. You cannot answer basic operational questions: how"," ","many transactions did the agent send today? Which workflow triggered this"," ","payment? Did the agent act within the boundaries you set?"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The XRP Ledger provides two lightweight fields that turn the ledger into a"," ","queryable audit trail: ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SourceTag"]}," for attribution, and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Memos"]}," for structured"," ","metadata. A third mechanism — WebSocket event subscriptions — lets an agent or"," ","monitoring process react to on-chain activity in real time. Used together, they"," ","give you a complete picture of agent behavior directly from the on-chain record,"," ","independent of application logs that can be lost, rotated, or tampered with."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["These patterns apply to every agentic workflow on the XRP Ledger — payments,"," ","trading, escrow, and any domain skill built on the shared Wallet skill."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"sourcetag--agent-attribution","__idx":1},"children":["SourceTag — agent attribution"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Every XRP Ledger transaction supports a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SourceTag"]}," field: a 32-bit unsigned integer that identifies the originating application or workflow. The XRPL Agent Wallet skill applies a default SourceTag (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["20260530"]},") automatically to every transaction that passes through the signing ceremony — you do not need to set it manually. All domain skills (Payments, and future skills) are tagged consistently without any per-skill configuration."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To use a custom value — for example, to distinguish transactions from different agents in the same deployment — set ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SourceTag"]}," on the transaction object before passing it to the Wallet skill. The skill respects any value already present and only applies the default when the field is absent. Setting ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SourceTag"]}," to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["0"]}," explicitly suppresses the default."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"from xrpl.models.transactions import Payment\nfrom xrpl.utils import xrp_to_drops\nfrom xrpl.transaction import submit_and_wait\n\n# Override only when you need a custom tag — the Wallet skill sets\n# 20260530 automatically when SourceTag is absent.\nCUSTOM_SOURCE_TAG = 99991234  # your team's registered value\n\npayment = Payment(\n    account=wallet.address,\n    amount=xrp_to_drops(10),\n    destination=DESTINATION,\n    source_tag=CUSTOM_SOURCE_TAG,\n)\nresponse = submit_and_wait(payment, client, wallet)\nprint(f\"Hash: {response.result['hash']}\")\n","lang":"python"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"js","header":{"controls":{"copy":{}}},"source":"// Override only when you need a custom tag — the Wallet skill sets\n // 20260530 automatically when SourceTag is absent.\nconst CUSTOM_SOURCE_TAG = 99991234; // your team's registered value\n\nconst result = await client.submitAndWait(\n  {\n    TransactionType: 'Payment',\n    Account: wallet.classicAddress,\n    Amount: xrpl.xrpToDrops('10'),\n    Destination: DESTINATION,\n    SourceTag: CUSTOM_SOURCE_TAG,\n  },\n  { wallet }\n)\nconsole.log('Hash:', result.result.hash)\n","lang":"js"},"children":[]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The default tag (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["20260530"]},") lets you filter all XRPL AI Starter Kit agentic transactions on-chain using any XRPL data API or block explorer, across every domain skill. Use a custom tag when you need per-agent or per-deployment attribution beyond the default."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"memos--structured-on-chain-metadata","__idx":2},"children":["Memos — structured on-chain metadata"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Memos"]}," field carries arbitrary structured metadata alongside every"," ","transaction. Where ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SourceTag"]}," answers \"which agent sent this?\", Memos answer"," ","\"why, in what context, and as part of which task?\" Combining the two gives you"," ","a correlation key between your application logs and the on-chain record."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Memo values must be hex-encoded. The pattern below encodes a JSON payload that"," ","links each transaction to a specific agent, session, action, and task ID."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"import json\nfrom xrpl.models.transactions import Payment\nfrom xrpl.models.transactions.transaction import Memo\nfrom xrpl.utils import xrp_to_drops\nfrom xrpl.transaction import submit_and_wait\n\ndef build_memo(agent_id: str, session_id: str, action: str, task_id: str) -> Memo:\n    payload = json.dumps({\n        \"agent_id\":   agent_id,\n        \"session_id\": session_id,\n        \"action\":     action,\n        \"task_id\":    task_id,\n    }, separators=(\",\", \":\"))\n    return Memo(memo_data=payload.encode().hex().upper())\n\npayment = Payment(\n    account=wallet.address,\n    amount=xrp_to_drops(25),\n    destination=DESTINATION,\n    source_tag=CUSTOM_SOURCE_TAG,\n    memos=[build_memo(\n        agent_id=\"invoice-agent-v1\",\n        session_id=\"sess-abc123\",\n        action=\"pay_invoice\",\n        task_id=\"inv-00789\",\n    )],\n)\nresponse = submit_and_wait(payment, client, wallet)\nprint(f\"Hash: {response.result['hash']}\")\n","lang":"python"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"js","header":{"controls":{"copy":{}}},"source":"function buildMemo(agentId, sessionId, action, taskId) {\n  const payload = JSON.stringify({\n    agent_id: agentId, session_id: sessionId, action, task_id: taskId,\n  });\n  return { Memo: { MemoData: Buffer.from(payload).toString('hex').toUpperCase() } };\n}\n\nconst result = await client.submitAndWait(\n  {\n    TransactionType: 'Payment',\n    Account: wallet.classicAddress,\n    Amount: xrpl.xrpToDrops('25'),\n    Destination: DESTINATION,\n    SourceTag: CUSTOM_SOURCE_TAG,\n    Memos: [buildMemo('invoice-agent-v1', 'sess-abc123', 'pay_invoice', 'inv-00789')],\n  },\n  { wallet }\n)\nconsole.log('Hash:', result.result.hash)\n","lang":"js"},"children":[]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To decode memos from a fetched transaction:"]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"import json\n\ndef decode_memo(memo_hex: str) -> dict:\n    return json.loads(bytes.fromhex(memo_hex).decode(\"utf-8\"))\n\nfor entry in response.result.get(\"Memos\", []):\n    data = decode_memo(entry[\"Memo\"][\"MemoData\"])\n    print(data)\n    # {\"agent_id\": \"invoice-agent-v1\", \"session_id\": \"sess-abc123\", ...}\n","lang":"python"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"js","header":{"controls":{"copy":{}}},"source":"function decodeMemo(memoHex) {\n  return JSON.parse(Buffer.from(memoHex, 'hex').toString('utf8'));\n}\n\nfor (const entry of result.result.Memos ?? []) {\n  console.log(decodeMemo(entry.Memo.MemoData));\n  // { agent_id: 'invoice-agent-v1', session_id: 'sess-abc123', ... }\n}\n","lang":"js"},"children":[]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Security note:"]}," The XRPL Agent Wallet skill decodes memos on incoming transactions for display only. Memo contents are never treated as instructions to the agent — this is a prompt-injection guard. Never write code that acts on memo contents without first routing the action through the full signing ceremony."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"websocket-monitoring--react-to-on-chain-events","__idx":3},"children":["WebSocket monitoring — react to on-chain events"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The XRP Ledger's WebSocket API lets an agent — or a dedicated monitoring"," ","process — subscribe to an account's transactions in real time. This is the"," ","right pattern for triggering downstream agent steps when an incoming payment"," ","arrives, an escrow completes, or any other account event occurs."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"Python","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"import asyncio\nimport json\nimport websockets\n\nTESTNET_WS = \"wss://s.altnet.rippletest.net:51233\"\n\nasync def monitor_account(address: str):\n    async with websockets.connect(TESTNET_WS) as ws:\n        await ws.send(json.dumps({\n            \"command\":  \"subscribe\",\n            \"accounts\": [address],\n        }))\n        print(f\"Subscribed to transactions for {address}\")\n\n        async for message in ws:\n            event = json.loads(message)\n            if event.get(\"type\") == \"transaction\":\n                tx   = event.get(\"transaction\", {})\n                meta = event.get(\"meta\", {})\n                if meta.get(\"TransactionResult\") == \"tesSUCCESS\":\n                    print(f\"Confirmed: {tx.get('TransactionType')} | {tx.get('hash')}\")\n                    # Trigger your agent's next step here.\n\nasyncio.run(monitor_account(wallet.address))\n","lang":"python"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"JavaScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"js","header":{"controls":{"copy":{}}},"source":"const xrpl = require('xrpl')\n\nasync function monitorAccount(address) {\n  const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')\n  await client.connect()\n\n  await client.request({ command: 'subscribe', accounts: [address] })\n  console.log(`Subscribed to transactions for ${address}`)\n\n  client.on('transaction', (event) => {\n    if (event.meta?.TransactionResult === 'tesSUCCESS') {\n      console.log(`Confirmed: ${event.transaction.TransactionType} | ${event.transaction.hash}`)\n      // Trigger your agent's next step here.\n    }\n  })\n}\n\nmonitorAccount(wallet.classicAddress)\n","lang":"js"},"children":[]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For production deployments, run the monitoring process separately from the"," ","agent process so a crashed agent does not stop telemetry collection. Persist"," ","the event stream to your logging infrastructure alongside the decoded memo"," ","payload for a complete, correlated audit trail."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"where-to-go-next","__idx":4},"children":["Where to go next"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/agents/getting-started-with-agentic-transactions/"},"children":["Get Started with Agentic Transactions"]}," —"," ","Install the skills and send your first payment."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/agents/xrpl-agent-wallet-skill/"},"children":["The XRPL Agent Wallet Skill"]}," —"," ","How the Wallet skill handles memos on incoming transactions as untrusted input."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/agents/xrpl-payments-skill/"},"children":["The XRPL Payments Skill"]}," —"," ","Full reference for payment patterns, including ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SourceTag"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Memos"]}," in context."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/docs/agents/agentic-payments-x402/"},"children":["Agentic Payments with X402"]}," —"," ","Apply these telemetry patterns to machine-to-machine HTTP payment flows."]}]}]},"headings":[{"value":"Track and Measure Agent Behavior","id":"track-and-measure-agent-behavior","depth":1},{"value":"SourceTag — agent attribution","id":"sourcetag--agent-attribution","depth":2},{"value":"Memos — structured on-chain metadata","id":"memos--structured-on-chain-metadata","depth":2},{"value":"WebSocket monitoring — react to on-chain events","id":"websocket-monitoring--react-to-on-chain-events","depth":2},{"value":"Where to go next","id":"where-to-go-next","depth":2}],"frontmatter":{"seo":{"title":"Track and Measure Agent Behavior on the XRP Ledger","description":"Use SourceTag, Memos, and WebSocket monitoring to attribute, audit, and react to agent-generated transactions on the XRP Ledger. Applies to all XRPL agentic workflows — payments, trading, escrow, and more.\n"},"labels":["AI","Agents","Observability","Payments"]},"editPage":{"to":"https://github.com/XRPLF/xrpl-dev-portal/tree/master/docs/agents/track-agent-behavior.md"},"lastModified":"2026-06-08T21:36:05.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/es-es/docs/agents/track-agent-behavior","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}