@mixpeek/prebid 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +153 -0
- package/ENDPOINTS.md +308 -0
- package/LICENSE +68 -0
- package/QUICKSTART.md +234 -0
- package/README.md +439 -0
- package/TESTING.md +341 -0
- package/dist/mixpeekContextAdapter.js +3 -0
- package/dist/mixpeekContextAdapter.js.LICENSE.txt +1 -0
- package/dist/mixpeekContextAdapter.js.map +1 -0
- package/docs/MIGRATION_V2.md +519 -0
- package/docs/api-reference.md +455 -0
- package/docs/health-check.md +348 -0
- package/docs/integration-guide.md +577 -0
- package/examples/publisher-demo/README.md +65 -0
- package/examples/publisher-demo/index.html +331 -0
- package/examples/publisher-demo/package.json +11 -0
- package/package.json +82 -0
- package/src/api/mixpeekClient.js +303 -0
- package/src/cache/cacheManager.js +245 -0
- package/src/config/constants.js +125 -0
- package/src/extractors/imageExtractor.js +142 -0
- package/src/extractors/pageExtractor.js +196 -0
- package/src/extractors/videoExtractor.js +228 -0
- package/src/modules/mixpeekContextAdapter.js +833 -0
- package/src/modules/mixpeekRtdProvider.js +305 -0
- package/src/prebid/prebidIntegration.js +117 -0
- package/src/utils/helpers.js +261 -0
- package/src/utils/iabMapping.js +367 -0
- package/src/utils/logger.js +64 -0
- package/src/utils/previousAdTracker.js +95 -0
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
# Mixpeek Context Adapter - Integration Guide
|
|
2
|
+
|
|
3
|
+
This guide will walk you through integrating the Mixpeek Context Adapter with Prebid.js.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
1. [Prerequisites](#prerequisites)
|
|
8
|
+
2. [Installation](#installation)
|
|
9
|
+
3. [Configuration](#configuration)
|
|
10
|
+
4. [Testing](#testing)
|
|
11
|
+
5. [Deployment](#deployment)
|
|
12
|
+
6. [Troubleshooting](#troubleshooting)
|
|
13
|
+
|
|
14
|
+
## Prerequisites
|
|
15
|
+
|
|
16
|
+
Before you begin, make sure you have:
|
|
17
|
+
|
|
18
|
+
- **Mixpeek Account**: Sign up at [mixpeek.com/start](https://mixpeek.com/start)
|
|
19
|
+
- **API Key**: Generate an API key from your Mixpeek dashboard
|
|
20
|
+
- **Collection**: Create a collection with feature extractors configured
|
|
21
|
+
- **Prebid.js**: Version 6.0.0 or higher installed on your site
|
|
22
|
+
|
|
23
|
+
### Setting Up Your Mixpeek Collection
|
|
24
|
+
|
|
25
|
+
1. **Create a Collection**:
|
|
26
|
+
```bash
|
|
27
|
+
curl -X POST https://api.mixpeek.com/v1/collections \
|
|
28
|
+
-H "Authorization: Bearer YOUR_API_KEY" \
|
|
29
|
+
-H "Content-Type: application/json" \
|
|
30
|
+
-d '{
|
|
31
|
+
"name": "contextual-targeting",
|
|
32
|
+
"description": "Collection for contextual ad targeting"
|
|
33
|
+
}'
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
2. **Note your Collection ID** from the response (e.g., `col_abc123`)
|
|
37
|
+
|
|
38
|
+
3. **Verify Feature Extractors** are available:
|
|
39
|
+
```bash
|
|
40
|
+
curl https://api.mixpeek.com/v1/collections/features/extractors \
|
|
41
|
+
-H "Authorization: Bearer YOUR_API_KEY"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
### Option 1: NPM (Recommended)
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm install @mixpeek/prebid-contextual-adapter
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Then include in your JavaScript:
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
import '@mixpeek/prebid-contextual-adapter'
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Option 2: CDN
|
|
59
|
+
|
|
60
|
+
```html
|
|
61
|
+
<script src="https://cdn.jsdelivr.net/npm/@mixpeek/prebid-contextual-adapter@latest/dist/mixpeekContextAdapter.js"></script>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Option 3: Download
|
|
65
|
+
|
|
66
|
+
Download the latest release from [GitHub releases](https://github.com/mixpeek/prebid-contextual-adapter/releases) and include it in your page:
|
|
67
|
+
|
|
68
|
+
```html
|
|
69
|
+
<script src="/path/to/mixpeekContextAdapter.js"></script>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Configuration
|
|
73
|
+
|
|
74
|
+
### Basic Setup
|
|
75
|
+
|
|
76
|
+
Add the Mixpeek RTD configuration to your Prebid setup:
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
var pbjs = pbjs || {};
|
|
80
|
+
pbjs.que = pbjs.que || [];
|
|
81
|
+
|
|
82
|
+
pbjs.que.push(function() {
|
|
83
|
+
// Configure Mixpeek as an RTD provider
|
|
84
|
+
pbjs.setConfig({
|
|
85
|
+
realTimeData: {
|
|
86
|
+
auctionDelay: 250, // Max time to wait for RTD providers
|
|
87
|
+
dataProviders: [{
|
|
88
|
+
name: 'mixpeek',
|
|
89
|
+
waitForIt: true, // Wait for Mixpeek before starting auction
|
|
90
|
+
params: {
|
|
91
|
+
apiKey: 'sk_your_api_key_here',
|
|
92
|
+
collectionId: 'col_your_collection_id',
|
|
93
|
+
featureExtractors: ['taxonomy'],
|
|
94
|
+
mode: 'auto',
|
|
95
|
+
timeout: 250,
|
|
96
|
+
cacheTTL: 300
|
|
97
|
+
}
|
|
98
|
+
}]
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Add your ad units
|
|
103
|
+
pbjs.addAdUnits([...]);
|
|
104
|
+
|
|
105
|
+
// Request bids
|
|
106
|
+
pbjs.requestBids({...});
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Health Check Configuration
|
|
111
|
+
|
|
112
|
+
The adapter includes smart health check functionality:
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
pbjs.setConfig({
|
|
116
|
+
realTimeData: {
|
|
117
|
+
auctionDelay: 250,
|
|
118
|
+
dataProviders: [{
|
|
119
|
+
name: 'mixpeek',
|
|
120
|
+
waitForIt: true,
|
|
121
|
+
params: {
|
|
122
|
+
apiKey: 'sk_your_api_key_here',
|
|
123
|
+
collectionId: 'col_your_collection_id',
|
|
124
|
+
|
|
125
|
+
// Health check modes:
|
|
126
|
+
healthCheck: 'lazy', // Default - check on first request (recommended)
|
|
127
|
+
// healthCheck: 'eager', // Check immediately on init (adds ~200-500ms)
|
|
128
|
+
// healthCheck: false, // Skip health check (max performance)
|
|
129
|
+
}
|
|
130
|
+
}]
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Recommended:** Use `lazy` (default) for production - validates API without impacting page load.
|
|
136
|
+
|
|
137
|
+
See [Health Check Documentation](health-check.md) for details.
|
|
138
|
+
|
|
139
|
+
### Advanced Configuration
|
|
140
|
+
|
|
141
|
+
For more control, use the full configuration object:
|
|
142
|
+
|
|
143
|
+
```javascript
|
|
144
|
+
pbjs.setConfig({
|
|
145
|
+
realTimeData: {
|
|
146
|
+
auctionDelay: 250, // Max time to wait for all RTD providers
|
|
147
|
+
dataProviders: [{
|
|
148
|
+
name: 'mixpeek',
|
|
149
|
+
waitForIt: true, // Wait for this provider before auction
|
|
150
|
+
params: {
|
|
151
|
+
// Required
|
|
152
|
+
apiKey: 'sk_your_api_key_here',
|
|
153
|
+
collectionId: 'col_your_collection_id',
|
|
154
|
+
|
|
155
|
+
// Optional
|
|
156
|
+
endpoint: 'https://api.mixpeek.com',
|
|
157
|
+
namespace: 'production',
|
|
158
|
+
|
|
159
|
+
// Content extraction
|
|
160
|
+
mode: 'auto', // 'auto', 'page', 'video', or 'image'
|
|
161
|
+
videoSelector: 'video', // CSS selector for video elements
|
|
162
|
+
maxImages: 5, // Max images to analyze
|
|
163
|
+
|
|
164
|
+
// Feature extractors
|
|
165
|
+
featureExtractors: [
|
|
166
|
+
'taxonomy',
|
|
167
|
+
'brand-safety',
|
|
168
|
+
'keywords',
|
|
169
|
+
'sentiment'
|
|
170
|
+
],
|
|
171
|
+
|
|
172
|
+
// Or with custom configuration
|
|
173
|
+
customExtractors: [
|
|
174
|
+
{
|
|
175
|
+
feature_extractor_id: 'taxonomy',
|
|
176
|
+
payload: {
|
|
177
|
+
version: '3.0',
|
|
178
|
+
threshold: 0.7
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
],
|
|
182
|
+
|
|
183
|
+
// Performance
|
|
184
|
+
timeout: 250, // ms
|
|
185
|
+
retryAttempts: 2,
|
|
186
|
+
|
|
187
|
+
// Caching
|
|
188
|
+
enableCache: true,
|
|
189
|
+
cacheTTL: 300, // seconds
|
|
190
|
+
|
|
191
|
+
// Debugging
|
|
192
|
+
debug: false
|
|
193
|
+
}
|
|
194
|
+
}]
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Integration Patterns
|
|
200
|
+
|
|
201
|
+
### Pattern 1: Page-Level Context (Default)
|
|
202
|
+
|
|
203
|
+
Best for article pages, blog posts, and content sites:
|
|
204
|
+
|
|
205
|
+
```javascript
|
|
206
|
+
pbjs.setConfig({
|
|
207
|
+
realTimeData: {
|
|
208
|
+
auctionDelay: 250,
|
|
209
|
+
dataProviders: [{
|
|
210
|
+
name: 'mixpeek',
|
|
211
|
+
waitForIt: true,
|
|
212
|
+
params: {
|
|
213
|
+
apiKey: 'sk_...',
|
|
214
|
+
collectionId: 'col_...',
|
|
215
|
+
mode: 'page',
|
|
216
|
+
featureExtractors: ['taxonomy', 'brand-safety']
|
|
217
|
+
}
|
|
218
|
+
}]
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
The adapter will automatically extract:
|
|
224
|
+
- Page URL and title
|
|
225
|
+
- Meta descriptions and keywords
|
|
226
|
+
- Body text content
|
|
227
|
+
- Open Graph tags
|
|
228
|
+
- Structured data (JSON-LD)
|
|
229
|
+
|
|
230
|
+
### Pattern 2: Video Context
|
|
231
|
+
|
|
232
|
+
For video content pages or video players:
|
|
233
|
+
|
|
234
|
+
```javascript
|
|
235
|
+
pbjs.setConfig({
|
|
236
|
+
realTimeData: {
|
|
237
|
+
auctionDelay: 300, // Longer delay for video processing
|
|
238
|
+
dataProviders: [{
|
|
239
|
+
name: 'mixpeek',
|
|
240
|
+
waitForIt: true,
|
|
241
|
+
params: {
|
|
242
|
+
apiKey: 'sk_...',
|
|
243
|
+
collectionId: 'col_...',
|
|
244
|
+
mode: 'video',
|
|
245
|
+
videoSelector: '#main-video', // Specific video element
|
|
246
|
+
featureExtractors: ['taxonomy', 'scene-detection']
|
|
247
|
+
}
|
|
248
|
+
}]
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
The adapter will extract:
|
|
254
|
+
- Video source URL
|
|
255
|
+
- Video metadata (title, description)
|
|
256
|
+
- Video dimensions and duration
|
|
257
|
+
- Poster image
|
|
258
|
+
- Frame snapshots (optional)
|
|
259
|
+
|
|
260
|
+
### Pattern 3: Image Gallery
|
|
261
|
+
|
|
262
|
+
For image-heavy pages:
|
|
263
|
+
|
|
264
|
+
```javascript
|
|
265
|
+
pbjs.setConfig({
|
|
266
|
+
realTimeData: {
|
|
267
|
+
auctionDelay: 250,
|
|
268
|
+
dataProviders: [{
|
|
269
|
+
name: 'mixpeek',
|
|
270
|
+
waitForIt: true,
|
|
271
|
+
params: {
|
|
272
|
+
apiKey: 'sk_...',
|
|
273
|
+
collectionId: 'col_...',
|
|
274
|
+
mode: 'image',
|
|
275
|
+
maxImages: 10,
|
|
276
|
+
featureExtractors: ['taxonomy', 'image-labels']
|
|
277
|
+
}
|
|
278
|
+
}]
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Pattern 4: Auto-Detection
|
|
284
|
+
|
|
285
|
+
Let the adapter automatically detect the content type:
|
|
286
|
+
|
|
287
|
+
```javascript
|
|
288
|
+
pbjs.setConfig({
|
|
289
|
+
realTimeData: {
|
|
290
|
+
auctionDelay: 250,
|
|
291
|
+
dataProviders: [{
|
|
292
|
+
name: 'mixpeek',
|
|
293
|
+
waitForIt: true,
|
|
294
|
+
params: {
|
|
295
|
+
apiKey: 'sk_...',
|
|
296
|
+
collectionId: 'col_...',
|
|
297
|
+
mode: 'auto', // Automatically detects page, video, or image content
|
|
298
|
+
featureExtractors: ['taxonomy', 'brand-safety', 'keywords']
|
|
299
|
+
}
|
|
300
|
+
}]
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## Event Handling
|
|
306
|
+
|
|
307
|
+
Listen to Mixpeek events for debugging and analytics:
|
|
308
|
+
|
|
309
|
+
```javascript
|
|
310
|
+
pbjs.que.push(function() {
|
|
311
|
+
// Context successfully loaded
|
|
312
|
+
pbjs.onEvent('mixpeekContextReady', function(context) {
|
|
313
|
+
console.log('Context:', context);
|
|
314
|
+
|
|
315
|
+
// Send to analytics
|
|
316
|
+
gtag('event', 'mixpeek_context', {
|
|
317
|
+
taxonomy: context.taxonomy.label,
|
|
318
|
+
score: context.taxonomy.score,
|
|
319
|
+
brand_safety: context.brandSafety
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
// Error occurred
|
|
324
|
+
pbjs.onEvent('mixpeekContextError', function(error) {
|
|
325
|
+
console.error('Mixpeek error:', error);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// Cache hit
|
|
329
|
+
pbjs.onEvent('mixpeekContextCached', function(context) {
|
|
330
|
+
console.log('Using cached context');
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
// API request made
|
|
334
|
+
pbjs.onEvent('mixpeekApiRequest', function(data) {
|
|
335
|
+
console.log('API request:', data);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
// API response received
|
|
339
|
+
pbjs.onEvent('mixpeekApiResponse', function(data) {
|
|
340
|
+
console.log('API response:', data);
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
## Targeting Keys
|
|
346
|
+
|
|
347
|
+
The adapter injects the following targeting keys into your ad requests:
|
|
348
|
+
|
|
349
|
+
### Current Page Context
|
|
350
|
+
|
|
351
|
+
| Key | Description | Example |
|
|
352
|
+
|-----|-------------|---------|
|
|
353
|
+
| `hb_mixpeek_taxonomy` | IAB taxonomy code | `IAB12-6` |
|
|
354
|
+
| `hb_mixpeek_category` | Human-readable category | `Technology > Mobile Phones` |
|
|
355
|
+
| `hb_mixpeek_node` | Taxonomy node ID | `node_mobile_phones` |
|
|
356
|
+
| `hb_mixpeek_path` | Category hierarchy | `tech/mobile/phones` |
|
|
357
|
+
| `hb_mixpeek_score` | Confidence score | `0.92` |
|
|
358
|
+
| `hb_mixpeek_safety` | Brand safety score | `0.98` |
|
|
359
|
+
| `hb_mixpeek_keywords` | Extracted keywords | `mobile,AI,5G` |
|
|
360
|
+
| `hb_mixpeek_sentiment` | Content sentiment | `positive` |
|
|
361
|
+
| `hb_mixpeek_embed` | Embedding ID | `emb_abc123` |
|
|
362
|
+
|
|
363
|
+
### Previous Ad Context (Adjacency Awareness)
|
|
364
|
+
|
|
365
|
+
| Key | Description | Example |
|
|
366
|
+
|-----|-------------|---------|
|
|
367
|
+
| `hb_mixpeek_prev_creative` | Last creative ID shown | `12345` |
|
|
368
|
+
| `hb_mixpeek_prev_bidder` | Last winning bidder | `appnexus` |
|
|
369
|
+
| `hb_mixpeek_prev_adunit` | Last ad unit code | `sidebar-1` |
|
|
370
|
+
| `hb_mixpeek_prev_cat` | Last ad categories | `IAB18-1,IAB12-3` |
|
|
371
|
+
|
|
372
|
+
These keys are available to all bidders and can be used for:
|
|
373
|
+
- Contextual targeting based on current page content
|
|
374
|
+
- Brand safety filtering
|
|
375
|
+
- Ad adjacency awareness and competitive separation
|
|
376
|
+
- Frequency capping and rotation logic
|
|
377
|
+
- Bid price optimization
|
|
378
|
+
- Reporting and analytics
|
|
379
|
+
|
|
380
|
+
## Testing
|
|
381
|
+
|
|
382
|
+
### 1. Test Configuration
|
|
383
|
+
|
|
384
|
+
First, verify your configuration is valid:
|
|
385
|
+
|
|
386
|
+
```javascript
|
|
387
|
+
// Enable debug mode
|
|
388
|
+
pbjs.setConfig({
|
|
389
|
+
realTimeData: {
|
|
390
|
+
auctionDelay: 250,
|
|
391
|
+
dataProviders: [{
|
|
392
|
+
name: 'mixpeek',
|
|
393
|
+
waitForIt: true,
|
|
394
|
+
params: {
|
|
395
|
+
apiKey: 'sk_...',
|
|
396
|
+
collectionId: 'col_...',
|
|
397
|
+
debug: true // Enable verbose logging
|
|
398
|
+
}
|
|
399
|
+
}]
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
Open your browser console and look for:
|
|
405
|
+
```
|
|
406
|
+
[mixpeek] Initializing Mixpeek Context Adapter
|
|
407
|
+
[mixpeek] Configuration { ... }
|
|
408
|
+
[mixpeek] Mixpeek Context Adapter initialized successfully
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### 2. Test Content Extraction
|
|
412
|
+
|
|
413
|
+
Check that content is being extracted properly:
|
|
414
|
+
|
|
415
|
+
```javascript
|
|
416
|
+
// Access the adapter directly
|
|
417
|
+
const context = await window.MixpeekContextAdapter.getContext();
|
|
418
|
+
console.log('Extracted context:', context);
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### 3. Test API Connection
|
|
422
|
+
|
|
423
|
+
Verify the API is responding:
|
|
424
|
+
|
|
425
|
+
```javascript
|
|
426
|
+
const health = await window.MixpeekContextAdapter.healthCheck();
|
|
427
|
+
console.log('Health check:', health);
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### 4. Test Targeting Keys
|
|
431
|
+
|
|
432
|
+
Inspect the enriched ad units:
|
|
433
|
+
|
|
434
|
+
```javascript
|
|
435
|
+
pbjs.onEvent('beforeRequestBids', function(bidRequest) {
|
|
436
|
+
console.log('Ad units:', bidRequest.adUnits);
|
|
437
|
+
|
|
438
|
+
// Check for Mixpeek keys
|
|
439
|
+
const firstUnit = bidRequest.adUnits[0];
|
|
440
|
+
console.log('Targeting keys:', firstUnit.ortb2Imp.ext.data);
|
|
441
|
+
});
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
### 5. Test Caching
|
|
445
|
+
|
|
446
|
+
Verify caching is working:
|
|
447
|
+
|
|
448
|
+
```javascript
|
|
449
|
+
// First request - should hit API
|
|
450
|
+
await window.MixpeekContextAdapter.getContext();
|
|
451
|
+
|
|
452
|
+
// Second request - should use cache
|
|
453
|
+
await window.MixpeekContextAdapter.getContext();
|
|
454
|
+
|
|
455
|
+
// Check cache stats
|
|
456
|
+
const stats = window.MixpeekContextAdapter.getCacheStats();
|
|
457
|
+
console.log('Cache stats:', stats);
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
## Deployment
|
|
461
|
+
|
|
462
|
+
### Production Checklist
|
|
463
|
+
|
|
464
|
+
Before deploying to production:
|
|
465
|
+
|
|
466
|
+
- [ ] Remove `debug: true` from configuration
|
|
467
|
+
- [ ] Set appropriate `timeout` (250ms recommended)
|
|
468
|
+
- [ ] Configure `cacheTTL` based on your content update frequency
|
|
469
|
+
- [ ] Test on multiple page types (articles, videos, galleries)
|
|
470
|
+
- [ ] Verify targeting keys are reaching bidders
|
|
471
|
+
- [ ] Monitor Mixpeek API usage in your dashboard
|
|
472
|
+
- [ ] Set up error monitoring for `mixpeekContextError` events
|
|
473
|
+
- [ ] Configure fallback behavior for API failures
|
|
474
|
+
|
|
475
|
+
### Environment Variables
|
|
476
|
+
|
|
477
|
+
Store sensitive configuration in environment variables:
|
|
478
|
+
|
|
479
|
+
```javascript
|
|
480
|
+
pbjs.setConfig({
|
|
481
|
+
mixpeek: {
|
|
482
|
+
apiKey: window.MIXPEEK_API_KEY, // Injected server-side
|
|
483
|
+
collectionId: window.MIXPEEK_COLLECTION_ID,
|
|
484
|
+
namespace: window.MIXPEEK_NAMESPACE
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### Content Security Policy
|
|
490
|
+
|
|
491
|
+
If using CSP, add Mixpeek API to your policy:
|
|
492
|
+
|
|
493
|
+
```
|
|
494
|
+
connect-src 'self' https://api.mixpeek.com;
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
## Troubleshooting
|
|
498
|
+
|
|
499
|
+
### Adapter Not Initializing
|
|
500
|
+
|
|
501
|
+
**Symptom**: No logs in console, no context enrichment
|
|
502
|
+
|
|
503
|
+
**Solutions**:
|
|
504
|
+
1. Verify Prebid.js is loaded before the adapter
|
|
505
|
+
2. Check for JavaScript errors in console
|
|
506
|
+
3. Ensure configuration is inside `pbjs.que.push()`
|
|
507
|
+
|
|
508
|
+
```javascript
|
|
509
|
+
// Correct
|
|
510
|
+
pbjs.que.push(function() {
|
|
511
|
+
pbjs.setConfig({ mixpeek: {...} });
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
// Incorrect
|
|
515
|
+
pbjs.setConfig({ mixpeek: {...} }); // Too early
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
### API Errors (401 Unauthorized)
|
|
519
|
+
|
|
520
|
+
**Symptom**: `mixpeekContextError` events with 401 status
|
|
521
|
+
|
|
522
|
+
**Solutions**:
|
|
523
|
+
1. Verify your API key is correct
|
|
524
|
+
2. Check that the API key hasn't expired
|
|
525
|
+
3. Ensure the API key has the right permissions
|
|
526
|
+
|
|
527
|
+
### API Timeout
|
|
528
|
+
|
|
529
|
+
**Symptom**: Requests timing out, no context returned
|
|
530
|
+
|
|
531
|
+
**Solutions**:
|
|
532
|
+
1. Increase `timeout` value (but keep under 300ms)
|
|
533
|
+
2. Check your network connection
|
|
534
|
+
3. Verify Mixpeek API status
|
|
535
|
+
|
|
536
|
+
### No Content Extracted
|
|
537
|
+
|
|
538
|
+
**Symptom**: Empty context, no classification
|
|
539
|
+
|
|
540
|
+
**Solutions**:
|
|
541
|
+
1. Check page has sufficient content (min 100 characters)
|
|
542
|
+
2. Verify the correct `mode` is set
|
|
543
|
+
3. For video mode, check `videoSelector` matches your video element
|
|
544
|
+
4. Look for errors in content extractors
|
|
545
|
+
|
|
546
|
+
### Cache Not Working
|
|
547
|
+
|
|
548
|
+
**Symptom**: Every request hits the API, no cache hits
|
|
549
|
+
|
|
550
|
+
**Solutions**:
|
|
551
|
+
1. Ensure `enableCache: true`
|
|
552
|
+
2. Check localStorage is available (not blocked)
|
|
553
|
+
3. Verify content isn't changing between requests
|
|
554
|
+
|
|
555
|
+
### Targeting Keys Not Appearing
|
|
556
|
+
|
|
557
|
+
**Symptom**: Ad requests don't include Mixpeek keys
|
|
558
|
+
|
|
559
|
+
**Solutions**:
|
|
560
|
+
1. Enable `debug: true` and check for errors
|
|
561
|
+
2. Verify context is loaded before bid requests
|
|
562
|
+
3. Check the `beforeRequestBids` event is firing
|
|
563
|
+
4. Inspect `bidRequest.adUnits[0].ortb2Imp.ext.data`
|
|
564
|
+
|
|
565
|
+
## Support
|
|
566
|
+
|
|
567
|
+
- **Documentation**: [docs.mixpeek.com](https://docs.mixpeek.com)
|
|
568
|
+
- **Email**: support@mixpeek.com
|
|
569
|
+
- **GitHub Issues**: [github.com/mixpeek/prebid-contextual-adapter/issues](https://github.com/mixpeek/prebid-contextual-adapter/issues)
|
|
570
|
+
- **Slack Community**: [Join our Slack](https://mixpeek.com/slack)
|
|
571
|
+
|
|
572
|
+
## Next Steps
|
|
573
|
+
|
|
574
|
+
- [API Reference](api-reference.md) - Detailed API documentation
|
|
575
|
+
- [Examples](../examples/) - Sample implementations
|
|
576
|
+
- [Migration Guide](migration-guide.md) - Upgrading from older versions
|
|
577
|
+
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Mixpeek Prebid Demo
|
|
2
|
+
|
|
3
|
+
This example demonstrates the Mixpeek Context Adapter integrated with Prebid.js.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
1. Build the adapter:
|
|
8
|
+
```bash
|
|
9
|
+
cd ../..
|
|
10
|
+
npm install
|
|
11
|
+
npm run build
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
2. Update the configuration in `index.html`:
|
|
15
|
+
- Replace `YOUR_MIXPEEK_API_KEY` with your actual API key
|
|
16
|
+
- Replace `YOUR_COLLECTION_ID` with your collection ID
|
|
17
|
+
|
|
18
|
+
3. Start the demo server:
|
|
19
|
+
```bash
|
|
20
|
+
npm start
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
4. Open http://localhost:8080 in your browser
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- Real-time contextual analysis of page content
|
|
28
|
+
- Automatic IAB taxonomy classification
|
|
29
|
+
- Brand safety scoring
|
|
30
|
+
- Keyword extraction
|
|
31
|
+
- Live debug panel showing enrichment data
|
|
32
|
+
- Multiple ad units with contextual targeting
|
|
33
|
+
|
|
34
|
+
## How It Works
|
|
35
|
+
|
|
36
|
+
1. The page loads with article content about mobile phones and AI
|
|
37
|
+
2. Mixpeek Context Adapter extracts the page content
|
|
38
|
+
3. Content is sent to Mixpeek API for classification
|
|
39
|
+
4. Taxonomy, brand safety, and keywords are returned
|
|
40
|
+
5. Targeting keys are injected into Prebid ad requests
|
|
41
|
+
6. Bidders receive enriched requests with contextual signals
|
|
42
|
+
7. Ads are served based on contextual relevance
|
|
43
|
+
|
|
44
|
+
## Configuration
|
|
45
|
+
|
|
46
|
+
See the Mixpeek configuration in `index.html`:
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
pbjs.setConfig({
|
|
50
|
+
mixpeek: {
|
|
51
|
+
apiKey: 'YOUR_MIXPEEK_API_KEY',
|
|
52
|
+
collectionId: 'YOUR_COLLECTION_ID',
|
|
53
|
+
mode: 'page',
|
|
54
|
+
featureExtractors: ['taxonomy', 'brand-safety', 'keywords'],
|
|
55
|
+
timeout: 250,
|
|
56
|
+
cacheTTL: 300,
|
|
57
|
+
debug: true
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Testing
|
|
63
|
+
|
|
64
|
+
Try changing the article content and refresh the page to see how the contextual data changes.
|
|
65
|
+
|