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

What Was Done

We enhanced the guest photo gallery system at shipcaptaincrew.queenofsandiego.com/g/{event_id} by activating dormant Instagram Graph API integration within the existing Lambda function. Previously, the system displayed only approved guest-uploaded photos. Now it fetches and displays Instagram posts from @sailjada during matching time windows, enriching the user experience with official social media content alongside guest contributions.

The Lambda function shipcaptaincrew (deployed in us-east-1, account 782785212866) already contained the integration logic—it was simply disabled due to missing environment variables. This walkthrough documents the precise steps to activate it.

Technical Architecture

The integration follows a three-layer pattern:

  • Token Layer: Short-lived tokens (60-day expiration) obtained via Instagram Graph API OAuth flow, exchanged for long-lived access
  • Lambda Layer: Environment variables IG_USER_ID and IG_ACCESS_TOKEN passed to the function; conditional logic checks for their presence before making API calls
  • Application Layer: Guest photo routes merge Instagram results with guest uploads based on event date and time window proximity

The key architectural decision: tokens are stored in Lambda environment variables rather than in Secrets Manager. This choice trades some security isolation for reduced latency and operational simplicity—Instagram tokens have explicit expiration and are lower-risk than database credentials or signing keys.

Step 1: Instagram App Configuration

Critical gotcha: The existing sailjada-social app was configured with the Messaging product, which grants DM-related scopes but not the instagram_basic scope required to read media. You must add the Graph API product separately.

Facebook App Dashboard
  → Apps → sailjada-social
    → Add Product
      → Search "Instagram"
        → Select "Instagram Graph API"
          → Complete setup

Why Graph API over Basic Display? Basic Display is read-only and simpler, but Graph API provides superior filtering and pagination for time-window queries, which is essential when matching photos to specific event dates.

Step 2: Instagram Account Linking

The @sailjada account must be a Business or Creator account linked to a Facebook Page (not a personal account). Verify this before proceeding:

  • Log into @sailjada on Instagram
  • Settings → Account → Account Type — should show "Business" or "Creator"
  • Settings → Linked Accounts — verify the associated Facebook Page is visible

Then in the Facebook App Dashboard, navigate to Instagram Graph API → API setup and click "Add Instagram account." This initiates OAuth and links @sailjada to the app.

Step 3: Generating Access Tokens

Two tokens are required; both come from the same flow:

Short-lived token (used temporarily):

  1. Visit developers.facebook.com/tools/explorer
  2. Select app dropdown → choose sailjada-social
  3. Click "Generate Access Token"
  4. Select the Facebook Page linked to @sailjada
  5. Adjust scopes to include: instagram_basic, pages_show_list
  6. Copy the token (valid for ~2 hours)

Retrieving IG_USER_ID:

curl "https://graph.instagram.com/v18.0/me/accounts?access_token=SHORT_LIVED_TOKEN"

This returns your Facebook Page ID. Use it in the next call:

curl "https://graph.instagram.com/v18.0/{PAGE_ID}?fields=instagram_business_account&access_token=SHORT_LIVED_TOKEN"

The id field nested under instagram_business_account is your IG_USER_ID. Store this value—it never changes.

Exchanging for long-lived token (60 days):

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

The returned access_token is your IG_ACCESS_TOKEN. This is what gets stored in Lambda environment variables.

Step 4: Lambda Configuration

Update the shipcaptaincrew Lambda function with environment variables:

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

The function code checks for these variables on invocation. If both are present and non-empty, it executes the Instagram query logic; otherwise, it skips Instagram integration and returns an empty array (maintaining backward compatibility).

Token Refresh Strategy

Long-lived tokens expire after 60 days. Set a calendar reminder to refresh monthly using the same POST /access_token call above. Alternatively, implement an EventBridge rule that triggers a Lambda-based refresh automation, but manual refresh is acceptable for this low-frequency requirement.

Verification

After deployment, navigate to a guest photo page with recent activity:

shipcaptaincrew.queenofsandiego.com/g/2026-04-29

If Instagram posts from @sailjada exist near that date, they should appear alongside guest uploads. CloudWatch Logs for the shipcaptaincrew function will show API call details if debugging is needed.

Key Decisions & Rationale

  • Environment variables over Secrets Manager: Reduces cold-start latency and operational overhead for non-critical tokens with explicit expiration
  • 60-day tokens over short-lived: Balances security (regular refresh) with stability (fewer token exchanges needed)
  • Event-driven activation: The integration was built but dormant, allowing us to activate without code changes—just configuration
  • Time-window matching: Photos are filtered by event date and a configurable time window to ensure contextual relevance

What's Next

Consider automating token refresh via a scheduled Lambda function or Step Functions state machine. Also plan to monitor Instagram API quota usage—the free tier has modest limits. Finally, document the monthly refresh process in your runbooks so future engineers know when and how to regenerate tokens.