Back to Blog

A WebRTC stats API for AI agents: what we changed

How we split our WebRTC stats API for AI agents: a 2 KB enrich answer next to the full analyze record, and which endpoint to call.

Posted by

A WebRTC stats API for AI agents: a woodblock robot hand takes a short stack of cards while a long tangled scroll of payload spills away behind it

Let's face it. You likely haven't read a lot of the lines of code you deployed in the past couple of months. And if we're honest with ourselves, most of you haven't really looked directly at a webrtc-internals file. Or other logs you're collecting for that matter.

And why is that? Because we now delegate a lot of that Sisyphean work to AI agents. I am sure this is something all developer-facing vendors are now experiencing - their direct users are no longer human - they're AI agents. Which is why at rtcStats we've decided to be extra helpful to our new set of users.

Here's what we did in the last couple of versions - a trend we're doubling down on moving forward even more.

The short version of a WebRTC stats API for AI agents: call POST /v1.0/enrich when an agent needs the answer, and POST /v1.0/analyze when you need the full record.

What we had: an API shaped like a screen

The rtcStats API returned what our session viewer needed. For a long time the session viewer was the main thing calling it. It returned every peer connection, every candidate pair, every stream with its timeline, three internal version fields, and aggregatedStats keys with no unit in their name. For a person looking at a rendered page, that works. The page adds the units, hides the fields nobody reads, and puts the important number in large type. The JSON underneath was built for storage and for drawing, and it did both jobs well.

Our human users endured - they integrated with the API, usually had a bit of a back and forth with us, and then things worked well for them.

At some point, the callers changed. As the v2.0 release notes put it, "more often than not, the first 'eyes' on a bug is an AI agent instead of a human." An agent reads the raw payload with nothing drawn on top of it, so every choice the UI used to smooth over becomes the agent's problem. And that problem grew bigger for our first-tier clients - the AI agents.

What a machine reader pays for

Here's what I learned myself the hard way. That was back when I started off with Claude and used its puny Pro $20/month plan. I asked it to go fetch me all the sessions in my rtcStats account (less than 20 if I recall correctly - these were mainly the showcase ones), via our MCP (which was pre-beta at the time) and the API, to compare a couple of things I wanted to look at.

Guess what? It used up all of its tokens before it finished and parked me on the sideline for 4.5 additional hours 🤬

I've grown my Claude account since then. And learned how to use context and tokens a lot more. But the lesson was learned. Our API and its payload weren't AI-friendly. So we initiated an internal project that I called "AI friendliness" in an effort to be an AI agent's best friend when it comes to WebRTC troubleshooting and observability.

Why mention it now? Because we're the friendliest of the bunch already, and we're only going to get better moving forward, so it is time to brag about it.

Storage JSON and agent JSON are different jobs

One of the first things we decided was to split the payloads we serve:

  • POST /v1.0/analyze keeps the full record, the same data object you get for a stored session.
  • POST /v1.0/enrich answers the question: scores, per-severity counts, flat observation records and the user-agent data, and the session is never stored.

Both API calls take the same dump, and both cost one credit.

I measured the difference on one real session on our staging API, prior to the release: a Chrome 143 call of 1 minute 45 seconds, a 1.5 MB dump. Minified, analyze returned 46,539 bytes of JSON. enrich on the same dump returned 2,300 bytes, about 5% of it. More than half of the analyze payload, about 25 KB, is the transports section. Longer calls carry more transport and stream data, and that data lives in analyze.

POST /v1.0/analyzePOST /v1.0/enrich
ReturnsThe full session recordScores, severity counts, flat Observations, user-agent data
StoredOnly with ?save=trueNever
Our test session, minified46,539 bytes2,300 bytes
CostOne creditOne credit
PlanDeveloper plan and aboveDeveloper plan and above

Here is the top of that enrich response, cut down to the scores and one of its 12 observations:

{
  "data": {
    "scores": {
      "experienceScore": 78.09,
      "audioScore": 4.66,
      "videoScore": 4.21,
      "connectivityScore": 4.15,
      "observationsScore": 26
    },
    "observationsCount": { "critical": 0, "high": 0, "medium": 3, "low": 5, "info": 4 },
    "observations": [
      {
        "type": "bufferbloat",
        "severity": "medium",
        "category": "streams",
        "tags": ["inbound", "audio", "network"],
        "firstSeenAt": 1768118095750,
        "durationInPercent": 27.88
      }
    ]
  }
}

An agent reads that as bufferbloat on inbound audio for about 28% of the time, at medium severity, with nothing to decode. If it does not know what bufferbloat means, one more call explains it. The knowledge base explains what Observations are; the explanation of each type is in the app and at GET /v1.0/observations/{type}.

This lets an AI agent explore WebRTC call sessions with ease, without losing any context and with real access to what went on in the session. Results are quicker, more focused and accurate - and they consume a lot fewer tokens.

Which endpoint to call

We used to have a single POST /v1.0/analyze API call, and now there are a few more calls. Here's when to use each, via API or MCP:

  • The agent needs to know what went wrong on a call: POST /v1.0/enrich.
  • You need the full record, with streams, transports and timelines: POST /v1.0/analyze, with ?save=true to store it.
  • The session is already stored: GET /v1.0/sessions/{rtcstatsId} or the MCP get_session tool.
  • The agent meets an Observation type it does not know: GET /v1.0/observations/{type} or get_observation_explanation.
  • The agent should only read: give it a read-only token.

Is the enrich endpoint free? No. POST /v1.0/enrich is on the Developer plan and above and costs one credit per dump, like analyze. The self-hosted rtcstats-enrichment server is not part of the open-source rtcstats-js and rtcstats-server trees; contact us for access. If you want enrichment next to your own database, enrich your own sessions walks through it.

I invite you and your AI agent to come use our service for WebRTC debugging and monitoring. Start with the quickstart in llms.txt, or connect your agent to our MCP server.