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_IDandIG_ACCESS_TOKENpassed to Lambda viaupdate-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.
- Navigate to
developers.facebook.com/apps - Click the app name (
sailjada-social) - In the left sidebar, scroll to the bottom and click + Add Product
- Search for Instagram and select Instagram Graph API (not Basic Display, not Messaging)
- 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.
- Inside Instagram Graph API settings, find API setup
- Click Add Instagram Account
- Log in with the
@sailjadacredentials - 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).
- Go to
developers.facebook.com/tools/explorer - In the top dropdown, select
sailjada-socialapp - Click Generate Access Token
- Select the Facebook Page linked to
@sailjada - In the Scopes section, ensure both
instagram_basicandpages_show_listare checked - 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:
- Parses the
event_idfrom the request path (e.g.,2026-04-29) - Converts the date to a Unix timestamp window
- Queries the Instagram Graph API endpoint:
/IG_USER_ID/media - Filters returned posts by timestamp
- 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
@sailjadahas 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