AdX Empty Ad Slots: Use collapseDiv, Not Manual Hiding
Empty display ad slots are easy to miss during local QA. The page looks structurally correct, the Google Publisher Tag script loads, and the AdSlot component reserves a stable box so the layout does not shift. Then production traffic gets a no-fill response, and that reserved 250px block remains visible as an awkward blank gap in the middle of the reader.
The tempting fix is to listen for GPT's slotRenderEnded event, check isEmpty, and set the wrapper to display: none. That removes the visual gap, but it moves the collapse decision out of Google Publisher Tag and into app code after the slot lifecycle has already started. On AdX-backed Google Ad Manager inventory, that is the wrong place to solve the problem.
Put more bluntly: manually hiding a GPT slot wrapper from slotRenderEnded is a dumb implementation pattern. It treats a Google Publisher Tag lifecycle concern as a React styling problem, which is exactly how you end up with a page that looks fixed while measurement and layout assumptions get worse.
The Correct Fix
For Google Publisher Tag / Google Ad Manager inventory, configure empty-slot collapse before services are enabled:
window.googletag = window.googletag || { cmd: [] };
googletag.cmd.push(function () {
googletag.setConfig({
singleRequest: true,
collapseDiv: "ON_NO_FILL",
});
googletag.enableServices();
});
ON_NO_FILL keeps the slot's reserved layout during the request and lets GPT collapse it only when no ad is returned. That keeps normal filled-slot behavior predictable while removing no-fill blanks.
Use this for AdX / Google Ad Manager sites that serve through GPT. Do not treat it as an AdSense feature.
Why Manual Hiding Is A Bad Pattern
Active View is based on whether enough ad pixels are visible in the viewport for the required time. If application code hides or reshapes the ad wrapper after GPT has rendered or completed the slot, the page can still look fine to a reader, but measurement and lifecycle assumptions become muddy.
The safer rule is simple:
- Reserve size on every ad wrapper before render to prevent CLS.
- Let GPT collapse no-fill slots with
collapseDiv: "ON_NO_FILL". - Do not hide
AdSlotwrappers manually fromslotRenderEnded; that is the wrong layer and should be treated as a code review failure. - Do not use deprecated
pubads().collapseEmptyDivs()in new code. - Do not copy this into AdSense
<ins class="adsbygoogle">components.
AdX vs AdSense
This fix applies to our AdX/GAM path because the page uses Google Publisher Tag:
<script async src="https://securepubads.g.doubleclick.net/tag/js/gpt.js"></script>
AdSense uses a different runtime and markup pattern:
<ins class="adsbygoogle"></ins>
For AdSense pages, keep the AdsenseSlot implementation separate: load the AdSense script once, reserve size, push {} when the unit should load, and follow AdSense placement policy. Do not configure collapseDiv there; it is not the control surface for AdSense units.
Production Rule
For AdX-backed fiction reader pages, the default should be:
googletag.setConfig({
singleRequest: true,
collapseDiv: "ON_NO_FILL",
});
Keep AdSlot boring: define the slot, add the service, display it, and destroy it on unmount. Empty-slot handling belongs in GPT configuration, not in React component event handlers.

