```html

Integrating Instagram Graph API with AWS Lambda: Building a Guest Photo Gallery with Social Media Feeds

What Was Done

The shipcaptaincrew application—a guest photo management system deployed at shipcaptaincrew.queenofsandiego.com—required integration with Instagram's Graph API to display curated @sailjada posts alongside guest-uploaded charter photos. The Lambda function had dormant Instagram integration code, but it was returning empty arrays due to missing environment variable configuration. This walkthrough documents the complete setup process: adding the Instagram Graph API product to the Facebook app, obtaining credentials, implementing token exchange for long-lived access, and wiring environment variables into the Lambda function.

Technical Details: Instagram Graph API Setup

Step 1: Adding the Correct Product to the Facebook App

The initial challenge was a product selection error. The app sailjada-social had the Messaging product added, which grants webhooks and direct messaging scopes but not the instagram_basic scope required to read media. The fix involves adding a separate product:

  • Navigate to developers.facebook.com/apps
  • Open the sailjada-social app configuration
  • Locate "Add Product" in the left sidebar (near the bottom)
  • Search for and select Instagram Graph API (distinct from Basic Display and Messaging)
  • Complete setup; the product now appears in the sidebar

Why this matters: Each Facebook product grants a different set of OAuth scopes. The Messaging product is for DM automation; the Graph API product unlocks read access to media metadata, captions, and engagement metrics.

Step 2: Connecting the Instagram Business Account

The @sailjada account must be a Business or Creator profile and linked to a Facebook Page. Within the app:

  • Open Instagram Graph APIAPI setup
  • Click Add Instagram account
  • Authenticate as @sailjada (the account owner must authorize)
  • Confirm the connection to the associated Facebook Page

Step 3: Generating a Short-Lived Access Token

The Graph API Explorer provides an interactive way to test calls and obtain initial tokens:

  • Visit developers.facebook.com/tools/explorer
  • In the top dropdown, select the sailjada-social app
  • Click Generate Access Token
  • When prompted, select the Facebook Page linked to @sailjada
  • In the scopes dialog, ensure instagram_basic and pages_show_list are checked
  • Complete authorization; the token appears in the input field (valid for approximately 1–2 hours)

Step 4: Retrieving the Instagram Business Account ID

With the short-lived token, two API calls retrieve the Instagram User ID:

# First call: get the Facebook Page's Instagram business account reference
curl -s "https://graph.instagram.com/v18.0/{PAGE_ID}?fields=instagram_business_account&access_token={SHORT_LIVED_TOKEN}" | jq .

# The response includes an "instagram_business_account" object with an "id" field.
# This ID becomes IG_USER_ID.

# Second call: verify media access with the Instagram User ID
curl -s "https://graph.instagram.com/v18.0/{IG_USER_ID}/media?fields=id,caption,media_type&access_token={SHORT_LIVED_TOKEN}" | jq .

Record the IG_USER_ID value for the next step.

Step 5: Exchanging for a Long-Lived Token

Short-lived tokens expire quickly. Facebook's fb_exchange_token endpoint converts them to long-lived tokens valid for approximately 60 days:

curl -X GET "https://graph.instagram.com/oauth/access_token" \
  -d "grant_type=fb_exchange_token" \
  -d "client_id={APP_ID}" \
  -d "client_secret={APP_SECRET}" \
  -d "access_token={SHORT_LIVED_TOKEN}"

The response includes a new access_token field with an extended expiration. This becomes IG_ACCESS_TOKEN in the Lambda environment.

Infrastructure: Lambda Environment Configuration

The Lambda function is deployed in region us-east-1 under account 782785212866:

  • Function name: shipcaptaincrew
  • Runtime: Python 3.x
  • Handler: lambda_function.lambda_handler
  • File location (development): /Users/cb/Documents/repos/sites/queenofsandiego.com/tools/shipcaptaincrew/lambda_function.py

Environment variables are updated via the AWS CLI:

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

The Lambda code, located in lambda_function.py, contains a function that checks for these variables and constructs a Graph API request:

def fetch_instagram_posts(ig_user_id, ig_access_token, event_date_str):
    if not ig_user_id or not ig_access_token:
        return []
    
    # Query Instagram media for the date range
    url = f"https://graph.instagram.com/v18.0/{ig_user_id}/media"
    params = {
        "fields": "id,caption,media_type,timestamp",
        "access_token": ig_access_token
    }
    # ... filter by event_date_str and return matching posts

Guest Photo Gallery Endpoint

The application serves guest photo pages at routes like /g/2026-04-29, where the path parameter represents an event date. The Lambda function:

  • Receives the event ID (e.g., 2026-04-29) from the URL path
  • Queries a database (or file store) for approved guest photos matching that event
  • Calls fetch_instagram_posts() with the same date to retrieve @sailjada posts from that window
  • Merges and returns both datasets to the frontend (served by index.html in the same directory)

The HTML front-