```html

Integrating Instagram Graph API with AWS Lambda: Building a Social Photo Gallery for Charter Events

What Was Done

We integrated Instagram Graph API into the ShipCaptainCrew guest photo gallery system to automatically surface @sailjada Instagram posts alongside user-uploaded photos from charter events. The guest page at shipcaptaincrew.queenofsandiego.com/g/{event_id} (e.g., /g/2026-04-29) now queries Instagram media in real-time when the Lambda function processes requests, combining two photo streams into a single curated gallery.

The integration required three critical infrastructure changes:

  • Meta app configuration to expose Instagram Graph API scopes
  • Environment variable management in AWS Lambda for API credentials
  • Token exchange and refresh strategy to maintain long-lived API access

Technical Details: Instagram Graph API Setup

Why Instagram Graph API instead of Basic Display? The Basic Display product is read-only and doesn't require app review, but it only returns the 18 most recent media items without filtering by date. For a charter event gallery tied to specific dates, we needed Graph API's full media endpoint with temporal filtering—even though it requires formal app review. This trade-off gives us precise control over which photos appear for each event.

Step 1: Add the Correct Product to Your Meta App

Navigate to developers.facebook.com/apps → [App Name: sailjada-social] → Add Product. Search for and select Instagram Graph API. (Note: The "Messaging" use case, while available in the sidebar, grants DM scopes, not media-reading scopes—a common configuration mistake.)

Step 2: Connect the Instagram Business Account

Within Instagram Graph API settings, click "API setup with Instagram login" and select "Add Instagram account." This requires @sailjada to log in and authorize the app. Behind the scenes, Meta creates a connection between the Instagram account and your Facebook Business Page—a prerequisite for Graph API access.

Step 3: Generate Short-Lived Access Token

Use the Graph API Explorer at developers.facebook.com/tools/explorer:

  • Select app: sailjada-social
  • Select the Facebook Page connected to @sailjada
  • Click "Generate Access Token"
  • Ensure scopes include instagram_basic and pages_show_list

This token is valid for ~1 hour and is used only to bootstrap the process.

Step 4: Retrieve IG_USER_ID

Execute two API calls to map from your Facebook Page to the Instagram Business Account ID:

curl -s "https://graph.instagram.com/v18.0/[PAGE_ID]?fields=instagram_business_account&access_token=[SHORT_LIVED_TOKEN]"

The response includes an instagram_business_account object with an id field. Store this as IG_USER_ID.

Step 5: Exchange for Long-Lived Token

The short-lived token expires quickly. Exchange it for a token valid for 60 days:

curl -s "https://graph.instagram.com/oauth/access_token?grant_type=ig_refresh_token&access_token=[SHORT_LIVED_TOKEN]"

The returned access_token is your IG_ACCESS_TOKEN. Store both credentials securely.

Infrastructure: Lambda Environment Variables

Update the ShipCaptainCrew Lambda function configuration in us-east-1 (account 782785212866):

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

These environment variables are injected into the Lambda runtime. The function checks for their presence; if either is missing, Instagram integration silently returns an empty array (graceful degradation).

Code Integration: Lambda Handler Updates

The file /Users/cb/Documents/repos/sites/queenofsandiego.com/tools/shipcaptaincrew/lambda_function.py contains the handler. When a request arrives at /g/{event_id}, the handler:

  1. Parses the event ID to extract the date (e.g., 2026-04-29)
  2. Queries the guest photo database (DynamoDB or S3) for approved uploads from that date
  3. If IG_USER_ID and IG_ACCESS_TOKEN are set, calls Instagram Graph API to fetch media from the same date window
  4. Merges both streams and returns JSON to the front-end

The Instagram query filters by timestamp to match the charter event window (e.g., 8 AM to 6 PM on the event date).

Front-End: Gallery Display

The file index.html (served at shipcaptaincrew.queenofsandiego.com/g/{event_id}) contains JavaScript that:

  • Fetches JSON from the Lambda API endpoint
  • Renders guest photos from the database
  • Renders Instagram posts from @sailjada in the same gallery grid
  • Distinguishes sources via CSS class (e.g., guest-photo vs instagram-post)

Key Decisions

60-day token refresh cadence: Rather than implement monthly automatic refresh via EventBridge, we chose a simpler manual refresh strategy. Since Instagram tokens are refreshed via the same endpoint used to obtain them, a developer can run the exchange command every 55 days. This avoids Lambda complexity and external scheduler dependencies. If automation becomes necessary, an EventBridge rule targeting a dedicated Lambda function can handle renewal.

Graceful degradation: If environment variables are missing or the Instagram API returns an error, the guest page still loads and displays guest-uploaded photos. Instagram integration is a feature enhancement, not a requirement.

Graph API over Basic Display: Graph API requires formal app review (typically 5–7 business days) but offers temporal filtering and higher rate limits. This is the correct long-term choice for an event-centric photo gallery.

Testing and Verification

After deploying credentials, verify the integration by navigating to https://shipcaptaincrew.queenofsandiego.com/g/2026-04-29 (or any past event date). Open the browser console and confirm:

  • No 401/403 errors from graph.instagram.com
  • The response includes both guest and Instagram photo objects
  • Photos render in the gallery grid

Monitor Lambda logs via:

aws logs tail /aws/lambda/shipcaptaincrew --region us-east-1 --follow

What's Next