-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Echo Ads module: initial release #14280
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Implements a new Prebid.js module that displays overlay ads when users reach the end of content. Key features include: - Configurable triggers: scroll depth, time on page, exit intent, or custom functions - Pre-fetch strategies: eager (immediate) or lazy (conditional) bid caching - Overlay/interstitial display formats with customizable close button delays - Frequency capping: session and daily limits with localStorage persistence - Publisher callbacks: onBidCached, onTrigger, onAdRender, onAdClose, onFrequencyCapReached - Multi-bidder support: works with any Prebid bidder adapter Demo includes GumGum integration with hardcoded test bid for demonstration. Files: - modules/echoAdsModule/index.js:662 - Core module implementation - modules/echoAdsModule.md - Module documentation - integrationExamples/gpt/echoAds_gumgum.html - Interactive demo page - modules/gumgumBidAdapter.js:607 - Test bid injection for demo 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Automated deployment script for Google Cloud Storage - Auto-builds Prebid bundle if not present - Fixes paths for GCS hosting (absolute URLs) - Sets proper content-types and public ACLs - No-cache headers for development testing Usage: ./deploy-demo.sh Demo URL: https://storage.googleapis.com/echoads-demo/index.html 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Automatic triggers (scroll, time, exit intent) now only fire once per page load - Manual triggers can still be called multiple times - Manual triggers still respect frequency caps but bypass hasBeenTriggered flag - Improves user experience by preventing duplicate automatic triggers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Automatic triggers (scroll, time) now fire only once per session - Set hasBeenTriggered immediately to prevent race conditions - Manual triggers bypass hasBeenTriggered and can fire multiple times - Clear cached bid immediately when ad is shown (not when closed) - Each bid is used only once - fresh auction for each manual trigger - Update demo creative to ACME image hosted on GCS 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Changed info box text from Nintendo to ACME creative - Reflects the updated hardcoded creative in GumGum adapter 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Use no-store, no-cache, must-revalidate for all demo files - Ensures fresh content on every reload for testing - Applies to HTML, JS bundle, and creative image 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Changed formula to show 0% at top, 100% at bottom - Previously showed percentage of content viewed (39% at top) - Now shows actual scroll position in scrollable area 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Changed module's scroll calculation to match demo page - Now correctly shows 0% at top, 100% at bottom - Previously used content-viewed formula instead of scroll position 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Created /demo folder with static site structure - Updated ACME creative URL to GitHub Pages - Fixed prebid.js path for demo deployment - Includes ACME 300x250 creative image - Ready for GitHub Pages deployment 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Move prebid.js directly to docs/ folder (no build path) - Avoids gitignore conflicts with build/ folder - Add deploy-github-pages.sh script for easy deployment - Updated HTML to reference prebid.js directly 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Added a server backend (server.py) to allow saving new test creatives directly to test-creatives/creatives.json from the demo UI.
Updated package.json to use the Python server for local development.
Overhauled the index.html demo interactive UX:
Users can now paste ad tags, assign custom names, and save/replace them permanently in the creatives list.
Saved creatives immediately appear in the dropdown for creative selection.
It tries saving to the backend first; fallback to JSON download if server is unavailable.
Optimized controls layout:
New configuration message.
Test Creative section (dropdown, paste tag, save) is directly below the configuration.
Controls & Metrics now show beneath Test Creative.
Logs (event log) appear last, in their own card with a heading.
UI buttons ("Use Pasted Tag", "Save to JSON") are now orange, matching other primary buttons.
|
Whoa there, partner! 🌵🤠 We wrangled some duplicated code in your PR:
Reducing code duplication by importing common functions from a library not only makes our code cleaner but also easier to maintain. Please move the common code from both files into a library and import it in each. We hate that we have to mention this, however, commits designed to hide from this utility by renaming variables or reordering an object are poor conduct. We will not look upon them kindly! Keep up the great work! 🚀 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if (selectedCreative) { | ||
| logWarn('[GumGum] DEMO MODE: Returning test bid for Echo Ads demo (' + selectedCreative.name + ')'); | ||
| return [{ | ||
| ad: selectedCreative.creative, | ||
| mediaType: BANNER, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Demo flag overrides real GumGum bids
When window.selectedTestCreative is present, the adapter short-circuits interpretResponse and returns a hardcoded banner with a fixed CPM instead of using the actual GumGum server response. Any page (including non-demo pages that happen to define that global) will replace legitimate bids with the static creative and price, breaking auction results and reporting whenever that flag is set.
Useful? React with 👍 / 👎.
| // Render the ad first - insert HTML directly | ||
| if (cachedBid.ad) { | ||
| adContainer.innerHTML = cachedBid.ad; | ||
| } else { | ||
| logError(`${MODULE_NAME}: Cached bid has no ad creative`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Echo Ads injects creatives without rendering scripts
The overlay renderer assigns cachedBid.ad directly to innerHTML; script tags inside the creative (or creatives delivered via adUrl) will not execute, so most bidder markup will never render or fire trackers, despite the module claiming to work with any Prebid bidder. The overlay will therefore show blank content for standard script-based banners rather than the winning ad.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the bot is right, you may want to create an iframe and pass its document to pbjs.renderAd instead
| @@ -0,0 +1,1422 @@ | |||
| <!-- | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all this demo stuff needs to be a folder inside integrationExamples
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this includes the first two bash scripts
| } | ||
| }, | ||
| onBidCached: function(bidInfo) { | ||
| logEvent('✓ Bid cached: ' + bidInfo.bidder + ' $' + bidInfo.cpm.toFixed(2) + ' CPM (' + bidInfo.size + ')'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no emojis
| logEvent('✓ Echo Ad closed by user'); | ||
| }, | ||
| onFrequencyCapReached: function() { | ||
| logEvent('⚠ Frequency cap reached - ad not shown'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no emojis
| // Add the ad unit | ||
| pbjs.addAdUnits([moduleConfig.adUnit]); | ||
|
|
||
| auctionInProgress = true; | ||
|
|
||
| // Request bids | ||
| pbjs.requestBids({ | ||
| adUnitCodes: [moduleConfig.adUnit.code], | ||
| bidsBackHandler: function(bids) { | ||
| logInfo(`${MODULE_NAME}: Bids returned`, bids); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can pass the ad unit directly to requestBids({adUnits: [moduleConfig.adUnit]}) which I think is preferable since it doesn't affect subsequent auctions as addAdUnits does.
If you expect this to be the only way to get the "special" bid you could also cache it from bidsBackHandler instead of using an event handler.
| // Render the ad first - insert HTML directly | ||
| if (cachedBid.ad) { | ||
| adContainer.innerHTML = cachedBid.ad; | ||
| } else { | ||
| logError(`${MODULE_NAME}: Cached bid has no ad creative`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the bot is right, you may want to create an iframe and pass its document to pbjs.renderAd instead
|
Whoa there, partner! 🌵🤠 We wrangled some duplicated code in your PR:
Reducing code duplication by importing common functions from a library not only makes our code cleaner but also easier to maintain. Please move the common code from both files into a library and import it in each. We hate that we have to mention this, however, commits designed to hide from this utility by renaming variables or reordering an object are poor conduct. We will not look upon them kindly! Keep up the great work! 🚀 |
Type of change
Bugfix
Feature
New bidder adapter
Updated bidder adapter
Code style update (formatting, local variables)
Refactoring (no functional changes, no api changes)
Build related changes
CI related changes
Does this change affect user-facing APIs or examples documented on http://prebid.org?
Other
Description of change
Other information