Integrating Instagram Graph API with Lambda: Adding Social Media to Guest Photo Galleries
Overview
The Ship Captain Crew guest photo system at shipcaptaincrew.queenofsandiego.com/g/{event_id} needed to display approved guest-uploaded photos alongside Instagram posts from the charter's social media account. The Lambda function had dormant Instagram integration code, but lacked proper API credentials and token management. This post details the process of properly configuring the Instagram Graph API, obtaining valid access tokens, and implementing a sustainable refresh strategy.
What Was Done
- Added Instagram Graph API product to the existing
sailjada-socialFacebook app - Connected the @sailjada Instagram business account to the app via Graph API setup flow
- Generated short-lived and long-lived access tokens using the Graph API Explorer
- Retrieved the Instagram User ID (
IG_USER_ID) from the business account metadata - Updated the Lambda function environment variables with the new credentials
- Modified the Lambda code to activate Instagram media retrieval when tokens are present
- Established a token refresh strategy for the 60-day expiration window
Technical Details: Adding the Graph API Product
The initial configuration mistake was adding the Instagram Messaging product, which grants DM-related permissions but not media access. The correct flow requires the Instagram Graph API product:
- Navigate to
developers.facebook.com/apps - Select the
sailjada-socialapp - Click Add Product in the left sidebar
- Search for and select Instagram Graph API (distinct from Basic Display and Messaging variants)
The Graph API product enables read access to instagram_basic scope, which allows querying media, captions, and metadata for business accounts.
Instagram Account Connection
After adding the product, the Instagram Graph API section appears in the dashboard. To connect @sailjada:
- Go to Instagram Graph API → API setup with Instagram login
- Click Add Instagram account
- Authenticate as @sailjada (must be a Business or Creator account with a linked Facebook Page)
Why this matters: Instagram Graph API requires a business account, not a personal account. The account must be linked to a Facebook Page that your app can access. This is Meta's requirement for programmatic media access.
Token Generation and Exchange
The token flow has three distinct stages:
Stage 1: Generate Short-Lived Token
Using the Graph API Explorer at developers.facebook.com/tools/explorer:
- Select app:
sailjada-social - Select the Facebook Page linked to @sailjada
- Click Generate Access Token
- Ensure scopes include:
instagram_basic,pages_show_list
This token is valid for approximately 1 hour and is used only to retrieve the permanent IG_USER_ID.
Stage 2: Extract IG_USER_ID
With the short-lived token, make a request to retrieve the business account ID:
curl -s "https://graph.instagram.com/me/instagram_business_account?access_token={SHORT_LIVED_TOKEN}" | jq '.instagram_business_account.id'
The returned id is your permanent IG_USER_ID. This never changes and is safe to store.
Stage 3: Exchange for Long-Lived Token
The short-lived token must be exchanged for a 60-day long-lived token using your app credentials:
curl -s "https://graph.instagram.com/access_token?grant_type=fb_exchange_token&client_id={APP_ID}&client_secret={APP_SECRET}&access_token={SHORT_LIVED_TOKEN}" | jq '.access_token'
The returned token is your IG_ACCESS_TOKEN, valid for 60 days.
Lambda Function Updates
The Lambda function resides at /Users/cb/Documents/repos/sites/queenofsandiego.com/tools/shipcaptaincrew/lambda_function.py in the development repository and is deployed to AWS Lambda in region us-east-1 under account 782785212866 with name shipcaptaincrew.
Update the function configuration with environment variables:
aws lambda update-function-configuration \
--region us-east-1 \
--function-name shipcaptaincrew \
--environment Variables={IG_USER_ID=your_user_id,IG_ACCESS_TOKEN=your_60day_token}
The Lambda code checks for these variables at runtime. When present, the /g/{event_id} route activates the Instagram media fetching logic, merging guest photos with social media posts from the same date range.
Key Architecture Decisions
Why Long-Lived Tokens Instead of Refresh Tokens
Meta's Instagram Graph API uses 60-day expiring tokens rather than refresh token flows. The decision to use long-lived tokens (vs. regenerating short-lived ones monthly) was made because:
- Simpler operational model — no complex token refresh logic needed in the Lambda
- The 60-day window aligns with charter seasons and batch photo uploads
- Manual refresh via the same exchange endpoint is straightforward when needed
Environment Variable Storage
Storing IG_ACCESS_TOKEN in Lambda environment variables (encrypted at rest by AWS) was chosen over hardcoding or fetching from Secrets Manager because:
- The token is long-lived (60 days), reducing API calls
- The function is deployed in a private account without public exposure
- No high-frequency rotation needed
- Simpler CI/CD pipeline without additional service calls
Media Filtering Strategy
The Lambda filters Instagram posts to match the event date and time window (e.g., all posts from 2026-04-29 and surrounding hours). This avoids cluttering the guest page with unrelated content and maintains a cohesive visual narrative tied to the specific charter event.
Deployment and Verification
After updating environment variables, verify the integration by accessing the guest page:
curl -s "https://shipcaptaincrew.queenofsandiego.com/g/2026-04-29" | grep -i "instagram"
The HTML response should include Instagram media elements alongside guest photo gallery sections. CloudWatch Logs for the Lambda function (at /aws/lambda/shipcaptaincrew) will show any API errors or token validation issues.
Token Refresh Strategy
A manual refresh process was established:
- Monthly check: Before the 60-day expiration, run the token exchange command again