Integrating Instagram Graph API with AWS Lambda: Building a Social Photo Gallery for Charter Events
What Was Done
We integrated Instagram Graph API into the ShipCaptainCrew guest photo gallery system to automatically surface @sailjada Instagram posts alongside user-uploaded photos from charter events. The guest page at shipcaptaincrew.queenofsandiego.com/g/{event_id} (e.g., /g/2026-04-29) now queries Instagram media in real-time when the Lambda function processes requests, combining two photo streams into a single curated gallery.
The integration required three critical infrastructure changes:
- Meta app configuration to expose Instagram Graph API scopes
- Environment variable management in AWS Lambda for API credentials
- Token exchange and refresh strategy to maintain long-lived API access
Technical Details: Instagram Graph API Setup
Why Instagram Graph API instead of Basic Display? The Basic Display product is read-only and doesn't require app review, but it only returns the 18 most recent media items without filtering by date. For a charter event gallery tied to specific dates, we needed Graph API's full media endpoint with temporal filtering—even though it requires formal app review. This trade-off gives us precise control over which photos appear for each event.
Step 1: Add the Correct Product to Your Meta App
Navigate to developers.facebook.com/apps → [App Name: sailjada-social] → Add Product. Search for and select Instagram Graph API. (Note: The "Messaging" use case, while available in the sidebar, grants DM scopes, not media-reading scopes—a common configuration mistake.)
Step 2: Connect the Instagram Business Account
Within Instagram Graph API settings, click "API setup with Instagram login" and select "Add Instagram account." This requires @sailjada to log in and authorize the app. Behind the scenes, Meta creates a connection between the Instagram account and your Facebook Business Page—a prerequisite for Graph API access.
Step 3: Generate Short-Lived Access Token
Use the Graph API Explorer at developers.facebook.com/tools/explorer:
- Select app:
sailjada-social - Select the Facebook Page connected to @sailjada
- Click "Generate Access Token"
- Ensure scopes include
instagram_basicandpages_show_list
This token is valid for ~1 hour and is used only to bootstrap the process.
Step 4: Retrieve IG_USER_ID
Execute two API calls to map from your Facebook Page to the Instagram Business Account ID:
curl -s "https://graph.instagram.com/v18.0/[PAGE_ID]?fields=instagram_business_account&access_token=[SHORT_LIVED_TOKEN]"
The response includes an instagram_business_account object with an id field. Store this as IG_USER_ID.
Step 5: Exchange for Long-Lived Token
The short-lived token expires quickly. Exchange it for a token valid for 60 days:
curl -s "https://graph.instagram.com/oauth/access_token?grant_type=ig_refresh_token&access_token=[SHORT_LIVED_TOKEN]"
The returned access_token is your IG_ACCESS_TOKEN. Store both credentials securely.
Infrastructure: Lambda Environment Variables
Update the ShipCaptainCrew Lambda function configuration in us-east-1 (account 782785212866):
aws lambda update-function-configuration \
--function-name shipcaptaincrew \
--region us-east-1 \
--environment Variables={IG_USER_ID=[your_user_id],IG_ACCESS_TOKEN=[your_token]}
These environment variables are injected into the Lambda runtime. The function checks for their presence; if either is missing, Instagram integration silently returns an empty array (graceful degradation).
Code Integration: Lambda Handler Updates
The file /Users/cb/Documents/repos/sites/queenofsandiego.com/tools/shipcaptaincrew/lambda_function.py contains the handler. When a request arrives at /g/{event_id}, the handler:
- Parses the event ID to extract the date (e.g.,
2026-04-29) - Queries the guest photo database (DynamoDB or S3) for approved uploads from that date
- If
IG_USER_IDandIG_ACCESS_TOKENare set, calls Instagram Graph API to fetch media from the same date window - Merges both streams and returns JSON to the front-end
The Instagram query filters by timestamp to match the charter event window (e.g., 8 AM to 6 PM on the event date).
Front-End: Gallery Display
The file index.html (served at shipcaptaincrew.queenofsandiego.com/g/{event_id}) contains JavaScript that:
- Fetches JSON from the Lambda API endpoint
- Renders guest photos from the database
- Renders Instagram posts from @sailjada in the same gallery grid
- Distinguishes sources via CSS class (e.g.,
guest-photovsinstagram-post)
Key Decisions
60-day token refresh cadence: Rather than implement monthly automatic refresh via EventBridge, we chose a simpler manual refresh strategy. Since Instagram tokens are refreshed via the same endpoint used to obtain them, a developer can run the exchange command every 55 days. This avoids Lambda complexity and external scheduler dependencies. If automation becomes necessary, an EventBridge rule targeting a dedicated Lambda function can handle renewal.
Graceful degradation: If environment variables are missing or the Instagram API returns an error, the guest page still loads and displays guest-uploaded photos. Instagram integration is a feature enhancement, not a requirement.
Graph API over Basic Display: Graph API requires formal app review (typically 5–7 business days) but offers temporal filtering and higher rate limits. This is the correct long-term choice for an event-centric photo gallery.
Testing and Verification
After deploying credentials, verify the integration by navigating to https://shipcaptaincrew.queenofsandiego.com/g/2026-04-29 (or any past event date). Open the browser console and confirm:
- No 401/403 errors from
graph.instagram.com - The response includes both guest and Instagram photo objects
- Photos render in the gallery grid
Monitor Lambda logs via:
aws logs tail /aws/lambda/shipcaptaincrew --region us-east-1 --follow