【第11回】SEO と SNS 自動投稿——作ったものを見つけてもらう仕組み
canonical URL、サイトマップ、OG画像、JSON-LD、postbuild チェッカー。そして Bluesky と X の自動投稿。サイトを「見つけてもらう」ために何をやったか、開発担当 Claude Code に聞いた
← 前の記事: 【第10回】記事も AI に書かせてみた——ネタ探しからインタビュー形式に至るまでコンテンツはある。記事も書ける。でも誰にも見つけてもらえなければ、存在しないのと同じだ。
yatmita.com はコンテンツを増やし続けてきたが、アクセスはなかなか伸びない。何が足りないのか? 今回は SEO 対策と SNS 自動投稿について、開発担当の Claude Code に聞いてみた。
まず何が問題だったの?
記者: サイトのアクセスが伸びないと。
開発者: コンテンツは増えているんです。レシピ、食材リファレンス、漫画、テック記事——合わせて100ページ以上ある。でも検索から来る人が少ない。
記者: なぜ?
開発者: SEO の基本をサボっていたから。
記者: 具体的には?
開発者: 監査してみたら5つ見つかりました。canonical URL がない、サイトマップに載っていないページがある、OG 画像がない、JSON-LD がない、そしてこれらの漏れを検出する仕組みがない。
canonical URL って何?
記者: ひとつずつ聞いていいですか。canonical URL って?
開発者: 「このページの正式な URL はこれです」と検索エンジンに教えるものです。
記者: なぜ必要?
開発者: 同じコンテンツに複数の URL でアクセスできることがある。クエリパラメータが付いたり、末尾のスラッシュがあったりなかったり。検索エンジンはそれを別のページだと思うかもしれない。canonical を指定すれば「この URL が本物です」と宣言できる。
記者: 全ページに入れた?
開発者: はい。Next.js の generateMetadata で alternates.canonical を指定するだけ。1ページ1行の変更。でもやっていなかった。
サイトマップの穴
記者: サイトマップの問題は?
開発者: labo の記事が53本あるのに、サイトマップに1本も載っていなかった。
記者: え、53本も?
開発者: はい。漫画のトップページや議論力のシリーズページも抜けていた。サイトマップに載っていないと Google のクローラーが見つけにくい。内部リンクを辿ってくれることもあるけど、保証はない。
記者: 修正は?
開発者: sitemap.ts に getPosts、getSeriesArticles の結果を追加した。Next.js の sitemap は TypeScript の関数なので、データ層の関数を呼ぶだけ。
OG 画像——SNS で見てもらうために
記者: OG 画像は?
開発者: Open Graph 画像。SNS でリンクを共有したときに表示されるサムネイルです。
記者: なかったんですか?
開発者: root layout にデフォルトの OG 画像は設定してあったけど、全ページ同じ画像だった。スムージーの記事もテック記事も同じサムネイル。
記者: それはもったいない。
開発者: そうなんです。カテゴリごとに OG 画像を作りました。labo は5カテゴリ(AI漫画、Claude Code、サイト構築、Obsidian、OpenClaw)、レシピは3ドメイン(スムージー、タンパク質スープ、タンパク質パスタ)。ImageMagick でテキストベースの画像を生成しました。
記者: テキストベースというのは?
開発者: カテゴリ名をドンと書いた1200x630の画像です。背景色をカテゴリごとに変えて。写真を使えればいいけど、素材がないなら文字だけでも「何のページか」は伝わる。
JSON-LD——検索エンジンへの自己紹介
記者: JSON-LD は?
開発者: 構造化データです。「このページは記事です、タイトルはこれで、公開日はこれです」と機械が読める形で埋め込む。
記者: 効果は?
開発者: Google の検索結果にリッチスニペットが表示されることがある。レシピなら調理時間やカロリーが出たり、記事なら公開日が出たり。クリック率に影響する。
記者: 既にレシピには入っていた?
開発者: はい。RecipeJsonLd コンポーネントがあった。記事用の ArticleJsonLd も作って、datePublished を追加しました。
漏れを防ぐ——postbuild チェッカー
記者: 5つ目の「検出する仕組み」は?
開発者: check-seo-meta.ts というスクリプトを作りました。ビルド後の HTML を全部スキャンして、canonical、description、OG タグ、JSON-LD の有無をチェックする。
記者: ビルドのたびに?
開発者: postbuild に組み込んであるので、pnpm run build すれば自動的に走ります。漏れがあればエラーで教えてくれる。
記者: 二度とサボれない。
開発者: そういうことです。手動チェックは忘れるけど、CI に入れれば忘れようがない。
記者: 似たようなチェッカーが他にもあるとか。
開発者: 内部リンクチェッカー check-internal-links.ts が先にありました。ビルド後の HTML から全リンクを抽出して、リンク先のページが実際に存在するか検証する。404 になるリンクがあればエラー。
記者: リンク切れって起きるんですか?
開発者: めちゃくちゃ起きます。記事を移動したり、slug を変えたり、ページを消したり。100ページ以上あると手動では追えない。これも postbuild に入っていて、SEO チェッカーと一緒に毎回走る。
記者: ビルドが通った時点で、リンク切れもメタデータ漏れもないことが保証される。
開発者: そう。だから安心してコンテンツを増やせる。壊しても気づける。
後半戦——SNS で届ける
記者: ここまでが SEO。次は?
開発者: 検索流入は時間がかかる。canonical を入れてすぐにアクセスが増えるわけじゃない。もっと能動的に「見つけてもらう」方法が必要だった。
記者: SNS ですね。
開発者: はい。AI で作った4コマ漫画が25話もストックされている。これを SNS に流せば、サイトへの導線になる。
X の壁
記者: まず X(Twitter)を試した?
開発者: Developer アカウントを作って API キーも取得しました。でもテスト投稿しようとしたら「クレジットが足りません」と。
記者: 無料じゃないんですか?
開発者: 2026年2月から Pay-Per-Use モデルに変わっていて、事前にクレジットを購入する必要がある。しかも料金表がどこにも見当たらない。
記者: 料金表なしでクレジットを買えと。
開発者: Developer Portal の Billing ページにも具体的な単価が書いてない。「View current rates in the Developer Console」と書いてあるのに Console にも見つからない。一旦 X は諦めました。
まず Bluesky
記者: 代わりに?
開発者: Bluesky です。API 完全無料、レート制限も緩い、アカウント作成も簡単。5分でテスト投稿まで行けました。
記者: 5分は早いですね。
開発者: AT Protocol の SDK(@atproto/api)がよくできていて、10行くらいで投稿できる。画像のアップロードも uploadBlob 一発。
自動投稿の仕組み
記者: どう自動化したんですか?
開発者: まず投稿コンテンツ。4つのシリーズから全38話分を登録しました。
| シリーズ | 話数 | 投稿形式 |
|---|---|---|
| 料理部つくってみた | 25話 | 4コマ全体を1枚 |
| yrgr | 7話 | 冒頭4ページ |
| ブッダイズム。 | 4話 | 冒頭4ページ |
| 最後は議論力がモノをいう | 2話 | 冒頭4ページ |
記者: ページ漫画は冒頭だけ?
開発者: 「続きはサイトで!」の導線です。タップすれば全画面で読めるし、スワイプでページもめくれる。
記者: 投稿文は?
開発者: 記事の frontmatter からタイトルと description を自動取得しています。手動でキャプションを書く必要がない。ハッシュタグもシリーズごとに設定済み。
著作権表示
記者: 画像にウォーターマークを入れているそうですね。
開発者: はい。Google Fonts の Caveat という手書き風フォントで、右下に「© yatmita.com」と入れています。ImageMagick でアップロード前に自動合成。
記者: 手書き風?
開発者: さりげないけど存在感がある。ゴシック体だと事務的すぎるし、明朝体だと堅い。手書き風がちょうどよかった。
cron で1日3回
記者: 投稿スケジュールは?
開発者: cron で1日3回。Bluesky が 6:58、11:58、19:58。X はその1分後の 6:59、11:59、19:59。
記者: 1分ずらすのは?
開発者: 同時実行を避けるためです。どちらもランダムに1作品選んで投稿するので、毎回違う内容になる。エラーが出たら Discord に通知が来る。
記者: X はエラーが多そう。クレジット切れとか。
開発者: クレジット切れも Discord に通知されます。exit 1 で終了するエラーは全部拾う仕組みにしてある。
記者: 被ることもある?
開発者: あります。でも初期はフォロワーが少ないし、繰り返し見てもらえる方がいい。
やっぱり X も
記者: X は諦めたんじゃなかったんですか?
開発者: X が公式で出している Playground というローカル開発ツールを使ってみたんです。X API v2 をシミュレートしてくれるツールで、起動したら console.x.com から料金データを自動でキャッシュしてきた。
記者: そこで単価がわかった?
開発者: 投稿1回 $0.01。1日3回なら月 $0.90。それなら出せると判断して、クレジットをチャージして動かすことにしました。
記者: Bluesky と同じスクリプトを使った?
開発者: 構造はほぼ同じです。認証が OAuth 1.0a になって、画像アップロードが v1.uploadMedia、投稿が v2.tweet に変わるだけ。280文字制限があるので説明文の切り詰め処理を追加しました。
記者: cron は?
開発者: Bluesky の1分後。6:59、11:59、19:59。エラーが出たら Discord に通知が来る。クレジット切れも同じ通知で飛んでくる。
結果
記者: 投稿してみてどうでした?
開発者: 最初のテスト投稿にすぐ「いいね」が付きました。
記者: え、フォロワーゼロなのに?
開発者: bot です。新規投稿を監視している bot がいるんです。でも、それでも反応があるのは悪くない。ハッシュタグ経由で人間にもリーチするはず。
まとめ
記者: 今日やったことを一言で?
開発者: 「作る」から「届ける」への投資です。コンテンツを作ることに集中しすぎて、見つけてもらう仕組みがなかった。SEO は検索エンジンへの名刺、SNS は能動的な営業。どっちも必要。
記者: これからは?
開発者: Bluesky と X、両方が動いています。新しいコンテンツが増えたら投稿スクリプトに追加するだけで自動的に回る。仕組みは作ったので、あとはコンテンツに集中できる。
記者: ありがとうございました。
開発者: こちらこそ。「見つけてもらう」のは終わりがないので、また進展があれば報告します。
Bluesky アカウント: @yatmita.bsky.social — AI漫画を毎日投稿中です。
X アカウント: @yatmita43616 — Bluesky と同じコンテンツを1日3回自動投稿中です。