Integrating Instagram Graph API with AWS Lambda: Connecting @sailjada Posts to Guest Photo Pages
What Was Done
We activated the dormant Instagram integration in the shipcaptaincrew Lambda function (us-east-1, account 782785212866) to display @sailjada Instagram posts alongside guest-uploaded charter photos on the guest photo page at shipcaptaincrew.queenofsandiego.com/g/{event_id}. The integration requires obtaining an Instagram Graph API access token and storing two environment variables (IG_USER_ID and IG_ACCESS_TOKEN) in the Lambda function configuration.
Technical Details: Instagram Graph API Setup
Why Instagram Graph API (Not Basic Display)
The sailjada-social Meta app initially had the Messaging product added, which only grants Direct Message scopes. To read Instagram business account media, we need the Instagram Graph API product, which provides the instagram_basic scope. This scope allows reading media, captions, and metadata from a connected business/creator account.
Account Prerequisites
- The @sailjada Instagram account must be a Business or Creator account (not a Personal account)
- It must be linked to a Facebook Page in Meta Business Suite
- The Meta app must be configured to allow Instagram account connection
Step 1: Add Instagram Graph API Product
Navigate to the Meta App Dashboard for sailjada-social:
- Go to
developers.facebook.com/appsand select thesailjada-socialapp - Click Add Product in the left sidebar
- Search for Instagram and select Instagram Graph API (not Basic Display)
- Complete setup — the product will appear in your sidebar
Step 2: Connect @sailjada Account
Within Instagram Graph API → API setup, click Add Instagram account and authenticate as @sailjada. This establishes the connection between the app and the business account.
Step 3: Generate a Short-Lived Access Token
Use the Graph API Explorer to generate an initial token with the correct scopes:
- Visit
developers.facebook.com/tools/explorer - Select
sailjada-socialapp from the dropdown - Generate Access Token with scopes:
instagram_basic,pages_show_list - Select the Facebook Page linked to @sailjada
Obtaining IG_USER_ID and IG_ACCESS_TOKEN
Retrieve IG_USER_ID from Facebook Page
Using the short-lived token from Step 3, make two API calls to map your Facebook Page to the Instagram Business Account ID:
curl -s "https://graph.instagram.com/me/accounts?access_token=YOUR_SHORT_LIVED_TOKEN"
This returns your Facebook Page ID. Then query the Instagram business account linked to that page:
curl -s "https://graph.instagram.com/{PAGE_ID}?fields=instagram_business_account&access_token=YOUR_SHORT_LIVED_TOKEN"
The id field within the instagram_business_account object is your IG_USER_ID. Store this value securely.
Exchange for a Long-Lived Access Token
The short-lived token from the Explorer expires quickly. Exchange it for a long-lived token valid for 60 days using your app credentials:
curl -s "https://graph.instagram.com/oauth/access_token" \
-d "grant_type=fb_exchange_token" \
-d "client_id=YOUR_APP_ID" \
-d "client_secret=YOUR_APP_SECRET" \
-d "access_token=YOUR_SHORT_LIVED_TOKEN"
The returned access_token is your IG_ACCESS_TOKEN. This token is valid for 60 days and can be refreshed using the same endpoint before expiration.
Infrastructure: Lambda Environment Variables
Update the shipcaptaincrew Lambda function in us-east-1 with the two environment variables:
aws lambda update-function-configuration \
--function-name shipcaptaincrew \
--region us-east-1 \
--environment Variables="{IG_USER_ID=YOUR_IG_USER_ID,IG_ACCESS_TOKEN=YOUR_IG_ACCESS_TOKEN}"
These variables are referenced in the Lambda handler code. When both are present, the function's Instagram integration activates; previously, missing values caused it to return an empty array.
Key Decisions
Token Refresh Strategy
Rather than implement automatic token refresh within the Lambda (which would require storing the app secret in the function environment, a security anti-pattern), we chose a manual monthly refresh workflow. The 60-day token lifespan provides a two-month buffer before manual intervention is needed. For production, this could be automated via:
- An EventBridge rule triggering a separate refresh Lambda every 30 days
- A secrets management service (AWS Secrets Manager) storing the app secret securely
- The refresh Lambda exchanging the current token for a fresh one and updating the function configuration
For now, the manual approach reduces operational complexity while maintaining functionality.
Scope Minimalism
We requested only instagram_basic and pages_show_list scopes rather than broader permissions. This follows the principle of least privilege—the Lambda only needs to read media from @sailjada's account, not manage it or access other resources.
Integration Verification
Once the environment variables are set, test the integration by visiting:
https://shipcaptaincrew.queenofsandiego.com/g/2026-04-29
The guest photo page should now display Instagram posts from @sailjada within the same date/time window as the uploaded guest photos. The Lambda handler queries the Instagram Graph API using the IG_USER_ID and IG_ACCESS_TOKEN, filters posts by timestamp, and merges them into the response.
What's Next
- Implement automatic token refresh: Create an EventBridge rule and refresh Lambda to exchange tokens 45 days after deployment
- Add error handling: Gracefully degrade if the Instagram API is unavailable or token is expired
- Cache Instagram posts: Consider caching API responses in DynamoDB to reduce API calls and improve page load time
- Monitor token expiration: Add CloudWatch alarms to alert when the access token is nearing expiration