# Intelligent Bot Classification Transformation Template

<p>You can now classify bot traffic by <strong>intent</strong> using the Intelligent bot classification <a href="https://www.rudderstack.com/docs/transformations/templates/" >transformation template</a>. It asks two separate questions about every event it evaluates — what produced the event, and whether the event looks like abuse.</p>

<blockquote class="warning">
  <div class="tip-quote">
    
    <div class="tip-text">This template sends event-derived signals to <strong>TypeSafe AI</strong>, a third-party service, and needs an API key you supply. Review that data transfer, and the limitations below before you enable it.</div>
  </div>
</blockquote>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="why-classify-bots-by-intent">Why classify bots by intent?</h2><p>A single &ldquo;is it a bot?&rdquo; check gets two common cases wrong:</p>
<ol>
<li>A bot farm driving real browsers looks human but is abusive</li>
<li>An AI agent buying on a customer&rsquo;s behalf is a bot with legitimate intent, and real revenue attached</li>
</ol>
<p>Separating the category from the intent lets you drop the first case while keeping the second.</p>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="key-features">Key features</h2><ul>
<li><strong>Category and intent scored separately</strong>: <code>context.bot.category</code> returns one of <code>human</code>, <code>ai_agent</code>, <code>ai_crawler</code>, <code>search_crawler</code>, <code>seo_tool</code>, <code>scraper</code>, or <code>other_automation</code>, alongside a <code>badIntent</code> probability from 0 to 1.</li>
<li><strong>Shadow mode by default</strong>: The template tags events without dropping any, so you can compare verdicts against real traffic before you enforce.</li>
<li><strong>Output matches Bot Management</strong>: Writes <code>context.isBot</code> and <code>context.bot</code>, the same shape as <a href="https://www.rudderstack.com/docs/data-governance/bot-management/" >Bot Management</a>, so your downstream logic works unchanged.</li>
<li><strong>Scoped to events that matter</strong>: Evaluates <code>identify</code> plus a configurable list of high-value events, so you only spend a classification call where a bot costs you money.</li>
<li><strong>Configurable endpoint</strong>: Point the template at a different classifier, including one you host yourself.</li>
</ul>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="get-started">Get started</h2><ol>
<li>Add your API key as a secret named <code>TYPESAFE_API_KEY</code> under <strong>Settings</strong> &gt; <strong>Workspace</strong> &gt; <strong>Credentials</strong> &gt; <strong>Secrets</strong>. See <a href="https://www.rudderstack.com/docs/transformations/credentials/" >Transformation Credentials</a>.</li>
<li>Go to <strong>Collect</strong> &gt; <strong>Transformations</strong> and click <strong>Create Transformation</strong>.</li>
<li>Select the <strong>Intelligent bot classification</strong> template.</li>
<li>If you use Bot Management, set it to forward bot events with a flag rather than drop them, so those events still reach this template.</li>
<li>Leave <code>MODE</code> as <code>shadow</code> until the verdicts look right, then change it to <code>enforce</code> to start dropping events above <code>BAD_INTENT_THRESHOLD</code>.</li>
</ol>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="using-a-self-hosted-classifier">Using a self-hosted classifier</h2><p>The endpoint is a constant at the top of the template. Change <code>TYPESAFE_API_URL</code> to point at any service that accepts the same request shape and returns the same response shape, including self-hosted alternatives such as Laya or Kev.</p>
<p>Check the request and response contract before you switch. The template posts a <code>model</code>, a <code>state</code> object, and a <code>questions</code> object containing a <code>choice</code> question and a <code>noul</code> question, then reads <code>answers.kind.choice</code>, <code>answers.kind.confidence</code>, and <code>answers.bad_intent.noul</code> from the response. A service that does not match that contract needs the <code>askJev</code> function adjusted, not just the URL.</p>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="known-limitations">Known limitations</h2><ul>
<li><strong>Identity redaction is incomplete for non-ASCII text</strong>: The template sends the <em>pattern</em> of an email local part and a name rather than the values, but the pattern helper only substitutes ASCII letters and digits. Characters outside that range, including accented Latin, Cyrillic, and CJK, are sent unchanged. Do not treat this as full redaction for a non-ASCII user base.</li>
<li><strong>A <code>human</code> verdict overrides an inbound bot flag</strong>: When the classifier returns <code>human</code>, the template sets <code>context.isBot</code> to <code>false</code>, replacing any flag Bot Management already set on the event.</li>
<li><strong>The template appears on every plan, but needs Growth or Enterprise to work</strong>: It reads the API key with <code>getCredential</code>, which is available on the Growth and Enterprise plans only. On other plans it logs an error and leaves events unchanged.</li>
<li><strong>Event properties are not sent by default</strong>: <code>ALLOWED_PROPERTY_KEYS</code> is empty. Add only scrubbed, non-sensitive keys if the classifier needs them.</li>
</ul>
<!-- end-chunk -->
<!-- begin-chunk -->
<h2 id="resources">Resources</h2><ul>
<li><a href="https://www.rudderstack.com/docs/transformations/templates/" >Transformation Templates</a>: All prebuilt templates</li>
<li><a href="https://www.rudderstack.com/docs/transformations/credentials/" >Transformation Credentials</a>: Storing the API key as a secret</li>
<li><a href="https://www.rudderstack.com/docs/transformations/runtime-functions/" >Runtime Functions in Transformations</a>: <code>getCredential</code>, <code>fetchV2</code>, and <code>log</code></li>
<li><a href="https://www.rudderstack.com/docs/data-governance/bot-management/" >Bot Management</a>: User agent based detection to pair with this template</li>
</ul>

