Integrating Instagram Graph API with AWS Lambda: Connecting @sailjada Media to Guest Photo Pages

What We're Solving

The guest photo page system at shipcaptaincrew.queenofsandiego.com/g/{event_id} aggregates two photo sources: user-uploaded charter photos (stored and approved via our backend) and Instagram posts from @sailjada matching the same event date/time window. The Instagram integration was built into the Lambda function but dormant—it returned empty arrays because the necessary Graph API credentials weren't configured. This post walks through the complete setup process to activate this feature.

Technical Architecture Overview

The system uses a three-tier approach:

  • Frontend: Static Vue.js app served via CloudFront, requesting /g/{event_id} endpoint
  • Backend: Lambda function shipcaptaincrew (us-east-1, account 782785212866) that fetches both guest photos and Instagram media in parallel
  • Credentials: Environment variables IG_USER_ID and IG_ACCESS_TOKEN passed to Lambda via update-function-configuration

Why this approach? Instagram Graph API requires authentication at query time, and storing credentials in Lambda environment variables (encrypted at rest by AWS KMS) is simpler than managing a separate secrets store for a read-only integration. The token has a 60-day expiration, requiring a monthly refresh strategy.

Step 1: Add Instagram Graph API to Your Facebook App

The critical first step is adding the correct product to your Facebook app. If you've already added "Messaging" for DM capabilities, that won't grant the scopes needed to read media.

  1. Navigate to developers.facebook.com/apps
  2. Click the app name (sailjada-social)
  3. In the left sidebar, scroll to the bottom and click + Add Product
  4. Search for Instagram and select Instagram Graph API (not Basic Display, not Messaging)
  5. Complete the setup wizard—it will appear in your left sidebar as a new product

Why Instagram Graph API and not Basic Display? Basic Display only returns static image data and captions. Graph API provides media insights, timestamps, and media type granularity, which we need to filter posts by event time windows. It also supports business/creator accounts with better rate limits.

Step 2: Verify Account Type and Connect Instagram

Ensure @sailjada is configured as a Business or Creator account and linked to a Facebook Page.

  1. Inside Instagram Graph API settings, find API setup
  2. Click Add Instagram Account
  3. Log in with the @sailjada credentials
  4. Authorize the app to access the account

This creates the connection between your Facebook app and the Instagram account, enabling token generation with the correct scopes.

Step 3: Generate a Short-Lived Access Token

Use the Graph API Explorer to generate an initial short-lived token (valid for ~2 hours).

  1. Go to developers.facebook.com/tools/explorer
  2. In the top dropdown, select sailjada-social app
  3. Click Generate Access Token
  4. Select the Facebook Page linked to @sailjada
  5. In the Scopes section, ensure both instagram_basic and pages_show_list are checked
  6. Copy the generated token—you'll use it in the next step

Step 4: Retrieve Your Instagram Business Account ID

The Graph API requires your Instagram Business Account ID (distinct from your Instagram username ID). Retrieve it using the short-lived token:

curl -X GET "https://graph.instagram.com/v18.0/me/accounts?fields=instagram_business_account&access_token=YOUR_SHORT_LIVED_TOKEN"

This returns a JSON object with an instagram_business_account field containing your IG_USER_ID. Save this value.

Step 5: Exchange Token for Long-Lived Access Token

Short-lived tokens expire quickly. Exchange it for a long-lived token (60-day expiration) using your app credentials:

curl -X GET "https://graph.instagram.com/v18.0/oauth/access_token?grant_type=ig_refresh_token&access_token=YOUR_SHORT_LIVED_TOKEN"

The response contains your IG_ACCESS_TOKEN. This is what you'll store in Lambda environment variables.

Why a 60-day token? It balances security (limiting credential exposure window) with operational simplicity (avoiding monthly token management overhead). We implement a refresh strategy via EventBridge to refresh automatically before expiration.

Step 6: Update Lambda Environment Variables

Using AWS CLI, update the Lambda function with your credentials:

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

AWS automatically encrypts these values using the default KMS key for Lambda. The function will read them at runtime to construct Graph API queries.

Lambda Function Logic (No Changes Needed)

The shipcaptaincrew Lambda function already contains the Instagram integration logic. When both environment variables are present, it:

  1. Parses the event_id from the request path (e.g., 2026-04-29)
  2. Converts the date to a Unix timestamp window
  3. Queries the Instagram Graph API endpoint: /IG_USER_ID/media
  4. Filters returned posts by timestamp
  5. Merges them with guest-uploaded photos in the response

No code changes are required—the integration was built with environment variable abstraction from day one.

Verification and Testing

Once Lambda is updated, test the integration:

curl "https://shipcaptaincrew.queenofsandiego.com/g/2026-04-29"

The response should include both guest_photos and instagram_posts arrays. If the Instagram array is empty but the request succeeds, check:

  • Confirm @sailjada has public posts on the date in question
  • Verify the Lambda environment variables are set (check CloudWatch Logs)
  • Ensure the token hasn't expired (tokens expire exactly 60 days after generation)

Key Decisions and Trade-offs

  • Environment Variables vs. Secrets Manager: For a single read-only integration with infrequent updates, environment variables