Open7
Next13 (Prebid.js + Google Publisher Tag)

1. Google Publisher Tagの型定義をinstallする
Google Publisher Tagは window.googletag
変数を使用します。
npm install --save-dev @types/google-publisher-tag

2. Google Publisher Tagのロードを実装する
/app/components/ad/gpt.tsx
"use client";
import Script from "next/script";
export const GptHead: React.FC = () => {
return (
<>
<Script
async
src="https://securepubads.g.doubleclick.net/tag/js/gpt.js"
strategy="afterInteractive"
/>
<Script
id="gpt-head"
dangerouslySetInnerHTML={{
__html: `
window.googletag = window.googletag || { cmd: [] };
window.googletag.cmd.push(function() {
window.googletag.pubads().disableInitialLoad();
googletag.enableServices();
});
`,
}}
/>
</>
);
};

3. Prebid.jsのロードを実装する
app/components/ad/prebid.tsx
"use client"
import Script from "next/script";
export const PrebidHead: React.FC = () => {
return (
<>
<Script
async
src="https://cdn.jsdelivr.net/npm/prebid.js@latest/dist/not-for-prod/prebid.js"
strategy="afterInteractive"
/>
<Script
id="prebid-head"
dangerouslySetInnerHTML={{
__html: `window.pbjs = window.pbjs || { que: [] };`,
}}
/>
</>
);
};

4. 2と3のcomponentを読み込む
layout.tsにcomponentのimport処理を追加する。

5. Header Biddingするコンポーネントを追加する
app/components/ad/slot.tsx
"use client";
import { usePathname, useSearchParams } from "next/navigation";
import { useEffect } from "react";
export type GptSlot = {
divId: string;
adUnitPath: string;
sizes: googletag.GeneralSize;
};
type PrebidSlot = {
code: string;
mediaTypes: {
banner: {
sizes: [number, number][];
};
};
bids: {
bidder: string;
params: object;
}[];
};
type SlotsProps = { slots: GptSlot[] };
export const AdSlot = (props: SlotsProps) => {
const gptSlots = props.slots;
const pathname = usePathname();
const searchParams = useSearchParams();
useEffect(() => {
googletag.cmd.push(function () {
const divIds = gptSlots.map((gptSlot) => gptSlot.divId);
const removeSlots = googletag
.pubads()
.getSlots()
.filter((slot) => {
return divIds.includes(slot.getSlotElementId());
});
if (destroySlots.length > 0) {
// ページ遷移時にslotを初期化する(destroyする)
destroySlots(removeSlots);
}
const slots = gptSlots.map((gptSlot) => {
const slot = googletag
.defineSlot(gptSlot.adUnitPath, gptSlot.sizes, gptSlot.divId)
?.addService(googletag.pubads());
return slot;
});
// @ts-ignore
pbjs.que.push(() => {
// @ts-ignore
pbjs.requestBids({
// Prebidの枠情報
adUnits: getPrebidSlots(gptSlots),
// タイムアウト値
timeout: 2000,
// Prebidオークション終了後のcallback関数
bidsBackHandler: function () {
// @ts-ignore
pbjs.setTargetingForGPTAsync(divIds);
googletag.pubads().refresh(slots as googletag.Slot[]);
divIds.forEach((divId) => googletag.display(divId));
},
});
});
});
}, [pathname, searchParams]);
return <></>;
};
function destroySlots(slots: googletag.Slot[]) {
googletag.cmd.push(function () {
googletag.destroySlots(slots);
});
}
function getPrebidSlots(slots: GptSlot[]): PrebidSlot[] {
const divIds = slots.map((slot) => slot.divId);
// SSPのIDを管理する変数
const allSlots: PrebidSlot[] = [
{
code: "div-1",
mediaTypes: {
banner: {
sizes: [
[300, 250],
[300, 600],
],
},
},
bids: [
{
bidder: "appnexus",
params: {
placementId: 13144370,
},
},
],
},
{
code: "div-2",
mediaTypes: {
banner: {
sizes: [
[728, 90],
[970, 250],
],
},
},
bids: [
{
bidder: "appnexus",
params: {
placementId: 13144370,
},
},
],
},
];
return allSlots.filter((slot) => divIds.includes(slot.code));
}

6. 5のcomponentをインポートする
page.tsにimport処理を追加する。
7. 広告を表示するdivタグを追加する

コード
参考サイト