Telltale Bot

Install guide

Install Telltale Bot

Telltale Bot is one tag. You put it on every page of your site, and it tells you whether each visitor is a person, an AI agent acting for a person, or a bot.

You need a login for the Telltale Bot viewer at app.telltale.bot. Each site has its own tag, so install the tag you copy for that site and no other.

1. Copy your tag

The tag is filled in for your site. Paste it as it is. Its settings look like this:

var CONFIG = {
  script: 'https://js.ttbcdn.net/v2/telltale.js',
  server: 'https://in.ttbcdn.net',
  path: '/c/YOUR_PATH',
  key: 'YOUR_SITE_KEY',
  dataLayer: 'dataLayer'
};

The key names your site. Anyone who reads your page can see it, and that is expected: it is not a password. If your login can see all of your account's sites, you may also see + Add a site on Sites. It creates a new site with its own tag.

2. Install it

Use one of the ways below, not two. If the tag runs twice on a page, the first copy does the work and the second does nothing.

Directly in the page (recommended). Paste the tag into the <head> of every page, as high as you can, before other scripts. This measures more visitors: ad and tracker blockers often block Google Tag Manager, and a tag in the page still runs for those visitors. It also starts earlier, so it sees more of the visit.

Through Google Tag Manager. GTM is easier to set up if you already use it.

Using GA4 too? Import a container instead. Installation in the viewer offers a GTM container for your site: the tag as a Custom HTML tag, with your site's values and the options you chose there, plus what the GA4 recipe sets up by hand (a trigger on the verdict, a variable for each of its fields and a tag that sends the verdict to GA4). It needs your GA4 Google tag in the same container.

Or with our GTM tag template. It is the same tag as a form in GTM, for containers that do not allow Custom HTML tags or teams that prefer templates. Download the template and fill in its fields from your tag.

The template may only load our script from js.ttbcdn.net. If you set up your own script hostname (custom domain), add the new hostname under the template's Permissions, Injects scripts. Without that, the tag stops and says why in the browser's console during GTM Preview.

For the member ID (see Member accounts), the template reads a cookie or a GTM variable. If your site keeps the ID in JavaScript, make a GTM variable that gives it, a JavaScript Variable or, for anything longer, a Custom JavaScript variable, and choose it under From a GTM variable. The template reads the variable once, when the tag fires, so a member who signs in without the page reloading is counted from their next page. The Custom HTML tag reads the ID at every report.

Through another tag manager. The tag is a single <script> element, so a tag manager that takes HTML (a custom HTML or custom code tag) takes it as it is. One that takes JavaScript only, such as Tealium iQ, takes what is between its two script tags.

addEventListener('telltale:verdict', function (e) {
  if (window.utag && utag.link) utag.link({
    tealium_event: 'telltale_verdict',
    telltale_actor: e.detail.actor,
    telltale_agent_id: e.detail.agentId,
    telltale_confidence: e.detail.confidence
  });
});

The tag loads its script in the background, after your page. It is built not to slow your page down, it changes nothing visible on it, and it sets no cookies. It lets the browser connect to our server while the script downloads, so the verdict comes sooner on a visitor's first page (see A faster first verdict).

3. Check that it works

What the tag adds to the dataLayer

When our server answers, the tag pushes the verdict to your page's dataLayer (and fires the page events). To keep it out of your dataLayer, set dataLayer: null in the tag's settings. For a visit from Claude in Chrome, for example:

{
  "event": "telltale.verdict",
  "telltale": {
    "actor": "agentic",
    "agentId": "claude-extension",
    "confidence": "high",
    "declared": false
  }
}

There are two events. Each has a dataLayer name for GTM and a matching page event for scripts on the page, and both carry the same fields:

dataLayer eventPage eventWhen it comes
telltale.verdict telltale:verdict Once per pageview, when our server answers: usually well under a second after the page loads. If our server can't be reached, nothing fires.
telltale.verdict-update telltale:verdict-update Only when the verdict changes while the visitor is still on the page. AI agents mostly show themselves when they act, so the tag checks again about two seconds after the first click or keypress. Most pages have none.

The verdict covers the visit so far (one browser tab), not only the current page. By default each event carries four fields:

Before each event the tag pushes { telltale: null }. That clears the previous values, because GTM merges pushes together.

To act on the verdict in GTM, trigger your tags on the telltale.verdict event, not on the page view. A tag that fires on the page view runs before the verdict is there.

Without GTM: the page events

The tag also tells the page itself, so any script can use the verdict without GTM. It fires telltale:verdict and telltale:verdict-update on window, at the same moments as their dataLayer events (see the table above), with the same fields in event.detail. They fire whether or not the dataLayer push is on.

Telltale.verdict always holds the latest verdict, so a script that starts after the event can still read it:

function useVerdict(v) {
  if (v.actor !== 'human') { /* e.g. skip an ad call, flag a form */ }
}
if (window.Telltale && Telltale.verdict) useVerdict(Telltale.verdict);
addEventListener('telltale:verdict', function (e) { useVerdict(e.detail); });
addEventListener('telltale:verdict-update', function (e) { useVerdict(e.detail); });

The names use a colon on purpose: jQuery reads a dot in an event name as a namespace, so $(window).on('telltale:verdict', …) works where a dotted name would not.

More fields: data layer fields

The default is the verdict alone. Every script on the page can read the verdict, so it never carries the evidence behind a verdict or anything that identifies a visitor. You can add more fields in the viewer: Site settings, then Data layer fields. They go with every copy of the verdict: the dataLayer push, the page events and Telltale.verdict.

A field with no value for a visitor is left out. Field names never change once they are offered, so your GTM variables keep working.

Sending the verdict to GA4 and other analytics tools

Recipes for GA4 (with GTM or gtag.js), Plausible, Matomo, Piano Analytics, PostHog, Mixpanel, Amplitude, Segment and other tools are on their own page: Send the verdict to your analytics.

Signed-in members: the Member accounts tab

If your site has member accounts, the tag can send your own ID for the signed-in member. The Member accounts tab then shows, per member, how many pageviews were automated (a member scraping through a paid account) and how many devices and networks used the account at once (account sharing). Turn the tab on under Account settings › Add-ons; the site's Installation page then has an option to set where the tag finds the ID.

The member ID is used only to group pageviews in your reports; it never changes a verdict and never goes to the dataLayer. On the All traffic tab, search account: and the ID to see that member's visitors; Site settings, then Delete, can erase everything stored for a member. Say in your privacy notice that you send your members' IDs to us for security.

Your own hostnames (optional)

The tag can load the script and send reports through hostnames on your own domain instead of ours. It takes two: one for reports, such as tt.example.com, and one for the script, such as tt-cdn.example.com, which our CDN serves.

  1. In Telltale Bot, open Site settings, then Custom domain, and add both hostnames.
  2. At your DNS provider, add a CNAME record for each: the reports hostname with the target in.ttbcdn.net, the script hostname with the target js.ttbcdn.net.
  3. When Custom domain shows Ready (we issue the certificates, usually within a few minutes of the records showing up), copy the tag again from Installation. It now uses your hostnames, each as soon as it is ready. The old tag keeps working, so there is no rush.

Important: the records must be DNS CNAMEs to our hostnames only, not a proxy.

Use CNAMEs, not A records with our addresses, as our IPs may change. To stop using a hostname, put the tag back first, then remove the hostname: reports sent to a removed hostname are refused, and a removed script hostname stops serving the script.

A faster first verdict

Before it loads its script, the tag adds this to the page's <head>, with your tag's server as the host:

<link rel="preconnect" href="https://in.ttbcdn.net" crossorigin>

It lets the browser open its connection to our server while the script downloads, so on a visitor's first page the verdict doesn't wait for that connection. It downloads nothing and changes nothing visible on the page. Later pages reuse the connection, so it only speeds up the first one: for visitors in Europe, by up to about a quarter of a second.

Content Security Policy

If your site sends a Content Security Policy, allow our two hosts:

With your own hostnames, allow your script hostname in script-src and your reports hostname in connect-src instead.

With the tag directly in the page and a policy that blocks inline scripts, the tag's <script> also needs your nonce or a hash. A nonce is easier: a hash changes whenever you edit the tag's settings. Through GTM, Custom HTML tags need what GTM's own instructions for Content Security Policy say.

If your policy uses 'strict-dynamic', the nonced tag is trusted to load our script, and browsers that support 'strict-dynamic' ignore the https://js.ttbcdn.net source. Keep it anyway for browsers that don't.

If your policy requires Trusted Types (require-trusted-types-for 'script'), the tag's line s.src = CONFIG.script needs a policy that allows script URLs on https://js.ttbcdn.net. Create one in your own code (for example a default policy whose createScriptURL passes that host and rejects others), and list its name in trusted-types if you restrict policy names.

Nothing else is needed: the script uses no eval, workers or blob URLs, sets no cookies, and loads no images, fonts or frames from anywhere.

Good to know

The tag sets no cookies. It keeps a random tab ID in the browser's session storage, which is deleted when the tab closes. If you set account, it also reads that one cookie of yours and sends the member ID. It reads details of the browser and of how the page is used (never what is typed), and our server looks up the visitor's IP address. Our privacy page lists everything that is collected.

Our recommendation: run it on every page, before consent, as a security measure. Under the GDPR, the legal basis is your legitimate interest in security and fraud prevention, which the regulation names itself (Recitals 47 and 49).

In the EU, the EEA and the UK, a second rule applies (ePrivacy Article 5(3); PECR in the UK). Reading information from a visitor's device needs consent unless it is strictly necessary for the service the visitor asked for, with or without cookies. Bot and fraud protection is commonly run under that exception, before consent, and we think Telltale Bot qualifies. To run it before consent:

Running it only after consent mostly defeats it. Automation seldom accepts a consent banner: most bots never answer it, and AI agents acting for a person tend to decline it. So after consent the tag measures the visitors who accepted, mostly people, and misses most of the automation it is there to find. If your consent tool holds back Google Tag Manager itself, install the tag directly in the page so it runs before the banner.

Outside the EU, the EEA and the UK, most privacy laws ask you to disclose security processing like this rather than get consent first: name it in your privacy policy. This is our position, not legal advice. The decision is yours, for your site and for where your visitors are.

Before you rely on it

Telltale Bot is in beta. Read what Telltale Bot misses: the visits it never sees, and the people it can mistake for automation. Once reports arrive, Reading your reports explains the viewer. Questions about installing it: support@telltale.bot.