Integrating Instagram Graph API with AWS Lambda: Guest Photo Timeline for Charter Events
Overview
We recently enabled Instagram media integration for the guest photo page system at shipcaptaincrew.queenofsandiego.com/g/{event_id}. The Lambda function (shipcaptaincrew, us-east-1, account 782785212866) now fetches and displays @sailjada Instagram posts alongside approved guest-uploaded photos from the same day/time window. This post details the architecture decisions, setup process, and infrastructure changes required to integrate Instagram's Graph API with our serverless backend.
What Was Done
The guest photo page previously displayed only user-uploaded images. We integrated the Instagram Graph API to pull media from the @sailjada business account, enriching the timeline with official Instagram content. The Lambda function queries Instagram's media endpoint when the event page loads, filters results by date/time window, and merges them with guest uploads in chronological order.
The integration required three key pieces:
- Creating a Facebook app with the correct Graph API product configuration
- Obtaining and managing long-lived access tokens (60-day lifecycle)
- Updating the Lambda function environment variables with Instagram credentials
Technical Architecture
Why Instagram Graph API (Not Basic Display)
Instagram offers two primary API products: Basic Display (simple image/caption retrieval) and Instagram Graph API (full media insights, captions, timestamps, engagement metrics). We selected Graph API because it provides structured timestamp data essential for filtering media by event date. The Basic Display API returns minimal metadata unsuitable for precise timeline matching.
App Configuration: sailjada-social
The Facebook app sailjada-social (App ID: 1688884572116630) serves as the OAuth provider. The app must explicitly enable the Instagram Graph API product in the dashboard—not the "Messaging" use case, which only grants direct message scopes and lacks media read permissions.
Critical Setup Step: The @sailjada account must be configured as a Business or Creator account and linked to a Facebook Page. This linkage is required because Instagram Graph API accesses media through the business account's relationship to a Page, not directly through the Instagram account.
Token Lifecycle & Scope Management
Instagram access tokens have a 60-day expiration window. The integration uses long-lived tokens (exchanged from short-lived tokens) rather than short-lived tokens because Lambda invocations are infrequent enough that manual monthly refresh is operationally acceptable. For higher-traffic systems, EventBridge could automate this refresh, but our event-driven architecture doesn't justify that overhead yet.
Required OAuth scopes:
instagram_basic— read access to Instagram media and account infopages_show_list— list Facebook Pages linked to the app user
Lambda Function Changes
The shipcaptaincrew Lambda function (runtime: Python 3.x) already contained dormant Instagram integration code. When IG_USER_ID and IG_ACCESS_TOKEN environment variables were missing, the function returned an empty array for Instagram posts. No code changes were required—only environment variable provisioning.
The function queries Instagram's media endpoint:
https://graph.instagram.com/v18.0/{IG_USER_ID}/media
?fields=id,caption,media_type,media_url,timestamp
&access_token={IG_ACCESS_TOKEN}
The response is filtered by timestamp to match the event date window, then merged with guest uploads. The @sailjada media URL is cached for 24 hours using Lambda's local execution environment to reduce API calls.
Environment Variable Configuration
Two environment variables were added to the Lambda function configuration:
IG_USER_ID— The Instagram Business Account ID (obtained via Graph API)IG_ACCESS_TOKEN— The long-lived access token (60-day expiration)
These are stored in the Lambda environment, not in Systems Manager Parameter Store, because Instagram tokens require manual refresh monthly. Parameter Store would add unnecessary infrastructure complexity. Token refresh is documented in the team playbook and scheduled as a calendar reminder.
Obtaining Credentials: The Multi-Step Process
Why multi-step? Instagram's OAuth flow is intentionally restrictive to prevent token leakage. Short-lived tokens (valid 1 hour) are exchanged for long-lived tokens to reduce the number of times credentials are exposed during manual setup.
Step 1: Generate a short-lived token using the Graph API Explorer at developers.facebook.com/tools/explorer. Select the sailjada-social app and the Facebook Page linked to @sailjada. Request scopes instagram_basic and pages_show_list.
Step 2: Retrieve IG_USER_ID via the Graph API by querying the Page's Instagram business account:
curl -s "https://graph.instagram.com/v18.0/{PAGE_ID}?fields=instagram_business_account&access_token={SHORT_LIVED_TOKEN}"
The response contains instagram_business_account.id, which becomes IG_USER_ID.
Step 3: Exchange for a long-lived token using the client credentials flow:
curl -s "https://graph.instagram.com/oauth/access_token?grant_type=fb_exchange_token&client_id={APP_ID}&client_secret={APP_SECRET}&fb_exchange_token={SHORT_LIVED_TOKEN}"
The returned access_token is the long-lived token (good for 60 days).
Infrastructure & Deployment
No additional AWS infrastructure was required. The existing Lambda function configuration was updated using:
aws lambda update-function-configuration \
--function-name shipcaptaincrew \
--region us-east-1 \
--environment "Variables={IG_USER_ID=...,IG_ACCESS_TOKEN=...}"
This update triggers a function version change but no redeployment since the code was already present.
Testing & Verification
The integration was verified by accessing the guest photo page at shipcaptaincrew.queenofsandiego.com/g/2026-04-29 and confirming that @sailjada posts from April 29, 2026 appeared alongside guest photos. CloudWatch Logs captured any API errors during token exchange.
Key Decisions & Rationale
- Long-lived tokens over EventBridge automation: Operational simplicity trumps infrastructure complexity for low-frequency manual tasks.
- Graph API over Basic Display: Timestamp filtering requires structured metadata that only Graph API provides.
- Environment variables over Parameter Store: Reduces operational overhead for credentials with predictable manual refresh cycles.
- No code changes: The function was designed with dormant integration support, enabling zero-downtime feature activation.