```html

Integrating Instagram Graph API with AWS Lambda: Adding Social Media Context to Guest Photo Galleries

What Was Done

We implemented Instagram Graph API integration into the existing guest photo gallery system at shipcaptaincrew.queenofsandiego.com/g/{event_id}. The Lambda function previously had dormant Instagram integration code that returned empty arrays due to missing environment variables. This post details the complete setup process to activate that integration, enabling the gallery to display authenticated @sailjada Instagram posts alongside guest-uploaded charter photos from matching time windows.

Architecture Overview

The system architecture consists of three layers:

  • Frontend: Guest photo gallery page served via CloudFront, displaying filtered photos by event date
  • Lambda Function: shipcaptaincrew in us-east-1 (account 782785212866) that queries both guest uploads and Instagram media
  • Social Integration: Facebook/Instagram Graph API providing authenticated access to @sailjada business account media

The Lambda function accepts {event_id} as a route parameter, parses it as a date, and makes two independent API calls: one to your database for guest photos, another to Instagram Graph API for posts within that date window. Results are merged and returned to the client.

Technical Details: Instagram Graph API Setup

Step 1: Add the Correct Product to Your App

Navigate to developers.facebook.com/apps and select the sailjada-social application. In the left sidebar, click Add Product. The critical decision here: you must add Instagram Graph API, not Basic Display or Messaging. This distinction matters because:

  • Basic Display: Read-only access to media and basic profile info—insufficient for our use case
  • Messaging: Designed for Instagram Direct Messages—wrong permission scope entirely
  • Instagram Graph API: Provides full business account access including media insights, hashtags, and paginated media feeds

If you previously added "Messaging" for another feature, that won't grant the instagram_basic scope required to read media. You need both products registered in your app.

Step 2: Connect Your Business Account

Within the Instagram Graph API product settings, locate API setup with Instagram login and click Add Instagram account. Log in using the @sailjada account credentials. This step links your personal Instagram account to the business/creator account framework required by Graph API.

Ensure @sailjada is set to Business or Creator mode on Instagram itself. Personal accounts cannot use Graph API. After connecting, confirm that @sailjada is linked to a Facebook Page (also named "SailJada" or similar). This Page becomes the intermediary through which you access the Instagram business account.

Step 3: Generate Initial Access Token

Visit developers.facebook.com/tools/explorer and:

  • Select sailjada-social from the app dropdown
  • Click Generate Access Token
  • Select the Facebook Page linked to @sailjada from the page selector
  • Ensure requested scopes include instagram_basic and pages_show_list

This generates a short-lived token (valid for ~2 hours) used only for the next step. Do not use this directly in Lambda.

Step 4: Retrieve IG_USER_ID

Using the short-lived token, make two API calls. First, retrieve your Facebook Page ID:


curl -X GET "https://graph.instagram.com/me/accounts?access_token=SHORT_LIVED_TOKEN"

This returns a list of Pages associated with your app. Note the id field (your Page ID). Then, query the Instagram business account linked to that Page:


curl -X GET "https://graph.instagram.com/PAGE_ID?fields=instagram_business_account&access_token=SHORT_LIVED_TOKEN"

The response includes instagram_business_account.id—this is your IG_USER_ID. Store this value; it does not change.

Step 5: Exchange for Long-Lived Token

Graph API tokens expire. Short-lived tokens last ~2 hours; long-lived tokens last ~60 days. Exchange your short-lived token:


curl -X GET "https://graph.instagram.com/oauth/access_token" \
  -d "grant_type=ig_refresh_token" \
  -d "access_token=SHORT_LIVED_TOKEN"

The response provides a long-lived access_token. This is your IG_ACCESS_TOKEN—the value you'll store in Lambda environment variables.

Infrastructure: Lambda Configuration

Update the Lambda function shipcaptaincrew in us-east-1 (account 782785212866) with environment variables:


aws lambda update-function-configuration \
  --function-name shipcaptaincrew \
  --region us-east-1 \
  --environment Variables="{IG_USER_ID=YOUR_IG_USER_ID,IG_ACCESS_TOKEN=YOUR_LONG_LIVED_TOKEN}"

Within the Lambda code (assumed to be Python 3.9+), the function checks for these environment variables. If present, it calls Instagram Graph API during request handling:


import boto3
import requests
import os

ig_user_id = os.environ.get('IG_USER_ID')
ig_access_token = os.environ.get('IG_ACCESS_TOKEN')

def fetch_instagram_posts(event_date):
    if not ig_user_id or not ig_access_token:
        return []
    
    url = f"https://graph.instagram.com/{ig_user_id}/media"
    params = {
        'fields': 'id,caption,media_type,media_url,timestamp',
        'access_token': ig_access_token
    }
    response = requests.get(url, params=params)
    return response.json().get('data', [])

Token Refresh Strategy

Long-lived tokens expire after 60 days. Implement a monthly refresh before expiration. Two approaches:

  • EventBridge scheduled rule: Trigger a separate Lambda function monthly that refreshes the token and updates the shipcaptaincrew environment variables
  • Manual refresh: Run the token exchange curl command monthly and update Lambda via AWS CLI or console

For production reliability, the EventBridge approach is preferred. Create an EventBridge rule named instagram-token-refresh with cron expression 0 0 1 * ? * (first day of each month). Target a dedicated Lambda function that performs the refresh and updates the parent function.

Verification