Marketing Pixel
Lightweight, no-code AI agent detection for analytics and marketing teams
Overview
The Checkpoint Marketing Pixel is a lightweight, no-code detection snippet that identifies AI agents and bots visiting your website. It loads asynchronously, has minimal impact on page performance, and installs via a simple script tag or your tag manager.
The Pixel is ideal for:
- Marketing teams who want bot traffic visibility without developer involvement
- Analytics teams who need to separate real users from automated traffic
- Content teams who want to monitor AI scraping activity
The pixel registers its JavaScript API on window.Checkpoint. The previous global
window.AgentShield and the agentshield:* events remain as deprecated aliases (both resolve
to the same object / both fire). The pixel writes two device-session cookies with identical
contents — checkpoint_user (canonical) and agentshield_user (legacy) — and reads whichever it
finds, so existing identities aren't lost. Read checkpoint_user; expect both on the wire.
Prerequisites
You'll need your Project ID before installing the Pixel — see Credentials for where to find it under Installations in your project dashboard.
Installation
Add the following script tag in your HTML <head> section:
<!-- Detect Pixel -->
<script>
(function () {
var as = document.createElement('script');
as.type = 'text/javascript';
as.async = true;
as.src = 'https://kya.vouched.id/pixel.js';
as.setAttribute('data-project-id', 'YOUR_PROJECT_ID');
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(as, s);
})();
</script>
<!-- End Detect Pixel -->Replace YOUR_PROJECT_ID with your Project ID (see Credentials). This is the exact snippet the dashboard generates for you.
Option A — Community Template (recommended). Install the official Checkpoint Pixel template once per container:
- Open the Checkpoint Pixel template in the GTM gallery (publisher: Know-That-Ai) — or in GTM go to Templates → Search Gallery and search Checkpoint (older gallery listings may still show the template's previous name, AgentShield, until Google syncs the rename)
- Click Add to Workspace, then Tags → New → Tag Configuration → Custom → Checkpoint Pixel, enter your Project ID, set Triggering to All Pages, and Save → Submit → Publish
Option B — Custom HTML tag. If your org disables community templates, use the same loader snippet the dashboard generates:
- Go to Tags → New → Tag Configuration → Custom HTML
- Paste the loader snippet:
<script>
(function () {
var as = document.createElement('script');
as.type = 'text/javascript';
as.async = true;
as.src = 'https://kya.vouched.id/pixel.js';
as.setAttribute('data-project-id', 'YOUR_PROJECT_ID');
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(as, s);
})();
</script>- Replace
YOUR_PROJECT_ID, set Triggering to All Pages, then Save → Submit → Publish
Both options report into the same project. With the Custom HTML tag you can set any of the
data-* options directly on the script tag; the Community Template exposes the
same options as configurable fields (all except data-require-consent).
Add the pixel to your layout or page using the Script component:
// app/layout.tsx
import Script from 'next/script';
export default function Layout({ children }) {
return (
<html>
<body>
{children}
<Script
src="https://kya.vouched.id/pixel.js"
data-project-id={process.env.NEXT_PUBLIC_CHECKPOINT_PROJECT_ID}
strategy="afterInteractive"
/>
</body>
</html>
);
}For server-side detection in Next.js, consider using the Middleware instead. The Pixel is client-side only.
How It Works
- The Pixel script loads asynchronously after your page renders
- It collects detection signals (user agent, headers, behavior, and — when enabled — a browser fingerprint)
- Signals are POSTed to the Checkpoint detection API (
POST /api/v1/pixel) - The result (classification + confidence) is logged to your project
- View results in the dashboard
The Pixel never blocks page rendering and adds no perceptible latency to the user experience.
Configuration
Project ID
Every Pixel installation requires a Project ID, set via data-project-id. See
Credentials for where to find it.
Script attributes
All options are set as data-* attributes on the script tag:
| Attribute | Default | Description |
|---|---|---|
data-project-id | Required | Your Checkpoint Project ID |
data-debug | false | "true" enables verbose console logging |
data-api-endpoint | <origin>/api/v1/pixel | Override the ingestion endpoint |
data-session-timeout | 1800000 | Session timeout in ms (30 minutes) |
data-respect-dnt | true | Honor the browser Do Not Track signal ("false" to disable) |
data-batch-size | 10 | Events per batch |
data-flush-interval | 5000 | Batch send interval (ms) |
data-enable-fingerprinting | true | Collect a browser fingerprint ("false" to disable) |
data-require-consent | false | GDPR: defer cookie storage until grantConsent() is called |
Custom Events
Send custom events with the window.Checkpoint.track method:
<script>
// Guard on the global — calls before pixel.js loads are lost (there is no queue)
window.Checkpoint &&
window.Checkpoint.track('form_submit', {
form_id: 'contact',
page: '/contact',
});
</script>JavaScript API
Once pixel.js loads, it exposes window.Checkpoint (and the deprecated alias window.AgentShield):
| Method / property | Description |
|---|---|
track(eventName, data?) | Send a custom event |
identify(userId, traits?) | Associate a user id (traits are sent server-side only, never stored in the cookie; rate-limited) |
getUser() | Returns { id } for the identified user, or null |
grantConsent() | Enable cookie storage after obtaining GDPR consent (see data-require-consent) |
reset() | Clear identity + cookie and start a fresh anonymous session (logout / GDPR) |
getSession() | Returns { id, startTime, duration, userId } |
getInitInfo() | Returns version/init diagnostics (useful for duplicate-load debugging) |
lastDetection | The most recent agent detection object. Unset until an agent is detected — human traffic never populates it |
window.Checkpoint.identify(userId, traits)
Identifies a user and associates them with the current session. Common uses:
- Unified Analytics: Sync user data between Checkpoint, Google Analytics, Amplitude, and other analytics platforms
- Personalized AI Responses: Track authenticated users' AI agent interactions
- Session Attribution: Connect unattributed AI sessions to known users when they log in
- Cross-Platform Tracking: Maintain user identity across different AI platforms and sessions
Important: This feature is for your customer-facing website, not the Checkpoint dashboard. The userId comes from your existing analytics (Amplitude, GA4, etc.), not from Checkpoint.
Parameters:
userId(string, required): Unique identifier for the usertraits(object, optional): Additional user properties
Important Notes:
- User ID is stored in cookies for persistent identification (requires user consent under GDPR)
- User traits (email, name, etc.) are sent to the server and NOT stored in cookies
- Call this method when users log in or when you want to identify a session
identify() enforces a 1-second minimum interval between calls. A call inside that window is
dropped (it returns without sending) and each successive violation doubles an internal backoff, up
to 10 seconds; the counter decays as soon as an allowed call goes through. Rate limiting is skipped
when data-debug="true" or on localhost, so a development run won't reproduce it.
Example:
window.Checkpoint.identify('user_123', {
email: 'john@example.com',
name: 'John Doe',
plan: 'premium',
company: 'Acme Corp',
});Privacy Note: User traits are sent to Checkpoint servers and stored in your database. Never send sensitive information like passwords or credit card numbers.
window.Checkpoint.getUser()
Returns the currently identified user or null if no user is identified.
Returns:
{
id: 'user_123';
}
// or null if not identifiedNote: User traits are not returned by this method (they're stored server-side only).
Example:
const user = window.Checkpoint.getUser();
if (user) {
console.log('Current user:', user.id);
} else {
console.log('No user identified');
}window.Checkpoint.reset()
Clears the current user identification and starts a new anonymous session. Call this when users log out.
What it does:
- Clears user ID from cookies
- Generates new session ID
- Generates new device ID
- Sends logout event to server
Example:
// On user logout
window.Checkpoint.reset();
console.log('User identification cleared');window.Checkpoint.track(eventName, data)
Track custom events for analytics and detection.
Parameters:
eventName(string, required): Name of the eventdata(object, optional): Additional event data
Example:
// Track form submission
window.Checkpoint.track('form_submit', {
form_id: 'contact-form',
page: window.location.pathname,
});
// Track button click
window.Checkpoint.track('button_click', {
button: 'pricing-cta',
plan: 'enterprise',
});Events
The pixel also dispatches window CustomEvents you can listen for:
| Event | detail |
|---|---|
checkpoint:detection | the detection result (isAgent, confidence, …). Fires only when an agent is detected, not on every pageview |
checkpoint:identify | { userId, traits, sessionId, deviceId } |
checkpoint:reset | { previousUserId, newSessionId } |
The legacy agentshield:detection / :identify / :reset events still fire as deprecated aliases.
What about bots and humans?
checkpoint:detection and lastDetection are gated on isAgent, which is true only for interactive AI assistants — ChatGPT, Claude, Perplexity. Bots (Googlebot, GPTBot, headless browsers) and humans classify with isAgent: false, so neither fires the event nor populates lastDetection. If you wire a GA4 forward off checkpoint:detection (as shown below), you are measuring AI-assistant traffic only, not all automation.
Every classification — agent, bot, and human alike — is still sent server-side and appears in the dashboard. Client-side, the pixel also records the last result to sessionStorage regardless of class:
// Written on every detection, not just agents.
const recent = JSON.parse(sessionStorage.getItem('checkpoint_recent_detection') || 'null');
// → { isAgent: boolean, isBot: boolean, confidence: number, timestamp: number }Read isBot there to react to crawler traffic on the client. (A duplicate agentshield_recent_detection key is written with identical contents for back-compat.)
checkpoint:identify fires when a user is identified, which is useful for syncing with other
analytics tools; checkpoint:reset fires when identification is reset (logout):
window.addEventListener('checkpoint:identify', (event) => {
console.log('User identified:', event.detail);
// event.detail contains: { userId, traits, sessionId, deviceId }
});
window.addEventListener('checkpoint:reset', (event) => {
console.log('User reset:', event.detail);
// event.detail contains: { previousUserId, newSessionId }
});For an end-to-end walkthrough of wiring identify() into your login flow, with framework patterns
for Next.js and React plus verification and troubleshooting, see the Identify Users
cookbook. To identify users via Google Tag Manager, see
the GTM + Next.js guide.
The pixel honors Do Not Track by default (data-respect-dnt) and auto-tracks SPA navigations
(History pushState/popstate/hashchange). It stores a device/session id in the
checkpoint_user cookie (deferred until grantConsent() when data-require-consent="true"). A
visitor with an existing agentshield_user cookie keeps their identity — that cookie is still
read.
Analytics Integration
Google Analytics 4
The pixel does not push to GA4 or the dataLayer on its own. Instead, listen for the checkpoint:detection event and forward it to GA4 yourself:
<script>
window.addEventListener('checkpoint:detection', function (e) {
var d = e.detail || {};
// Forward to GA4 (gtag must already be installed)
window.gtag &&
window.gtag('event', 'checkpoint_detection', {
is_agent: d.isAgent,
confidence: d.confidence,
});
});
</script>This lets you build GA4 audiences that exclude bot traffic and measure true conversion rates.
Pixel vs Beacon
| Feature | Pixel | Beacon |
|---|---|---|
| Installation | Script tag / GTM | npm package |
| Code required | None | Yes |
| Signal richness | Basic + fingerprint | Advanced |
| Event tracking | track() | trackEvent() |
| Web Worker | No | Yes |
| Bundle size | ≈5 KB gzipped, plus ≈4.5 KB for the fingerprint detector it loads when data-enable-fingerprinting is on (the default) | npm dependency |
| Best for | Marketing, analytics | Application integration |
For more advanced client-side collection, see the JavaScript Beacon.
Troubleshooting
Pixel Not Loading
- Check that the Project ID is correct
- Verify no ad blockers or content security policies are blocking the script
- Check the browser console for errors (set
data-debug="true")
No Detections in Dashboard
- Confirm the Pixel is loading (check the Network tab for
pixel.jsand aPOST /api/v1/pixel) - Verify the Project ID matches your dashboard project
- Check that GTM is published (if using GTM)
- If the visitor's browser sends Do Not Track, the pixel collects nothing unless you set
data-respect-dnt="false"
Content Security Policy
If your site uses CSP headers, add the Pixel domain to your script-src directive:
Content-Security-Policy: script-src 'self' https://kya.vouched.id;Next Steps
- Pixel Cookbook — Step-by-step pixel setup guide
- Identify Users Cookbook — Associate pixel sessions with your authenticated users
- JavaScript Beacon — Advanced client-side detection
- Dashboard Analytics — View your detection data
- Enforce — Add enforcement to your detection
