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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@mixpeek/prebid

v1.0.0

Published

Mixpeek for Prebid.js - Enrich bid requests with real-time multimodal AI contextual data

Downloads

4

Readme

Mixpeek Contextual Adapter for Prebid.js

npm version npm downloads License Node Version Bundle Size Dependencies GitHub Stars PRs Welcome

🎯 Overview

The Mixpeek Contextual Adapter enables publishers and SSPs using Prebid.js to enrich bid requests with real-time contextual data powered by Mixpeek's multimodal AI engine. This adapter provides:

  • Privacy-First Targeting: No cookies, just content-based context
  • Multimodal Analysis: Text, images, video, and audio processing
  • IAB Taxonomy: Automatic classification into IAB content categories
  • Brand Safety: Real-time brand safety scoring
  • Ad Adjacency Awareness: Tracks previous ad to avoid repetition and improve user experience
  • Sub-100ms Performance: Optimized for header bidding speed requirements
  • Graceful Fallbacks: Never blocks the auction

🚀 Quick Start

Installation

npm install @mixpeek/prebid

Basic Setup

// 1. Include the Mixpeek RTD module
import '@mixpeek/prebid'

// 2. Configure Mixpeek as an RTD provider
pbjs.setConfig({
  realTimeData: {
    auctionDelay: 250,  // Max time to wait for contextual data (ms)
    dataProviders: [{
      name: 'mixpeek',
      waitForIt: true,  // Wait for Mixpeek before starting auction
      params: {
        apiKey: 'YOUR_MIXPEEK_API_KEY',
        collectionId: 'your-collection-id',
        
        // Use development server (temporary)
        endpoint: 'https://server-xb24.onrender.com',
        // Or production: endpoint: 'https://api.mixpeek.com',
        
        namespace: 'your-namespace', // optional
        featureExtractors: ['taxonomy', 'brand-safety'],
        mode: 'page', // 'page', 'video', or 'auto'
        timeout: 5000, // ms - higher for dev server
        cacheTTL: 300 // seconds
      }
    }]
  }
})

// 3. The RTD module automatically enriches bid requests!
pbjs.requestBids({
  adUnits: [...],
  bidsBackHandler: function(bids) {
    // Bids now include Mixpeek contextual data in ortb2
  }
})

📋 Prerequisites

  1. Mixpeek Account: Sign up at mixpeek.com
  2. API Key: Generate an API key in your Mixpeek dashboard
  3. Collection: Create a collection with feature extractors configured
  4. Prebid.js: Version 6.0.0 or higher

🔧 Configuration Options

RTD Configuration

| Option | Type | Required | Default | Description | |--------|------|----------|---------|-------------| | realTimeData.auctionDelay | number | ❌ | 250 | Max time to wait for all RTD providers (ms) | | realTimeData.dataProviders[].name | string | ✅ | - | Must be 'mixpeek' | | realTimeData.dataProviders[].waitForIt | boolean | ❌ | false | Wait for Mixpeek before starting auction |

Mixpeek Parameters

| Option | Type | Required | Default | Description | |--------|------|----------|---------|-------------| | params.apiKey | string | ✅ | - | Your Mixpeek API key | | params.collectionId | string | ✅ | - | Mixpeek collection ID for document processing | | params.endpoint | string | ❌ | https://server-xb24.onrender.com | Mixpeek API endpoint (dev server default) | | params.namespace | string | ❌ | - | Optional namespace for data isolation | | params.featureExtractors | array | ❌ | ['taxonomy'] | Feature extractors to use (taxonomy, brand-safety, etc.) | | params.mode | string | ❌ | auto | Content mode: page, video, image, or auto | | params.timeout | number | ❌ | 250 | API request timeout in milliseconds | | params.cacheTTL | number | ❌ | 300 | Cache TTL in seconds | | params.enableCache | boolean | ❌ | true | Enable local caching | | params.debug | boolean | ❌ | false | Enable debug logging | | params.batchSize | number | ❌ | 1 | Number of concurrent requests | | params.retryAttempts | number | ❌ | 2 | Number of retry attempts on failure |

📊 Output: OpenRTB 2.6 Data Structure

The RTD module injects contextual data into your bid requests using the OpenRTB 2.6 standard:

Site-Level Data (ortb2.site.content)

{
  "ortb2": {
    "site": {
      "content": {
        "cat": ["IAB19-11"],              // IAB Content Categories
        "cattax": 6,                       // IAB Content Taxonomy v3.0
        "genre": "Technology - AI",        // Human-readable category
        "keywords": "ai,technology,ml",    // Extracted keywords
        "language": "en",                  // Content language
        "title": "Article Title",          // Page title
        "url": "https://example.com",      // Page URL
        "ext": {
          "data": {
            "mixpeek": {
              "score": 0.94,               // Confidence score
              "brandSafety": 0.98,         // Brand safety score
              "sentiment": "positive",      // Content sentiment
              "embeddingId": "emb_abc123"  // Embedding ID
            }
          }
        }
      }
    }
  }
}

Impression-Level Data (ortb2Imp.ext.data)

{
  // Current page context
  "hb_mixpeek_taxonomy": "IAB19-11",       // Primary IAB taxonomy code
  "hb_mixpeek_category": "Technology > AI", // Human-readable category
  "hb_mixpeek_node": "node_tech_ai",       // Taxonomy node ID
  "hb_mixpeek_path": "tech/ai/ml",         // Hierarchical path
  "hb_mixpeek_score": "0.94",              // Confidence score
  "hb_mixpeek_safety": "0.98",             // Brand safety score
  "hb_mixpeek_keywords": "AI,ML,tech",     // Extracted keywords
  "hb_mixpeek_embed": "emb_abc123",        // Embedding ID for retrieval
  
  // Previous ad context (adjacency awareness)
  "hb_mixpeek_prev_creative": "12345",     // Last creative ID shown
  "hb_mixpeek_prev_bidder": "appnexus",    // Last bidder that won
  "hb_mixpeek_prev_adunit": "sidebar-1",   // Last ad unit code
  "hb_mixpeek_prev_cat": "IAB18-1,IAB12-3" // Last ad categories
}

🎥 Usage Examples

Page Context (Articles, Blogs)

pbjs.setConfig({
  realTimeData: {
    auctionDelay: 250,
    dataProviders: [{
      name: 'mixpeek',
      waitForIt: true,
      params: {
        apiKey: 'sk_your_api_key',
        collectionId: 'col_articles',
        mode: 'page',
        featureExtractors: ['taxonomy', 'brand-safety', 'keywords']
      }
    }]
  }
})

Video Context (Pre-roll, Mid-roll)

pbjs.setConfig({
  realTimeData: {
    auctionDelay: 300,  // Longer delay for video processing
    dataProviders: [{
      name: 'mixpeek',
      waitForIt: true,
      params: {
        apiKey: 'sk_your_api_key',
        collectionId: 'col_videos',
        mode: 'video',
        videoSelector: '#main-video', // CSS selector for video element
        featureExtractors: ['taxonomy', 'scene-detection']
      }
    }]
  }
})

Multi-Content Auto-Detection

pbjs.setConfig({
  realTimeData: {
    auctionDelay: 250,
    dataProviders: [{
      name: 'mixpeek',
      waitForIt: true,
      params: {
        apiKey: 'sk_your_api_key',
        collectionId: 'col_mixed',
        mode: 'auto', // Automatically detects page, video, or image content
        featureExtractors: ['taxonomy', 'brand-safety', 'clustering']
      }
    }]
  }
})

🏗️ How It Works

sequenceDiagram
    participant Publisher
    participant Prebid
    participant MixpeekAdapter
    participant MixpeekAPI
    participant SSP

    Publisher->>Prebid: Request Bids
    Prebid->>MixpeekAdapter: beforeRequestBids event
    MixpeekAdapter->>MixpeekAdapter: Extract page/video content
    MixpeekAdapter->>MixpeekAdapter: Check cache
    alt Cache Miss
        MixpeekAdapter->>MixpeekAPI: POST /collections/{id}/documents
        MixpeekAPI->>MixpeekAPI: Process with feature extractors
        MixpeekAPI-->>MixpeekAdapter: Return enrichments
        MixpeekAdapter->>MixpeekAdapter: Cache result
    end
    MixpeekAdapter->>Prebid: Inject contextual key-values
    Prebid->>SSP: Send enriched bid request
    SSP-->>Prebid: Return bids
    Prebid-->>Publisher: Render ad

🧪 Testing

# Run all tests
npm test

# Run with coverage
npm run test:coverage

# Watch mode
npm run test:watch

📖 Advanced Configuration

Custom Feature Extractors

pbjs.setConfig({
  realTimeData: {
    auctionDelay: 250,
    dataProviders: [{
      name: 'mixpeek',
      waitForIt: true,
      params: {
        apiKey: 'sk_your_api_key',
        collectionId: 'col_custom',
        customExtractors: [
          {
            feature_extractor_id: 'sentiment-analyzer',
            payload: {
              model: 'sentiment-v2',
              threshold: 0.7
            }
          }
        ]
      }
    }]
  }
})

Conditional Loading

// Only enrich on specific pages
if (window.location.pathname.startsWith('/articles/')) {
  pbjs.setConfig({
    realTimeData: {
      auctionDelay: 250,
      dataProviders: [{
        name: 'mixpeek',
        waitForIt: true,
        params: {
          apiKey: 'sk_your_api_key',
          collectionId: 'col_articles',
          mode: 'page'
        }
      }]
    }
  })
}

Event Callbacks

pbjs.onEvent('mixpeekContextReady', function(context) {
  console.log('Mixpeek context loaded:', context)
  // Custom analytics or modifications
})

pbjs.onEvent('mixpeekContextError', function(error) {
  console.error('Mixpeek context error:', error)
  // Custom error handling
})

🔄 Previous Ad Tracking (Adjacency Awareness)

The adapter automatically tracks the most recently served ad to enable adjacency-aware targeting. This helps:

  • Avoid Ad Repetition: Prevent showing the same creative or category repeatedly
  • Frequency Capping: Build frequency cap rules based on previous impressions
  • Competitive Separation: Avoid showing competing brands consecutively
  • Enhanced User Experience: Improve ad diversity and relevance

How It Works

  1. Automatic Tracking: On every bidResponse event, the adapter stores minimal information about the winning ad
  2. Lightweight Storage: Data is stored in memory + localStorage (privacy-safe, no PII)
  3. Targeting Keys: Previous ad data is automatically injected into subsequent bid requests

Data Tracked

| Field | Description | Example | |-------|-------------|---------| | creativeId | Winning creative ID | "12345" | | bidder | Winning bidder code | "appnexus" | | adUnitCode | Ad unit that served the ad | "sidebar-1" | | categories | IAB categories of the ad | ["IAB18-1", "IAB12-3"] | | timestamp | When the ad was served | 1697123456789 |

Targeting Keys Injected

The following keys are automatically added to ortb2Imp.ext.data:

  • hb_mixpeek_prev_creative - Last creative ID
  • hb_mixpeek_prev_bidder - Last winning bidder
  • hb_mixpeek_prev_adunit - Last ad unit code
  • hb_mixpeek_prev_cat - Last ad categories (comma-separated)

SSP/DSP Usage

SSPs and DSPs can use these keys for advanced targeting rules:

// Example: Avoid showing the same creative twice in a row
if (bidRequest.ortb2Imp.ext.data.hb_mixpeek_prev_creative === currentCreative.id) {
  // Skip this creative or reduce bid
}

// Example: Competitive separation
const prevCategories = bidRequest.ortb2Imp.ext.data.hb_mixpeek_prev_cat?.split(',') || []
if (prevCategories.includes('IAB18-1') && currentAd.category === 'IAB18-1') {
  // Don't show competing fashion ads back-to-back
}

Privacy & Storage

  • No User Tracking: Only ad metadata is stored, no user identifiers or behavior
  • Session-Scoped: Data persists across page views within a session
  • Local Storage: Falls back to memory-only if localStorage is unavailable
  • Minimal Data: Only essential fields are stored (< 200 bytes)
  • GDPR/CCPA Compliant: No consent required as it doesn't track users

Programmatic Control

You can access the previous ad tracker directly if needed:

import previousAdTracker from '@mixpeek/prebid/utils/previousAdTracker'

// Get last ad info
const lastAd = previousAdTracker.getLast()
console.log('Last creative:', lastAd?.creativeId)

// Clear history (e.g., on user logout or page type change)
previousAdTracker.clear()

🔒 Security & Privacy

  • No PII: The adapter never sends user identifiers or cookies
  • Content-Only: Only page/video content is analyzed
  • HTTPS: All API calls use TLS encryption
  • API Key Safety: Store API keys securely (environment variables, server-side rendering)
  • GDPR/CCPA Compliant: Contextual targeting doesn't require user consent

📚 Documentation

User Guides

Developer Resources

🤝 Support

📄 License

Apache 2.0 - see LICENSE file for details.

🙏 Credits

Built with ❤️ by Mixpeek

Integrates with Prebid.js - an open-source header bidding solution