What Terrific Does and What It Does Not Do
Before diving into technical details, it is important to clarify Terrific’s role in the monetization chain.
What Terrific Does
Executes the tag configured by the client (GPT or VAST).
Properly renders the Ad Server response.
Supports both Display (GPT) and Video (VAST) ads.
Allows Web-compatible integrations within the Timeline.
Respects targeting, priorities, and rules defined in the client’s Ad Manager.
What Terrific Does Not Do
Does not manage advertising campaigns.
Does not configure line items.
Does not control priorities or targeting.
Does not participate in the programmatic auction.
Cannot guarantee fill rate.
Does not decide which creative is displayed.
All monetization logic lives inside the client’s Google Ad Manager.
Recommended Formats
For a vertical 9:16 environment:
Display (GPT)
320x480
300x600
300x250 (fallback)
1x1 (tracking / backup)
Recommendation: Prioritize 320x480 and 300x600 to maintain visual consistency.
Video (VAST)
360x640
720x1280
1080x1920
Strategic recommendation: Always validate that inventory is configured for vertical formats.
What Happens When There is no Fill?
When no eligible campaign exists:
The Ad Server returns an empty response.
The slot remains without content.
The Timeline card may appear empty.
Recommendations to Maximize Fill Rate
Fill rate depends entirely on inventory configuration within Google Ad Manager. However, there are best practices that help ensure the Timeline consistently displays advertising content.
Always Configure House Ads as Fallback
Primary recommendation: Every Ad Unit should include a House line item as fallback.
Why? If there is no:
Active Sponsorship
Direct campaign
Programmatic demand
Eligible Open Auction bid
The slot will remain empty. A House Ad ensures the placement never stays without content.
Allow Multiple Compatible Sizes
In GPT, instead of defining a single size: [320, 480]
It is better to allow: [[320,480], [300,600], [300,250]]
This increases auction eligibility and improves fill opportunities.
Avoid Overly Restrictive Targeting
Ensure there are no excessive filters applied to:
Geolocation
Device
Domain
Audience
Schedule
Pay special attention when the Timeline runs inside an iframe.
Properly Authorize Domains
If the domain where the Timeline runs is not authorized in Google Ad Manager, no-fill may occur even if the campaign is active.
Understand That Fill Is Dynamic
Fill rate may vary depending on:
Time of day
Available budget
Auction competition
User profile
A placement may show an ad at one moment and not at another.
How It's Managed in the Terrific Admin Panel
Each carousel can have its own Google Ads integration. The configuration can be done through the Ad Integration option within the carousel settings.
Ads will only be displayed once the user starts navigating the full-screen version (vertical scroll) within the carousel.
To configure Ads in this section, the first step is to enable the functionality by turning on the toggle shown as (1) in the image. After that, the following options can be configured:
2. Skip Ad: Allows enabling the Ad skip option. When enabled, a skip button will appear after 3 seconds. If disabled, users will not be able to skip the Ad until it finishes playing.
3. Ad Frequency: Defines how often an Ad will appear between cards/content.
For example, if set to 5, the carousel will display 4 content cards and the 5th element will be an Ad.
4. Ad Start Point: Defines from which card/content Ads will start appearing.
This helps create a more personalized UX. For example, Ads can be configured to start from asset 10, and from that point the frequency defined in the previous step will apply.
5. Audience Limit: Allows setting a maximum number of users who will see Ads. If left empty, Ads will be shown to all users.
6. Device Targeting: Allows configuring whether Ads should appear on Mobile, Desktop, or both.
7. Ad Script: This is where the Ad Unit script provided by the client should be added, either VAST or GPT.
8. Confirmation: It is mandatory to confirm that the nature of the integration is understood.
9. Preview: You can preview how the Ads will appear.
Due to domain restrictions, in some cases the content may not appear in the preview, but it will work correctly once the integration is live on the production site.
10. Save: Save the configuration and you're done.
Integration Script Templates
Below you will find two templates that can be used as a base for the Ads integration.
GPT
When using the following template, you only need to replace lines 20 to 29 with the script provided by the client.
<html style="overflow:hidden">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>UnoTV Ads</title>
<script async src="https://securepubads.g.doubleclick.net/tag/js/gpt.js" crossorigin="anonymous"></script>
<style>
.ad-wrap {
max-width: 970px;
margin: 24px auto; text-align: center;
}
#div-gpt-ad-1761930849217-0 {
width: 100%;
}
</style>
</head>
<body>
<div class="ad-wrap">
<div id="div-gpt-ad-1761930849217-0">
<script>
window.googletag = window.googletag || {cmd: []};
googletag.cmd.push(function()
{ // Definir slot con múltiples tamaños
googletag.defineSlot('/121173452/UnoTV/noticias/inicio/terrificdisplay',[[300, 600], [320, 480]], 'div-gpt-ad-1761930849217-0').addService(googletag.pubads());
googletag.pubads().enableSingleRequest();
googletag.pubads().collapseEmptyDivs();
googletag.enableServices();
googletag.display('div-gpt-ad-1761930849217-0'); });
</script>
</div>
</div>
</body>
</html>
VAST
When using the following template, you only need to replace the URL on line 35 with the URL provided by the client.
<html lang="es" style="overflow:hidden">
<head>
<meta charset="utf-8" />
<title>VAST</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
.video-wrap { position: relative; width: 100%; max-width: 360px; margin: 0 auto; }
.video-9x16 { position: relative; width: 100%; aspect-ratio: 9 / 16; background: #000; overflow: hidden; }
#ad-container { position: absolute; inset: 0; }
#player video,
#player iframe,
#player div[style*="absolute"] {
object-fit: contain !important;
width: 100% !important;
height: 100% !important;
max-width: 100% !important;
max-height: 100% !important;
position: absolute !important;
top: 50% !important;
left: 50% !important;
transform: translate(-50%, -50%) !important;
}
</style>
<script src="https://imasdk.googleapis.com/js/sdkloader/ima3.js"></script>
</head>
<body>
<div class="video-wrap">
<div class="video-9x16" id="player">
<video id="content" playsinline webkit-playsinline muted></video>
<div id="ad-container"></div>
</div>
</div>
<script>
const adTagUrl = "https://pubads.g.doubleclick.net/gampad/ads?iu=/205320464/RCN_RADIO/EL_SOL/RCN_RADIO_EL_SOL_TERRIFIC&description_url=www.elsol.com.co&tfcd=0&npa=0&sz=1x1%7C300x600%7C320x480&gdfp_req=1&unviewed_position_start=1&output=vast&env=vp&impl=s&correlator=256&plcmt=1&vpmute=1&vpa=auto";
const contentVideo = document.getElementById('content');
const adContainer = document.getElementById('ad-container');
let adDisplayContainer, adsLoader, adsManager;
let initialized = false, requested = false;
function initIMA() {
if (initialized) return;
initialized = true;
adDisplayContainer = new google.ima.AdDisplayContainer(adContainer, contentVideo);
adsLoader = new google.ima.AdsLoader(adDisplayContainer);
adsLoader.addEventListener(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, onAdsManagerLoaded);
adsLoader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, onAdError);
}
function requestAds() {
if (requested) return;
requested = true;
const req = new google.ima.AdsRequest();
req.adTagUrl = adTagUrl;
req.setAdWillAutoPlay(true);
req.setAdWillPlayMuted(true);
adsLoader.requestAds(req);
}
function onAdsManagerLoaded(e) {
adsManager = e.getAdsManager(contentVideo);
adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, () => {
try { adsManager.start(); } catch (err) { console.warn('[IMA] Start error:', err); }
});
adsManager.addEventListener(google.ima.AdEvent.Type.ALL_ADS_COMPLETED, () => {
console.log('[IMA] Todos los anuncios completados');
});
adsManager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, onAdError);
const rect = document.getElementById('player').getBoundingClientRect();
adsManager.init(rect.width, rect.height, google.ima.ViewMode.NORMAL);
}
function onAdError(ev) {
const err = ev && ev.getError ? ev.getError() : ev;
console.warn('[IMA] AdError:', err);
if (adsManager) { try { adsManager.destroy(); } catch(_){} }
}
function tryAutoplay() {
contentVideo.muted = true;
contentVideo.playsInline = true;
try {
initIMA();
adDisplayContainer.initialize();
requestAds();
} catch (e) {
bindFirstUserGesture();
}
}
function bindFirstUserGesture() {
const once = () => {
document.removeEventListener('pointerdown', once);
document.removeEventListener('touchstart', once);
document.removeEventListener('keydown', once);
initIMA();
try { adDisplayContainer.initialize(); } catch(_) {}
requestAds();
};
document.addEventListener('pointerdown', once, { passive: true });
document.addEventListener('touchstart', once, { passive: true });
document.addEventListener('keydown', once);
console.log('[IMA] Esperando interacción del usuario para iniciar el anuncio…');
}
window.addEventListener('resize', () => {
if (!adsManager) return;
const rect = document.getElementById('player').getBoundingClientRect();
adsManager.resize(rect.width, rect.height, google.ima.ViewMode.NORMAL);
});
window.addEventListener('DOMContentLoaded', tryAutoplay);
</script>
</body>
</html>
