本文へスキップ

シングルページのアプリケーションにおけるフルページ・インタースティシャル広告

このガイドでは、直接APIコールを使用してシングルページアプリケーション(SPA)にフルページインタースティシャル(FPI)広告を実装する方法を示します。React、Vue、Angular、その他のフレームワークで動作します。

Full Page Interstitial (FPI) Ads in Single Page Applications

ステップ・バイ・ステップの実施

ステップ1:コンポーネントの状態を設定する

まず、広告システムとナビゲーションを追跡するためのステート変数を作成します:

'use client'

import { useEffect, useState } from 'react'

export default function HomePage() {
const [adLoaded, setAdLoaded] = useState(false)
const [currentPage, setCurrentPage] = useState('home')

useEffect(() => {
setAdLoaded(true)
console.log('✅ FPI API method initialized')
}, [])
}

ステップ2:APIリクエスト関数の作成

この関数はFPI広告サーバーに直接HTTPリクエストを行う:

const triggerFPIAd = async () => {
console.log('🎯 Making direct API call to FPI service...')

try {
// Prepare request with user context
const requestBody = {
user: {
ua: navigator.userAgent,
language: navigator.language || 'en-US',
referer: window.location.href,
consumer: 'ad-provider',
gdpr: { gdpr: 0 },
screen_resolution: `${screen.width}x${screen.height}`,
window_orientation: screen.width > screen.height ? 'landscape' : 'portrait',
cookies: [],
scr_info: btoa('async||3')
},
zones: [{
custom_targeting: {},
id: 1234567, // Your FPI Zone ID (use mobile FPI zone ID for mobile devices)
extra_params: {
first_request: true,
zone_type: 35 // Interstitial format
}
}]
}

// Make API call
const response = await fetch('https://s.pemsrv.com/v1/api.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(requestBody)
})

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}

const data = await response.json()
console.log('📥 Full API Response:', data)

// Process response
if (data.zones && data.zones.length > 0) {
const zone = data.zones[0]

if (zone.data) {
console.log('🎨 Displaying ad...')
await displayInterstitialAd(zone.data)
} else {
console.log('❌ No ad data in response')
}
}

} catch (error) {
console.error('❌ FPI API Error:', error)
}
}

広告表示ハンドリング

ステップ3:表示機能の作成

この関数は複数の広告フォーマットを扱う

const displayInterstitialAd = async (adData: any) => {
console.log('🎨 Starting to display interstitial ad...')

try {
// Remove any existing overlay
const existingOverlay = document.getElementById('fpi-interstitial-overlay')
if (existingOverlay) {
document.body.removeChild(existingOverlay)
}

// Create fullscreen overlay
const overlay = document.createElement('div')
overlay.id = 'fpi-interstitial-overlay'
overlay.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.9);
z-index: 999999;
display: flex;
align-items: center;
justify-content: center;
`

// Create ad container
const adContainer = document.createElement('div')
adContainer.style.cssText = `
position: relative;
width: 100vw;
height: 100vh;
background: white;
overflow: hidden;
`

// Create close button
const closeButton = document.createElement('button')
closeButton.innerHTML = '✕'
closeButton.style.cssText = `
position: absolute;
top: 10px;
right: 10px;
width: 40px;
height: 40px;
border: none;
background: rgba(0, 0, 0, 0.7);
color: white;
font-size: 20px;
border-radius: 50%;
cursor: pointer;
z-index: 1000000;
`

closeButton.onclick = () => {
document.body.removeChild(overlay)
console.log('🚪 Interstitial ad closed')
}

// Determine ad format and create content
let adContent = ''

// Format 1: Iframe Ad
if (adData.html && adData.html.includes('iframe.php')) {
adContent = `
<iframe
src="${adData.html}"
width="100%"
height="100%"
frameborder="0"
allowfullscreen
sandbox="allow-scripts allow-forms allow-popups"
style="width: 100vw; height: 100vh; border: none;"
></iframe>
`
console.log('🖼️ Created iframe ad')
}
Click to expand additional ad formats
    if (adData.html && adData.html.includes('iframe.php')) {
adContent = `
<iframe
src="${adData.html}"
width="100%"
height="100%"
frameborder="0"
allowfullscreen
sandbox="allow-scripts allow-forms allow-popups"
style="width: 100vw; height: 100vh; border: none;"
></iframe>
`
console.log('🖼️ Created iframe ad')
}

// Format 2: Video Ad
else if (adData.video) {
const hasClickUrl = adData.url && adData.url.trim() !== ''

if (hasClickUrl) {
// Video with click-through
adContent = `
<div style="position: relative; width: 100vw; height: 100vh; cursor: pointer;"
onclick="window.open('${adData.url}', '_blank')">
<video
width="100%"
height="100%"
autoplay
muted
loop
style="object-fit: cover; width: 100vw; height: 100vh;"
>
<source src="${adData.video}" type="video/mp4">
</video>
<div style="
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.7);
color: white;
padding: 8px 16px;
border-radius: 20px;
font-size: 14px;
">
Click to visit advertiser
</div>
</div>
`
console.log('🎬 Created clickable video banner ad')
} else {
// Regular video
adContent = `
<video
width="100%"
height="100%"
autoplay
muted
controls
style="object-fit: cover; width: 100vw; height: 100vh;"
>
<source src="${adData.video}" type="video/mp4">
</video>
`
console.log('🎬 Created video ad')
}
}

// Format 3: Click-Through Ad
else if (adData.url) {
adContent = `
<div style="
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background: linear-gradient(45deg, #0072ba, #28a745);
padding: 20px;
">
<h2 style="color: white; margin-bottom: 20px; font-size: 48px;">
🎯 Interstitial Ad
</h2>
<p style="color: white; margin-bottom: 30px; font-size: 24px;">
Click to visit advertiser
</p>
<a href="${adData.url}"
target="_blank"
style="
padding: 15px 30px;
background: white;
color: #0072ba;
text-decoration: none;
border-radius: 25px;
font-weight: bold;
font-size: 18px;
">
Visit Now
</a>
</div>
`
console.log('🔗 Created click-through ad')
}

// Format 4: Native Ads
else if (adData.ad_items && adData.ad_items.length > 0) {
const adItemsHtml = adData.ad_items.map((item: any) => `
<div style="
background: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
cursor: pointer;
" onclick="window.open('${item.url}', '_blank')">
<div style="height: 200px; overflow: hidden;">
<img src="${item.optimum_image || item.image}"
style="width: 100%; height: 100%; object-fit: cover;"
alt="${item.title}">
</div>
<div style="padding: 15px;">
<h3 style="margin: 0 0 8px 0; font-size: 18px;">${item.title}</h3>
${item.description ? `<p style="font-size: 14px; color: #666;">${item.description}</p>` : ''}
<div style="font-size: 12px; color: #999;">${item.brand || 'Sponsored'}</div>
</div>
</div>
`).join('')

adContent = `
<div style="
width: 100vw;
height: 100vh;
background: #f5f5f5;
overflow-y: auto;
padding: 20px;
">
<h2 style="text-align: center; margin-bottom: 20px;">Sponsored Content</h2>
<div style="
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 15px;
">
${adItemsHtml}
</div>
</div>
`
console.log('🎯 Created native ad grid')
}

// Add content to container
adContainer.innerHTML = adContent
adContainer.appendChild(closeButton)
overlay.appendChild(adContainer)
document.body.appendChild(overlay)

// Track impression
if (adData.impression) {
fetch(adData.impression, { method: 'GET', mode: 'no-cors' })
.then(() => console.log('📊 Impression tracked'))
.catch(e => console.log('⚠️ Impression tracking failed:', e))
}

} catch (error) {
console.error('❌ Error displaying ad:', error)
}
}

ステップ4:トリガーボタンの追加

return (
<div>
<h1>My Page</h1>
<button onClick={triggerFPIAd}>
Load FPI Ad
</button>
</div>
)

完全なコード例

実際にデモをご覧になりたいですか?上記のすべてのステップを組み合わせたインタラクティブなデモをご覧ください。

ライブデモ: コードとデモサイトを見る

Full Page Interstitial (FPI) Ads in Single Page Applications