Integrating Instagram Graph API with AWS Lambda for Dynamic Photo Gallery Aggregation
We recently activated Instagram media integration for the Ship Captain Crew guest photo gallery system at shipcaptaincrew.queenofsandiego.com/g/{event_id}. The goal was to surface @sailjada Instagram posts alongside guest-uploaded charter photos in a unified view, without manual curation. This post documents the technical architecture, authentication flow, and Lambda configuration required to make this work.
What We Built
The guest photo page previously displayed only approved user-uploaded images. We extended the shipcaptaincrew Lambda function (us-east-1, account 782785212866) to fetch Instagram media from @sailjada within a configurable time window matching the event date. The integration pulls media via the Instagram Graph API, filters by timestamp, and renders both sources in the same gallery view.
The system was architecturally dormant—the Lambda already had conditional logic to call Instagram's API when environment variables IG_USER_ID and IG_ACCESS_TOKEN were present. It returned an empty array otherwise. We focused on populating those credentials securely.
Technical Architecture & Authentication Flow
Instagram's Graph API requires a long-lived access token (valid for 60 days) linked to a specific Business/Creator account. The token must be generated through Facebook's OAuth flow and exchanged for longevity. Here's the flow we implemented:
- Facebook App Setup: The existing
sailjada-socialapp in our Facebook Developer dashboard had the Messaging product added, but that grantsinstagram_manage_messagesscope—insufficient for media reads. We added the Instagram Graph API product separately to accessinstagram_basicscope. - Account Linking: @sailjada (a Creator/Business account) was connected to a Facebook Page within the app dashboard. The Graph API requires a Business account; personal Instagram accounts cannot be queried directly.
- Token Generation: Using Facebook's Graph API Explorer, we generated a short-lived user access token (valid ~2 hours) with scopes
instagram_basicandpages_show_list. This token is the bootstrap credential. - User ID Resolution: The short-lived token was exchanged in a two-step curl request to fetch the Facebook Page ID, then query that page for the linked
instagram_business_account, extracting its numeric ID. - Long-Lived Token Exchange: The short-lived token was exchanged for a 60-day token using the app's client credentials (APP_ID and APP_SECRET), which the Lambda function stores securely.
Infrastructure & Configuration
Lambda Function Configuration
The shipcaptaincrew Lambda function (runtime: Python 3.11) required two new environment variables:
IG_USER_ID: The numeric ID of the @sailjada Business account (e.g.,17841406984310032)IG_ACCESS_TOKEN: The 60-day long-lived token issued by Facebook's token exchange endpoint
Both values are stored in AWS Lambda's encrypted environment variable store. The Lambda execution role already has permissions to read these via its IAM policy; no additional permissions were required.
API Gateway & Routing
The event ID route /g/{event_id} was already wired to the Lambda via API Gateway (REST API, us-east-1). The path parameter event_id is passed to the Lambda handler as event['pathParameters']['event_id']. The function uses this to query the guest photo DynamoDB table and construct a time window for Instagram queries.
Data Flow & Filtering
The Lambda's existing logic (in the handler's media aggregation section) performs these steps when Instagram credentials are available:
- Parse
event_idas a date (e.g.,2026-04-29→ April 29, 2026) - Query Instagram Graph API endpoint:
/v18.0/{IG_USER_ID}/ig_hashtag_search?user_id={IG_USER_ID}&fields=id,nameto find relevant hashtags, or directly fetch media from/v18.0/{IG_USER_ID}/media?fields=id,caption,media_type,media_url,timestamp - Filter results to media posted within ±4 hours of the event date (configurable window)
- Merge with guest-uploaded photos in the response JSON
- Return unified gallery metadata to the frontend
If IG_USER_ID or IG_ACCESS_TOKEN are missing or expired, the function gracefully returns an empty Instagram array; the page continues to display guest photos without error.
Key Technical Decisions
Why Long-Lived Tokens Instead of Refreshing at Query Time?
We chose to pre-exchange for a 60-day token rather than store the user's credentials and refresh at each page load. This approach:
- Reduces API calls (no token refresh per request)
- Eliminates the need to store or handle user credentials in Lambda
- Simplifies error handling (token expiry is a scheduled maintenance task, not a runtime failure)
- Improves latency—the Lambda makes one Graph API call instead of two
Environment Variables Over Secrets Manager
We stored credentials in Lambda environment variables (with encryption at rest) rather than AWS Secrets Manager. For this read-only integration, the reduced operational complexity justified the trade-off. Secrets Manager would add latency and cost; environment variables are sufficient for non-rotating credentials.
Manual Token Refresh Over EventBridge Automation
Token expiry is monthly (every 60 days). We opted for a manual refresh process documented in a runbook rather than an EventBridge-triggered Lambda. Reasons:
- Infrequent rotation—once per 2 months, not warranting automation overhead
- Reduced blast radius—manual execution allows validation before deployment
- Audit trail—explicit token exchanges are easier to log and review
If Instagram media becomes critical to the photo gallery experience, we can upgrade to automated refresh using EventBridge + a dedicated token-refresh Lambda.
Verification & Testing
After populating the environment variables, we tested the integration by accessing a live event page: shipcaptaincrew.queenofsandiego.com/g/2026-04-29. The Lambda's CloudWatch logs showed successful Graph API calls, and Instagram media appeared in the gallery within seconds. We verified:
- Correct filtering by event date (±4-hour window)
- Media type handling (images and carousels render correctly)
- Fallback behavior when credentials are missing (guest photos still load)
What's Next
Future enhancements include:
- Token Refresh Automation: If Instagram integration becomes critical, implement an EventBridge rule