ブログ一覧

favicon を設定しているのに検索結果は地球儀のまま — 原因は robots.txt だった

運用中の 8 サイトを Cloudflare のログで週次監視しているのですが(監視の設計は「Google Analytics を入れずにブログ群を運用する」参照)、そのうちの 1 サイトで奇妙な現象に気づきました。favicon はきちんと設定されていて、ブラウザのタブにも表示される。なのに Google の検索結果では、いつまで経ってもデフォルトの地球儀アイコンのままなのです。

favicon が検索結果に出ない原因としてよく挙がるのは「そもそも favicon がない」「サイズ要件を満たしていない」あたりですが、今回はどちらでもありませんでした。原因は robots.txt です。この組み合わせは特にヘッドレス CMS やサイトビルダーの構成で構造的に起きやすいので、診断手順と合わせて書き残します。

症状: ブラウザでは表示されるのに、検索結果は地球儀

現象を整理するとこうです。

  • ブラウザでサイトを開くと、タブに favicon が表示される
  • HTML にも <link rel="icon" href="..."> が正しく出力されている
  • しかし Google 検索結果のサイト名の横は、デフォルトの地球儀アイコンのまま

「設定してあるのに反映されない」ので、最初はクロール待ちを疑って放置しがちです。しかし数週間経っても変わらないなら、待っていても解決しません。

まず定番の原因を消し込む

本題の前に、先に消し込むべき定番の原因を挙げておきます。

  • favicon が実は 404: curl -I https://example.com/favicon.ico で確認します。rel="icon" を書いていないサイトでは、Google もブラウザもこの規定パスにフォールバックするため、ここが 404 だと表示されません
  • `rel="icon"` の書き忘れ: HTML ソースを確認します
  • サイズ要件: Google のドキュメントでは favicon は正方形で 最小 8×8px、推奨は 48×48px 以上とされています。極端に小さいと表示品質が落ちます
  • ホームページ自体が noindex: favicon はホームページとセットで評価されます

今回のサイトはこれらを全て通過していました。rel="icon" はあり、参照先も 200 を返し、ICO として正常。それでも地球儀のまま。

本当の原因: robots.txt が favicon の URL をブロックしていた

該当サイトの HTML はこうなっていました。favicon は CMS のメディア管理機能でアップロードしたもので、API 経由のパスから配信されています。

<link rel="icon" href="/_emdash/api/media/file/01KREAVF56A6R4VVCT2NZCHYN7.ico">

そして robots.txt はこうです。

User-agent: *
Allow: /

# Disallow admin and API routes
Disallow: /_emdash/

管理画面と API のパスをクローラーから隠すのは定石で、この Disallow 自体は正しい設定です。しかしこの結果、favicon の配信 URL がまるごと Disallow の傘の下に入っていました

ここで効いてくるのが Google の仕様です。Google のドキュメントには、検索結果に favicon を表示する条件として 「favicon の URL とホームページの URL がクロール可能であること(Google に対してブロックされていないこと)」が明記されています。つまり robots.txt で favicon の URL をブロックしていると、Google は favicon を取得できず、地球儀にフォールバックします。

厄介なのはこの障害の非対称性です。ブラウザは favicon の取得で robots.txt を参照しません。だからタブには正常に表示され続け、壊れているのは検索結果だけになる。「設定してあるし表示もされている」という思い込みが生まれ、robots.txt を疑う発想がなかなか出てきません。

この構造は「ヘッドレス CMS + robots の定石」で自動的に発生する

今回の構成を抽象化すると、次の 2 つの定石の掛け算で事故が起きています。

  1. アップロードされたメディアを API パス(`/api/...`、`/_cms/...` など)から配信する — ヘッドレス CMS、サイトビルダー、独自管理画面を持つ構成では普通の設計です
  2. 管理画面・API のパスプレフィックスを robots.txt で Disallow する — これも SEO の定石です

favicon を管理画面からアップロードできる機能を持つシステムで、その配信パスが API プレフィックスの下にある場合、両方の定石に従うと必ずこの事故が起きます。私のケース(EmDash という CMS)に限らず、同じ形のシステムなら同じことが起きるはずです。

診断手順

疑わしい場合の確認は 3 ステップです。

  1. HTML ソースで `rel="icon"` の href を確認するcurl -s https://example.com/ | grep 'rel="icon"'
  2. その URL を robots.txt と突き合わせる — href のパスが Disallow ルールに一致していないか目視で確認します。Search Console の「robots.txt テスター」相当の確認でも構いません
  3. URL 自体の健全性を確認するcurl -I で 200 と画像系の Content-Type が返ること

2 で一致していたら、それが原因です。

対策: 静的な /favicon.ico を併設する

対策は 2 通りありますが、私は静的併設を選びました。

  • 静的な `/favicon.ico` を置く(推奨): 同じアイコンをルート直下の /favicon.ico にも静的ファイルとして配置します。ここは robots.txt の Allow 範囲内なので Google がクロールでき、しかも rel="icon" がない場合の Google の規定フォールバック先でもあるので、二重に安全です。既存の rel="icon"(API パス)はブラウザ用にそのまま残して共存できます
  • robots.txt に例外の Allow を書く: Allow: /_emdash/api/media/ のように favicon の配信パスだけ許可する方法です。動きますが、「管理系パスは全部 Disallow」というルールの例外が増えていくと管理が壊れやすいので、私は採りませんでした

なお、静的に置く ICO は 16/32/48px のマルチサイズにしておくと、Google の 48px 推奨とブラウザタブの小サイズ表示の両方をカバーできます。Node.js で ICO を生成する方法は別記事「Node.js の sharp は ICO を書き出せない — favicon.ico を約 30 行で手組みする」にまとめました。

対応後の反映はクロール依存です。Google は favicon をホームページのクロール時に取得するため、反映まで数日〜数週間かかります。急ぐ場合は Search Console からホームページの再クロールをリクエストできます。

まとめ

  • favicon を設定していてブラウザには表示されるのに検索結果が地球儀の場合、robots.txt が favicon の URL をブロックしていないか確認する
  • Google は「favicon の URL がクロール可能であること」を表示条件にしている。一方ブラウザは robots.txt を読まないため、「タブでは見える・検索では地球儀」という非対称な壊れ方をする
  • 「メディアを API パスから配信する」×「API パスを robots.txt で Disallow する」という 2 つの定石の掛け算で自動的に発生する。ヘッドレス CMS・サイトビルダー構成は要注意
  • 対策は静的な `/favicon.ico` の併設が最も安全。robots.txt に例外 Allow を足す方法もあるが管理が壊れやすい
  • favicon は正方形で最小 8×8px、推奨 48×48px 以上。反映はクロール依存で数日〜数週間

参考リンク

この記事をシェア