DEV Community

Cover image for 2026년 인스타그램 그래프 API 사용법
Rihpig
Rihpig

Posted on • Originally published at apidog.com

2026년 인스타그램 그래프 API 사용법

요약

인스타그램 그래프 API는 개발자가 인스타그램 비즈니스 및 크리에이터 계정을 프로그래밍 방식으로 관리할 수 있도록 합니다. 페이스북 로그인 OAuth 2.0 인증, 콘텐츠 게시, 인사이트, 댓글, 메시징을 위한 GraphQL 기반 엔드포인트를 사용하며, 앱당 시간당 200회 호출로 속도 제한이 있습니다. 이 가이드는 인증 설정, 콘텐츠 게시, 인사이트 검색, 댓글 관리 및 프로덕션 통합 전략을 다룹니다.

지금 Apidog을 사용해보세요


소개

인스타그램은 월간 활성 사용자 수가 20억 명을 넘으며, 2억 개 이상의 비즈니스가 인스타그램 비즈니스 계정을 사용하고 있습니다. 소셜 미디어 관리 도구, 분석 플랫폼, 전자상거래 통합을 구축하는 개발자에게 인스타그램 그래프 API 통합은 필수입니다.

10개 이상의 계정을 관리하는 소셜 미디어 관리자들은 수동 게시, 댓글 응답, 분석 취합에 매주 20~30시간을 낭비합니다. 견고한 인스타그램 API 통합으로 콘텐츠 게시, 댓글 관리, 감성 분석, 성과 보고를 자동화할 수 있습니다.

이 가이드는 인스타그램 그래프 API 통합의 전체 과정을 다룹니다. 페이스북 로그인 인증, 콘텐츠 게시, 미디어 인사이트, 댓글 관리, 웹훅 통합, 프로덕션 배포 전략까지 실전에서 바로 적용 가능한 구현법을 제공합니다.

💡 Apidog는 API 통합 테스트를 간소화합니다. 인스타그램 엔드포인트 테스트, OAuth 흐름 검증, 응답 검사, 게시 문제 디버깅을 하나의 작업 공간에서 할 수 있습니다. API 사양 가져오기, 응답 모의(mock), 테스트 시나리오 팀 공유까지 지원합니다.


인스타그램 그래프 API란 무엇인가요?

인스타그램 그래프 API는 페이스북 그래프 API를 통해 인스타그램 비즈니스 및 크리에이터 계정에 대한 프로그래밍 방식 접근을 제공합니다. 주요 기능:

  • 콘텐츠 게시 (사진, 동영상, 릴스, 캐러셀)
  • 미디어 인사이트 및 분석
  • 댓글 및 언급 관리
  • 다이렉트 메시징
  • 해시태그 및 언급 추적
  • 스토리 관리
  • 쇼핑 및 제품 태그

주요 기능

기능 설명
그래프 기반 API 노드 기반 리소스 접근
OAuth 2.0 페이스북 로그인 인증
웹훅 댓글, 언급 관련 실시간 알림
속도 제한 앱당 시간당 200회 호출
콘텐츠 게시 사진, 동영상, 릴스, 캐러셀
인사이트 참여, 도달, 노출 메트릭
관리 댓글, 언급, 메시지 관리

계정 요구사항

계정 유형 API 접근
비즈니스 계정 전체 API 접근
크리에이터 계정 전체 API 접근
개인 계정 API 접근 불가 (전환 필요)
비공개 계정 제한된 인사이트

API 아키텍처 개요

인스타그램 API는 페이스북 그래프 API 구조를 따릅니다:

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

API 버전 비교

버전 상태 종료일 사용 사례
v18.0 현재 2026년 3월 모든 새로운 통합
v17.0 더 이상 사용되지 않음 2026년 1월 기존 통합
v16.0 사용 중지됨 만료됨 사용하지 마세요

항상 최신 안정 버전을 대상으로 통합을 구성하세요.


시작하기: 인증 설정

1단계: 페이스북 개발자 계정 생성

  1. 페이스북 개발자 포털 접속
  2. 페이스북 계정으로 로그인
  3. 비즈니스 유형의 앱 생성
  4. 인스타그램 그래프 API 제품 추가

2단계: 인스타그램 비즈니스 계정 연결

  1. 페이스북 페이지 설정 > 인스타그램 메뉴 이동
  2. 계정 연결 클릭
  3. 인스타그램 로그인 및 승인
  4. 비즈니스 계정 연결 확인

참고: 개인 인스타그램 계정은 API 사용 불가. 인스타그램 앱 설정에서 비즈니스/크리에이터 계정으로 전환 필요

3단계: 액세스 토큰 받기

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;

// 인증 URL 생성
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단계: 인스타그램 비즈니스 계정 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) => {
  // Step 1: 미디어 컨테이너 생성
  const containerResponse = await instagramRequest(`/${igAccountId}/media`, {
    method: 'POST',
    image_url: photoData.imageUrl,
    caption: photoData.caption,
    location_id: photoData.locationId, // Optional
    is_carousel_item: 'false'
  });
  const creationId = containerResponse.id;

  // Step 2: 미디어 게시
  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' // Optional
});
console.log(`Published media ID: ${post.id}`);
Enter fullscreen mode Exit fullscreen mode

동영상 게시

const publishVideo = async (igAccountId, videoData) => {
  // Step 1: 미디어 컨테이너 생성
  const containerResponse = await instagramRequest(`/${igAccountId}/media`, {
    method: 'POST',
    video_url: videoData.videoUrl,
    cover_url: videoData.coverUrl, // 썸네일
    caption: videoData.caption,
    media_type: 'REELS', // or 'VIDEO'
    share_to_feed: 'true' // 릴스일 경우
  });
  const creationId = containerResponse.id;

  // 동영상 처리 대기
  await waitForVideoProcessing(creationId);

  // Step 2: 미디어 게시
  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 (array), 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

웹훅

웹훅 구성

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

웹훅 처리

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) {
    console.log('Webhook verified');
    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

웹훅 필드

필드 트리거
comments 새 댓글 또는 답글
mentions 계정 언급
message_reactions 스토리 반응
story_status 스토리 답글/조회

속도 제한

속도 제한 이해

  • 앱당 시간당 200회 호출 (모든 사용자 공유)
  • 비즈니스 검색: 사용자당 시간당 200회 호출
  • 콘텐츠 게시: 작업별 추가 제한 제한 초과 시 HTTP 400(오류 코드 613) 발생

속도 제한 모범 사례

  1. 응답 캐싱: 변경 없는 데이터 반복 호출 금지
  2. 요청 배치: 필드 확장으로 호출 최소화
  3. 웹훅 활용: 폴링 대신 실시간 알림
  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(`Rate limited. Retrying in ${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 구현
  • [ ] 토큰 안전 저장(암호화)
  • [ ] 토큰 자동 새로 고침
  • [ ] 웹훅 엔드포인트 HTTPS 적용
  • [ ] 속도 제한/요청 큐 구현
  • [ ] 모든 API 오류 처리
  • [ ] API 호출 로깅
  • [ ] 콘텐츠 관리 워크플로우 설계
  • [ ] 다양한 계정 유형으로 테스트

실제 사용 사례

소셜 미디어 예약 도구

마케팅 플랫폼에서 게시 자동화:

  • 과제: 50개+ 클라이언트 계정 수동 게시
  • 해결: 인스타그램 API로 예약 게시
  • 결과: 시간 80% 절감, 일관된 게시 스케줄

주요 구현:

  • 드래그 앤 드롭 방식 콘텐츠 캘린더
  • 사진/동영상/캐러셀 자동 게시
  • 콘텐츠 기반 해시태그 추천

고객 서비스 자동화

전자상거래 브랜드의 댓글 자동 응답:

  • 과제: 고객문의 응답 지연
  • 해결: 웹훅 기반 자동 답변
  • 결과: 평균 응답 5분, 만족도 90%

주요 구현:

  • 키워드 탐지(가격/재고/배송)
  • 제품 링크 포함 자동 답글
  • 복잡 문의 상담원 에스컬레이션

결론

인스타그램 그래프 API는 인스타그램 비즈니스 및 크리에이터 계정의 통합 및 자동화에 강력한 기능을 제공합니다. 정리:

  • 60일 토큰 기반 페이스북 로그인 OAuth 2.0 인증
  • 사진/동영상/릴스/캐러셀 자동 게시 지원
  • 인사이트 API로 참여·도달·인구통계 데이터 수집
  • 웹훅 실시간 댓글 및 언급 모니터링
  • 앱당 시간당 200회 속도 제한 관리 필요
  • Apidog은 API 테스트 및 협업 간소화에 유용

자주 묻는 질문

인스타그램 API에 어떻게 접근할 수 있나요?

페이스북 개발자 계정 생성 → 비즈니스 앱 생성 → 인스타그램 그래프 API 제품 추가 → 권한 부여 및 OAuth 인증 진행.

인스타그램에 자동으로 게시할 수 있나요?

네, 콘텐츠 게시 API로 비즈니스/크리에이터 계정에 사진, 동영상, 릴스, 캐러셀 자동 게시가 가능합니다.

어떤 유형의 인스타그램 계정이 API를 지원하나요?

비즈니스/크리에이터 계정만 전체 API 접근 권한. 개인 계정은 제한적이거나 접근 불가.

인스타그램에서 댓글을 어떻게 가져올 수 있나요?

Comments 엔드포인트(/media-id/comments)로 특정 미디어의 댓글을 조회. 웹훅으로 실시간 알림도 가능.

인스타그램 속도 제한은 무엇인가요?

앱당 시간당 200회 호출. 일부 엔드포인트는 사용자별 제한 추가 적용.

API를 통해 스토리를 게시할 수 있나요?

네, 스토리도 피드 게시물과 동일한 게시 흐름으로 게시할 수 있습니다.

인스타그램 인사이트에 어떻게 접근할 수 있나요?

OAuth 시 instagram_manage_insights 권한 요청. Insights 엔드포인트로 미디어/계정 메트릭 조회.

댓글에 자동으로 답글을 달 수 있나요?

네, Comments API로 답글 자동 게시 가능. 고객 서비스 자동화에 널리 활용됩니다.

Top comments (0)