Integrating Instagram Graph API with AWS Lambda: Building a Unified Charter Photo Timeline
What Was Done
We implemented Instagram Graph API integration into an existing AWS Lambda function that serves guest-uploaded charter photos from a PostgreSQL database. The system now has the infrastructure to display approved guest photos alongside @sailjada Instagram posts from matching event dates and time windows, all served through a dynamic guest photo page at shipcaptaincrew.queenofsandiego.com/g/{event_id}.
The Lambda function (shipcaptaincrew, us-east-1, account 782785212866) previously returned an empty array for Instagram posts. We've wired up the Instagram Graph API integration points, defined the token exchange workflow, and documented the environment variable configuration needed to activate the feature.
Technical Details: The Guest Photo Page Architecture
The guest photo system is built on three layers:
- Frontend:
/tools/shipcaptaincrew/index.html— a client-side Vue.js application that fetches guest photo data via the Lambda API endpoint - API Layer: AWS Lambda function (
lambda_function.py) running in us-east-1, triggered via an API Gateway endpoint - Data Sources: PostgreSQL database for guest photos (via approval workflow) and Instagram Graph API for
@sailjadaposts
When a request arrives at /g/2026-04-29, the frontend makes an HTTP call to the Lambda API with the event_id parameter. The Lambda function:
- Queries PostgreSQL for approved guest photos matching that event date
- Calls Instagram Graph API to fetch media posted within a time window around the event
- Returns both datasets as a unified JSON response, which the frontend renders chronologically
This hybrid approach gives event attendees a complete visual record—photos they approved for sharing plus official @sailjada content from the same window.
Instagram Graph API Integration: Implementation Details
The Instagram integration uses two environment variables set on the Lambda function:
IG_USER_ID— the Instagram Business Account ID for@sailjadaIG_ACCESS_TOKEN— a long-lived access token (valid for 60 days) withinstagram_basicscope
Inside lambda_function.py, the integration is gated by a simple check:
if not os.getenv('IG_USER_ID') or not os.getenv('IG_ACCESS_TOKEN'):
return [] # Instagram posts disabled
When both variables are present, the function calls the Graph API endpoint:
GET https://graph.instagram.com/{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's date range, then merged with guest photos before returning to the client.
Infrastructure and Configuration
Lambda Function Details:
- Function name:
shipcaptaincrew - Region: us-east-1
- Account: 782785212866
- Runtime: Python 3.x with boto3 and requests libraries
- Handler:
lambda_function.lambda_handler - Timeout: 30 seconds (sufficient for DB query + Instagram API call)
- Environment Variables:
IG_USER_ID,IG_ACCESS_TOKEN, plus existing database connection strings
API Gateway Setup:
The Lambda is exposed via API Gateway with a GET endpoint accepting event_id as a path parameter. CloudFront caches responses with a 5-minute TTL to reduce Lambda invocations and API quota usage.
Token Lifecycle Management:
Instagram Graph API access tokens issued through the server-side flow are valid for 60 days. Rather than implementing token refresh logic in the Lambda itself, we recommend a monthly scheduled Lambda (triggered by EventBridge) that exchanges the current token for a fresh one before expiration. This keeps the main function focused on serving requests and avoids unnecessary API calls.
Key Decisions and Rationale
Why separate the token refresh from the main handler: The guest photo page serves hundreds of requests per day. Embedding token refresh logic in the hot path would add latency and expose us to Instagram API rate limits during the token exchange. A scheduled job running once monthly is cleaner and more resilient.
Why Instagram Graph API (not Basic Display): We chose Graph API because it grants instagram_basic scope, allowing us to read media metadata, captions, and timestamps. Basic Display is a lighter endpoint but doesn't expose the timestamp field needed for event-window matching.
Why environment variables (not hardcoding in code): Keeping credentials in Lambda env vars allows us to rotate tokens and update IG_USER_ID without redeploying the function. Environment variables are encrypted at rest in Lambda and masked in CloudWatch logs.
Why no caching layer for Instagram data: Guest photos rarely change during an event window, but Instagram posts arrive in real-time. We fetch fresh Instagram data on every request but could add a lightweight cache (DynamoDB or ElastiCache) if Instagram API quota becomes a constraint.
What's Next
The integration is architecturally complete and ready for token setup. The immediate next steps are:
- Add the Instagram Graph API product to the Facebook app (
sailjada-social) in App Dashboard - Authenticate
@sailjadaand generate a short-lived access token via the Graph API Explorer - Exchange the short-lived token for a long-lived token (60-day expiry)
- Extract
IG_USER_IDfrom the authenticated account details - Update Lambda environment variables via AWS CLI or Console
- Test at
/g/2026-04-29to verify Instagram posts appear alongside guest photos
Once live, monitoring should track Instagram API response times (target: <200ms) and error rates (target: <0.1%). CloudWatch logs will capture any token expiration errors, triggering the monthly refresh job if needed.
```