Instagramは更新できていても、ホームページのギャラリーやお知らせまで同じ内容を入力するのは手間がかかります。
そこで、福岡市西区のトリミングサロン「Dog care salon apricot」様のホームページでは、Instagramの投稿をサイト内へ自動表示する仕組みを実装しました。
今回の方法では、投稿時に専用のハッシュタグを付けると、ホームページの「ギャラリー」または「お知らせ」へ振り分けられます。更新は即時ではなく、GitHub ActionsとCloudflare Pagesを使って6時間ごとに行います。
この記事では、実際に採用した構成とコードをもとに、どこで投稿を取得し、どのように画像を保存しているかを紹介します。Meta側の画面操作を網羅する手順書ではなく、現在動いている実装の設計と処理を確認する記事です。
今回の実装でできること
- Instagramの投稿をギャラリーとお知らせへ振り分ける
- 画像をWebPへ変換し、ホームページ側へ保存する
- カルーセル投稿の複数画像と動画のサムネイルにも対応する
- 6時間ごとに自動で新しい投稿を反映する
実装の前提
今回利用したのは、Instagramプロアカウントの投稿を取得できるAPIです。個人アカウントの投稿を無条件に取得できる仕組みではありません。
認証には「Instagram API with Instagram Login」の構成を採用しています。この構成ではInstagramのプロアカウントを使用し、基本情報の取得に instagram_business_basic 権限を使います。Facebookページとの連携は必須ではありません。
Metaには「Instagram API with Facebook Login」という別の構成もあり、こちらはFacebookページとの連携や必要な権限が異なります。古い解説記事には両者が混ざっている場合があるため、実装前にMeta公式のInstagram API資料で、選んだ認証方式と権限名を確認する必要があります。
なお、Metaの管理画面やAPI仕様は変更されることがあります。本記事は2026年9月時点のapricot様サイトの実装を基準にしています。
今回の構成
Instagramへ投稿した直後に、ホームページが書き換わるわけではありません。GitHub Actionsが6時間ごとにCloudflare PagesのDeploy Hookを呼び出し、新しいビルドを開始します。
Cloudflare Pagesのビルド中に投稿データと画像を取得し、Astroが完成した静的サイトを生成します。
この構成にした理由は、閲覧者がページを開くたびにInstagramへ問い合わせる必要をなくすためです。公開後のページには取得済みの文章と画像が含まれるので、通常の静的ページと同じように表示できます。
APIの準備
Cloudflare Pagesには、次の2つを環境変数として登録しています。
INSTAGRAM_ACCESS_TOKEN
INSTAGRAM_USER_ID
INSTAGRAM_ACCESS_TOKEN はInstagram APIへ接続するためのアクセストークン、INSTAGRAM_USER_ID は投稿を取得するアカウントのIDです。値をコードやGitHubリポジトリへ直接書かず、Cloudflare側で管理します。
一方、GitHub Actionsに登録するのは CLOUDFLARE_DEPLOY_HOOK_URL だけです。Instagramの認証情報をGitHub Actionsへ渡し、そこで投稿を取得する構成にはしていません。
実装時は、開発用と本番用の値を混同しないこと、トークンやDeploy HookのURLを画面共有・ログ・コミットへ残さないことも重要です。
投稿を取得する
同期用スクリプトは、Instagram APIの /{user-id}/media へアクセスします。制作時のコードではAPIバージョンを v23.0 に固定し、1回に100件ずつ取得しています。
const API_VERSION = 'v23.0';
const GRAPH_BASE = `https://graph.instagram.com/${API_VERSION}`;
const fields = [
'id',
'caption',
'media_type',
'media_url',
'permalink',
'timestamp',
'thumbnail_url',
'children{id,media_type,media_url,thumbnail_url}',
].join(',');
let page = await graphGet(`${USER_ID}/media`, {
fields,
limit: '100',
});
取得するのは投稿ID、本文、投稿種別、画像URL、Instagram上の投稿URL、投稿日時などです。カルーセル投稿では children も取得し、2枚目以降の画像を保存できるようにしています。
100件を超えた場合は paging.next をたどります。ただし、サイトへ表示する件数まで100件にする必要はありません。取得処理と画面上の表示件数は分けて考え、ページでは必要な件数だけを使います。
投稿先を振り分ける
apricot様サイトでは、次の2つを運用専用タグとして決めました。
| 専用タグ | 表示先 |
|---|---|
#apricot_gallery | 仕上がりギャラリー |
#apricot_news | お知らせ |
投稿本文からハッシュタグを取り出し、専用タグが含まれているかを判定します。
const caption = media.caption || '';
const hashtags = [...caption.matchAll(/#([A-Za-z0-9_]+)/g)]
.map((match) => match[1].toLowerCase());
const showInGallery = hashtags.includes('apricot_gallery');
const showInNews = hashtags.includes('apricot_news');
この正規表現は、英数字とアンダースコアで作った運用タグだけを対象にしています。一般的な日本語ハッシュタグが付いていても、表示先の判定には影響しません。
どちらの専用タグもない投稿は、ホームページには表示しない仕様です。両方のタグを付けた投稿は、ギャラリーとお知らせの両方へ表示されます。
画像を保存する
APIから返る画像URLを、そのままページの画像URLとして使う構成にはしていません。ビルド時に画像をダウンロードし、最大1280pxに縮小してWebPへ変換します。
export async function imageWebp(input, maxSize = 1280) {
return sharp(input)
.rotate()
.resize({
width: maxSize,
height: maxSize,
fit: 'inside',
withoutEnlargement: true,
})
.webp({ quality: 82, effort: 6, alphaQuality: 100 })
.toBuffer();
}
通常投稿は画像を保存し、動画投稿は thumbnail_url からサムネイルを保存します。カルーセル投稿では子要素を順番に処理します。
投稿情報はJSON、画像はWebPとして生成します。これらは毎回のビルドで作るデータなので、GitHubにはコミットしていません。Cloudflare Pagesが生成済みのファイルを含むサイトを公開します。
6時間ごとに更新
定期実行にはGitHub Actionsのスケジュール機能を使っています。ワークフローが行うのは、Cloudflare PagesのDeploy Hookを呼ぶことだけです。
name: Trigger Cloudflare Build
on:
schedule:
- cron: '0 */6 * * *'
workflow_dispatch:
jobs:
trigger-cloudflare-build:
runs-on: ubuntu-latest
steps:
- name: Trigger Cloudflare Pages deploy hook
run: curl --fail --request POST "${CLOUDFLARE_DEPLOY_HOOK_URL}"
env:
CLOUDFLARE_DEPLOY_HOOK_URL: ${{ secrets.CLOUDFLARE_DEPLOY_HOOK_URL }}
cronの 0 */6 * * * は6時間ごとの実行です。投稿時刻によって待ち時間が変わるため、ホームページへの反映は最大約6時間にビルド時間を加えた程度になります。
急いで反映したい場合は、GitHub Actionsの workflow_dispatch から手動実行できます。Instagram投稿者へGitHubの操作まで求めるのではなく、通常は次回の自動更新を待つ運用です。
トークンを管理する
この構成では、アクセストークンの更新を自動化せず、運用作業として扱っています。
トークンには発行方法に応じた期限や失効条件があります。期限が近づいた場合は、新しいトークンを発行し、Cloudflare Pagesの INSTAGRAM_ACCESS_TOKEN を更新します。
完全自動化する場合は、トークンを更新するだけでなく、安全な保存先へ反映する処理、失敗通知、権限の最小化まで含めて別途設計が必要です。コード例だけを追加して運用済みと考えないほうが安全です。
エラー時の動き
Instagram APIの取得に失敗した場合は同期処理をエラーで終了し、その回のCloudflare Pagesビルドを公開しない設計です。
APIエラー時に前回のJSONから新しいビルドを作るのではなく、直前に公開成功したサイトをそのまま残します。取得に失敗した内容で公開中のページを置き換えないための方針です。
確認する場所は2つです。GitHub Actionsが失敗している場合はDeploy Hookの登録、Cloudflare Pagesのビルドが失敗している場合はトークン・ユーザーID・APIレスポンスを確認します。
運用時の確認事項
- MetaのAPIバージョンと権限名に変更がないか確認する
- アクセストークンの期限と更新担当を決めておく
- Cloudflare Pagesのビルド失敗を定期的に確認する
- 専用タグの綴りを投稿担当者と共有する
向いているサイト
この方法は、写真でサービスの雰囲気や実績を伝える店舗サイトと相性がよい構成です。トリミングサロン、美容室、飲食店、教室、施工事例を掲載する事業などが考えられます。
すでにInstagramへの投稿が続いていて、ホームページにも同じ写真を掲載したい場合は、入力を二重にしない運用を作れます。サイト側のデザインへ合わせて表示できるため、外部ウィジェットをそのまま埋め込む方法より見た目を調整しやすい点も特徴です。
一方、投稿直後の反映が必須なサイト、長文記事を細かく編集したいサイト、Meta APIの保守担当を置けないサイトでは、別の方法が向く場合があります。手動掲載や外部サービスも含め、更新頻度と運用体制から選ぶ必要があります。
導入前の確認
同じ構成を検討する場合は、実装前に次の内容を決めておくと進めやすくなります。
- Instagramをプロアカウントとして運用できるか
- どの投稿をホームページへ表示するか
- 表示先を分ける専用タグを何にするか
- 反映まで最大何時間なら許容できるか
- トークン更新とエラー確認を誰が行うか
- 動画・カルーセル投稿をどのように見せるか
投稿をすべて自動表示するより、今回のように専用タグで掲載対象を選ぶほうが運用しやすいケースもあります。Instagramでは自然な投稿でも、ホームページのギャラリーには不要な写真があるためです。
実装したサイト
今回の仕組みは、Dog care salon apricot様のホームページで使用しています。制作全体については、apricot様のホームページ制作事例で紹介しています。
Instagram連携の導入方法や費用を事業者向けに知りたい方は、Instagram連携できるホームページ制作もご覧ください。
まとめ
apricot様サイトでは、Instagram投稿を6時間ごとに取得し、専用タグでギャラリーとお知らせへ振り分けています。画像はWebPへ変換してサイト内へ保存し、Astroで静的ページを生成しています。
重要なのは、Instagram APIを使うこと自体ではなく、投稿する方が迷わず続けられ、サイト側も安定して表示できる運用にすることです。
Instagram連携が必要かどうかも含め、事業内容と現在の更新方法を確認したうえでご提案します。