Integrating Instagram Graph API with AWS Lambda: Connecting @sailjada Photos to Guest Charter Events
What Was Done
We activated the dormant Instagram integration in the shipcaptaincrew Lambda function (us-east-1, account 782785212866) to populate the guest photo page at shipcaptaincrew.queenofsandiego.com/g/{event_id} with @sailjada Instagram posts. Previously, the integration returned an empty array due to missing environment variables. This post documents the step-by-step process to acquire the necessary Instagram Graph API credentials and deploy them to production.
Why This Matters
The guest photo page already aggregates approved user-uploaded photos from a DynamoDB table. By connecting Instagram natively through the Graph API, we eliminate the need for manual curation while maintaining photo consistency—all images from @sailjada on a given charter date are automatically available without additional backend logic. This approach is more maintainable than scraping or using deprecated Instagram Basic Display endpoints.
Technical Details: Instagram Graph API Setup
Step 1: Add the Correct Product to Your App
The initial blocker was a product mismatch. The sailjada-social app already had the Messaging API product configured (intended for Instagram DMs), which grants different scopes than what's needed for reading media.
- Navigate to
developers.facebook.com/apps - Click on the
sailjada-socialapp - In the left sidebar, locate Add Product (near the bottom)
- Search for Instagram and select Instagram Graph API (not Basic Display)
- Complete setup to expose the product in the sidebar
Why Graph API over Basic Display? Basic Display is read-only and provides minimal metadata. Graph API allows token refresh, returns timestamp and caption data, and integrates cleanly with business/creator accounts.
Step 2: Connect the @sailjada Business Account
Instagram Graph API requires the account being queried to be a Business or Creator account linked to a Facebook Page (not a personal account). Verify this setup:
- Go to
instagram.com/@sailjadaand confirm the account type in settings - In the Meta Business Suite (
business.instagram.com), confirm @sailjada is linked to a Facebook Page - In your app's Instagram Graph API section, click API setup with Instagram login
- Click Add Instagram account and log in as @sailjada
Step 3: Generate a Short-Lived Access Token
Access tokens power API calls. We generate a short-lived token first, use it to fetch credentials, then exchange it for a long-lived token with a 60-day expiration.
- Go to
developers.facebook.com/tools/explorer - Select
sailjada-socialfrom the app dropdown (top-right) - Click Generate Access Token
- Select the Facebook Page linked to @sailjada
- In the Permissions section, add scopes:
instagram_basicandpages_show_list - Click Generate and copy the token (valid for ~2 hours)
Step 4: Retrieve IG_USER_ID
The Lambda function requires IG_USER_ID—the unique identifier for the @sailjada Instagram Business Account. Fetch it via the Graph API:
curl -X GET "https://graph.instagram.com/v18.0/me/accounts?fields=name,instagram_business_account&access_token=YOUR_SHORT_LIVED_TOKEN"
From the response, locate the Facebook Page's ID, then use it to fetch the Instagram Business Account ID:
curl -X GET "https://graph.instagram.com/v18.0/{PAGE_ID}?fields=instagram_business_account&access_token=YOUR_SHORT_LIVED_TOKEN"
The id nested inside instagram_business_account is your IG_USER_ID. Save this value.
Step 5: Exchange for a Long-Lived Access Token
Short-lived tokens expire quickly. Exchange yours for a 60-day token using your app credentials:
curl -X GET "https://graph.instagram.com/v18.0/access_token?grant_type=ig_refresh_token&access_token=YOUR_SHORT_LIVED_TOKEN"
The response contains a new access_token (your IG_ACCESS_TOKEN) with extended expiration.
Infrastructure: Lambda Environment Configuration
The shipcaptaincrew Lambda function reads two environment variables. Update them via the AWS console or CLI:
aws lambda update-function-configuration \
--function-name shipcaptaincrew \
--region us-east-1 \
--environment Variables="{IG_USER_ID=VALUE_FROM_STEP_4,IG_ACCESS_TOKEN=VALUE_FROM_STEP_5}"
Do not commit these values to version control. Store them in Systems Manager Parameter Store or Secrets Manager if additional security is needed.
Key Architecture Decisions
- Token Refresh Strategy: The 60-day token must be refreshed monthly to avoid expiration. A scheduled EventBridge rule (optional but recommended) can trigger a Lambda to call the refresh endpoint and update the environment variable automatically.
- Media Filtering: The Lambda already filters Instagram posts by date window (matching charter date ±1 day) before returning them to the frontend. This reduces payload size and prevents unrelated posts from appearing.
- DynamoDB vs. Graph API: User-uploaded photos live in DynamoDB; Instagram photos are queried live. This hybrid approach keeps approval workflows intact while adding curated social content.
- Scope Minimization: We requested only
instagram_basic(read media) andpages_show_list(list business pages), avoiding broader permissions likeinstagram_manage_messages.
Testing the Integration
After deploying the environment variables, test the endpoint:
curl https://shipcaptaincrew.queenofsandiego.com/g/2026-04-29
The response should include an instagram_posts array alongside guest_photos. If the array is empty, verify:
- @sailjada has posts dated 2026-04-29 (or within the ±1 day window)
- Posts are public and not archived
- The token hasn't expired (re-run Step 5 if needed)
- CloudWatch logs show no API errors in the Lambda execution
What's Next
Future improvements include automating token refresh via EventBridge, caching Instagram posts in ElastiCache to reduce API calls, and expanding to other crew