@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/QUICKSTART.md ADDED
@@ -0,0 +1,234 @@
1
+ # Quick Start Guide
2
+
3
+ Get the Mixpeek Context Adapter running in 5 minutes.
4
+
5
+ ## 1. Get Your API Key
6
+
7
+ 1. Sign up at [mixpeek.com/start](https://mixpeek.com/start)
8
+ 2. Navigate to your dashboard
9
+ 3. Generate an API key (starts with `sk_`)
10
+ 4. Copy the API key
11
+
12
+ ## 2. Set Up Environment
13
+
14
+ ```bash
15
+ # Clone or navigate to the repository
16
+ cd /path/to/prebid.js
17
+
18
+ # Install dependencies
19
+ npm install
20
+
21
+ # Set your API credentials
22
+ export MIXPEEK_API_KEY="sk_your_api_key_here"
23
+
24
+ # Use development server (temporary)
25
+ export MIXPEEK_API_ENDPOINT="https://server-xb24.onrender.com"
26
+
27
+ # Optional: Set a collection ID (will create if not set)
28
+ export MIXPEEK_COLLECTION_ID="col_your_collection_id"
29
+ ```
30
+
31
+ > **Note**: We're currently using the development server at `https://server-xb24.onrender.com`. When ready for production, change to `https://api.mixpeek.com`.
32
+
33
+ ## 3. Validate Setup
34
+
35
+ ```bash
36
+ npm run validate
37
+ ```
38
+
39
+ Expected output:
40
+ ```
41
+ 🔍 Mixpeek API Setup Validation
42
+
43
+ ================================
44
+
45
+ 📋 Configuration Check:
46
+ API Key: ✅ Set
47
+ Collection ID: ⚠️ Not set (will create)
48
+ Namespace: ⚠️ Not set (using default)
49
+ Endpoint: https://api.mixpeek.com
50
+
51
+ 🌐 Testing API Connection...
52
+
53
+ ✅ API Connection: Success
54
+ Status: healthy
55
+
56
+ 🧩 Testing Feature Extractors Endpoint...
57
+
58
+ ✅ Feature Extractors: Available
59
+ Found 12 extractors
60
+ Available: taxonomy, brand-safety, keywords, sentiment, clustering
61
+
62
+ ================================
63
+
64
+ ✅ Setup validation complete!
65
+ ```
66
+
67
+ ## 4. Run Tests
68
+
69
+ ### Unit Tests (No API Required)
70
+
71
+ ```bash
72
+ npm test
73
+ ```
74
+
75
+ ### Live API Tests
76
+
77
+ ```bash
78
+ npm run test:live
79
+ ```
80
+
81
+ ### All Tests
82
+
83
+ ```bash
84
+ npm run test:all
85
+ ```
86
+
87
+ ## 5. Build the Adapter
88
+
89
+ ```bash
90
+ npm run build
91
+ ```
92
+
93
+ Output: `dist/mixpeekContextAdapter.js`
94
+
95
+ ## 6. Try the Example
96
+
97
+ ```bash
98
+ # Update the example with your credentials
99
+ # Edit: examples/publisher-demo/index.html
100
+
101
+ # Run the demo
102
+ cd examples/publisher-demo
103
+ npm install
104
+ npm start
105
+
106
+ # Open http://localhost:8080
107
+ ```
108
+
109
+ ## 7. Integrate with Your Site
110
+
111
+ ### Basic Integration
112
+
113
+ ```html
114
+ <!-- Load Prebid.js -->
115
+ <script src="https://cdn.jsdelivr.net/npm/prebid.js@latest/dist/prebid.js"></script>
116
+
117
+ <!-- Load Mixpeek Adapter -->
118
+ <script src="path/to/mixpeekContextAdapter.js"></script>
119
+
120
+ <script>
121
+ var pbjs = pbjs || {};
122
+ pbjs.que = pbjs.que || [];
123
+
124
+ pbjs.que.push(function() {
125
+ // Configure Mixpeek as an RTD provider
126
+ pbjs.setConfig({
127
+ realTimeData: {
128
+ auctionDelay: 250, // Max time to wait for contextual data
129
+ dataProviders: [{
130
+ name: 'mixpeek',
131
+ waitForIt: true, // Wait for Mixpeek before starting auction
132
+ params: {
133
+ apiKey: 'YOUR_API_KEY',
134
+ collectionId: 'YOUR_COLLECTION_ID',
135
+ endpoint: 'https://server-xb24.onrender.com', // Development server
136
+ featureExtractors: ['taxonomy'],
137
+ mode: 'auto',
138
+ timeout: 5000, // Higher timeout for dev server
139
+ cacheTTL: 300
140
+ }
141
+ }]
142
+ }
143
+ });
144
+
145
+ // Add your ad units
146
+ pbjs.addAdUnits([
147
+ {
148
+ code: 'div-banner-1',
149
+ mediaTypes: {
150
+ banner: { sizes: [[300, 250]] }
151
+ },
152
+ bids: [
153
+ {
154
+ bidder: 'rubicon',
155
+ params: { /* ... */ }
156
+ }
157
+ ]
158
+ }
159
+ ]);
160
+
161
+ // Request bids
162
+ pbjs.requestBids({
163
+ bidsBackHandler: function(bids) {
164
+ // Your bid handling code
165
+ // Bids now include Mixpeek contextual data in ortb2
166
+ }
167
+ });
168
+ });
169
+ </script>
170
+ ```
171
+
172
+ ## Troubleshooting
173
+
174
+ ### "API key not set"
175
+
176
+ ```bash
177
+ export MIXPEEK_API_KEY="sk_your_key"
178
+ npm run validate
179
+ ```
180
+
181
+ ### "Collection not found"
182
+
183
+ Create a collection:
184
+
185
+ ```bash
186
+ curl -X POST https://api.mixpeek.com/v1/collections \
187
+ -H "Authorization: Bearer $MIXPEEK_API_KEY" \
188
+ -H "Content-Type: application/json" \
189
+ -d '{
190
+ "name": "prebid-contextual",
191
+ "description": "Contextual targeting for Prebid"
192
+ }'
193
+ ```
194
+
195
+ Save the `collection_id` and export it:
196
+
197
+ ```bash
198
+ export MIXPEEK_COLLECTION_ID="col_abc123"
199
+ ```
200
+
201
+ ### Tests Timing Out
202
+
203
+ Increase timeout in `jest.config.live.js`:
204
+
205
+ ```javascript
206
+ testTimeout: 60000 // 60 seconds
207
+ ```
208
+
209
+ ## Next Steps
210
+
211
+ - 📚 [Integration Guide](docs/integration-guide.md) - Detailed integration instructions
212
+ - 📖 [API Reference](docs/api-reference.md) - Complete API documentation
213
+ - 🧪 [Testing Guide](TESTING.md) - Comprehensive testing guide
214
+ - 🎯 [Examples](examples/) - Sample implementations
215
+
216
+ ## Support
217
+
218
+ - **Documentation**: https://docs.mixpeek.com
219
+ - **Email**: support@mixpeek.com
220
+ - **GitHub Issues**: https://github.com/mixpeek/prebid-contextual-adapter/issues
221
+
222
+ ## What's Next?
223
+
224
+ The adapter is now set up and ready to use! Here's what happens:
225
+
226
+ 1. **Page loads** with Prebid and Mixpeek adapter
227
+ 2. **Content is extracted** from the page (text, images, video)
228
+ 3. **Mixpeek API classifies** the content into IAB categories
229
+ 4. **Targeting keys** are injected into bid requests
230
+ 5. **Bidders receive** enriched requests with contextual signals
231
+ 6. **Ads are served** based on content relevance
232
+
233
+ All of this happens in <250ms without blocking your ad auction! 🚀
234
+
package/README.md ADDED
@@ -0,0 +1,439 @@
1
+ # Mixpeek Contextual Adapter for Prebid.js
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@mixpeek/prebid.svg)](https://www.npmjs.com/package/@mixpeek/prebid)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@mixpeek/prebid.svg)](https://www.npmjs.com/package/@mixpeek/prebid)
5
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
6
+ [![Node Version](https://img.shields.io/node/v/@mixpeek/prebid.svg)](https://www.npmjs.com/package/@mixpeek/prebid)
7
+ [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@mixpeek/prebid)](https://bundlephobia.com/package/@mixpeek/prebid)
8
+ [![Dependencies](https://img.shields.io/librariesio/release/npm/@mixpeek/prebid)](https://www.npmjs.com/package/@mixpeek/prebid)
9
+ [![GitHub Stars](https://img.shields.io/github/stars/mixpeek/prebid?style=social)](https://github.com/mixpeek/prebid)
10
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/mixpeek/prebid/pulls)
11
+
12
+ ## 🎯 Overview
13
+
14
+ 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:
15
+
16
+ - **Privacy-First Targeting**: No cookies, just content-based context
17
+ - **Multimodal Analysis**: Text, images, video, and audio processing
18
+ - **IAB Taxonomy**: Automatic classification into IAB content categories
19
+ - **Brand Safety**: Real-time brand safety scoring
20
+ - **Ad Adjacency Awareness**: Tracks previous ad to avoid repetition and improve user experience
21
+ - **Sub-100ms Performance**: Optimized for header bidding speed requirements
22
+ - **Graceful Fallbacks**: Never blocks the auction
23
+
24
+ ## 🚀 Quick Start
25
+
26
+ ### Installation
27
+
28
+ ```bash
29
+ npm install @mixpeek/prebid
30
+ ```
31
+
32
+ ### Basic Setup
33
+
34
+ ```javascript
35
+ // 1. Include the Mixpeek RTD module
36
+ import '@mixpeek/prebid'
37
+
38
+ // 2. Configure Mixpeek as an RTD provider
39
+ pbjs.setConfig({
40
+ realTimeData: {
41
+ auctionDelay: 250, // Max time to wait for contextual data (ms)
42
+ dataProviders: [{
43
+ name: 'mixpeek',
44
+ waitForIt: true, // Wait for Mixpeek before starting auction
45
+ params: {
46
+ apiKey: 'YOUR_MIXPEEK_API_KEY',
47
+ collectionId: 'your-collection-id',
48
+
49
+ // Use development server (temporary)
50
+ endpoint: 'https://server-xb24.onrender.com',
51
+ // Or production: endpoint: 'https://api.mixpeek.com',
52
+
53
+ namespace: 'your-namespace', // optional
54
+ featureExtractors: ['taxonomy', 'brand-safety'],
55
+ mode: 'page', // 'page', 'video', or 'auto'
56
+ timeout: 5000, // ms - higher for dev server
57
+ cacheTTL: 300 // seconds
58
+ }
59
+ }]
60
+ }
61
+ })
62
+
63
+ // 3. The RTD module automatically enriches bid requests!
64
+ pbjs.requestBids({
65
+ adUnits: [...],
66
+ bidsBackHandler: function(bids) {
67
+ // Bids now include Mixpeek contextual data in ortb2
68
+ }
69
+ })
70
+ ```
71
+
72
+ ## 📋 Prerequisites
73
+
74
+ 1. **Mixpeek Account**: Sign up at [mixpeek.com](https://mixpeek.com/start)
75
+ 2. **API Key**: Generate an API key in your Mixpeek dashboard
76
+ 3. **Collection**: Create a collection with feature extractors configured
77
+ 4. **Prebid.js**: Version 6.0.0 or higher
78
+
79
+ ## 🔧 Configuration Options
80
+
81
+ ### RTD Configuration
82
+
83
+ | Option | Type | Required | Default | Description |
84
+ |--------|------|----------|---------|-------------|
85
+ | `realTimeData.auctionDelay` | number | ❌ | 250 | Max time to wait for all RTD providers (ms) |
86
+ | `realTimeData.dataProviders[].name` | string | ✅ | - | Must be `'mixpeek'` |
87
+ | `realTimeData.dataProviders[].waitForIt` | boolean | ❌ | false | Wait for Mixpeek before starting auction |
88
+
89
+ ### Mixpeek Parameters
90
+
91
+ | Option | Type | Required | Default | Description |
92
+ |--------|------|----------|---------|-------------|
93
+ | `params.apiKey` | string | ✅ | - | Your Mixpeek API key |
94
+ | `params.collectionId` | string | ✅ | - | Mixpeek collection ID for document processing |
95
+ | `params.endpoint` | string | ❌ | `https://server-xb24.onrender.com` | Mixpeek API endpoint (dev server default) |
96
+ | `params.namespace` | string | ❌ | - | Optional namespace for data isolation |
97
+ | `params.featureExtractors` | array | ❌ | `['taxonomy']` | Feature extractors to use (taxonomy, brand-safety, etc.) |
98
+ | `params.mode` | string | ❌ | `auto` | Content mode: `page`, `video`, `image`, or `auto` |
99
+ | `params.timeout` | number | ❌ | 250 | API request timeout in milliseconds |
100
+ | `params.cacheTTL` | number | ❌ | 300 | Cache TTL in seconds |
101
+ | `params.enableCache` | boolean | ❌ | `true` | Enable local caching |
102
+ | `params.debug` | boolean | ❌ | `false` | Enable debug logging |
103
+ | `params.batchSize` | number | ❌ | 1 | Number of concurrent requests |
104
+ | `params.retryAttempts` | number | ❌ | 2 | Number of retry attempts on failure |
105
+
106
+ ## 📊 Output: OpenRTB 2.6 Data Structure
107
+
108
+ The RTD module injects contextual data into your bid requests using the OpenRTB 2.6 standard:
109
+
110
+ ### Site-Level Data (`ortb2.site.content`)
111
+ ```javascript
112
+ {
113
+ "ortb2": {
114
+ "site": {
115
+ "content": {
116
+ "cat": ["IAB19-11"], // IAB Content Categories
117
+ "cattax": 6, // IAB Content Taxonomy v3.0
118
+ "genre": "Technology - AI", // Human-readable category
119
+ "keywords": "ai,technology,ml", // Extracted keywords
120
+ "language": "en", // Content language
121
+ "title": "Article Title", // Page title
122
+ "url": "https://example.com", // Page URL
123
+ "ext": {
124
+ "data": {
125
+ "mixpeek": {
126
+ "score": 0.94, // Confidence score
127
+ "brandSafety": 0.98, // Brand safety score
128
+ "sentiment": "positive", // Content sentiment
129
+ "embeddingId": "emb_abc123" // Embedding ID
130
+ }
131
+ }
132
+ }
133
+ }
134
+ }
135
+ }
136
+ }
137
+ ```
138
+
139
+ ### Impression-Level Data (`ortb2Imp.ext.data`)
140
+ ```javascript
141
+ {
142
+ // Current page context
143
+ "hb_mixpeek_taxonomy": "IAB19-11", // Primary IAB taxonomy code
144
+ "hb_mixpeek_category": "Technology > AI", // Human-readable category
145
+ "hb_mixpeek_node": "node_tech_ai", // Taxonomy node ID
146
+ "hb_mixpeek_path": "tech/ai/ml", // Hierarchical path
147
+ "hb_mixpeek_score": "0.94", // Confidence score
148
+ "hb_mixpeek_safety": "0.98", // Brand safety score
149
+ "hb_mixpeek_keywords": "AI,ML,tech", // Extracted keywords
150
+ "hb_mixpeek_embed": "emb_abc123", // Embedding ID for retrieval
151
+
152
+ // Previous ad context (adjacency awareness)
153
+ "hb_mixpeek_prev_creative": "12345", // Last creative ID shown
154
+ "hb_mixpeek_prev_bidder": "appnexus", // Last bidder that won
155
+ "hb_mixpeek_prev_adunit": "sidebar-1", // Last ad unit code
156
+ "hb_mixpeek_prev_cat": "IAB18-1,IAB12-3" // Last ad categories
157
+ }
158
+ ```
159
+
160
+ ## 🎥 Usage Examples
161
+
162
+ ### Page Context (Articles, Blogs)
163
+
164
+ ```javascript
165
+ pbjs.setConfig({
166
+ realTimeData: {
167
+ auctionDelay: 250,
168
+ dataProviders: [{
169
+ name: 'mixpeek',
170
+ waitForIt: true,
171
+ params: {
172
+ apiKey: 'sk_your_api_key',
173
+ collectionId: 'col_articles',
174
+ mode: 'page',
175
+ featureExtractors: ['taxonomy', 'brand-safety', 'keywords']
176
+ }
177
+ }]
178
+ }
179
+ })
180
+ ```
181
+
182
+ ### Video Context (Pre-roll, Mid-roll)
183
+
184
+ ```javascript
185
+ pbjs.setConfig({
186
+ realTimeData: {
187
+ auctionDelay: 300, // Longer delay for video processing
188
+ dataProviders: [{
189
+ name: 'mixpeek',
190
+ waitForIt: true,
191
+ params: {
192
+ apiKey: 'sk_your_api_key',
193
+ collectionId: 'col_videos',
194
+ mode: 'video',
195
+ videoSelector: '#main-video', // CSS selector for video element
196
+ featureExtractors: ['taxonomy', 'scene-detection']
197
+ }
198
+ }]
199
+ }
200
+ })
201
+ ```
202
+
203
+ ### Multi-Content Auto-Detection
204
+
205
+ ```javascript
206
+ pbjs.setConfig({
207
+ realTimeData: {
208
+ auctionDelay: 250,
209
+ dataProviders: [{
210
+ name: 'mixpeek',
211
+ waitForIt: true,
212
+ params: {
213
+ apiKey: 'sk_your_api_key',
214
+ collectionId: 'col_mixed',
215
+ mode: 'auto', // Automatically detects page, video, or image content
216
+ featureExtractors: ['taxonomy', 'brand-safety', 'clustering']
217
+ }
218
+ }]
219
+ }
220
+ })
221
+ ```
222
+
223
+ ## 🏗️ How It Works
224
+
225
+ ```mermaid
226
+ sequenceDiagram
227
+ participant Publisher
228
+ participant Prebid
229
+ participant MixpeekAdapter
230
+ participant MixpeekAPI
231
+ participant SSP
232
+
233
+ Publisher->>Prebid: Request Bids
234
+ Prebid->>MixpeekAdapter: beforeRequestBids event
235
+ MixpeekAdapter->>MixpeekAdapter: Extract page/video content
236
+ MixpeekAdapter->>MixpeekAdapter: Check cache
237
+ alt Cache Miss
238
+ MixpeekAdapter->>MixpeekAPI: POST /collections/{id}/documents
239
+ MixpeekAPI->>MixpeekAPI: Process with feature extractors
240
+ MixpeekAPI-->>MixpeekAdapter: Return enrichments
241
+ MixpeekAdapter->>MixpeekAdapter: Cache result
242
+ end
243
+ MixpeekAdapter->>Prebid: Inject contextual key-values
244
+ Prebid->>SSP: Send enriched bid request
245
+ SSP-->>Prebid: Return bids
246
+ Prebid-->>Publisher: Render ad
247
+ ```
248
+
249
+ ## 🧪 Testing
250
+
251
+ ```bash
252
+ # Run all tests
253
+ npm test
254
+
255
+ # Run with coverage
256
+ npm run test:coverage
257
+
258
+ # Watch mode
259
+ npm run test:watch
260
+ ```
261
+
262
+ ## 📖 Advanced Configuration
263
+
264
+ ### Custom Feature Extractors
265
+
266
+ ```javascript
267
+ pbjs.setConfig({
268
+ realTimeData: {
269
+ auctionDelay: 250,
270
+ dataProviders: [{
271
+ name: 'mixpeek',
272
+ waitForIt: true,
273
+ params: {
274
+ apiKey: 'sk_your_api_key',
275
+ collectionId: 'col_custom',
276
+ customExtractors: [
277
+ {
278
+ feature_extractor_id: 'sentiment-analyzer',
279
+ payload: {
280
+ model: 'sentiment-v2',
281
+ threshold: 0.7
282
+ }
283
+ }
284
+ ]
285
+ }
286
+ }]
287
+ }
288
+ })
289
+ ```
290
+
291
+ ### Conditional Loading
292
+
293
+ ```javascript
294
+ // Only enrich on specific pages
295
+ if (window.location.pathname.startsWith('/articles/')) {
296
+ pbjs.setConfig({
297
+ realTimeData: {
298
+ auctionDelay: 250,
299
+ dataProviders: [{
300
+ name: 'mixpeek',
301
+ waitForIt: true,
302
+ params: {
303
+ apiKey: 'sk_your_api_key',
304
+ collectionId: 'col_articles',
305
+ mode: 'page'
306
+ }
307
+ }]
308
+ }
309
+ })
310
+ }
311
+ ```
312
+
313
+ ### Event Callbacks
314
+
315
+ ```javascript
316
+ pbjs.onEvent('mixpeekContextReady', function(context) {
317
+ console.log('Mixpeek context loaded:', context)
318
+ // Custom analytics or modifications
319
+ })
320
+
321
+ pbjs.onEvent('mixpeekContextError', function(error) {
322
+ console.error('Mixpeek context error:', error)
323
+ // Custom error handling
324
+ })
325
+ ```
326
+
327
+ ## 🔄 Previous Ad Tracking (Adjacency Awareness)
328
+
329
+ The adapter automatically tracks the most recently served ad to enable adjacency-aware targeting. This helps:
330
+
331
+ - **Avoid Ad Repetition**: Prevent showing the same creative or category repeatedly
332
+ - **Frequency Capping**: Build frequency cap rules based on previous impressions
333
+ - **Competitive Separation**: Avoid showing competing brands consecutively
334
+ - **Enhanced User Experience**: Improve ad diversity and relevance
335
+
336
+ ### How It Works
337
+
338
+ 1. **Automatic Tracking**: On every `bidResponse` event, the adapter stores minimal information about the winning ad
339
+ 2. **Lightweight Storage**: Data is stored in memory + localStorage (privacy-safe, no PII)
340
+ 3. **Targeting Keys**: Previous ad data is automatically injected into subsequent bid requests
341
+
342
+ ### Data Tracked
343
+
344
+ | Field | Description | Example |
345
+ |-------|-------------|---------|
346
+ | `creativeId` | Winning creative ID | `"12345"` |
347
+ | `bidder` | Winning bidder code | `"appnexus"` |
348
+ | `adUnitCode` | Ad unit that served the ad | `"sidebar-1"` |
349
+ | `categories` | IAB categories of the ad | `["IAB18-1", "IAB12-3"]` |
350
+ | `timestamp` | When the ad was served | `1697123456789` |
351
+
352
+ ### Targeting Keys Injected
353
+
354
+ The following keys are automatically added to `ortb2Imp.ext.data`:
355
+
356
+ - `hb_mixpeek_prev_creative` - Last creative ID
357
+ - `hb_mixpeek_prev_bidder` - Last winning bidder
358
+ - `hb_mixpeek_prev_adunit` - Last ad unit code
359
+ - `hb_mixpeek_prev_cat` - Last ad categories (comma-separated)
360
+
361
+ ### SSP/DSP Usage
362
+
363
+ SSPs and DSPs can use these keys for advanced targeting rules:
364
+
365
+ ```javascript
366
+ // Example: Avoid showing the same creative twice in a row
367
+ if (bidRequest.ortb2Imp.ext.data.hb_mixpeek_prev_creative === currentCreative.id) {
368
+ // Skip this creative or reduce bid
369
+ }
370
+
371
+ // Example: Competitive separation
372
+ const prevCategories = bidRequest.ortb2Imp.ext.data.hb_mixpeek_prev_cat?.split(',') || []
373
+ if (prevCategories.includes('IAB18-1') && currentAd.category === 'IAB18-1') {
374
+ // Don't show competing fashion ads back-to-back
375
+ }
376
+ ```
377
+
378
+ ### Privacy & Storage
379
+
380
+ - **No User Tracking**: Only ad metadata is stored, no user identifiers or behavior
381
+ - **Session-Scoped**: Data persists across page views within a session
382
+ - **Local Storage**: Falls back to memory-only if localStorage is unavailable
383
+ - **Minimal Data**: Only essential fields are stored (< 200 bytes)
384
+ - **GDPR/CCPA Compliant**: No consent required as it doesn't track users
385
+
386
+ ### Programmatic Control
387
+
388
+ You can access the previous ad tracker directly if needed:
389
+
390
+ ```javascript
391
+ import previousAdTracker from '@mixpeek/prebid/utils/previousAdTracker'
392
+
393
+ // Get last ad info
394
+ const lastAd = previousAdTracker.getLast()
395
+ console.log('Last creative:', lastAd?.creativeId)
396
+
397
+ // Clear history (e.g., on user logout or page type change)
398
+ previousAdTracker.clear()
399
+ ```
400
+
401
+ ## 🔒 Security & Privacy
402
+
403
+ - **No PII**: The adapter never sends user identifiers or cookies
404
+ - **Content-Only**: Only page/video content is analyzed
405
+ - **HTTPS**: All API calls use TLS encryption
406
+ - **API Key Safety**: Store API keys securely (environment variables, server-side rendering)
407
+ - **GDPR/CCPA Compliant**: Contextual targeting doesn't require user consent
408
+
409
+ ## 📚 Documentation
410
+
411
+ ### User Guides
412
+ - [Quick Start](QUICKSTART.md) - Get running in 5 minutes
413
+ - [Integration Guide](docs/integration-guide.md) - Step-by-step integration
414
+ - [API Reference](docs/api-reference.md) - Complete API documentation
415
+ - [Testing Guide](TESTING.md) - How to test the adapter
416
+ - [Endpoint Configuration](ENDPOINTS.md) - Configure API endpoints
417
+ - [Health Check](docs/health-check.md) - Health check configuration
418
+
419
+ ### Developer Resources
420
+ - [Mixpeek API Docs](https://docs.mixpeek.com) - Platform documentation
421
+ - [Internal Planning](tasks/) - Gap analysis & implementation plans (internal)
422
+
423
+ ## 🤝 Support
424
+
425
+ - **Email**: support@mixpeek.com
426
+ - **GitHub Issues**: [Create an issue](https://github.com/mixpeek/prebid/issues)
427
+ - **Documentation**: [docs.mixpeek.com](https://docs.mixpeek.com)
428
+ - **Slack Community**: [Join our Slack](https://mixpeek.com/slack)
429
+
430
+ ## 📄 License
431
+
432
+ Apache 2.0 - see [LICENSE](LICENSE) file for details.
433
+
434
+ ## 🙏 Credits
435
+
436
+ Built with ❤️ by [Mixpeek](https://mixpeek.com)
437
+
438
+ Integrates with [Prebid.js](https://prebid.org) - an open-source header bidding solution
439
+