3行まとめ
- 公的データの災害リスクを町丁目単位で配信している個人開発サイトが、再申請でAdSenseに承認された。承認当日〜翌日に「法令対応」「手動広告枠」「トップページの広告除外」の3つを実装した
- 自動広告(Auto Ads)は長いページの最下部にしか入らなかったので、
AdSlot.astroコンポーネントで手動枠を作り、アフィリエイト枠と交互になるようコンテンツの区切りに配置した。トップページは管理画面の除外機能が自サイトのX-Frame-Optionsで使えなかったため、レイアウト側でスクリプト自体を読み込まない形で除外した - 法令面は、景品表示法のステマ規制に対応する「広告表示ポリシー」ページの新設と、電気通信事業法の外部送信規律に対応する外部送信ポリシーへのAdSense追記。どちらも「承認されたら広告タグを貼って終わり」では済まない部分だった
公的データ(地震・洪水・土砂災害などのハザード情報や人口統計)を町丁目単位で可視化する個人開発サイトを運営している。一度AdSense審査で「有用性の低いコンテンツ」判定を受け、対策して再申請した経緯は前回の記事に書いた。
その再申請が2026年9月30日に通った。この記事は、その後にやった実装の話になる。サービス名は非公開だが、使った仕組みは具体的に書く。
前提:承認前から Auto Ads のタグは入っていた
AdSenseの審査では、サイトに広告コードが入っていることが前提になる。このサイトでも承認前から、全ページ共通のレイアウトBaseLayout.astroの<head>にAuto Adsのスクリプトを入れ、ads.txtも設置していた。
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-XXXXXXXXXXXXXXXX" crossorigin="anonymous"></script>
なので承認された瞬間から、Googleが自動で選んだ位置に広告が出始める。逆に言うと、承認後に何もしなければ、広告の位置も法令表示もGoogle任せ・承認前のままになる。ここから3つ手を入れた。
対応1:法令対応のページを承認当日に整える
広告で収益を得るようになると、法令上の対応を考えておくべきものが出てくる。どこまでが義務かはサイトの立場によって変わるが、このサイトでは「該当しうるものは先に対応しておく」判断をした。承認当日に対応したのは2つ。
景品表示法のステマ規制 →「広告表示ポリシー」ページを新設
2023年10月1日から、広告であることを隠した表示(いわゆるステルスマーケティング)が景品表示法の不当表示として規制されている。直接の規制対象は広告主(事業者)の表示だが、掲載する媒体側としても広告であることを明示しておくのが実務上の安全策になる。このサイトはもともとA8.net等のアフィリエイト枠を置いていて、フッターに「アフィリエイト広告を掲載している」旨の一文はあったが、AdSenseが加わったのを機に独立したポリシーページ(/ads-policy/)を作った。
書いた内容は大きく5つ。
| 項目 | 書いた内容(要旨) |
|---|---|
| 運営費 | データの取得費やサーバー代などの運営費を広告収入でまかなっていること。広告の有無はリスクスコアの算出に影響しないこと |
| AdSense | 第三者配信でCookieを使うこと、無効化の方法(Googleの広告設定へのリンク) |
| アフィリエイト | 成果報酬を受け取る場合があること。紹介先はデータとの関連性で選び、報酬額だけで選ばないこと |
| 表示方法 | AdSense枠にはGoogle側のラベルが付くこと、アフィリエイト枠には「PR」等を明示すること、本文と広告を視覚的に区別すること |
| 責任範囲 | 広告の内容・価格等は広告主が定めるもので、運営者は保証しないこと |
災害リスクを扱うサイトなので、「広告主の都合でスコアが変わるのでは」と思われるのが一番まずい。運営費の項目で、広告とスコア算出が独立していることを最初に明言している。
フッターの文言も、アフィリエイトに加えてAdSenseの広告も載せていることが分かる形に更新し、このポリシーページへのリンクを足した。
電気通信事業法の外部送信規律 → 外部送信ポリシーに AdSense を追記
2023年6月施行の改正電気通信事業法(第27条の12)では、対象となる事業者が利用者の端末から第三者に情報を送信させる場合、送信される情報・送信先・利用目的などを公表することが求められる。対象範囲の詳細は総務省のガイドラインで確認してほしい。このサイトにはもともと外部送信ポリシーページがあり、アクセス解析(Cloudflare Web Analytics)などを載せていた。ここにGoogle AdSenseの項目を追加した。
| 項目 | 記載内容 |
|---|---|
| 送信先 | Google LLC(Google AdSense) |
| 送信される情報 | 閲覧中のURLや参照元、Cookieの識別子、IPアドレス、端末・ブラウザの情報など |
| 利用目的 | 広告の表示と最適化、効果測定、不正なクリックの検出 |
| プライバシーポリシー | Googleのプライバシーポリシーへのリンク |
| オプトアウト | Googleの広告設定へのリンク |
もともとCloudflare Web AnalyticsはCookieを使わないので「Cookie同意バナーは不要」と書いていたが、AdSenseはCookieを使う。そこで「AdSenseは広告配信のためにCookieを使うが、広告設定のリンクから無効化できる」という一文を追記して、既存の記述と矛盾しないようにした。プライバシーポリシー側の「利用している外部サービス」の表にもAdSenseを1行足している。
対応2:Auto Ads が最下部にしか入らない → 手動枠を作る
承認翌日、実際のページを見て気づいたのが、町丁目ページのような縦に長いページでは、Auto Adsが最下部付近にしか広告を入れないことだった。町丁目ページは総合スコア、ハザード別スコア、地図、詳細データ、災害履歴、不動産価格、人口統計、避難場所、周辺施設、FAQ……と縦に長く、最下部まで読む人は少ない。
そこで、文脈上ちょうどいい位置に固定の広告ユニットを置くことにした。AdSenseの管理画面でディスプレイ広告ユニットを作り、Astroのコンポーネントにする。
---
// 手動配置のAdSense広告枠(ディスプレイ広告・レスポンシブ)。
// Auto Adsとは別に、文脈上の良い位置を固定で確保するために使う。
interface Props {
slot: string;
}
const { slot } = Astro.props;
---
<div class="mb-5">
<p class="text-[10px] font-medium text-gray-400 uppercase tracking-wider text-center mb-1.5">広告</p>
<ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-XXXXXXXXXXXXXXXX"
data-ad-slot={slot}
data-ad-format="auto"
data-full-width-responsive="true"></ins>
</div>
<script is:inline>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
ポイントは3つ。
-
<script is:inline>: Astroは通常<script>をバンドルして1回だけ読み込む形に最適化する。広告枠は「1枠ごとに1回pushする」必要があるので、is:inlineで最適化を止め、枠の数だけそのまま出力させている -
window.adsbygoogle || []:adsbygoogle.jsはasyncで読み込んでいるので、枠のpushのほうが先に実行されることがある。その場合はただの配列に積んでおき、スクリプトが読み込まれた時点でまとめて処理される。AdSense公式のコードそのままだが、Astroのような静的出力で枠を量産するときはこのキューの仕組みに乗っていることを意識しておくと安心できる - 「広告」ラベルを枠の上に出す: 対応1のポリシーで「本文と広告を視覚的に区別する」と書いたので、それを枠側でも担保している
置き場所:アフィリエイト枠と交互に、スコア表示には割り込ませない
町丁目ページには3枠、市・区のページと政令市の親ページには2枠を置いた。データが揃っている町丁目ページでの並びはこうなっている(災害履歴・人口統計・周辺施設・FAQなどはデータがある場合だけ表示される)。
総合スコア
ハザード別スコア
地図
── 広告枠1
詳細データ
災害履歴
── アフィリエイト枠
不動産取引価格
家賃相場
── アフィリエイト枠
人口統計
── 広告枠2
避難場所
周辺施設
── アフィリエイト枠
近くのエリアへのリンク
FAQ
── 広告枠3
注意書き
決めたルールは2つ。
1つ目は、ページの主役であるスコアと地図には割り込ませないこと。検索から来たユーザーが最初に見たいのは「この町のリスクはどうか」なので、そこまでは邪魔をしない。最初の広告枠は地図を見終わった直後に置いた。
2つ目は、既存のアフィリエイト枠と隣接させないこと。アフィリエイト枠は火災保険・引越し・賃貸探しなど、直前のセクション(災害履歴・家賃相場・周辺施設)の文脈に合わせて置いている。AdSense枠をその隣に並べると広告が2連続になって、どちらもただのノイズになる。セクションを最低1つ挟んで、広告とアフィリエイトが交互に出るようにした。ただし間に挟むセクションが条件付き表示の場合、たとえば人口統計データがない町丁目では、家賃相場の後のアフィリエイト枠と広告枠2が隣り合ってしまう。ここは今後の課題として残っている。
なお、同じ広告ユニットを複数のページ種別で使い回している(町丁目ページの「地図の後」と市区町村ページの対応位置が同じユニット、など)。ユニットは「ページ内のどの位置か」の単位で分けておくと、管理画面のレポートで位置ごとの成績を比べやすい。
手動枠を置いてもAuto Adsは止めていないので、Googleが他に良い位置を見つければ追加で広告が入る。「最低限ここには出す」を手動枠で決め、それ以外は自動に任せる分担だ。
対応3:トップページだけ広告をゼロにする
トップページは住所検索の入り口で、ここで離脱されると下の町丁目ページに一切流れない。広告枠は置かない方針にした。手動枠を置かないのは簡単だが、Auto Adsはレイアウト共通のスクリプト経由でサイト全体に効くので、トップにも勝手に広告が入る。
AdSenseの管理画面には、Auto Adsで特定のページやエリアを除外する機能がある。ところが除外設定のプレビュー画面はサイトをiframeで読み込む作りで、このサイトはCloudflare Pagesの_headersで全ページにX-Frame-Options: SAMEORIGINを返している。
/*
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Referrer-Policy: strict-origin-when-cross-origin
Google側のドメインからはiframeに表示できず、プレビューが真っ白で除外設定ができなかった。クリックジャッキング対策のヘッダをAdSenseの設定画面のためだけに緩めるのは筋が悪いので、コード側でトップページだけスクリプトを読み込まないようにした。
---
const currentPath = Astro.url.pathname;
---
{currentPath !== '/' && (
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-XXXXXXXXXXXXXXXX" crossorigin="anonymous"></script>
)}
currentPathはもともとヘッダーナビゲーションの現在地ハイライトに使っていた変数で、それを流用しただけの2行の変更だ。スクリプト自体を読み込まなければ、Auto Adsの設定がどうであれトップには広告が出ない。管理画面の設定は後から変わりうるが、コードで止めておけば確実に「広告ゼロ」を担保できる。
このサイトはビルド時にHTMLを出力して配信する構成なので、Astro.url.pathnameはビルド時にページごとに確定する。トップだけ<head>の中身が違うHTMLが出力されるだけで、実行時の分岐コストはない。
まとめ
- AdSense承認は「タグを貼って終わり」ではなく、そこから法令表示・広告の位置・広告を出さないページの3つを決める作業が始まる
- 法令面は、ステマ規制向けの広告表示ポリシーと、外部送信規律向けの外部送信ポリシー追記。災害リスクを扱うサイトなので、広告がスコアに影響しないことを明言した
- Auto Adsは長いページで最下部にしか入らなかったので、
AdSlot.astroで手動枠を作り、主役のスコア・地図を避け、アフィリエイト枠と交互になるよう配置した - トップの除外は管理画面が自サイトの
X-Frame-Optionsで使えなかったため、レイアウトでスクリプトを条件付き出力にした。セキュリティヘッダを緩めずに済み、設定変更に左右されない
公的データ×災害リスクサイトのアーキテクチャ全体(DB型SEO・出典自動生成・法務設計)は、以下の本でさらに詳しく解説している。
https://zenn.dev/sktt_panda/books/public-data-hazard-site
この記事は Zenn にも同じ内容を投稿しています。