npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@axeptio/cmp-agents

v2.0.0

Published

Reverse-engineered interfaces able to interact with Consent Management Platforms online

Readme

CMP Agents

CI NPM

A collection of reverse-engineered JavaScript interfaces to interact with Consent Management Platforms (CMPs) online.

This library is intended to run in the browser. It detects and drives CMP UIs in the page context. When using NPM you must either (1) bundle your code and inject that script into the browser, or (2) inject the pre-built bundle (dist/cmp-agents.js) into the page and then run code that uses window.CMPAgents. It does not run in Node.js alone.

Overview

CMP Agents provides a unified API to detect, read, and interact with 40+ different Consent Management Platforms. Whether you're building a cookie scanner, consent automation tool, or privacy assistant, this library gives you the building blocks to work with CMPs programmatically.

Supported CMPs

| CMP | Detection | Accept/Reject | Granular Consent | |-----|-----------|---------------|------------------| | Axeptio | ✅ | ✅ | ✅ | | CookieBot | ✅ | ✅ | ✅ | | Didomi | ✅ | ✅ | ✅ | | OneTrust | ✅ | ✅ | ✅ | | UserCentrics | ✅ | ✅ | ✅ | | TrustArc | ✅ | ✅ | ✅ | | iubenda | ✅ | ✅ | ✅ | | CookieYes | ✅ | ✅ | ✅ | | Complianz | ✅ | ✅ | ✅ | | TarteAuCitron | ✅ | ✅ | ✅ | | ...and 30+ more | ✅ | ✅ | Varies |

See docs/integrations.md for the complete list.

Installation

NPM

npm install @axeptio/cmp-agents

Use the library in code that will run in the browser: bundle that code (e.g. with Webpack, Rollup) and inject the resulting script into the page, or inject the pre-built bundle (node_modules/@axeptio/cmp-agents/dist/cmp-agents.js) and call CMPAgents.create() from your own injected script.

CDN (Script tag)

<!-- Latest version -->
<script src="https://unpkg.com/@axeptio/cmp-agents/dist/cmp-agents.min.js"></script>

<!-- Or from jsDelivr -->
<script src="https://cdn.jsdelivr.net/npm/@axeptio/cmp-agents/dist/cmp-agents.min.js"></script>

<!-- Specific version -->
<script src="https://unpkg.com/@axeptio/[email protected]/dist/cmp-agents.min.js"></script>

Requirements

  • Browser: The library runs in the browser (script tag or injected bundle).
  • Node.js >= 22.17.0 < 23.0.0 and npm >= 10 for development, CLI, and building your own bundle.

Quick Start

Browser Usage (CDN)

<script src="https://unpkg.com/@axeptio/cmp-agents/dist/cmp-agents.min.js"></script>
<script>
  const agent = CMPAgents.create();
  agent.on('cmp', async (cmp) => {
    console.log('Detected:', cmp.getName());
    const vendors = await cmp.getVendors();
    console.log('Vendors:', vendors);
  });
  agent.run();
</script>

NPM / Bundled script (browser)

Bundle this code and inject the bundle into the page so it runs in the browser:

import { CMPDetector, CookieBot, OneTrust, Didomi, CONSENT_INTENT } from '@axeptio/cmp-agents';

// Create a detector and register CMPs (runs in browser)
const cmpDetector = new CMPDetector();
cmpDetector.registerIntegrations(new CookieBot(), new OneTrust(), new Didomi());

// Listen for CMP detection
cmpDetector.on('cmp', async (cmp) => {
  console.log(`Detected: ${cmp.getName()}`);

  // Get vendors
  const vendors = await cmp.getVendors();
  console.log('Vendors:', vendors);

  // Accept all using the new API
  await cmp.applyPreferences({ intent: CONSENT_INTENT.ACCEPT_ALL });
});

// Start detection
cmpDetector.run();

Using Individual Integrations

import CookieBot from '@axeptio/cmp-agents/integrations/cookiebot';
import { CONSENT_INTENT } from '@axeptio/cmp-agents';

const cookiebot = new CookieBot();

// Check if CookieBot is present
if (window.Cookiebot) {
  cookiebot.trigger('detection');

  // Get current consent status
  await cookiebot.retrieveConsent();
  console.log('Consent:', cookiebot.consent);

  // Accept all vendors
  await cookiebot.applyPreferences({ intent: CONSENT_INTENT.ACCEPT_ALL });
}

Granular Vendor Consent

import { CONSENT_INTENT } from '@axeptio/cmp-agents';

const cmp = cmpDetector.getCMP();
const vendors = await cmp.getVendors();

// Build a map of vendor preferences
const vendorConsents = {};

// Allow Analytics vendor, deny Advertising
const analyticsVendor = vendors.find(v => v.name.includes('Analytics'));
const adsVendor = vendors.find(v => v.name.includes('Advertising'));

if (analyticsVendor) vendorConsents[analyticsVendor.name] = true;
if (adsVendor) vendorConsents[adsVendor.name] = false;

// Apply custom choices by passing vendors directly
await cmp.applyPreferences({
  intent: CONSENT_INTENT.APPLY_CUSTOM,
  vendors: vendorConsents
});

Architecture

┌─────────────────────────────────────────────────────────────┐
│                      CMPDetector                             │
│  - Registers CMP integrations                               │
│  - Manages detection lifecycle                              │
│  - Selects highest-priority detected CMP                    │
└─────────────────────┬───────────────────────────────────────┘
                      │
          ┌───────────┴───────────┐
          │                       │
          ▼                       ▼
┌─────────────────┐     ┌─────────────────┐
│   CMP (Base)    │     │   TCF_CMP       │
│                 │     │   (extends CMP) │
│ - getName()     │     │                 │
│ - getVendors()  │     │ - TCF v2 API    │
│ - applyPrefs()  │     │ - getVendorList │
│ - acceptAll()   │     │ - getTCData()   │
│ - rejectAll()   │     │                 │
└────────┬────────┘     └────────┬────────┘
         │                       │
         └───────────┬───────────┘
                     │
    ┌────────────────┼────────────────┐
    │                │                │
    ▼                ▼                ▼
┌─────────┐    ┌─────────┐    ┌─────────┐
│CookieBot│    │ OneTrust│    │ Didomi  │
└─────────┘    └─────────┘    └─────────┘

API Reference

CMP Base Class

All CMP integrations extend the CMP base class:

class CMP {
  // Detection
  getName(): string
  getMatchingResources(): RegExp[]
  onTick(): void

  // Configuration
  getLayout(): string        // 'banner' | 'popup' | 'widget' | etc.
  getBehaviors(): string[]   // ['ACCEPTABLE', 'REJECTABLE', etc.]
  getGranularity(): string   // 'NONE' | 'GLOBAL' | 'VENDOR' | 'PURPOSE'

  // Data retrieval
  getVendors(): Promise<Vendor[]>
  getPurposes(): Promise<Purpose[]>
  retrieveConsent(): void
  hasExistingConsent(): boolean

  // Binary actions
  acceptAll(): Promise<void>
  rejectAll(): Promise<void>

  // Lifecycle methods
  applyPreferences(options): Promise<void>
  show(screenType): Promise<void>
  dismiss(): Promise<void>
}

// applyPreferences options:
// {
//   intent: CONSENT_INTENT,       // ACCEPT_ALL | REJECT_ALL | APPLY_CUSTOM
//   vendors: { [id]: boolean },   // Vendor consent map (for APPLY_CUSTOM)
//   purposes: { [id]: boolean },  // Purpose consent map (for APPLY_CUSTOM)
//   autoDismiss: boolean          // Auto-close CMP UI (default: true)
// }

Constants

import {
  BEHAVIORS,
  LAYOUTS,
  GRANULARITY,
  CONSENT_INTENT,
  SCREEN_TYPE
} from '@axeptio/cmp-agents';

// Behaviors
BEHAVIORS.ACCEPTABLE    // User can accept
BEHAVIORS.REJECTABLE    // User can reject
BEHAVIORS.CLOSABLE      // CMP can be closed
BEHAVIORS.OBSTRUCTIVE   // CMP blocks content

// Layouts
LAYOUTS.BANNER
LAYOUTS.POPUP
LAYOUTS.WIDGET
LAYOUTS.PAGE

// Granularity
GRANULARITY.NONE      // No choice possible
GRANULARITY.GLOBAL    // Accept/reject all only
GRANULARITY.VENDOR    // Per-vendor choice
GRANULARITY.PURPOSE   // Per-purpose choice

// Consent Intent (for applyPreferences)
CONSENT_INTENT.ACCEPT_ALL    // Accept all vendors
CONSENT_INTENT.REJECT_ALL    // Reject all vendors
CONSENT_INTENT.APPLY_CUSTOM  // Apply vendor-specific choices

// Screen Type (for show)
SCREEN_TYPE.DEFAULT   // Initial consent banner
SCREEN_TYPE.VENDORS   // Vendor list view
SCREEN_TYPE.PURPOSES  // Purpose/category view
SCREEN_TYPE.SETTINGS  // Settings panel

Adding a New Integration

Use the CLI to scaffold a new integration:

npm run cli:create

Or create manually in src/integrations/yourCmp/:

import { CMP } from '../../cmp.js';
import { GRANULARITY, SCREEN_TYPE } from '../../constants.js';

export default class YourCMP extends CMP {
  getName() {
    return 'YourCMP';
  }

  getGranularity() {
    return GRANULARITY.VENDOR;
  }

  getMatchingResources() {
    return [/yourcmp\.com\/sdk/];
  }

  onTick() {
    if (window.YourCMPSDK) {
      this.trigger('detection');
    }
  }

  async getVendors() {
    return window.YourCMPSDK.getVendors().map(v => ({
      name: v.name,
      iabId: v.id
    }));
  }

  async acceptAll() {
    window.YourCMPSDK.acceptAll();
  }

  async rejectAll() {
    window.YourCMPSDK.rejectAll();
  }

  retrieveConsent() {
    this.consent = window.YourCMPSDK.hasConsent();
    this.consentDate = window.YourCMPSDK.getConsentDate();
  }

  // Override for granular consent support
  async _applyCustomConsent(options = {}) {
    const { vendors = {}, purposes = {} } = options;
    Object.entries(vendors).forEach(([id, enabled]) => {
      window.YourCMPSDK.setVendorConsent(id, enabled);
    });
    Object.entries(purposes).forEach(([id, enabled]) => {
      window.YourCMPSDK.setPurposeConsent(id, enabled);
    });
    window.YourCMPSDK.save();
  }

  // Override for UI control
  async show(screenType = SCREEN_TYPE.DEFAULT) {
    window.YourCMPSDK.open();
  }

  async dismiss() {
    window.YourCMPSDK.close();
  }
}

See CONTRIBUTING.md for detailed guidelines.

Testing

# Run unit tests (fast, no external dependencies)
npm run test:unit

# Run unit tests in watch mode
npm run test:unit:watch

# Run unit tests with coverage
npm run test:unit:coverage

# Run E2E tests (requires build first)
npm test

# Run E2E tests for a specific CMP
npx playwright test --config=test/config.js -g "CookieBot"

# Run in complete mode (all test websites + extended flow tests)
TEST_MODE=complete npm test

Test Structure

test/
├── unit/                              # Unit tests (Vitest + jsdom)
│   ├── cmp.unit.test.js               # CMP base class tests
│   ├── tcf-cmp.unit.test.js           # TCF_CMP class tests
│   ├── vendor.unit.test.js            # Vendor class tests
│   ├── cmpDetector.unit.test.js       # CMPDetector + create() factory tests
│   ├── consent-signals.unit.test.js   # Consent signal detection tests
│   └── consentManager.unit.test.js    # ConsentManager integration tests
├── common.js                          # Shared E2E test helpers
└── config.js                          # Playwright configuration

See the Testing Guide for detailed instructions.

Documentation

Guides

Reference

Internal

Use Cases

1. Cookie Scanner (Shake)

Detect and analyze CMPs on websites during automated scans:

// In Playwright test
await page.addScriptTag({ path: 'dist/cmp-agents.js' });
await page.evaluate(() => {
  const agent = CMPAgents.create();
  window.cmpAgent = agent;
  agent.run();
});
const cmp = await page.evaluate(() => window.cmpAgent.getCMP());
const vendors = await page.evaluate(() => window.cmpAgent.getCMP().getVendors());

2. Privacy Assistant (Taste)

Auto-consent on behalf of users in a browser extension:

import { CONSENT_INTENT, BEHAVIORS } from '@axeptio/cmp-agents';

// Content script
const cmp = cmpDetector.getCMP();
if (cmp && cmp.getBehaviors().includes(BEHAVIORS.REJECTABLE)) {
  // Reject all vendors
  await cmp.applyPreferences({ intent: CONSENT_INTENT.REJECT_ALL });
}

3. Granular Consent Management

Apply specific vendor preferences:

import { CONSENT_INTENT } from '@axeptio/cmp-agents';

const cmp = cmpDetector.getCMP();
const vendors = await cmp.getVendors();

// Build vendor consent map
const vendorConsents = {};

// Find and configure specific vendors
const metaVendor = vendors.find(v => v.name.includes('Meta'));
const analyticsVendor = vendors.find(v => v.name.includes('Analytics'));

if (metaVendor) vendorConsents[metaVendor.name] = false;  // Deny Meta
if (analyticsVendor) vendorConsents[analyticsVendor.name] = true;  // Allow Analytics

// Apply custom choices by passing vendors directly
await cmp.applyPreferences({
  intent: CONSENT_INTENT.APPLY_CUSTOM,
  vendors: vendorConsents
});

4. UI Control for Testing

Open specific CMP views for manual testing or screenshots:

import { SCREEN_TYPE, CONSENT_INTENT } from '@axeptio/cmp-agents';

const cmp = cmpDetector.getCMP();

// Open vendor list for inspection
await cmp.show(SCREEN_TYPE.VENDORS);

// Apply preferences but keep UI open
await cmp.applyPreferences({
  intent: CONSENT_INTENT.APPLY_CUSTOM,
  autoDismiss: false
});

// Take screenshot, then close
await cmp.dismiss();

5. Research & Compliance

Analyze CMP configurations across websites:

const analysis = {
  name: cmp.getName(),
  layout: cmp.getLayout(),
  behaviors: cmp.getBehaviors(),
  granularity: cmp.getGranularity(),
  vendorCount: (await cmp.getVendors()).length,
  hasExistingConsent: cmp.hasExistingConsent()
};

License

This project is licensed under a custom license. See LICENSE for details.

TL;DR: Free for CMP industry peers to use, modify, and contribute. Redistribution as a competing product requires permission.

Credits

Developed and maintained by Axeptio.

Links