Automated social media posting system that posts one photo per day from a specific Flickr album to Instagram with AI-generated captions using GitHub Actions and OpenAI GPT Vision.
Instagram's API requires source photos to be published online. I chose my Flickr gallery as the source: https://flickr.com/photos/schaerer/albums/.
The ID '72177720326826937' of a Flickr album (found in the URL; for example, https://flickr.com/photos/schaerer/albums/72177720326826937) serves as the source configuration key.
I take lots of photos that I edit in Adobe Lightroom and publish on my travel blogs, https://travelmemo.com in English and https://reisememo.ch in German.
However, I don't take the time to post them on Instagram. This automation helps me repurpose my photos.
- 📅 Daily Posting: Posts one photo per day until the album is complete
- 🎯 Single Album Focus: Processes one specific Flickr album
- 🤖 AI-Generated Captions: Uses OpenAI GPT-4 Vision for engaging Instagram captions
- 📊 Progress Tracking: Shows completion progress and statistics
- 🔧 Manual Control: Run automation manually with different options
- 🛡️ Smart Stopping: Automatically stops when all photos are posted
- 📈 Analytics: Built-in statistics and monitoring
- Fork or clone this repository
- In the file caption_generator.py, adapt the branding to reflect your own brand instead of my Travelmemo brand
- No other code changes are needed - all configuration is done via environment variables
- Optional: To change the publishing schedule, edit the workflow file social-media-automation.yml
Add the following secrets to your GitHub repository (Settings > Secrets and variables > Actions > Repository secrets
):
FLICKR_API_KEY=your_flickr_api_key
FLICKR_USER_ID=your_flickr_user_id
INSTAGRAM_ACCESS_TOKEN=your_instagram_access_token
INSTAGRAM_ACCOUNT_ID=your_instagram_business_account_id
OPENAI_API_KEY=your_openai_api_key
Add the following variables to your GitHub repository (Settings > Secrets and variables > Actions > Repository variables
):
FLICKR_USERNAME=your_flickr_username
FLICKR_ALBUM_ID=your_flickr_album_id
GRAPH_API_VERSION=v18.0 (current Facebook/Instagram API version)
OPENAI_MODEL=gpt-4o-mini (current OpenAI vision model number. The mini version will do just fine at a lower cost)
- Go to
Actions
tab in your repository - Click on "Flickr to Instagram Automation"
- Click "Run workflow"
- Check "Run without posting (dry run)" for testing
- Click "Run workflow"
The automation follows this simple process:
- Daily Schedule: Runs every day at 9 AM UTC
- Check Album: Fetches all photos from your specified Flickr album
- Find Next Photo: Identifies the next unposted photo
- Generate Caption: Uses GPT-4 Vision to create an engaging caption
- Post to Instagram: Publishes the photo with the generated caption
- Track Progress: Records the post in GitHub Issues
- Auto-Complete: Stops automatically when all photos are posted
The system is now fully configurable via GitHub repository variables. No code changes are needed.
Set your Flickr album by updating the repository variables:
FLICKR_ALBUM_ID
: Your specific album IDFLICKR_USERNAME
: Your Flickr username
To change albums, simply update the FLICKR_ALBUM_ID
variable in your GitHub repository settings.
Your Flickr album URL looks like:
https://flickr.com/photos/[your_username]/albums/72177720326826937
The album ID is the number at the end: 72177720326826937
The automation system follows a modular architecture with clear separation of concerns, robust error handling, and comprehensive state management.
graph TB
%% External Services
subgraph "External APIs"
FA[📷 Flickr API<br/>Photo Retrieval]
IA[📱 Instagram Graph API<br/>Photo Posting]
OA[🤖 OpenAI GPT-4 Vision<br/>Caption Generation]
end
%% GitHub Infrastructure
subgraph "GitHub Infrastructure"
GR[📁 GitHub Repository<br/>Code & Configuration]
GA[⚙️ GitHub Actions<br/>Workflow Engine]
GI[📋 GitHub Issues<br/>State Management]
GS[🔐 GitHub Secrets<br/>Credential Storage]
end
%% Core Application
subgraph "Application Core"
MC[🎮 main.py<br/>Orchestration]
CF[⚙️ config.py<br/>Configuration]
subgraph "API Integrations"
FL[📷 flickr_api.py<br/>Photo Fetching]
CG[🤖 caption_generator.py<br/>AI Caption Creation]
IG[📱 instagram_api.py<br/>Social Media Posting]
end
SM[📊 state_manager.py<br/>Progress Tracking]
end
%% Triggers
subgraph "Triggers"
CR[⏰ Cron Schedule<br/>Daily at 9 AM UTC]
MN[👤 Manual Trigger<br/>Workflow Dispatch]
end
%% Data Flow
CR --> GA
MN --> GA
GA --> MC
MC --> CF
CF --> GS
MC --> FL
FL --> FA
FA --> FL
FL --> CG
CG --> OA
OA --> CG
CG --> IG
IG --> IA
IA --> IG
MC --> SM
SM --> GI
GI --> SM
SM --> MC
%% Styling
classDef external fill:#e1f5fe,stroke:#01579b,stroke-width:2px
classDef github fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
classDef core fill:#e8f5e8,stroke:#1b5e20,stroke-width:2px
classDef trigger fill:#fff3e0,stroke:#e65100,stroke-width:2px
class FA,IA,OA external
class GR,GA,GI,GS github
class MC,CF,FL,CG,IG,SM core
class CR,MN trigger
sequenceDiagram
participant GA as GitHub Actions
participant MC as main.py
participant FL as flickr_api.py
participant FA as Flickr API
participant SM as state_manager.py
participant GI as GitHub Issues
participant CG as caption_generator.py
participant OA as OpenAI API
participant IG as instagram_api.py
participant IA as Instagram API
Note over GA: Daily Trigger (9 AM UTC)
GA->>MC: Execute automation
MC->>SM: Check if album complete
SM->>GI: Query posted photos
GI-->>SM: Return posted photo IDs
SM-->>MC: Album status
alt Album not complete
MC->>FL: Get unposted photos
FL->>FA: Fetch album photos
FA-->>FL: Return photo metadata
FL-->>MC: Processed photo list
MC->>SM: Get next photo to post
SM-->>MC: Next unposted photo
MC->>CG: Generate caption
CG->>OA: Analyze image with GPT-4 Vision
OA-->>CG: Generated caption text
CG-->>MC: Complete Instagram caption
MC->>IG: Validate image URL
IG-->>MC: Validation result
MC->>IG: Post to Instagram
IG->>IA: Create media container
IA-->>IG: Container ID
IG->>IA: Publish container
IA-->>IG: Post ID
IG-->>MC: Success/failure
MC->>SM: Record post result
SM->>GI: Create tracking issue
GI-->>SM: Issue created
MC->>GA: Report completion
else Album complete
MC->>GA: Skip - all photos posted
end
graph LR
subgraph "Configuration Layer"
ENV[🔐 Environment Variables<br/>- API Keys<br/>- Album Settings<br/>- Credentials]
CFG[⚙️ Config Manager<br/>- Validation<br/>- API Endpoints<br/>- Settings]
end
subgraph "Service Layer"
FLS[📷 Flickr Service<br/>- Photo Retrieval<br/>- Metadata Extraction<br/>- URL Generation]
IGS[📱 Instagram Service<br/>- Media Upload<br/>- Publishing<br/>- Validation]
CPS[🤖 Caption Service<br/>- AI Generation<br/>- Text Processing<br/>- Retry Logic]
STS[📊 State Service<br/>- Progress Tracking<br/>- Issue Management<br/>- Completion Detection]
end
subgraph "Orchestration Layer"
MAIN[🎮 Main Controller<br/>- Workflow Coordination<br/>- Error Handling<br/>- Logging]
end
ENV --> CFG
CFG --> FLS
CFG --> IGS
CFG --> CPS
CFG --> STS
FLS --> MAIN
IGS --> MAIN
CPS --> MAIN
STS --> MAIN
classDef config fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef service fill:#e8f5e8,stroke:#1b5e20,stroke-width:2px
classDef orchestration fill:#e3f2fd,stroke:#0d47a1,stroke-width:2px
class ENV,CFG config
class FLS,IGS,CPS,STS service
class MAIN orchestration
graph TB
subgraph "Development"
DEV[👨💻 Local Development<br/>- .env files<br/>- Dry run testing<br/>- Debug logging]
end
subgraph "Repository"
REPO[📁 GitHub Repository<br/>- Source code<br/>- Configuration<br/>- Documentation]
end
subgraph "Production"
PROD[🏭 GitHub Actions<br/>- Automated execution<br/>- Secure credentials<br/>- Error handling]
end
subgraph "Monitoring"
LOGS[📊 Monitoring<br/>- GitHub Issues<br/>- Workflow logs<br/>- Artifacts]
end
DEV --> REPO
REPO --> PROD
PROD --> LOGS
LOGS --> DEV
classDef dev fill:#e8f5e8,stroke:#1b5e20,stroke-width:2px
classDef repo fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
classDef prod fill:#e1f5fe,stroke:#01579b,stroke-width:2px
classDef monitor fill:#fff3e0,stroke:#e65100,stroke-width:2px
class DEV dev
class REPO repo
class PROD prod
class LOGS monitor
Category | Component | Technology | Purpose |
---|---|---|---|
Infrastructure | Orchestration | GitHub Actions | Workflow automation, scheduling |
Runtime | Python 3.11 | Core application logic | |
State Storage | GitHub Issues API | Progress tracking, audit trail | |
Configuration | Credentials | GitHub Secrets | Encrypted credential storage |
Settings | Environment Variables | Secure configuration management | |
External APIs | Photo Source | Flickr API | Photo metadata and URLs |
Social Media | Instagram Graph API | Photo posting and publishing | |
AI Services | OpenAI GPT-4 Vision | AI-powered caption generation | |
Reliability | Error Handling | Exponential Backoff | Retry logic for API failures |
Monitoring | Python Logging | Comprehensive audit trails | |
Validation | URL Checking | Image accessibility verification |
- Visit Flickr App Garden
- Create a new app and get your API key
- Find your User ID from your Flickr profile URL
- Create a Facebook App at developers.facebook.com
- Add Instagram Graph API product
- Get a long-lived access token
- Connect your Instagram Business account
- Sign up at platform.openai.com
- Create an API key
- Ensure you have credits for GPT-4 Vision
- Runs automatically every day at 9 AM UTC
- Posts one photo per day from your album
- Automatically stops when all photos are posted
- No manual intervention required
Use the manual workflow trigger with these options:
- Dry Run: Test without posting to Instagram
- Show Stats: Display posting statistics and progress
# Install dependencies
pip install -r requirements.txt
# Post next photo (dry run)
python main.py --dry-run
# Post next photo (live)
python main.py
# Show statistics
python main.py --stats
The system uses GitHub Issues to track progress:
- Posted Photos: Each posted photo creates an issue with metadata
- Automation Logs: Success/failure records for each run
- Progress Tracking: Shows completion status
automated-post
: Photos posted by automationinstagram
: Posted to Instagramflickr-album
: From the configured Flickr albumposted
: Successfully postedfailed
: Failed to postautomation-log
: Automation run records
Run the workflow with "Show statistics only" checked, or use:
python main.py --stats
This shows:
- Total photos in album
- Photos posted so far
- Photos remaining
- Completion percentage
- Success rate
View GitHub Issues in your repository to see:
- Each photo that was posted
- Instagram post IDs
- Timestamps
- Any errors that occurred
When all photos in your album have been posted:
- 🎉 The automation displays "Album complete!"
- ⏸️ Scheduled runs automatically skip execution
- 📊 Statistics show 100% completion
- 🔄 To start a new album, update the
FLICKR_ALBUM_ID
variable in GitHub repository settings
├── main.py # Main automation script
├── config.py # Configuration management (environment variables)
├── flickr_api.py # Flickr API integration
├── caption_generator.py # OpenAI caption generation
├── instagram_api.py # Instagram posting
├── state_manager.py # GitHub Issues state management
├── requirements.txt # Python dependencies
└── .github/
└── workflows/
└── social-media-automation.yml # GitHub Actions workflow
Album Complete Message
🎉 Album complete! All photos have been posted to Instagram.
- This means all photos from your album have been successfully posted
- To start posting from a new album, update the
FLICKR_ALBUM_ID
variable in GitHub repository settings
Missing Environment Variables
Error: Missing required environment variables
- Ensure all secrets are configured in GitHub repository settings
- Check that secret names match exactly (case-sensitive)
Instagram API Errors
Error: Failed to create media container
- Check Instagram access token validity (tokens can expire)
- Verify business account connection
- Review Instagram API rate limits (200 requests/hour)
OpenAI API Errors
Error: Rate limit exceeded
- Check OpenAI account credits and usage limits
- Verify GPT-4 Vision model access
- Consider using GPT-4o-mini for lower costs
Flickr API Errors
Error: Failed to retrieve photos
- Verify Flickr API key and user ID
- Check album visibility settings (must be public or accessible)
- Ensure album ID is correct in your GitHub repository variables
No Photos Found
Warning: No photos found in the album
- Check that the album ID in your GitHub repository variables is correct
- Verify the album exists and contains photos
- Ensure album is public or accessible with your API key
Enable debug logging for troubleshooting:
python main.py --log-level DEBUG --dry-run
Test your Flickr album access:
# Check if your album is accessible
curl "https://www.flickr.com/services/rest/?method=flickr.photosets.getPhotos&api_key=YOUR_API_KEY&photoset_id=YOUR_ALBUM_ID&format=json&nojsoncallback=1"
- All API credentials stored as GitHub Secrets
- Environment-specific deployment protection
- Input validation for all external data
- Secure state management via GitHub Issues
- No credentials stored in code
For issues and questions:
- Check Configuration: Verify your GitHub repository variables and secrets
- Test with Dry Run: Use
--dry-run
flag to test without posting - Review Logs: Check GitHub Actions logs and artifacts
- Statistics: Use
--stats
to check progress and identify issues - GitHub Issues: Don't create an issue because I don't have the resources to follow up
Use this repo for free. It comes as is, i.e. without any warranty whatsoever. I don't offer support due to limited time.
Here's what a typical automation cycle looks like:
- Day 1: Posts photo 1/13 from your album
- Day 2: Posts photo 2/13 from your album
- Day 3: Posts photo 3/13 from your album
- ...
- Day 13: Posts photo 13/13 from your album
- Day 14: Shows "Album complete!" and stops
The automation intelligently tracks which photos have been posted and always selects the next unposted photo in the album order.
I'm working on this repo in a very limited capacity. Therefore, I can't review PRs or develop the functionality any further.
This project is licensed under the MIT License.