DEV Community

Cover image for 2026年版:Instagram Graph API 使い方ガイド
Akira
Akira

Posted on • Originally published at apidog.com

2026年版:Instagram Graph API 使い方ガイド

要するに

InstagramグラフAPIは、Instagramビジネスアカウントおよびクリエイターアカウントをプログラムで管理できるようにします。FacebookログインOAuth 2.0認証、コンテンツ公開、インサイト、コメント、メッセージングのためのGraphQLベースのエンドポイントを使用し、アプリごとに1時間あたり200件のAPI呼び出しというレート制限があります。このガイドでは、認証設定、コンテンツ公開、インサイト取得、コメント管理、および本番環境での統合戦略について、実装手順を中心に解説します。

今すぐApidogを試す

はじめに

Instagramは20億人を超える月間アクティブユーザーを持ち、2億以上の企業がInstagramビジネスアカウントを利用しています。ソーシャルメディア管理ツールや分析プラットフォーム、Eコマース統合を構築する開発者にとって、InstagramグラフAPIとの連携は必須です。

手動で複数アカウントを管理する場合、毎週20~30時間を消費します。APIを活用することで、コンテンツ公開/コメントモデレーション/インサイト取得/レポーティングなどを自動化できます。

本ガイドは、公式ドキュメントを補完し、Facebookログイン認証からAPI連携、Webhook、デプロイまで、現場で使えるコード例と手順を詳述します。

💡 ApidogはAPI統合テストを効率化します。Instagramのエンドポイントテスト、OAuth認証フローの検証、レスポンスの検査・モック、テストシナリオの共有までワークスペースで一括管理できます。

InstagramグラフAPIとは?

InstagramグラフAPIは、FacebookグラフAPI経由でInstagramビジネスアカウントおよびクリエイターアカウントにプログラムからアクセス可能にするAPIです。主要な用途は以下です。

  • コンテンツ公開(写真・動画・リール・カルーセル)
  • メディアインサイト取得
  • コメント・メンション管理
  • ダイレクトメッセージ(Messenger Platformと組み合わせ)
  • ハッシュタグ・メンションのトラッキング
  • ストーリー管理
  • ショッピング・商品タグ

主な機能

機能 説明
グラフベースAPI ノードベースのリソースアクセス
OAuth 2.0 Facebookログイン認証
Webhooks コメント・メンションのリアルタイム通知
レート制限 アプリごとに1時間200回
コンテンツ公開 写真・動画・リール・カルーセル
インサイト エンゲージメント・リーチ・インプレッション
モデレーション コメント・メンション・メッセージ管理

アカウント要件

アカウントタイプ APIアクセス
ビジネスアカウント 全APIアクセス
クリエイターアカウント 全APIアクセス
個人アカウント APIアクセス不可(変換必須)
非公開アカウント 一部インサイトのみ

APIアーキテクチャの概要

APIベースURL例:

https://graph.facebook.com/v18.0/
Enter fullscreen mode Exit fullscreen mode

APIバージョンの比較

バージョン ステータス 終了日 ユースケース
v18.0 現在 2026年3月 すべての新しい統合
v17.0 非推奨 2026年1月 既存の統合
v16.0 廃止済み 期限切れ 使用不可

四半期ごとにバージョンアップあり。常に最新バージョンで開発しましょう。


はじめに: 認証設定

ステップ1: Facebook開発者アカウントの作成

  1. Facebook開発者ポータルにアクセス
  2. Facebookアカウントでサインイン
  3. 新規アプリ(タイプ: ビジネス)作成
  4. InstagramグラフAPI製品を追加

ステップ2: Instagramビジネスアカウントのリンク

  1. Facebookページの「設定」→「Instagram」へ移動
  2. 「アカウントを接続」をクリック
  3. Instagramへログインし認証
  4. ビジネスアカウントとしてリンクされていることを確認

※ 個人アカウントはGraph API不可。設定からビジネス/クリエイターへ変換必須。

ステップ3: アクセストークンの取得

OAuth認証URLを生成し、ユーザーに認可を促します。

const FB_APP_ID = process.env.FB_APP_ID;
const FB_APP_SECRET = process.env.FB_APP_SECRET;
const FB_REDIRECT_URI = process.env.FB_REDIRECT_URI;

const getAuthUrl = (state) => {
  const params = new URLSearchParams({
    client_id: FB_APP_ID,
    redirect_uri: FB_REDIRECT_URI,
    scope: 'instagram_basic,instagram_content_publish,instagram_manage_comments,instagram_manage_insights,pages_read_engagement',
    state: state
  });
  return `https://www.facebook.com/v18.0/dialog/oauth?${params.toString()}`;
};
Enter fullscreen mode Exit fullscreen mode

必要な権限

権限 説明
instagram_basic プロフィール・メディアリスト
instagram_content_publish 写真・動画・カルーセル公開
instagram_manage_comments コメント操作
instagram_manage_insights インサイト取得
pages_read_engagement ページアクセス
pages_manage_posts ページ経由での公開

ステップ4: 長期間有効なトークンへ交換

短期(1時間)トークンを長期(60日)有効トークンに交換します。

const exchangeForLongLivedToken = async (shortLivedToken) => {
  const response = await fetch(
    `https://graph.facebook.com/v18.0/oauth/access_token?` +
    `grant_type=fb_exchange_token&` +
    `client_id=${FB_APP_ID}&` +
    `client_secret=${FB_APP_SECRET}&` +
    `fb_exchange_token=${shortLivedToken}`
  );
  const data = await response.json();
  return data;
};

// 例
const longLivedToken = await exchangeForLongLivedToken(shortLivedToken);
console.log(`Token expires: ${new Date(longLivedToken.expires_at * 1000)}`);
Enter fullscreen mode Exit fullscreen mode

ステップ5: InstagramビジネスアカウントIDの取得

const getInstagramAccountId = async (pageId, accessToken) => {
  const response = await fetch(
    `https://graph.facebook.com/v18.0/${pageId}?fields=instagram_business_account&access_token=${accessToken}`
  );
  const data = await response.json();
  return data.instagram_business_account.id;
};

// 例
const igAccountId = await getInstagramAccountId('12345678', accessToken);
console.log(`Instagram Account ID: ${igAccountId}`);
Enter fullscreen mode Exit fullscreen mode

ステップ6: 認証済みAPI呼び出し

再利用可能なAPIクライアント例:

const IG_BASE_URL = 'https://graph.facebook.com/v18.0';

const instagramRequest = async (endpoint, params = {}) => {
  const url = new URL(`${IG_BASE_URL}${endpoint}`);
  url.searchParams.append('access_token', process.env.INSTAGRAM_ACCESS_TOKEN);

  Object.entries(params).forEach(([key, value]) => {
    url.searchParams.append(key, value);
  });

  const response = await fetch(url.toString());

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Instagram API Error: ${error.error.message}`);
  }

  return response.json();
};

// 例
const account = await instagramRequest(`/me`);
console.log(`Instagram Account: ${account.username}`);
Enter fullscreen mode Exit fullscreen mode

コンテンツの公開

写真の公開

const publishPhoto = async (igAccountId, photoData) => {
  // メディアコンテナ作成
  const containerResponse = await instagramRequest(`/${igAccountId}/media`, {
    method: 'POST',
    image_url: photoData.imageUrl,
    caption: photoData.caption,
    location_id: photoData.locationId, // 任意
    is_carousel_item: 'false'
  });
  const creationId = containerResponse.id;

  // メディア公開
  const publishResponse = await instagramRequest(`/${igAccountId}/media_publish`, {
    method: 'POST',
    creation_id: creationId
  });
  return publishResponse;
};

// 使用例
const post = await publishPhoto({
  igAccountId: '17841400000000000',
  imageUrl: 'https://example.com/image.jpg',
  caption: 'Excited to announce our new product! 🚀 #launch #innovation',
  locationId: '123456789' // 任意
});
console.log(`Published media ID: ${post.id}`);
Enter fullscreen mode Exit fullscreen mode

動画の公開

const publishVideo = async (igAccountId, videoData) => {
  // メディアコンテナ作成
  const containerResponse = await instagramRequest(`/${igAccountId}/media`, {
    method: 'POST',
    video_url: videoData.videoUrl,
    cover_url: videoData.coverUrl, // サムネイル任意
    caption: videoData.caption,
    media_type: 'REELS', // フィードなら'VIDEO'
    share_to_feed: 'true'
  });
  const creationId = containerResponse.id;

  // 動画処理完了までポーリング
  await waitForVideoProcessing(creationId);

  // メディア公開
  const publishResponse = await instagramRequest(`/${igAccountId}/media_publish`, {
    method: 'POST',
    creation_id: creationId
  });
  return publishResponse;
};

const waitForVideoProcessing = async (creationId, maxAttempts = 30) => {
  for (let i = 0; i < maxAttempts; i++) {
    const status = await instagramRequest(`/${creationId}`);
    if (status.status_code === 'FINISHED') {
      return true;
    } else if (status.status_code === 'EXPIRED') {
      throw new Error('Video processing expired');
    }
    await new Promise(resolve => setTimeout(resolve, 2000));
  }
  throw new Error('Video processing timeout');
};
Enter fullscreen mode Exit fullscreen mode

カルーセル(複数メディア)の公開

const publishCarousel = async (igAccountId, carouselData) => {
  const children = [];
  // 各メディアコンテナ作成
  for (const item of carouselData.items) {
    const containerResponse = await instagramRequest(`/${igAccountId}/media`, {
      method: 'POST',
      [item.type === 'video' ? 'video_url' : 'image_url']: item.url,
      caption: item.caption || '',
      is_carousel_item: 'true'
    });
    children.push(containerResponse.id);
  }
  // カルーセルコンテナ作成
  const carouselContainerResponse = await instagramRequest(`/${igAccountId}/media`, {
    method: 'POST',
    media_type: 'CAROUSEL',
    children: children.join(','),
    caption: carouselData.caption
  });
  const creationId = carouselContainerResponse.id;
  // カルーセル公開
  const publishResponse = await instagramRequest(`/${igAccountId}/media_publish`, {
    method: 'POST',
    creation_id: creationId
  });
  return publishResponse;
};

// 使用例
const carousel = await publishCarousel('17841400000000000', {
  caption: 'Product showcase 2026',
  items: [
    { type: 'image', url: 'https://example.com/img1.jpg', caption: 'Product 1' },
    { type: 'image', url: 'https://example.com/img2.jpg', caption: 'Product 2' },
    { type: 'video', url: 'https://example.com/vid1.mp4', caption: 'Demo' }
  ]
});
Enter fullscreen mode Exit fullscreen mode

メディアタイプ

メディアタイプ パラメータ ユースケース
IMAGE image_url, caption 写真
VIDEO video_url, cover_url, caption 動画
REELS video_url, cover_url, caption, share_to_feed リール
CAROUSEL children(配列), caption 複数メディア

メディアとインサイトの取得

ユーザーメディアの取得

const getUserMedia = async (igAccountId, limit = 25) => {
  const response = await instagramRequest(`/${igAccountId}/media`, {
    fields: 'id,caption,media_type,media_url,permalink,timestamp,like_count,comments_count',
    limit: limit.toString()
  });
  return response;
};

// 使用例
const media = await getUserMedia('17841400000000000');
media.data.forEach(item => {
  console.log(`${item.media_type}: ${item.caption}`);
  console.log(`Likes: ${item.like_count}, Comments: ${item.comments_count}`);
  console.log(`URL: ${item.permalink}`);
});
Enter fullscreen mode Exit fullscreen mode

メディアインサイトの取得

const getMediaInsights = async (mediaId) => {
  const response = await instagramRequest(`/${mediaId}/insights`, {
    fields: 'impressions,reach,engagement,saved,video_views,profile_visits,follows'
  });
  return response;
};

// 使用例
const insights = await getMediaInsights('17890000000000000');
insights.data.forEach(metric => {
  console.log(`${metric.name}: ${metric.values[0].value}`);
});
Enter fullscreen mode Exit fullscreen mode

利用可能なインサイト指標

指標 説明 メディアタイプ
impressions 合計ビュー数 全て
reach 到達ユニークアカウント数 全て
engagement いいね+コメント+保存 全て
saved 保存回数 全て
video_views 3秒以上の動画視聴回数 動画・リール
plays 合計動画再生数 動画・リール
profile_visits 投稿からのプロフィール訪問数 全て
follows 投稿からのフォロー 全て
comments コメント数 全て
like_count いいね数 全て

アカウントインサイトの取得

const getAccountInsights = async (igAccountId, metricNames, since = null, until = null) => {
  const params = {
    metric: metricNames.join(','),
    period: 'day'
  };
  if (since) params.since = since;
  if (until) params.until = until;
  const response = await instagramRequest(`/${igAccountId}/insights`, params);
  return response;
};

// 例:直近30日
const accountInsights = await getAccountInsights(
  '17841400000000000',
  ['impressions', 'reach', 'profile_views', 'email_contacts', 'website_clicks'],
  '2026-02-23',
  '2026-03-25'
);

accountInsights.data.forEach(metric => {
  console.log(`${metric.name}:`);
  metric.values.forEach(value => {
    console.log(`  ${value.end_time}: ${value.value}`);
  });
});
Enter fullscreen mode Exit fullscreen mode

アカウントレベルの指標

指標 説明
impressions プロフィール+コンテンツ表示数
reach 到達ユニークアカウント数
profile_views プロフィール訪問数
website_clicks プロフィールリンククリック数
email_contacts メールボタンタップ数
phone_call_clicks 電話ボタンタップ数
text_message_clicks SMSボタンタップ数
get_directions_clicks 住所クリック数
follower_count 合計フォロワー数
audience_city フォロワー都市
audience_country フォロワー国
audience_gender_age 人口統計

コメント管理

コメントの取得

const getMediaComments = async (mediaId, limit = 50) => {
  const response = await instagramRequest(`/${mediaId}/comments`, {
    fields: 'id,text,timestamp,username,hidden',
    limit: limit.toString()
  });
  return response;
};

// 使用例
const comments = await getMediaComments('17890000000000000');
comments.data.forEach(comment => {
  console.log(`@${comment.username}: ${comment.text}`);
  console.log(`Hidden: ${comment.hidden}`);
});
Enter fullscreen mode Exit fullscreen mode

コメントへの返信

const replyToComment = async (mediaId, commentId, replyText) => {
  const response = await instagramRequest(`/${mediaId}/comments`, {
    method: 'POST',
    response_to: commentId,
    message: replyText
  });
  return response;
};

// 使用例
const reply = await replyToComment(
  '17890000000000000',
  '17900000000000000',
  'Thank you for your interest! Check your DM for details.'
);
console.log(`Reply posted: ${reply.id}`);
Enter fullscreen mode Exit fullscreen mode

コメントの非表示

const hideComment = async (commentId) => {
  const response = await instagramRequest(`/${commentId}`, {
    method: 'POST',
    hide: 'true'
  });
  return response;
};

// 使用例
await hideComment('17900000000000000');
console.log('Comment hidden');
Enter fullscreen mode Exit fullscreen mode

コメントの削除

const deleteComment = async (commentId) => {
  await instagramRequest(`/${commentId}`, {
    method: 'DELETE'
  });
  console.log('Comment deleted');
};
Enter fullscreen mode Exit fullscreen mode

Webhook

Webhookの構成

const subscribeToWebhooks = async (appId, pageId, accessToken) => {
  const response = await fetch(
    `https://graph.facebook.com/v18.0/${appId}/subscriptions`,
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        object: 'instagram',
        callback_url: 'https://myapp.com/webhooks/instagram',
        verify_token: process.env.WEBHOOK_VERIFY_TOKEN,
        access_token: accessToken,
        fields: ['comments', 'mentions', 'message_reactions']
      })
    }
  );
  return response.json();
};
Enter fullscreen mode Exit fullscreen mode

Webhookの処理

const express = require('express');
const app = express();

// 検証
app.get('/webhooks/instagram', (req, res) => {
  const mode = req.query['hub.mode'];
  const token = req.query['hub.verify_token'];
  const challenge = req.query['hub.challenge'];
  if (mode === 'subscribe' && token === process.env.WEBHOOK_VERIFY_TOKEN) {
    res.status(200).send(challenge);
  } else {
    res.status(403).send('Verification failed');
  }
});

// イベント受信
app.post('/webhooks/instagram', express.json(), async (req, res) => {
  const body = req.body;
  if (body.object !== 'instagram') {
    return res.status(404).send('Not found');
  }
  for (const entry of body.entry) {
    const igId = entry.id;
    const changes = entry.changes;
    for (const change of changes) {
      switch (change.field) {
        case 'comments':
          await handleNewComment(change.value);
          break;
        case 'mentions':
          await handleMention(change.value);
          break;
        case 'message_reactions':
          await handleReaction(change.value);
          break;
      }
    }
  }
  res.status(200).send('OK');
});

async function handleNewComment(data) {
  console.log(`New comment on media ${data.media_id}`);
  console.log(`From: ${data.from_id}`);
  console.log(`Text: ${data.text}`);
  // スパムなら自動非表示
  if (isSpam(data.text)) {
    await hideComment(data.id);
  }
}
Enter fullscreen mode Exit fullscreen mode

Webhookフィールド

フィールド トリガー
comments 新規コメント/返信
mentions アカウントのメンション
message_reactions ストーリーへのリアクション
story_status ストーリーの返信/表示

レート制限

レート制限の理解

  • アプリごとに1時間200回(全ユーザー合算)
  • ビジネスディスカバリー:ユーザーごとに1時間200回
  • コンテンツ公開:アクション別に制限あり

超過するとHTTP 400(サブコード613)エラー。

レート制限のベストプラクティス

  1. 応答キャッシュ - 変更がないデータは再取得しない
  2. バッチリクエスト - フィールド展開で呼び出し数削減
  3. Webhook活用 - ポーリングではなくリアルタイム取得
  4. バックオフ実装 - 429エラー時は指数バックオフ
const makeRateLimitedRequest = async (endpoint, params = {}, maxRetries = 3) => {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await instagramRequest(endpoint, params);
      return response;
    } catch (error) {
      if (error.message.includes('429') && attempt < maxRetries) {
        const delay = Math.pow(2, attempt) * 1000;
        console.log(`レート制限に達しました。${delay}ms後に再試行します...`);
        await new Promise(resolve => setTimeout(resolve, delay));
      } else {
        throw error;
      }
    }
  }
};
Enter fullscreen mode Exit fullscreen mode

一般的な問題のトラブルシューティング

問題: OAuthトークンの期限切れ

症状: 「無効なOAuthアクセストークン」エラー

解決策:

  1. 60日以内にトークン更新を自動化
  2. 有効期限を保存し、期限前にアラート
  3. 期限切れなら再認証リダイレクト

問題: メディア公開の失敗

症状: 公開時エラー

解決策:

  1. 画像URLが公開アクセス可能か確認
  2. 画像形式(JPEG/PNG)、サイズ(8MB未満)を確認
  3. 動画はMP4、1GB未満、90秒未満
  4. 動画処理完了まで待機

問題: インサイトが利用できない

症状: インサイトAPIが空データを返す

解決策:

  1. ビジネス/クリエイターアカウントであることの確認
  2. インサイト生成まで24~48時間待つ
  3. アカウントが十分アクティブであるか確認

本番デプロイチェックリスト

  • [ ] テストアカウントをビジネス/クリエイターに変換
  • [ ] 長期トークンでOAuth 2.0実装
  • [ ] トークンを暗号化・安全に保存
  • [ ] 自動トークン更新の実装
  • [ ] WebhookエンドポイントをHTTPSで公開
  • [ ] レート制限対策・リクエストキュー導入
  • [ ] エラー処理の実装
  • [ ] API呼び出しのロギング
  • [ ] コンテンツモデレーションワークフロー作成
  • [ ] 複数アカウントタイプでテスト

実世界のユースケース

ソーシャルメディアスケジュールツール

  • 課題: 50超のクライアントアカウントを手動で投稿管理
  • 解決策: Instagram APIでスケジュール自動投稿
  • 結果: 作業時間80%削減・一貫した投稿

実装例

  • コンテンツカレンダーでのドラッグ&ドロップスケジューリング
  • 写真・動画・カルーセルの自動公開
  • 投稿内容からハッシュタグ自動提案

カスタマーサービス自動化

  • 課題: 顧客対応の遅延
  • 解決策: Webhook+キーワード検出で自動返信
  • 結果: 平均応答5分、満足度90%

実装例

  • 「価格」「在庫」「発送」などの自動応答
  • 商品リンク付き自動返信
  • 複雑な問合せは人間エージェントへ転送

結論

InstagramグラフAPIはビジネス/クリエイターアカウントの自動化に最適なAPIです。

  • 60日間有効なOAuth 2.0トークンで認証
  • 写真・動画・リール・カルーセルのAPI投稿
  • 各種インサイト取得・分析
  • Webhookでコメント・メンションを即時取得
  • レート制限対策必須(1時間200回)
  • ApidogでAPIテスト・コラボレーションを効率化

FAQセクション

Instagram APIにアクセスするにはどうすればよいですか?

Facebook開発者アカウント+ビジネスアプリ作成+InstagramグラフAPI製品追加+OAuth認証権限付与で利用できます。

Instagramに自動的に投稿できますか?

はい。API経由で写真・動画・リール・カルーセルの自動投稿が可能です。

Instagram APIをサポートするアカウントタイプは何ですか?

ビジネスアカウント・クリエイターアカウントのみ。個人アカウントは不可または制限あり。

Instagramからコメントを取得するにはどうすればよいですか?

/{media-id}/commentsエンドポイントで取得。Webhookを使えばリアルタイム通知も受信可能。

Instagramのレート制限は何ですか?

アプリごとに1時間あたり200回。エンドポイントごとに追加制限あり。

API経由でストーリーを公開できますか?

はい。通常投稿と同じフローでストーリー公開も可能です。

Instagramインサイトにアクセスするにはどうすればよいですか?

instagram_manage_insights権限が必要。インサイトエンドポイントで取得できます。

コメントに自動返信できますか?

はい。コメントAPIで自動返信が可能。カスタマーサービス自動化にも応用できます。

Top comments (0)