Integrating Instagram Graph API with AWS Lambda: Bridging Social Media into Guest Photo Events
What Was Done
We activated Instagram Graph API integration for the Ship Captain Crew guest photo page system, enabling the Lambda function to fetch and display @sailjada Instagram posts alongside user-uploaded charter photos on event pages like /g/2026-04-29. The integration was built but dormant in the codebase—it required proper Facebook App configuration, token generation, and Lambda environment variable setup to become functional.
Technical Details: Instagram Graph API Configuration
The core challenge was that the existing Instagram product in the sailjada-social Facebook App was configured for the Messaging use case, which grants DM-related scopes but not the instagram_basic scope needed to read media.
Step 1: Add the Correct Product
- Navigated to developers.facebook.com/apps
- Selected the
sailjada-socialapplication - Clicked Add Product in the left sidebar
- Selected Instagram Graph API (distinct from Basic Display and Messaging)
This product registration exposes the Graph API endpoints and scope permissions needed to read Instagram Business Account media.
Step 2: Connect the Instagram Business Account
The @sailjada account must be a Business or Creator account linked to a Facebook Page. Within the Instagram Graph API product setup:
- Clicked API setup with Instagram login
- Selected Add Instagram account
- Authenticated as @sailjada
This establishes the relationship between the Facebook App, the Instagram Business Account, and the associated Facebook Page.
Step 3 & 4: Generate Short-Lived Access Token
Using the Facebook Graph API Explorer at developers.facebook.com/tools/explorer:
- Selected the
sailjada-socialapp from the dropdown - Clicked Generate Access Token
- Selected the Facebook Page linked to @sailjada
- Ensured scopes included:
instagram_basicandpages_show_list
The resulting short-lived token (valid ~2 hours) was used to query the Instagram Business Account ID:
curl -s "https://graph.instagram.com/me/instagram_business_account?access_token=TOKEN" | jq .
The response contains the Instagram Business Account ID under instagram_business_account.id. This became IG_USER_ID in the Lambda environment.
Step 5: Exchange for Long-Lived Token
Short-lived tokens expire in hours. We exchanged it for a long-lived token (60-day validity) using the app credentials:
curl -X GET "https://graph.instagram.com/oauth/access_token" \
-d grant_type=fb_exchange_token \
-d client_id=APP_ID \
-d client_secret=APP_SECRET \
-d access_token=SHORT_LIVED_TOKEN
The returned access_token became IG_ACCESS_TOKEN.
Infrastructure: Lambda Environment Configuration
Updated the shipcaptaincrew Lambda function in us-east-1 (AWS Account 782785212866
aws lambda update-function-configuration \
--function-name shipcaptaincrew \
--region us-east-1 \
--environment Variables="{IG_USER_ID=value,IG_ACCESS_TOKEN=value}"
These variables are read by the Lambda handler in /Users/cb/Documents/repos/sites/queenofsandiego.com/tools/shipcaptaincrew/lambda_function.py when processing requests to /g/{event_id} routes.
Lambda Function Logic
The Lambda handler checks for both environment variables on startup. If either is missing, the Instagram integration gracefully returns an empty array—preventing crashes while keeping guest photos functional. With tokens present, the handler queries:
https://graph.instagram.com/{IG_USER_ID}/media?access_token={IG_ACCESS_TOKEN}
It filters results by timestamp to match the event date window and merges them with user-uploaded photos in the response payload.
Key Decisions and Architecture Rationale
Why Instagram Graph API Over Basic Display?
Instagram Graph API provides business insights, media metadata, and media/children edges—critical for filtering posts by timestamp and rendering captions. Basic Display only returns the media URL and caption, without timestamp filtering at the API level.
Long-Lived Tokens Over Short-Lived
Generating new short-lived tokens for every request would require periodic manual intervention or a separate credential-refresh service. Long-lived tokens (60 days) strike a balance: they're valid for typical event seasons while still being refreshable without user re-authentication. A monthly refresh via EventBridge or cron can keep the token fresh indefinitely.
Graceful Degradation
The Lambda checks for token presence and returns an empty Instagram array if tokens are missing. This ensures the guest photo page remains functional even if Instagram integration is temporarily disabled, rather than failing the entire request.
Environment Variables Over Hardcoding
Storing IG_USER_ID and IG_ACCESS_TOKEN as Lambda environment variables (rather than in code) allows credential rotation without redeploying the function. Sensitive values are encrypted at rest by AWS Lambda's default encryption.
Verification
After updating Lambda, the guest page at https://shipcaptaincrew.queenofsandiego.com/g/2026-04-29 should fetch and display Instagram posts from @sailjada within the event's date window. CloudWatch logs in /aws/lambda/shipcaptaincrew show API response times and any filtering logic executed.
What's Next: Token Refresh Strategy
While 60-day tokens are sufficient for a single season, a production-grade solution implements monthly refresh:
- EventBridge Rule: Triggers the token refresh Lambda on the first of each month
- Refresh Lambda: Calls the Instagram token exchange endpoint, stores the new token in Secrets Manager or Parameter Store
- Main Lambda: Reads the refreshed token from Secrets Manager instead of environment variables
This approach ensures tokens never expire in production, regardless of event season duration.
```