Skip to content

Conversation

@dyachoksa
Copy link
Collaborator

Add OptablePrebidAnalytics class to track auction and bid events from Prebid.js and send them to Optable's witness API. The addon supports configurable sampling rates, debug logging, and custom analytics data injection.

Key features:

  • Tracks auctionEnd and bidWon events with detailed bid request/response data
  • Extracts and reports Optable EID matchers and sources from ORTB2 data
  • Implements deterministic and random sampling strategies
  • Handles missed events by processing Prebid's event history

The witness API type definition is updated to support nested objects and arrays in event properties to accommodate complex auction data structures.

Add OptablePrebidAnalytics class to track auction and bid events from Prebid.js and send them to Optable's witness API. The addon supports configurable sampling rates, debug logging, and custom analytics data injection.

Key features:
- Tracks auctionEnd and bidWon events with detailed bid request/response data
- Extracts and reports Optable EID matchers and sources from ORTB2 data
- Implements deterministic and random sampling strategies
- Handles missed events by processing Prebid's event history

The witness API type definition is updated to support nested objects and arrays in event properties to accommodate complex auction data structures.
@dyachoksa dyachoksa requested review from benschaff and zapo November 4, 2025 13:42
@dyachoksa dyachoksa added type:feature New feature or request javascript Pull requests that update javascript code labels Nov 4, 2025
Add new fields to improve analytics tracking and debugging:
- Replace 'missed' with 'optableLoaded' for clearer semantics
- Rename 'hasOptable' to 'optableTargetingDone' for consistency
- Include 'optableSampling' rate in witness payload
- Add 'userAgent' to payload for better debugging
- Expose 'optableTargetingDone' at bidder request level
Copy link

@jrosendahl-opt jrosendahl-opt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two questions about sampling and handling auctions with no bid won events.

If i missed where this is happening, please feel free to explain.

}

// Random sampling
return Math.random() < this.config.samplingRate!;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like the sample rate by default is on a per auction basis. Preferably we want to sample per session, we should be able to use a session cookie to manage sampling rate.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added additional parameter to the config that allow sample per session, but I've kept per-event sampling as default option as it will provide more visibility. But both variants are configurable and can be set for each bundle individually.


// Store the processed auction
this.auctions.set(auctionId, { auctionEnd: event, createdAt: new Date(), missed });

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not seeing where we are sending auction data in cases where no bid won event occurs.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added extra processing. Default timeout for bidWon event 10s. Configurable.

Introduce `bidWinTimeout` to track bid win events. If a bid win is not received within the configured timeout after an auction ends, a witness event is sent with `bidWon: null` to indicate a missed bid.

Add `samplingVolume` configuration, allowing analytics sampling to be applied either per `event` (default) or per `session`. Session-based sampling ensures a consistent sampling decision for a user throughout their browsing session.

The analytics payload is enhanced with `auctionEndAt`, `bidWonAt`, and `optableLoaded` fields, and the `bidWon` object can now be `null` to explicitly represent cases where no bid was won or tracked.

Update `witness.ts` to allow `null` values in the witness payload properties. Refactor `analytics.test.ts` to simplify `eids` structure and remove redundant fields.
Clears the `auctionEndTimeoutId` when a bid is won to prevent it
from firing after the auction is complete. Additionally, removes
the auction object from the internal map to prevent memory leaks
and ensure proper resource cleanup.
Copy link
Contributor

@Yoshiji Yoshiji left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code LGTM. Thank you for the test coverage 👍


declare global {
interface Window {
// @ts-ignore
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand there is not much value in typing the window object, however should we add
OptablePrebidAnalytics["constructor"] to OptableGlobal for completion or just get rid of OptableGlobal type?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Moves device object assignment to a higher scope for consistent use across the analytics payload.
Removes the redundant `userAgentRaw` field, as the parsed `userAgent` is already available.
@dyachoksa dyachoksa requested review from Yoshiji and zapo December 5, 2025 14:09
Copy link

@domngco domngco left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some minor nice to have for the documentation of the methods added.

But overall LGTM, great test coverage 👍

I would wait for an approval from @Yoshiji or @zapo before merging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

javascript Pull requests that update javascript code type:feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants