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

What Was Done

We implemented Instagram Graph API integration into the existing shipcaptaincrew Lambda function (us-east-1, account 782785212866) to display authenticated Instagram posts alongside guest-uploaded charter photos on the guest gallery pages. The integration fetches media from the @sailjada Instagram business account and displays it within the same event-day time window as uploaded guest photos.

The system architecture uses environment variables to store Instagram credentials, allowing the Lambda to remain dormant until credentials are provisioned. When activated, the function queries the Instagram Graph API to retrieve recent media posts filtered by event date, merging them with the existing guest photo dataset returned to the frontend.

Technical Details: Instagram Graph API Setup

Product Configuration in Facebook App Dashboard

The initial setup required adding the correct Instagram product to the existing sailjada-social app in the Facebook Developer Console:

  • Navigate to developers.facebook.com/apps → select the sailjada-social application
  • Click Add Product in the left sidebar (near the bottom)
  • Search for Instagram and select Instagram Graph API (critical: not "Basic Display" or "Messaging")
  • The Messaging product, which was initially configured, only grants DM-related scopes and explicitly excludes instagram_basic, required for reading media metadata

Why this matters: Facebook's product offerings are intentionally siloed. The Messaging API grants scopes like instagram_manage_messages, but the scope resolver explicitly denies media-read permissions. The Graph API product is the only path to instagram_basic and pages_show_list scopes needed for the integration.

Account Linkage and Token Generation

The @sailjada Instagram account must be linked to a Facebook Business or Creator account with admin access. This step is performed once in the app dashboard:

  • Inside Instagram Graph APIAPI Setup → click Add Instagram Account
  • Authenticate with the @sailjada account credentials
  • This creates a business connection between the app and the Instagram account

Token generation uses the Facebook Graph API Explorer tool:

  • Visit developers.facebook.com/tools/explorer
  • Select sailjada-social app from the dropdown
  • Click Generate Access Token
  • Select the Facebook Page linked to @sailjada
  • Request scopes: instagram_basic, pages_show_list
  • This produces a short-lived token (valid for ~2 hours)

Retrieving the Instagram User ID

The Instagram User ID (IG_USER_ID) is extracted via two sequential API calls. First, retrieve the Facebook Page ID associated with the app:

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

The response contains a page_id field. Use this ID to query the linked Instagram business account:

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

The instagram_business_account.id field in the response is your IG_USER_ID.

Long-Lived Token Exchange

Short-lived tokens are insufficient for production use. Exchange the short-lived token for a long-lived access token (valid for 60 days) using the app credentials:

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

The returned access_token becomes the IG_ACCESS_TOKEN environment variable. This extended lifetime reduces operational overhead while maintaining security through token rotation policies.

Infrastructure: Lambda Configuration

The shipcaptaincrew Lambda function (runtime: Python 3.11, role: shipcaptaincrew-role) stores Instagram credentials as environment variables:

  • IG_USER_ID — the Instagram business account numeric ID
  • IG_ACCESS_TOKEN — the long-lived access token

When either variable is missing or empty, the function returns an empty array for Instagram posts, allowing the deployment to remain active without breaking the guest photo page.

Update the Lambda configuration using the AWS CLI:

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}

No code changes are required. The function's existing conditional logic detects the presence of these variables and activates media fetching accordingly.

Key Decisions

  • Environment variable strategy: Storing credentials as env vars keeps the Lambda code generic and allows easy credential rotation without redeployment. Secrets Manager was not used here because token rotation is infrequent (60-day cycle) and the cost-benefit analysis favored operational simplicity.
  • Dormant-by-default design: Missing credentials trigger a graceful fallback (empty array) rather than an error, allowing the system to function with guest photos alone until Instagram integration is needed.
  • Time-window filtering: Posts are filtered by event date to show only media relevant to the specific charter event, preventing unrelated content from appearing on guest pages.
  • Graph API version pinning: Using a specific API version (e.g., v18.0) in API calls ensures predictable behavior across token exchanges and prevents unexpected deprecation issues.

Verification and Testing

After updating the Lambda environment variables, verify the integration by navigating to a guest page at:

shipcaptaincrew.queenofsandiego.com/g/{event_id}

For example: shipcaptaincrew.queenofsandiego.com/g/2026-04-29

The page should now display both guest-uploaded photos and @sailjada Instagram posts from the specified event date. Check CloudWatch Logs for the Lambda function to confirm successful API calls and debug any token-related errors.

What's Next

  • Token rotation automation: Implement an EventBridge scheduled rule to exchange the long-lived token every 55 days, preventing token expiration in production.
  • Error handling and monitoring: Add CloudWatch alarms for Instagram API failures (rate limits, network errors) to alert the team before guest pages are affected.
  • Scope expansion: Consider additional scopes like instagram_content_publishing if cross-posting from guest photos to the @