はじめに (対象読者・この記事でわかること)

この記事は、Flutterでモバイルアプリ開発を行っているエンジニア、特にInstagramのデータを活用したい方を対象としています。Flutterの基本的な知識はあるが、外部API、特にInstagram Graph API の認証フローやエンドポイントの扱いに不安があるという方に最適です。本記事を読むことで、以下ができるようになります。

  • Instagram ビジネスアカウントまたはクリエイターアカウントのアクセストークン取得手順
  • Flutter アプリから Graph API を呼び出し、指定したユーザーのメディアオブジェクト(画像・動画・キャプション)を取得
  • 取得したデータを ListView で表示し、簡易的なフィード UI を実装

背景として、2024 年に Instagram が従来の旧 API を完全に廃止し、Graph API が唯一の公式手段となった点があります。そのため、最新の認証方式とデータ取得手順を把握しておくことが、今後のアプリ開発で必須となります。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。

  • Flutter の基本的なプロジェクト構成と Dart の文法
  • HTTP 通信(http パッケージ)や JSON パースの経験
  • Instagram ビジネスアカウントまたはクリエイターアカウントの取得手順(管理画面での設定)

Instagram API の概要と取得したい情報

Instagram Graph API は、Facebook の Graph API の一部として提供されており、認証には OAuth 2.0 が必須です。取得できる主なエンドポイントは次のとおりです。

エンドポイント 主な取得項目 必要な権限
/me/media メディア ID、キャプション、メディアタイプ、URL、タイムスタンプ instagram_basicpages_read_engagement
/media/{media-id} 画像/動画の URL、サムネイル、コメント数、いいね数 同上

今回の目的は、他人のクリエイター/ビジネスアカウント の最新投稿を取得し、アプリ内で一覧表示することです。Graph API では、対象ユーザーのアクセストークン が必要になります。つまり、アプリ側で 自らが所有するビジネスアカウント を通じて、対象アカウントのメディア情報を取得できる構成になります。これにより、サーバーサイドでのプロキシ を介さずに直接 Flutter アプリからデータを取得可能です。

必要な権限と許可取得

  1. instagram_basic
    - ユーザーの基本プロフィール情報とメディアへのアクセス権限。
  2. pages_read_engagement
    - Facebook ページ(ビジネスアカウント)が所有する Instagram アカウントのデータ取得に必要。

これらは Facebook 開発者コンソールでアプリに追加し、認証時に scope パラメータでリクエストします。

具体的な手順と実装

以下では、Flutter アプリ単体 で Instagram Graph API にアクセスし、他人アカウントの投稿を取得するまでのフローをステップごとに示します。

ステップ 1: Facebook 開発者コンソールの設定

  1. アプリ作成
    - https://developers.facebook.com/ へログインし「My Apps」 > 「Create App」 → 「Consumer」テンプレートで作成。
  2. Instagram Graph API の追加
    - 「Add Product」 > 「Instagram」 → 「Set Up」ボタンをクリック。
  3. アクセストークン取得用のリダイレクト URI 設定
    - https://{your-domain}/auth/callback など、Flutter 側で受け取れるエンドポイントを登録。ローカル開発の場合は https://localhost:8080/auth/callback を使用。
  4. 権限のリクエスト
    - 「App Review」 > 「Permissions and Features」 で instagram_basicpages_read_engagement を追加し、必要なら審査依頼(テストユーザー限定なら不要)。

ステップ 2: OAuth2 認証フローの実装

Flutter 側では flutter_web_auth パッケージを利用し、外部ブラウザで認証画面を表示します。

Dart
import 'package:flutter_web_auth/flutter_web_auth.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; Future<String> obtainAccessToken() async { final clientId = 'YOUR_FACEBOOK_APP_ID'; final redirectUri = 'myapp://auth'; final authUrl = 'https://www.facebook.com/v20.0/dialog/oauth?client_id=$clientId' '&redirect_uri=$redirectUri' '&scope=instagram_basic,pages_read_engagement' '&response_type=code'; // ブラウザで認証させ、リダイレクトされた URL を取得 final result = await FlutterWebAuth.authenticate( url: authUrl, callbackUrlScheme: 'myapp', ); // URL から認可コードを抽出 final code = Uri.parse(result).queryParameters['code']; // 認可コードからアクセストークンを取得 final tokenResponse = await http.get(Uri.parse( 'https://graph.facebook.com/v20.0/oauth/access_token?client_id=$clientId' '&redirect_uri=$redirectUri' '&client_secret=YOUR_APP_SECRET' '&code=$code')); final tokenJson = json.decode(tokenResponse.body); return tokenJson['access_token']; }

ポイント
- redirect_uri はカスタムスキーム (myapp://auth) にすると、認証後に自アプリに戻ることができ、外部サーバー不要です。
- アプリ内で client_secret を保持するとセキュリティ上問題があるため、実運用ではバックエンドプロキシでトークン取得を行うことが推奨されます。

ステップ 3: 対象アカウントのビジネスアカウント ID を取得

取得したユーザーアクセストークンを使い、自分のビジネスアカウント が管理する 対象アカウント の IG User ID を取得します。

Dart
Future<String> getIgUserId(String userAccessToken, String targetUsername) async { // まず自分の Facebook ページ ID を取得 final pagesResp = await http.get(Uri.parse( 'https://graph.facebook.com/v20.0/me/accounts?access_token=$userAccessToken')); final pagesJson = json.decode(pagesResp.body); final pageId = pagesJson['data'][0]['id']; // 1 件目のページを使用 // ページに紐付く Instagram ビジネスアカウント情報を取得 final igResp = await http.get(Uri.parse( 'https://graph.facebook.com/v20.0/$pageId?fields=instagram_business_account&access_token=$userAccessToken')); final igJson = json.decode(igResp.body); final igBusinessAccountId = igJson['instagram_business_account']['id']; // ビジネスアカウントから Username を検索し、対象ユーザーの IG User ID を特定 final searchResp = await http.get(Uri.parse( 'https://graph.facebook.com/v20.0/$igBusinessAccountId?fields=followers_count,username&access_token=$userAccessToken')); // 直接検索 API が無いため、対象ユーザーが自アカウントのフォロワーである前提で取得 // 企業側で公開情報から手動で IG User ID を取得し、コードにハードコーディングする手段もある // ここでは例として取得済みの IG User ID を返す return 'TARGET_IG_USER_ID'; }

注意点
- Graph API には「任意のユーザー ID を検索」するエンドポイントは提供されていません。取得できるのは、自分が管理するビジネスアカウント もしくは 自分がフォローしているユーザー に限られます。そのため、対象アカウントは自社・クライアントが所有するビジネスアカウント に限定するか、事前に IG User ID を取得してコードに組み込む必要があります。

ステップ 4: メディア情報取得エンドポイント呼び出し

対象 IG User ID とアクセストークンが揃ったら、/media エンドポイントで最新 10 件の投稿情報を取得します。

Dart
Future<List<dynamic>> fetchMedia(String accessToken, String igUserId) async { final mediaUrl = Uri.parse( 'https://graph.facebook.com/v20.0/$igUserId/media' '?fields=id,caption,media_type,media_url,permalink,thumbnail_url,timestamp' '&limit=10' '&access_token=$accessToken'); final resp = await http.get(mediaUrl); final jsonData = json.decode(resp.body); return jsonData['data']; // List of media objects }

取得したデータは以下のように Flutter の UI にバインドします。

Dart
class InstagramFeedPage extends StatefulWidget { @override _InstagramFeedPageState createState() => _InstagramFeedPageState(); } class _InstagramFeedPageState extends State<InstagramFeedPage> { List<dynamic> _media = []; @override void initState() { super.initState(); _loadFeed(); } Future<void> _loadFeed() async { final token = await obtainAccessToken(); // ステップ2 final igUserId = await getIgUserId(token, 'target_user'); // ステップ3 final media = await fetchMedia(token, igUserId); // ステップ4 setState(() => _media = media); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Instagram Feed')), body: _media.isEmpty ? Center(child: CircularProgressIndicator()) : ListView.builder( itemCount: _media.length, itemBuilder: (context, index) { final item = _media[index]; return Card( margin: EdgeInsets.symmetric(vertical: 8, horizontal: 12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (item['media_type'] == 'IMAGE' || item['media_type'] == 'CAROUSEL_ALBUM') Image.network(item['media_url'], fit: BoxFit.cover, width: double.infinity), if (item['media_type'] == 'VIDEO') Stack( alignment: Alignment.center, children: [ Image.network(item['thumbnail_url'], fit: BoxFit.cover, width: double.infinity), Icon(Icons.play_circle_fill, size: 64, color: Colors.white70), ], ), Padding( padding: const EdgeInsets.all(8.0), child: Text( item['caption'] ?? '', style: TextStyle(fontSize: 14), ), ), Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Text( DateTime.parse(item['timestamp']) .toLocal() .toString() .split('.') .first, style: TextStyle(fontSize: 12, color: Colors.grey), ), ), ], ), ); }, ), ); } }

コードのポイント

ポイント 説明
flutter_web_auth 外部ブラウザで OAuth2 認証を実施し、カスタムスキームでリダイレクトを捕捉
http パッケージ Graph API への GET リクエストをシンプルに実装
ListView.builder 取得したメディア配列をスクロール可能なカードリストで表示
メディアタイプ別表示 画像と動画で表示ロジックを分岐し、サムネイル上に再生アイコンを重ねる

ハマった点やエラー解決

  1. redirect_uri が一致しないエラー
    - 認証時に設定したリダイレクト URL と実際に受信した URL が不一致になると Error validating verification code が返ります。対策は、開発者コンソールの「Valid OAuth Redirect URIs」 に正確に myapp://auth(カスタムスキーマ)を登録し、Flutter 側でも同一スキーマで FlutterWebAuth.authenticate を呼び出すことです。

  2. instagram_basic 権限が不足
    - テストユーザーでしか権限が付与されないケースがあります。開発コンソールで「Roles > Test Users」へ対象アカウントを追加し、テストモードで認証すると取得できます。実運用時は Facebook の審査が必要です。

  3. Media URL が null になる
    - media_typeVIDEO の場合、media_url は動画本体の URL であり、プレビューには thumbnail_url を使用する必要があります。取得フィールドに thumbnail_url を必ず含めるようにしましょう。

  4. 取得した IG User ID が取得できない
    - Graph API では任意のユーザー ID を直接検索できません。解決策として、対象アカウントの IG User ID(数値)を事前に取得し、ハードコード するか、自社が管理するビジネスページのフォロワーとして対象アカウントを追加 して ID を取得します。

解決策まとめ

発生した問題 具体的な対処法
リダイレクト URI が不一致 コンソール側とコード側で同一スキーマを設定、myapp://auth を正確に登録
権限不足でデータ取得エラー テストユーザーに権限付与、必要なら審査依頼
動画サムネイルが表示されない fieldsthumbnail_url を追加し、動画はサムネイルで表示
IG User ID が取得できない 事前に ID を取得してコードに埋め込むか、対象アカウントを自社ページのフォロワーに追加

まとめ

本記事では、Flutter アプリから Instagram Graph API を利用し、クリエイター/ビジネスアカウントの投稿を取得・表示する方法 をステップごとに解説しました。

  • OAuth2 認証とアクセストークン取得 の流れを実装し、カスタムスキーマでリダイレクトを処理。
  • 対象 IG User ID の取得 は、ビジネスページに紐づくアカウントか、事前に取得した ID を使用する必要がある点を整理。
  • /media エンドポイント で最新投稿を取得し、Flutter の ListView で画像・動画を適切に表示。
  • 実装時に遭遇しやすいエラー(リダイレクト不一致、権限不足、ID 取得不可)とその具体的な解決策を提示。

これにより、自社アプリ内で Instagram のフィードをシームレスに再現 でき、ユーザーエンゲージメント向上やマーケティング効果の測定が可能になります。次のステップとして、取得したコメントやいいね数の集計、無限スクロール実装、バックエンドでのキャッシュ戦略 など、より高度な機能拡張を検討していきます。

参考資料