Package Exports
- @mixpeek/prebid
- @mixpeek/prebid/dist/mixpeekContextAdapter.js
- @mixpeek/prebid/src/modules/mixpeekContextAdapter.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@mixpeek/prebid) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Mixpeek Contextual Adapter for Prebid.js
๐ฏ 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/prebidBasic 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
- Mixpeek Account: Sign up at mixpeek.com
- API Key: Generate an API key in your Mixpeek dashboard
- Collection: Create a collection with feature extractors configured
- 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
- Automatic Tracking: On every
bidResponseevent, the adapter stores minimal information about the winning ad - Lightweight Storage: Data is stored in memory + localStorage (privacy-safe, no PII)
- 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 IDhb_mixpeek_prev_bidder- Last winning bidderhb_mixpeek_prev_adunit- Last ad unit codehb_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
- Quick Start - Get running in 5 minutes
- Integration Guide - Step-by-step integration
- API Reference - Complete API documentation
- Testing Guide - How to test the adapter
- Endpoint Configuration - Configure API endpoints
- Health Check - Health check configuration
Developer Resources
- Mixpeek API Docs - Platform documentation
- Internal Planning - Gap analysis & implementation plans (internal)
๐ค Support
- Email: support@mixpeek.com
- GitHub Issues: Create an issue
- Documentation: docs.mixpeek.com
- Slack Community: Join our Slack
๐ License
Apache 2.0 - see LICENSE file for details.
๐ Credits
Built with โค๏ธ by Mixpeek
Integrates with Prebid.js - an open-source header bidding solution