忍者AdMaxの審査が「審査中」から進まない3つの原因と解決法【SPA / Cloudflare】

概要

今回は、忍者AdMaxの審査が「審査中」から進まない問題について、実際に半日ハマって解決した記録を紹介していきます。
舞台はReact+Viteで作ったSPA(在庫管理ツール「ざいこにゃん」)で、Cloudflare Pagesにデプロイしています。

各画面の末尾に広告枠を1つ置いただけなのに、忍者AdMaxの管理画面では枠がずっと「審査中」のまま一歩も進まない
アプリ側の広告枠も空っぽで、何も表示されません。
「これは忍者側の不具合では?」と疑ったのですが、調べていくと原因は3つとも全部自分側の設定でした。

しかも1つは完全な思い込みで、触らなくていいところを触って遠回りしています(- -;
同じ症状で「審査が進まない」「広告枠が空のまま」と困っている個人開発者の方が、原因を切り分けて自力で直せるように、症状→切り分け→解決の順で書いていきます。

それではやっていきましょう!

この記事はReact SPA + Cloudflare Pagesの組み合わせを題材にしていますが、考え方(クローラが本文を読めているか → タグの種類は合っているか → URLは関係あるか)はVueなど他のSPAでもそのまま使えます。

目次

症状:審査が「審査中」から進まない

実際に出ていた症状はこの3つです。
管理画面の広告枠が2つとも「審査中」のまま固まっています。

忍者AdMaxの広告枠一覧。PC 728x90とSP 300x250の2枠がずっと「審査中」のまま
忍者AdMaxの広告枠一覧画面。ざいこにゃんのPC枠とSP枠が2つとも審査中ステータスで止まっている

審査ステータスの画面を開くと、こんなメッセージが出ます。

http://site-de-zaiko.shinpinoshi.com/ で広告枠タグの掲載が確認できておりません。
正しく掲載いただいていると、以下のような広告が表示されます。
新しいドメインの場合、上記のバナーが表示されてから30分以内に審査が開始します。
忍者からのメッセージと自社バナー。これが「URLの問題だ」と思わせる罠だった
忍者AdMaxの審査ステータス画面。広告枠タグの掲載が確認できていないというメッセージと収益化を促す自社バナーが表示されている

そしてアプリ側を見ると、「広告」ラベルの箱が空っぽ。
タグは入れたはずなのに、何も描画されていません。

アプリ /app 画面の広告枠が空っぽ。タグは入れたのに広告が出ない
ざいこにゃんのアプリ画面下部にある広告ラベルの箱が空のまま表示されている

厄介なのが、忍者の審査画面には「再実行ボタン」が無いこと。
待っても進まないし、自分でリトライもできない。
完全に手詰まり感がありますよね(- -;

結論:原因は3つ、全部自分側だった

先に結論から言ってしまいます。
半日デバッグして判明した原因は、次の3つでした。

  • 原因①:Cloudflareのセキュリティルールが審査クローラを403で弾いていた
    • 実機ブラウザでは見えるのに審査だけ通らない症状の正体で、これが最大の罠
  • 原因②:SPAでは「PC/SP切替タグ」のswitch型IDでないと描画されない
    • 入れていたadmax_idが別種別のものだったため、広告枠が空のままだった本命バグ
  • 誤解③:登録URLは触らなくてよかった
    • 「掲載確認できておりません」はURLの問題に見えて実は違い、先にいじると遠回りになる

切り分けの順番をフロー図にするとこうなります。
上から順に潰していけば、たいていここに収束するはずです。

忍者AdMaxの審査が進まないときの切り分けフロー。クローラが読めているか→タグの種類→URLの順で見る
審査が進まないときの切り分けフロー図。ボットUAでads.txtが403ならボット遮断ルールを緩め、admax_idがswitch型でなければ切替タグに差し替え、登録URLは触らずに広告が発火すれば審査が通る、という流れ

それぞれ詳しく見ていきます。

原因①:Cloudflareのセキュリティルールが審査クローラを403で弾く

これが一番の罠でした。
Cloudflareにはボット対策系のセキュリティルール(Bot Fight ModeやWAFのカスタムルールなど)があり、設定によってはブラウザと検証済みボット(Googlebot等)「以外」の自動アクセスを403で拒否します。

忍者AdMaxの審査クローラやads.txtチェッカーは「検証済みボット」ではないので、こうしたルールに引っかかると403を食らい、サイト本文もads.txtも読めず、審査が永久に止まる
実機ブラウザでは普通に広告が見えるのに審査だけ通らない、という症状はこれが正体でした。

curlでUA別に切り分ける

疑わしいときは、User-Agentを変えてcurlを投げると一発で分かります。
ブラウザのUAは通るのに、無名のボットUAだけ403なら、ボット保護が犯人です。

切り分け

1
2
3
# ブラウザUAは通るのにボットUAが403ならボット対策ルールを疑う
curl -A "Mozilla/5.0 ... Chrome/124.0" https://<domain>/ads.txt # → 200 が正常
curl -A "SomeCrawler/1.0" https://<domain>/ads.txt # → 403 なら弾かれている

実際の結果がこちらです。
ブラウザUAとGooglebot UAは200で通るのに、一般ボットUAだけが403で弾かれていました。

User-Agent /ads.txt /(トップ)
Chrome(ブラウザ)UA 200
Googlebot UA 200
一般ボットUA(SomeCrawler/1.0 403 ❌(修正前) 403
curl/8.0(ツール名そのまま) 403 403

直し方:弾いているルールを見直し、ads.txtを許可

Cloudflareダッシュボードから次の対処をします。

  • Security → Events でブロック元を特定する
    • 非Google系UAがBlock / Challengeされている行を探す。原因がBot Fight Modeなら該当機能を、WAFのカスタムルールならそのルールを止める/緩める
  • ads.txt は全UAに開放しておく
    • WAFで http.request.uri.path eq "/ads.txt" をSkip / Allowにして、広告審査系のチェッカーを通す

解除後にもう一度テストすると、SomeCrawler/1.0 でも /ads.txt/ が200を返し、本文(adm.shinobi.jp,230217,DIRECT など)も読めるようになりました。
curl/8.0 だけは別ルールで弾かれたままですが、忍者のクローラは “curl” とは名乗らないので無関係です。

ads.txtが読めないと、広告ネットワーク側は「このサイトは自分を承認していない」と判断してしまい、審査が永久に進みません。 ボット対策系のルール(Bot Fight ModeやWAFのカスタムルール)は便利な反面、広告・SEO系の正規クローラまで巻き込みやすいので、収益化サイトでは挙動を必ず確認してください。

原因②:SPAは「PC/SP切替タグの非同期(switch)」でないと空になる

Cloudflareを直しても、広告枠はまだ空のまま。
ここが本命のバグでした。

忍者AdMaxには3種類のタグがある

実は忍者AdMaxには用途の違う3種類のタグがあり、admax_id(ハッシュ)もそれぞれ別物です。
ここを取り違えると、コードと受け皿が噛み合わず何も描画されません。

タグ種別 SPAコードと合う?
① 標準(同期) <script src="adm.shinobi.jp/s/<ID>"> ✗ document.writeでSPA不可
② 個別枠の非同期(banner) <div class="admax-ads"> + push({type:"banner"}) ✗ class/type不一致で描画ゼロ
③ PC/SP切替の非同期(switch) <div class="admax-switch"> + push({type:"switch"}) ✓ これだけ正解

自分のコード(後述のReactコンポーネント)は admax-switch + type:"switch" で描画する設計なのに、入れていたadmax_idが②の個別枠/banner型のIDでした。
/st/t.js ローダが一致する受け皿(admax-switch のdiv)を見つけられず、何も描画されない=空枠。
当然、忍者の審査もタグを検出できません。

ダメな例と正解を並べるとこうです。

1
2
<!-- (A) ダメ:標準同期タグ(document.write方式でSPA不可) -->
<script src="https://adm.shinobi.jp/s/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"></script>
1
2
3
4
<!-- (B) ダメ:個別枠の非同期 banner タグ(admax-switchコードとは噛み合わず空枠) -->
<div class="admax-ads" data-admax-id="xxxx" style="display:inline-block;width:728px;height:90px;"></div>
<script>(admaxads = window.admaxads || []).push({admax_id: "xxxx", type: "banner"});</script>
<script src="https://adm.shinobi.jp/st/t.js" async></script>
1
2
3
4
<!-- (C) 正解:PC/SP切替タグの非同期タグ(これを使う) -->
<div class="admax-switch" data-admax-id="xxxx" style="display:inline-block;"></div>
<script>(admaxads = window.admaxads || []).push({admax_id: "xxxx", type: "switch"});</script>
<script src="https://adm.shinobi.jp/st/t.js" async></script>

見た目は似ていますが、classtype と、何よりadmax_idそのものが別物です。
コードが正しくても、idが別種別なら受け皿が見つからず空になります。

なぜ同期(document.write)はSPAで死ぬのか

ここは少し技術コラムです。
忍者AdMaxの標準タグ <script src="adm.shinobi.jp/s/<ID>">document.write() 方式で動いています。

document.write() は「HTMLパース中」しか正常に挿入できず、ページ読み込み後に呼ぶとドキュメント全体を白紙に上書きしてしまうんですよね。
SPA(React)では広告コンポーネントは初回ロード後にマウントされ、画面遷移もJSで切り替わります。
つまり同期タグは原理的に使えません(出した瞬間アプリが真っ白になるか、遷移後に出ない)。

だから忍者AdMaxも非同期タグ自体は公式に用意しています。
ただしSPAでの利用は公式にはサポートされていません
有志がまとめた非同期タグの実装サンプル(非公式・自己責任)がGitHubにあるので、SPAではそれらを参考にしつつ非同期タグ一択で組む、という整理になります。

切替タグの作り方

正しいタグは、忍者AdMaxの左メニューから作ります。

  • 「PC/SP広告切替」→「切替タグの作成」
    • PC用枠(728x90)とSP用枠(300x250)を束ねた切替タグを作る
  • 「非同期タグを表示」を押す
    • admax-switch / type:"switch" 形式のadmax_idが出てくるので、これに差し替える

このswitch型のidに差し替えたら、広告がちゃんと表示されました
タグが正しく発火すれば、忍者の審査もそれを検出できます。

React SPAに組み込むときの肝だけ書いておくと、次のとおりです。

  • switch型のdivとpushを置く
    • <div class="admax-switch" data-admax-id={id}>window.admaxads.push({ admax_id: id, type: "switch" })useRef で1回だけ)
  • 画面遷移ごとにローダを再注入する
    • 既存の #admax-script を削除 → window.__admax_tag__ / __admax_render__ をundefinedでクリア → 100ms後に adm.shinobi.jp/st/t.js を再注入
  • これをしないと遷移後に再描画されない
    • SPAは画面が破棄・再構築されるので、ローダを撒き直さないと2画面目以降が空になる

有志がまとめた非公式のSPA実装サンプルが参考になるので、組み込む際は一度目を通しておくのがお勧めです。

くり返しになりますが、忍者AdMaxはSPAを公式サポートしていないため、ここでの再注入は自己責任の実装です。
規約(第10条 禁止事項)には「不正な表示を行う行為」「正常な広告効果が期待できないと当社が認める行為」が含まれるので、ローダの再注入は実際にユーザーがページを切り替えたときだけに留め、同一ページを一定間隔で自動リロードしてインプレッションを水増しするような使い方は避けてください。
広告枠も増やしすぎず(公式の推奨上限は1ページ3枠まで)、各画面に1枠程度の控えめな配置が無難です。

誤解③:登録URLは触らなくてよかった

最後は、自分がやらかした遠回りの話です。
忍者のメッセージが /(LP)を見ているので、「広告は /app/* にしか無い→登録URLを /app に変えるべきだ」と考えて変更しました。
でも、これは完全に不要でした

真因は①②(タグが壊れて何も発火していなかった)であって、URLは関係ありません。
タグが正しく発火すれば、忍者はドメイン単位で検出してくれます。
実際、登録URLを / のままに戻しても審査は通りました。

教訓は、「掲載確認できておりません」はURLの問題に見えて違うということ。
先にURLをいじると、原因から目をそらして遠回りになります。
まずはタグが本当に発火しているか(div.admax-switch の中身が空でないか)をDevToolsで確認するのが先です。

まとめ:審査が進まない時に見る順番

忍者AdMaxが「審査中」から進まないとき、上から順に確認するチェックリストです。

  • ボットUAでads.txtが200か
    • curl -A "SomeCrawler/1.0" https://<domain>/ads.txt が403なら、弾いているボット対策ルールを緩め、ads.txtをWAFで許可
  • 使っているidは「切替タグ」のものか
    • admax-switch / type:"switch" のid以外(個別枠banner・標準同期)だと空枠になる
  • 本番で div.admax-switch の中身が空でないか
    • DevToolsで確認し、空ならadmax_idの種類が間違っている
  • 画面遷移後も再描画されるか
    • t.jsの再注入が効いているか。2画面目以降が空ならここ
  • 登録URLは慌てて変えない
    • タグが正しく発火すればドメイン単位で検出される。URLいじりは遠回り
  • 審査に手動再実行は無い
    • タグ発火後、30分〜1,2日で巡回が回るのを待つ

振り返ると、3つとも「忍者の問題」ではなく全部自分の設定の問題でした。
Cloudflareのボット保護、タグの種類、そしてURLという思い込み。
この3点を順に潰せば、たいていの「審査中から進まない」は自力で解決できるはずです。

今回ハマった内容は再利用できる雛形・チェックリストとして手元のスキルにまとめたので、同じSPA構成で詰まっている方の参考になれば嬉しいです。

以上となります。
広告収入は少ないですが、モチベ維持には重要ですよね!
それではお疲れさまでした!

忍者AdMax公式
admax.shinobi.jphttps://admax.shinobi.jp/

SPA実装サンプル(有志による非公式リポジトリ。忍者AdMaxはSPA非サポート)
github.comhttps://github.com/ninjatools/admax-spa-examples