← このサイトの仕組み(目次)

How this site works

Instagram連携 ― 外部ウィジェットを貼らずにSNSを載せる

トップページの下部に、Instagram の最新投稿が並んでいます。よくある貼り付け型のウィジェットは使っていません。その作り方と、実際に一度フィードを全部消してしまった話を書きます。

最終更新:2026年8月19日

なぜウィジェットを貼らないのか

よくある作り方は、フィード配信サービスが用意した JavaScript のタグを貼る「埋め込みウィジェット方式」です。 貼るだけで動くので手軽ですが、代わりに次のものを引き受けることになります。

  • 閲覧者のブラウザが、ページ表示のたびに第三者のサーバーへ通信する
  • その通信が終わるまで枠が空で、後から中身が入ってレイアウトがずれる
  • 提供元が止まれば、そのままサイトの一部が欠ける
  • 表示回数がそのまま利用料に効いてくる料金体系が多い

このサイトでは、ウィジェットを貼らずに 公開する前に取得を終えておく 方式を採っています。 閲覧者が見るのは、ただの静的な HTML と自サイトの画像だけです。 全体アーキテクチャで書いた 「公開する前に全部作り終えておく」という方針を、SNS連携にも通した形になります。

仕組み:毎朝すくって、リポジトリに貯める

  1. 1

    毎朝すくう

    朝6時、GitHub Actions が Instagram の最新6件を取りに行きます。サイトのビルドとは切り離してあります。

  2. 2

    画像をダウンロードして貯める

    まだ持っていない投稿だけ画像を落とし、リポジトリに保存します。最大30件まで貯め、溢れた分は古いものから消します。

  3. 3

    新しい投稿があった日だけ公開

    差分が無い日は何もしません。投稿があった日だけコミットが生まれ、それを合図にサイトが組み直されます。

  4. 4

    静的HTMLに焼き込み

    貯めた画像とキャプションがHTMLに組み込まれます。閲覧者のブラウザは外部に何も取りに行きません。

  5. 5

    取れなかった日は、前回のまま

    取得に失敗しても止まりません。リポジトリに貯めた分がそのまま表示され続けます。

要点は 「閲覧者のブラウザには一切の外部通信をさせない」 ことです。 Instagram と通信するのは朝6時の自動処理だけで、しかも公開の前に終わっています。 そのため表示は速く、レイアウトのずれも起きず、Instagram 側が不調でもページは何事もなく表示されます。

罠その1:画像のURLは数日で切れる

Instagram の API が返す画像URLは、有効期限つきの署名がついた一時的なものです。 これを HTML にそのまま書き込むと、公開直後は正常に見えるのに、数日後には キャプションだけが残って画像が全部消えます。 データの取得は成功し続けているので、エラーもログも出ません。気づくのは目視した時だけです。

この対策が、上の手順2「画像をダウンロードして貯める」です。 画像そのものを落として自サイトから配信すれば、期限つきURLはどこにも残りません。

どこから取ってくるか

ここまでが「器」の話です。器を決めたうえで、投稿データの取得元をどこにするかという別の問題が残ります。 当初は Meta(Facebook)の Graph API を自分で直接叩いていましたが、これには アクセストークンが約60日で失効し、そのたびに手作業で更新する必要がある という弱点があります。 失効しても画面上はエラーにならず、フィードが静かに止まるので、気づきにくいのも厄介です。

そこで3案を比較し、C案(Behold)に移行しました

比較項目 A. Graph API 直 旧方式 自前のMetaアプリと自前トークンで、Meta の API を直接叩く B. Graph API 直+自動更新 A に、トークンを自動で再発行する仕組みを足す C. Behold JSON 採用 取得とトークン管理を外部サービスに任せ、その JSON を読む
取得元 Graph API 直Graph API 直Behold JSON
画像 自前ホスト /ig/同左同左(ダウンロード元が変わるだけ)
トークンの更新 60日ごとに手動自動不要(サービス側が管理)
Meta開発者アプリの維持 必要必要不要
費用 0円0円0円(無料枠:6投稿/月1,200リクエスト)
外部への依存 Meta のみMeta のみMeta + Behold
実装の差分 約40行+月1回の定期実行約30行(取得URLと項目名の対応づけ)
副次的な効果 代替テキスト・ハッシュタグ除去済みキャプション・WebP最適化
主なリスク 失効すると無言で止まる60日以上デプロイが無いと失効する無料枠の縮小やサービス終了

色を敷いた2行が、判断を分けた軸です。

決め手はトークンではなく Meta開発者アプリを維持し続けるかどうか でした。 B案でトークンを自動更新しても、APIバージョンの強制的な切り替え、権限まわりの仕様変更、 Facebookページとの連携切れといった「いつか壊れる要因」は残ります。 年に一度そういう対応が発生すると考えると、そこを専業のサービスに預けるほうが、 自前のコードで守り続けるより安く付く、と判断しました。

この記事を公開した翌日に、旧方式が実際に壊れた

ここからは、書いた直後に現実になった話です。 上の比較表で、A案のリスクを「失効すると無言で止まる」と書きました。 その翌日、トップページから Instagramのフィードが丸ごと消えていました

エラーページも、空の枠も出ません。セクションごと、何事もなかったかのように無くなります。 アクセス解析にも異常は出ません。気づいたのは、たまたま自分のサイトを見ていたときでした。

罠その2:「失敗しても前回のデータを使う」が、効いていなかった

取得スクリプトには、最初から「取得に失敗してもビルドを止めず、前回のデータをそのまま残す」 という安全装置を書いてありました。ところが、これがまったく機能していませんでした

理由は2つが噛み合っていたためです。ひとつは、ダウンロードした画像とデータを 「毎回作り直す一時ファイル」とみなして、リポジトリの管理対象から外していたこと。 もうひとつは、ビルドが毎回まっさらな状態から始まること。 つまり「残すべき前回のデータ」が、そもそも存在しなかったのです。 1回でも取得に失敗すれば、その時点で全損する構造でした。

フォールバックを書いたことと、フォールバックが効くことは別物だった、という話です。 これは Instagram に限らず、外部から取ってきて静的化する処理すべてに当てはまります。

生簀(いけす)方式 ― 6件しか取れないのに、30件出せる理由

乗り換え先のBeholdは、無料プランで取得できるのが 最新6件だけ です。 しかも7件目に押し出された投稿は、あとから取りに行くことができません。 窓は常に「最新6件」の位置にあり、過去に向かって開くことはないからです。

そこで、毎朝その6件をすくってリポジトリに貯めます。 すでに持っている投稿は飛ばし、新しいものだけを足していく。 こうして日を追うごとに手持ちが増え、最大30件まで貯まります。 生簀が満杯になったら、古いものから逃がします。

そして、この「貯める」がそのまま罠その2の対策になっています。 貯める先はリポジトリなので、画像もデータも当然コミット対象です。 取得に失敗した日は、前回までに貯めた分がそのまま表示され続けます。 今度は「残すべき前回のデータ」が本当に存在します。

ついでに、有料プラン(月$10・50件)に上げずに表示できる母数が増えました。 無料枠の制約を、設計で回した形です。

無料枠は「取得回数」で数える

Beholdの無料枠は月1,200リクエストですが、これはデータを取りに行った回数で数えます。 ウィジェットを貼ると訪問者1人につき1回消費するので、 1日40人見に来ただけで月末を待たずに止まります。 一方この方式なら、1日1回すくうだけなので月30回程度。桁が2つ違います。 無料枠に収まっているのは、けちっているからではなく叩く回数が根本的に少ないからです。

現在の構成:C案(Behold)+ 生簀方式。毎朝6時に最新6件をすくい、最大30件まで蓄積。 新しい投稿があった日だけサイトを組み直します。トークンの手動更新は不要になりました。

前の記事:全体アーキテクチャ ― データベースを持たず、Gitがすべての正本

ホームページのご相談も承っています

ここで公開しているのは、実際に自社サイトで使っている作り方そのものです。 新しく作りたい方、いま使っているサイトを引き取りたい方は、お気軽にご相談ください。

最終更新: