Publisher Integration Guide
A one-tag drop-in: runs a Prebid auction against limelightDigital, stitches the winning bid into your GAM ad call, plays the result through video.js + IMA.
Overview
One <script> tag with data-* attributes handles: lazy-loading video.js + IMA + Prebid (≈ 250 KB), running the auction, stitching hb_pb / hb_bidder / hb_uuid / hb_size / hb_format / hb_adid into GAM's cust_params, and rendering the cached creative via IMA.
Engine hosted at versioned, immutable jsDelivr URLs. Pin to a tag (e.g. @v2.5.1) — the bytes cannot silently change.
How it works
data-*; registers a video ad unit.POST {host}/ortbhbhb_* set into the GAM tag's cust_params, applies floor bias to hb_pb, refreshes correlator.hb_pb wins.%%PATTERN:hb_uuid%% resolved.Prebid load failure, bidder timeout, or no-bid → engine still calls GAM with hb_pb=0.00&hb_bidder=none. Your house line item fills the slot.
Prerequisites
- Google Ad Manager account with video inventory; a GAM Master Ad Tag URL ending in
correlator=. - Limelight Digital publisher ID + ad unit ID.
- Domain allowlisted by Limelight (1–3 business days). Without this, every auction returns no-bid.
- HTTPS publisher pages; content video URL (.mp4 / .m3u8) on your CDN.
The publisher domain not being on Limelight's allowlist. Verify before launch.
Quick start
Generate the tag
Open the Tag Generator, fill in version, GAM tag, Limelight pub/ad-unit IDs, content URL → copy the
<script>.Set up GAM
Create the key-values, the VAST wrapper creative, and one line item per
$0.10bucket (one-time setup — see GAM setup).Embed
Paste the snippet where the player should render. The engine auto-creates a mount
<div>.Verify
Open with
?debug=true— see testing checklist.Monitor
GAM Reports → filter by
hb_bidder=limelightDigitalfor impressions / eCPM / fill.
Embed code reference
The v2 tag shape uses data-bidders — a JSON array of every SSP that should bid in this auction. The Prebid bundle at data-prebid-url must include adapters for every bidder listed.
<script src="https://cdn.jsdelivr.net/gh/shashwatsilverpush/bidding-player@v2.5.1/engine/player.js"
id="adtech-player-core"
data-bidders='[
{"bidder":"limelightDigital","params":{"host":"ads-jbi003.rtba.bidsxchange.com","publisherId":"649658371","adUnitId":972556929,"adUnitType":"video"}},
{"bidder":"appnexus","params":{"placementId":12345678}}
]'
data-tag="https://pubads.g.doubleclick.net/gampad/ads?iu=/…&sz=640x480&output=vast&correlator="
data-video="https://your-cdn.example.com/content.mp4"
data-prebid-url="https://cdn.jsdelivr.net/gh/shashwatsilverpush/bidding-player@v2.5.1/prebid/prebid-limelight-appnexus.js"
data-timeout="1200" data-bias="0.10"
data-autoplay="true" data-muted="true" data-fluid="true"
async></script>
Attribute reference
| Attribute | Req | Default | Notes |
|---|---|---|---|
src | Yes | — | Versioned jsDelivr URL. Pin to a tag — never @main. |
id | Yes | adtech-player-core | Must be exactly this value. |
async | Yes | — | Required HTML attr; engine boots after DOMReady. |
data-bidders | Yes* | — | v2 multi-bidder. JSON array of Prebid bid objects ({bidder, params}). Each entry's params shape is per-SSP — see Prebid bidder docs. *Optional if you use the legacy three-attr shortcut instead. |
data-pub-id / -adunit-id / -host | Legacy | — | v1 legacy single-bidder shortcut. Engine builds a 1-element limelightDigital array from these. Use when you want only Limelight and can't / won't write the JSON. Ignored when data-bidders is set. |
data-tag | Yes | — | GAM master ad tag URL; must end with correlator=. |
data-prebid-url | Yes | — | Prebid.js build URL. Must include an adapter for every bidder in data-bidders — Prebid silently drops unknown bidders. Pick a bundle from prebid/ in this repo, or build a new one (see prebid/README.md). |
data-video | No | — | Content video (.mp4 / .m3u8). Required for instream; omitted for outstream. |
data-placement | No | instream | instream plays the ad against your content video. outstream needs no content video — slot stays collapsed until ≥50% in view, autoplays muted, then collapses. See Placement & sticky below. |
data-sticky | No | false | Instream only. true floats the player to the bottom-right corner when scrolled out of view (keeps playing, × to dismiss) and reflows the live ad to fit. |
data-timeout | No | 1200 | Prebid bidder timeout (ms). Industry default 1500–2000. |
data-bias | No | 0.10 | USD added to winning CPM before bucketing. Explicit 0.00 disables the bias. |
data-floor-min | No | — | Reject bids below this CPM (fall through to house line item). Omitted = no floor. |
data-floor-max | No | — | Cap the winning CPM before bias + bucketing. Omitted = no cap. |
data-autoplay / data-muted | No | true / true | Browser policy: autoplay requires muted. Outstream + sticky both rely on muted autoplay. |
data-fluid | No | true | true = responsive 16:9; false = fixed 640×480. |
data-loop | No | false | Loop content after end. |
data-preload | No | metadata | metadata / auto / none. |
data-vpaid | No | insecure | insecure / enabled / disabled. |
data-div-id | No | comparos-video-placement | Mount div ID. Auto-created if missing. |
data-cache | No | prebid.adnxs.com/pbc/v1/cache | Prebid Cache server. |
Placement & sticky
Instream (default) plays the ad as pre-roll against your data-video content. Outstream (data-placement="outstream") needs no content video — drop it into a text article and the slot stays collapsed until it scrolls ≥50% into view, autoplays muted, then collapses when the ad finishes.
For instream, add data-sticky="true" to keep the player visible while the reader scrolls: it floats to the bottom-right corner (still playing, × to dismiss) and snaps back inline on scroll-up, with the original layout space preserved. This raises viewability and completed-view rates — off by default, opt in per placement.
Adding a new SSP / Prebid bundle
The prebid/ directory holds pre-built Prebid.js bundles. Each data-prebid-url points at one of these. To add a new bundle (e.g. when onboarding a publisher that uses a different SSP), trigger the "Build Prebid bundle" workflow in the Actions tab — supply the comma-separated module list and a filename, the workflow runs gulp build and commits the result. Full instructions in prebid/README.md.
src, data-prebid-url, and data-bidders in sync
Always point src and data-prebid-url at the same version tag. The Tag Generator enforces this. Make sure every bidder named in data-bidders has its adapter in the bundle at data-prebid-url.
GAM setup
One-time setup: key-values, a VAST wrapper creative, and price-bucket line items.
1. Custom key-values
GAM → Inventory → Key-values → New key-value:
| Key | Type | Values |
|---|---|---|
hb_pb | Predefined | 0.00, 0.10, …, 20.00 (per $0.10 step) |
hb_bidder | Predefined | limelightDigital, none |
hb_uuid | Free-form | (dynamic UUIDs) |
hb_size | Predefined | 640x360, 1280x720, 1920x1080 |
hb_format | Predefined | video |
hb_adid | Free-form | (dynamic) |
hb_source | Predefined | client, s2s |
2. VAST wrapper creative
GAM → Delivery → Creatives → New → Video → VAST 3.0 ad tag. Paste:
https://prebid.adnxs.com/pbc/v1/cache?uuid=%%PATTERN:hb_uuid%%
Duration: 0:00 (wrapper resolves real duration). Substitute your own cache URL if not using the AppNexus public cache.
3. Price-bucket line items
One line item per $0.10 bucket (200 total for $0–$20). Use Prebid's Line Item Generator to bulk-create via CSV.
| Field | Value |
|---|---|
| Name | Prebid HB $2.50 |
| Type | Price Priority |
| CPM | Exact bucket (e.g. $2.50) |
| Targeting → key-values | hb_pb is one of 2.50 |
| Creative | The VAST wrapper from step 2 |
Prebid emits "2.50" (two decimals). A line item targeting "2.5" will never serve.
4. House fallback + order
Add a low-priority line item targeting hb_pb=0.00 with your house creative or AdSense passback. Wrap all line items in one Order (e.g. "Prebid Header Bidding") for one-click pause/activate.
Limelight onboarding
- Apply for a Limelight account via your CSM.
- Receive credentials:
publisherId→data-pub-id;adUnitId→data-adunit-id;host→data-host. - Submit publisher domain(s) for allowlist approval (1–3 business days).
- Verify bidding using the testing checklist.
You can test integration mechanics before allowlisting completes — the bidder returns no-bid and GAM's fallback fills.
Consent management
Defaults are tuned for non-EU traffic. EU and US-state-privacy publishers override.
| Framework | Default |
|---|---|
| GDPR (TCF v2) | Static gdprApplies: false — non-EU-safe. |
| USP (CCPA) | Auto-detects __uspapi (100 ms timeout). |
| GPP | Off — module cancels auction without a GPP CMP. |
EU — enable TCF v2
Place a registered CMP (OneTrust, Sourcepoint, Quantcast, Didomi…). Add this script before the engine tag:
<script>
window.pbjs = window.pbjs || { que: [] };
pbjs.que.push(function() {
pbjs.setConfig({
consentManagement: {
gdpr: { cmpApi: 'iab', timeout: 8000, defaultGdprScope: true }
}
});
});
</script>
US state privacy — enable GPP
pbjs.setConfig({ consentManagement: { gpp: { cmpApi: 'iab', timeout: 3000 } } });
The engine ships the technical hooks. Legal compliance depends on your CMP, privacy policy, and DPAs. Consult counsel.
Testing & verification
Append ?debug=true to your URL.
Console (filter for STEP)
- STEP 1 Auction Initialized · Target: limelightDigital · Timeout: 1200ms
- STEP 1.5 Requesting from Limelight. Player size: WxH
- WINNER <bidder> · Raw CPM: $X.XX, or NO MARKET DEMAND
- STEP 6 Dispatching VAST Request
Network
| Request | Status |
|---|---|
cdn.jsdelivr.net/.../player.js + .../prebid.js | 200 |
imasdk.googleapis.com/.../ima3.js | 200 |
POST {host}/ortbhb — inspect Payload | 200 |
prebid.adnxs.com/pbc/v1/cache (winning bid only) | 200 |
GET pubads.g.doubleclick.net/gampad/ads — decode cust_params, must contain hb_pb, hb_bidder, hb_uuid | 200 |
Visual
- Pre-roll plays before content; Video.js controls (play / pause / mute / volume / progress / fullscreen) respond.
Troubleshooting
No POST /ortbhb in Network
pbjs.installedModulesmust includelimelightDigitalBidAdapter. If missing, fixdata-prebid-url.- Look for "Canceling auction as per consentManagement config" in console (see Consent).
200 response but empty seatbid
- Domain not allowlisted by Limelight — the most common cause.
- Player rendered < 300×200 — bidders may reject small inventory.
Bid wins but no ad plays / GAM falls through
cust_paramsmust containhb_uuid. Missing → engine < v1.2.0, upgrade.- Line item targeting must match Prebid's string format exactly:
"2.50"not"2.5". - VAST wrapper must use
%%PATTERN:hb_uuid%%.
Request timeout after 1200ms
Increase data-timeout to 1500–2000 ms, or ask Limelight for a regional endpoint.
Autoplay doesn't start
Confirm data-autoplay="true" AND data-muted="true". HTTPS required. iOS Safari has additional restrictions with no workaround.
Mixed-content warnings
HTTPS page + http:// content URL / GAM tag / creative. Force everything to HTTPS.
FAQ
Multiple players on the same page?
Not currently. Workaround: iframe per player.
Other Prebid bidders / multiple SSPs?
Yes — v2 supports multi-bidder via data-bidders. Ask your account manager which SSPs you need; they will generate a Prebid bundle containing those adapters.
If Prebid fails to load?
Engine catches it and calls GAM with hb_pb=0.00&hb_bidder=none. House line item fills.
Auction analytics?
Impression-level: GAM Reports filtered by hb_bidder. Auction-level (bid latency / rate): request a Prebid build with an analytics adapter.
Latency impact?
async script — zero impact on Time to Interactive. Adds the bidder timeout (default 1200 ms) before pre-roll start.
Auction refresh / mid-rolls?
Not currently supported. Once per page load.
@v2.5.1 vs @main?
Tags are immutable (1-year CDN cache). @main = latest commit (~12 h cache). Pin tags for prod.