Zum Hauptinhalt springen
Back to Blog
Actor Intelligence

Why Unknown is a valid result when classifying AI traffic

A classifier that always answers is guessing some of the time. Here is why Unknown belongs in every AI traffic model, and how to design your app around it.

Toshendra Sharma

By Toshendra SharmaFounder & CEO, AgentCredia · Published November 12, 2026

Why Unknown is a valid result when classifying AI traffic
November 12, 2026
10 min read
#Actor Intelligence#AI Agent Traffic#Classification#Application Security

Unknown is a valid result because some interactions do not carry enough evidence to classify reliably, and a classifier that always answers is guessing on exactly those. Keep Unknown as a first-class class next to Human, Human + AI and Agent, measure how often it appears on each route, and give every route an explicit fallback so uncertain traffic gets behavior you chose on purpose.

Every system that classifies traffic eventually faces the same temptation: give every request a label. A dashboard full of confident labels looks complete. A dashboard with a column of "Unknown" looks unfinished. That instinct is understandable, and it is wrong.

When you are trying to tell apart people, people working with AI assistance, and autonomous agents, there will always be interactions where the available evidence does not support a reliable answer. A well-designed classifier says so. This post explains why Unknown is a first-class result, what it actually tells you, and how to build application behavior around it. For the product view, see unknown automated traffic.

The problem with a classifier that always answers

Imagine two systems looking at the same stream of requests to your API.

The first system assigns every request to either Human or Agent. Some of those labels rest on strong evidence, such as a request signature that validates against a published key under RFC 9421. Others rest on weak evidence, such as a user-agent string, and some rest on almost nothing at all. In the dashboard, all of them look the same: a label and a row.

The second system assigns a label only when the evidence supports one, and otherwise returns Unknown. Its dashboard shows fewer confident labels, but each label means something, and the Unknown column tells you exactly where your visibility ends.

The first system feels more capable. The second is the one you can safely build on. When you later write a policy such as "route agents to the structured API" or "add review for automated account changes", the first system will apply that policy to requests it merely guessed about. The second applies it only where the evidence holds, and leaves the rest to a fallback you chose deliberately.

A forced label does not remove uncertainty. It hides it inside a decision.

Why some traffic is genuinely unknowable

Unknown results are not a sign that detection is immature. They follow from how the web works.

Many clients describe themselves however they like

A client that does not sign its requests describes itself however it likes. A user-agent header is a string the client chooses; HTTP defines it only as information about the user agent originating the request (RFC 9110). A client name declared over a protocol connection is a declaration too: the MCP specification says clientInfo is self-reported, not verified by the protocol, and should not be relied on for security decisions (MCP base protocol). Both are useful context, but neither proves anything on its own. A request that carries only a self-description and nothing else often does not support a confident class.

Integrations see only their own context

A server-side integration sees request context: headers, protocol details, timing, the route being called. It does not see a person's screen. A browser integration sees interaction on the pages where it runs. It does not see other tabs, other applications or another device. An MCP server sees the client's declared details and the tool calls it makes.

Each context has a boundary. Requests that arrive with little context, such as a call without browser signals, without a signature and without a meaningful declaration, can fall outside what any of these integrations can establish.

Humans and assistants blur together

When a person asks an assistant in another tab and pastes the answer into your form, ordinary web traffic usually shows a human-directed session, because a human directed it. When an agent drives a real browser, its traffic can resemble a person's. These are not edge cases you can engineer away. They are properties of the interaction itself, and a classifier that pretends otherwise is guessing.

Evidence goes stale

Evidence has a time and a scope. A signal observed at the start of a session says less about a sensitive action twenty minutes later. When fresh evidence is missing for the action that matters, the right answer for that action may be Unknown even if earlier steps were classified.

Unknown is information, not absence of information

It is tempting to read Unknown as "the system did nothing". In practice it carries three useful facts.

First, it tells you the evidence was insufficient for this interaction in this context. That is a precise statement about coverage, not a shrug.

Second, it tells you where to invest. If one route produces a high share of Unknown results, you know that route lacks the signals needed for a determination. You might add a browser integration to that page, ask a partner to sign their requests following the IETF Web Bot Auth work, or expose a structured endpoint that cooperating agents can identify themselves on. Our guide on verifying signed agent requests explains what to check once they do.

Third, it protects your decisions. Any policy you apply only to Human or Agent results is applied only where the evidence supports it. Everything else goes to a fallback you defined in advance, which is exactly where uncertain traffic belongs.

What Unknown must never mean

Two mistakes undo all of this.

Unknown is not Human

The most common shortcut is to treat anything that is not clearly automated as a person. It feels generous, and it quietly converts every coverage gap into a confident "Human" label. If you later grant human-only privileges, such as relaxed limits or skipped review, you have granted them to every client your integration could not see.

A safe system never assigns Human by default. If there is no evidence of human-directed interaction, the result is Unknown.

Unknown is not malicious

The opposite mistake is to treat Unknown as suspicious. Plenty of legitimate traffic arrives without rich signals: privacy-focused browsers, accessibility tools, server-to-server integrations, people on restrictive networks, and well-behaved crawlers that have not adopted signing. Blocking or challenging all of them punishes your users for the limits of your own visibility.

Unknown should route to a neutral fallback, chosen per route, that is appropriate for the risk of that route.

Designing around Unknown

Treating Unknown as a first-class result is mostly a design discipline. Four practices make it concrete.

1. Give every route an explicit fallback

For each route or workflow, decide in advance what happens when the result is Unknown. For a public pricing page, the answer is usually "serve the page as normal". For a password change, the answer might be "keep the existing re-authentication flow", which you already run regardless of actor classification. For a high-volume read API, it might be "apply the standard rate limit".

The key point is that the fallback is written down and owned by the application team, not improvised by a default somewhere in a library. Our guide on handling unknown traffic walks through choosing fallbacks route by route.

2. Keep the basis next to the class

A useful result carries both a class and the basis behind it: verified, declared, inferred or unknown. An Agent result backed by a validated signature and an Agent result inferred from request patterns should not be treated the same way in a security-sensitive workflow. When the basis travels with the class, your policies can be precise, and nobody mistakes an inference for a verification.

3. Track the unknown rate per route

Before you enforce anything, watch the share of Unknown results on each route over time. A falling unknown rate after you add a browser integration to a sign-up page tells you the integration is doing its job. A route where Unknown stays high is a route where enforcement based on actor class would mostly be enforcement based on guesses. That is a signal to keep observing, add evidence sources, or rely on other controls.

4. Treat timeouts as Unknown

If a classification call times out or the integration is unavailable, the result for that request is Unknown, and the route's fallback applies. Whether that fallback fails open (the request proceeds as it would without classification) or fails closed (your existing stronger check applies) is a choice you make per route and per risk tier. What must not happen is a timeout silently becoming a Human result.

A worked example

Consider a SaaS application with three routes.

  • GET /pricing: public, low risk.
  • GET /api/v1/catalog: a read-only API used by integrations and assistants, a common pattern on APIs.
  • POST /account/email: changes the email address on an account.

A sensible starting policy, written by the application team, might look like this:

TS
type ActorClass = "human" | "human_ai" | "agent" | "unknown";
type Basis = "verified" | "declared" | "inferred" | "unknown";

interface ActorResult {
  actor: ActorClass;
  basis: Basis;
}

type Action = "allow" | "structured_api" | "standard_limit" | "existing_checks";

function decide(route: string, result: ActorResult): Action {
  switch (route) {
    case "/pricing":
      // Public page: no actor-based decision at all.
      return "allow";

    case "/api/v1/catalog":
      if (result.actor === "agent" && result.basis === "verified") return "structured_api";
      // Declared, inferred and unknown callers get the normal limit.
      return "standard_limit";

    case "/account/email":
      // Sensitive action: existing re-authentication always applies.
      // The actor result is recorded for analysis, not used to relax checks.
      return "existing_checks";

    default:
      return "allow";
  }
}

Notice what this policy does not do. It does not block Unknown callers on the catalog API. It does not relax account checks for requests classified as Human. It only grants special handling where the evidence is strongest, and it lets Unknown fall through to behavior the team would have applied anyway.

That is the pattern to aim for: actor intelligence adds precision where evidence exists, and never removes protections where it does not.

Unknown and the people on the other side

There is a human reason to respect Unknown as well. When an application treats uncertainty as guilt, the cost lands on real people: someone using an accessibility tool, someone on a corporate network that strips headers, someone whose browser blocks scripts. When an application treats uncertainty as innocence, the cost lands on the application and on its users when an automated client is given privileges meant for people.

Neither outcome is acceptable for decisions that matter. That is why an inferred classification, on its own, should never decide something consequential about a person, such as access to an account, a job application or a financial product. Use actor results to shape experiences and to route traffic to the right interface. For consequential decisions, rely on the controls designed for them, and use actor context as one input your team can review.

How Proof of Actor handles Unknown

Proof of Actor treats Unknown as one of four public classes, alongside Human, Human + AI and Agent. Every result carries its basis, so a verified signature and a behavioral inference are always distinguishable. Unknown is never converted into Human, and it is never presented as suspicious.

The product is organized around three capabilities. Detect gathers the signals available to your integration and separates verified assertions from inferences. Understand shows trends, evidence and the unknown rate by route, so you can see exactly where your coverage ends. Route applies policies your team writes, with explicit fallbacks for Unknown and for timeouts. Teams start in observation mode, and the application owner decides if and when any policy is enforced.

If you want to see how the classes and their limits are defined, read Detection & Limitations and How It Works. If you operate an application, website, API or MCP server and want to understand who is using it, apply for early access.

Sources

Key Takeaways

  • Unknown is not a failure state. It is the honest output when the evidence available to an integration does not support a determination.
  • Forcing every interaction into Human or Agent hides your coverage gaps and turns guesses into decisions.
  • The unknown rate per route is one of the most useful numbers you can track before enforcing any policy.
  • Every route needs an explicit, app-defined fallback for Unknown, and Unknown should never silently become Human.