Skip to content
Gallery
nytgames
CreativeTech Wiki (internal)
Share
Explore
Recipes

icon picker
General Recipes

Mobile “Play” Tab Targeting
body[data-typ='play'] .className {
font-size: 1rem;
}

Slideshow Autoplay

Copy and paste the following code to your units for an autoplay slideshow. Chang the intervalTime parameter to adjust the timing of the slide changes.

Desktop

// FlexFrame Slideshow DESKTOP
let infoAutoplay = {
intervalTime: 3500,
};
const rightBtn = document.querySelector('.right-btn');
const autoplayInterval = setInterval(() => {
rightBtn.click();
}, infoAutoplay.intervalTime);
const stopAutoplay = () => {
clearInterval(autoplayInterval);
};
const navBtns = document.querySelectorAll('.btn-group button');
navBtns.forEach((btn) => {
btn.addEventListener('click', (e) => {
e.isTrusted ? stopAutoplay() : console.log('not trusted, keep');
});
});

Mobile

// FlexFrame Slideshow MOBILE
let infoAutoplay = {
intervalTime: 3500,
};
const rightBtn = document.querySelector('.swiper-button-next');
const autoplayInterval = setInterval(() => {
rightBtn.click();
}, infoAutoplay.intervalTime);
const stopAutoplay = () => {
clearInterval(autoplayInterval);
};
const navBtns = document.querySelectorAll('.navigation button');
navBtns.forEach((btn) => {
btn.addEventListener('click', (e) => {
e.isTrusted ? stopAutoplay() : console.log('not trusted, keep');
});
})

Adding Event Tracking to Clickable Elements

const eventTrackingElements = [
{
"target": ".puzzle-container",
"type": "clickURL",
"location": "background",
"redirect": "%%CLICK_URL_UNESC%%"
},
{
"target": ".result-screen",
"type": "clickURL",
"location": "background",
"redirect": "%%CLICK_URL_UNESC%%"
},
]
eventTrackingElements.forEach(el=> {
let node = document.querySelector(el.target)
node.classList.add("NYTAdTrack");
node.dataset.eventType = el.type;
node.dataset.eventLocation = el.location;
node.addEventListener("click",()=>{
window.open(el.redirect, '_blank');
});
});

Adjusting Height Media Queries

It is possible to override mobile heights for custom situations. To do so, apply a media query such as the one below and change the values to fit your situation. In order to “override” existing media queries, note the “!important” for the height value.
// CustomCSS
@media screen and (min-width: 414px) and (max-width: 430px)
:root {
--height: calc(100vw * 1.65)!important;
}

Preventing the Video Flash

PENDING REVIEW: On video ad units, the last frame of the video flashes when user replays a video. This is because the video is in the end state when the replay event is triggered. Until a fix is issued, to mitigate this issue, use the following code.
This solution hides the video when complete, then adds a 250ms transition to the start of the video, essentially hiding the flash.
const targetNode = document.getElementById("media-container");
const observer = new MutationObserver(()=>{
if(targetNode.classList.contains('end-state')) {
console.log('end-state')
window.Player.video.style.opacity = 0
window.Player.posterPlayBtn.addEventListener( 'click', () => {
setTimeout(()=>{
window.Player.video.style.opacity = 1;
window.Player.video.style.transition = "all 250ms ease-in-out";
},250)
}, { once: true } );
}
});
observer.observe(targetNode, { attributes: true, childList: true, subtree: true });

Carousel Height Listener

Listens for the height of the ad parent container and sets the "flex-frame" height based on height it gets back. This example adjusts the height of the “#flex-frame” container. To use on other ads, you may need to adjust this.
/**
* Listens for the height of the ad parent container and sets
* the "flex-frame" height based on height it gets back.
* @author Michael Waskiewicz
* @version 1.00
* @param event Object (listener)
*/
if ("%%PATTERN:pos%%" === "ssint") {
const setFrameHeight = (event) => {
try {
const container = event.data.container || {};
if (container.height && container.width) {
const containerHeight = container.height;
const containerWidth = container.width;
const furnitureHeight = 37;
const ratio = Math.round(( containerWidth/containerHeight ) * 100) / 100;
const isResizable = (ratio === 1.78 || ratio === 1.5);
if (isResizable) {
document.querySelector('#flex-frame').style.height = (containerHeight - furnitureHeight) + "px";
window.removeEventListener("message", setFrameHeight);
}
}
} catch(error) {
console.error("containerGeometryPostMessageListener", error.message);
}
};
window.addEventListener('message', setFrameHeight);
}

Deeplink Override

This recipe allows you to override the functionality of a standard link and use a “deeplink” for linking within a mobile app.
To add this functionality, simply copy and paste the javascript below to the customJS GAM field. Then modify your HTML link by add and customizing the “data” elements seen below. Be sure to use all three. The “event” attributes will ensure that this link will still send events to the Event Tracker.
WARNING: This software will affect your Google Analytics as you are overriding GAMs core linking functionality.
<!-- HTML ELEMENT -->
<a href="%%CLICK_URL_UNESC%%%%DEST_URL%%" data-deeplink="nytimes://..." data-event-type="clickUrl" data-event-location="cta">STANDARD LINK</a>
<button data-deeplink="nytimes://...#" data-event-type="clickUrl" data-event-location="cta">BUTTON LINK</button>
// Javascript
document.addEventListener('click', e => {
const link = e.target.dataset.deeplink;
const openType = '_self'; // Choose '_blank' to open in new tab/window
if ( link && window.inApp ) {
e.preventDefault();
window.open( link, openType );
}
});
// Javascript OPTION #2 for Window Shoppers
// This will override all a tags on a page and respect product ctas.
const deeplinkURL = "https://yahoo.com";
const cta = document.getElementsByTagName("a");
for (var i = 0; i < cta.length; i++) {
cta[i].dataset.deeplink = deeplinkURL;
cta[i].dataset.eventType = "clickURL";
if (cta[i].dataset.indexNumber !== 0 && ( cta[i].className !== "cta-atag" && typeof cta[i].className !== 'undefined' ) ){
cta[i].dataset.eventLocation = `product-${cta[i].dataset.indexNumber}`;
} else {
cta[i].dataset.eventLocation = "cta";
}
console.log(cta[i])
}

document.addEventListener('click', e => {
const link = e.target.dataset.deeplink;
const openType = '_self'; // Choose '_blank' to open in new tab/window
if ( link && window.inApp ) {
e.preventDefault();
window.open( link, openType );
}
});

Adding Timed Text Elements

Adding timed elements is easy. Simply wrap your timed element with a <span class="datecheck" data-date-start="" data-date-end=""> tag. Be sure to include the human-readable start and end date in the following format: dd/mm/yy hh:ss:mm. Once done, copy the CustomJS code below to your GAM ad.
NOTE: If you’re already wrapping your timed text in a <span> tag, simply add the datacheck class and the data tags as listed above to your existing element.
CAUTION: There are no guards on this JS function that prevents multiple items from appearing OR default values. If you use this feature, be sure to check your dates and ensure there will always be a value. The example below shows a limited time message, then display a “default” message for a protracted term.
// HTML (add to your GAM text)
// Depending on your usage, you may need to use single quotes instead of double.

// Double quotes version
<p>Producing bold, impactful research for the betterment of society and preparing students to take on <span class="datecheck" data-date-start="06/28/2023 12:00:00" data-date-end="06/28/2023 13:00:00">today's</span><span class="datecheck" data-date-start="06/28/2023 13:00:01" data-date-end="06/28/2030 23:59:59">tomorrow's</span> challenges.</p>

// Single quotes version
<p>Producing bold, impactful research for the betterment of society and preparing students to take on <span class='datecheck' data-date-start='06/28/2023 12:00:00' data-date-end='06/28/2023 13:00:00'>today's</span><span class='datecheck' data-date-start='06/28/2023 13:00:01' data-date-end='06/28/2030 23:59:59'>tomorrow's</span> challenges.</p>

// Custom Javascript (add to the CustomJS section in your GAM ad)
Array.from(document.getElementsByClassName('datecheck')).forEach((el) => {
const startDateTimestamp = new Date(el.dataset.dateStart).getTime();
const endDateTimestamp = new Date(el.dataset.dateEnd).getTime();
const currentTimestamp = new Date().getTime();
if ( currentTimestamp < startDateTimestamp || currentTimestamp > endDateTimestamp) el.remove();
});

// On slideshows, you may need to add an observer to ensure it works on each slide
const datecheck = () => {
Array.from(document.getElementsByClassName('datecheck')).forEach((el) => {
const startDateTimestamp = new Date(el.dataset.dateStart).getTime();
const endDateTimestamp = new Date(el.dataset.dateEnd).getTime();
const currentTimestamp = new Date().getTime();
if ( currentTimestamp < startDateTimestamp || currentTimestamp > endDateTimestamp) el.remove();
});
};
datecheck();
const elementToObserve = document.querySelector("#slidesummary");
const observer = new MutationObserver(() => {
console.log("callback that runs when observer is triggered");
datecheck();
});
observer.observe(elementToObserve, { subtree: true, childList: true });

Force Autoplay in Interstitials

Just a workaround until default autoplay behavior is added to interstitials.
// FOR GAM PREVIEW ONLY (remove this line after testing)
document.getElementById('ad').dataset.pos = 'intsl'
Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.