A self-hosted, safety-first Instagram DM outreach pipeline built with FastAPI and n8n. Manages user interactions, tracks replies, classifies leads, and protects accounts through gradient warm-up, proxy rotation, and automatic pause/resume logic.
This project interacts with Instagram via the unofficial instagrapi library.
Use at your own risk. Automated messaging may violate Instagram's Terms of Service.
The authors are not responsible for account bans or other consequences.
- Automated DM outreach β sends batched Instagram direct messages to contacts sourced from Google Sheets, respecting configurable daily limits
- Gradient account warm-up β automatically ramps daily message limits from 5 to 50 over a 15-day schedule to reduce ban risk on new accounts
- Proxy rotation β integrates with a 4G/mobile proxy provider REST API; rotates IP after every 50 messages or 24 hours
- Human-like delays β Gaussian-distributed inter-message delays and typing-speed simulation to mimic organic behavior
- Reply tracking & lead classification β polls Instagram inbox every 30 minutes,
classifies responses as
Interested/Not Interested/Unclear, and writes tags back to Google Sheets - Auto-pause & auto-resume β detects
ChallengeRequired/LoginRequirederrors, pauses outreach for 24 hours, validates session health before resuming - Telegram alerts β instant notifications on account block events and new interested leads via n8n webhook workflows
- API key authentication β all FastAPI endpoints protected by
X-API-Keyheader - Encrypted session storage β Instagram session persisted to an encrypted JSON file
- Fully containerized β FastAPI backend and n8n orchestrator run in Docker Compose on a shared internal network
| Layer | Technology |
|---|---|
| API Backend | FastAPI + Uvicorn |
| Instagram Library | instagrapi |
| Workflow Orchestrator | n8n (self-hosted) |
| Data Layer | Google Sheets via gspread |
| Configuration | Pydantic Settings |
| Containerization | Docker + Docker Compose |
| Dependency Management | Poetry |
| Linting & Formatting | Ruff |
| State Persistence | JSON file (MVP); Redis-compatible for production |
| Proxy | 4G Mobile Proxy with provider REST API rotation |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β n8n (port 5679) β
β β
β βββββββββββββββββββ ββββββββββββββββββββββββββββ β
β β Outreach Trigger β β Reply Polling (30 min) β β
β β (cron 10:00) β β β FastAPI check-replies β β
β ββββββββββ¬βββββββββ ββββββββββββββββ¬ββββββββββββ β
β β β β
β ββββββββββΌβββββββββ ββββββββββββββββΌββββββββββββ β
β β Warmup Trigger β β Telegram Lead Alert β β
β β (cron 00:01) β β (if interested > 0) β β
β ββββββββββ¬βββββββββ ββββββββββββββββββββββββββββ β
β β β
β ββββββββββΌβββββββββ β
β β Block Alert β β
β β (webhook POST) β β
β βββββββββββββββββββ β
ββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ
β HTTP (internal network)
ββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββ
β FastAPI Backend (port 8003) β
β β
β OutreachEngine β ReplyTracker β WarmupManager β
β PauseManager β ProxyRotator β SheetsClient β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- Docker & Docker Compose
- A Google Cloud service account with Sheets API enabled (
credentials.json) - A 4G/mobile proxy with REST API access
- A Telegram bot token and chat ID for alerts
git clone https://github.com/PyDevDeep/FastGram-Outreach.git
cd fastgramcp .env.example .envEdit .env with your credentials:
# Instagram
INSTAGRAM_USERNAME=your_username
INSTAGRAM_PASSWORD=your_password
# Security
API_KEY=your_secure_api_key_here
SESSION_ENCRYPTION_KEY=your_32_byte_key
# Google Sheets
GOOGLE_SHEETS_ID=your_spreadsheet_id
GOOGLE_APPLICATION_CREDENTIALS=/app/credentials.json
# Proxy
PROXY_URL=http://user:pass@host:port
PROXY_API_URL=https://api.your-proxy-provider.com
PROXY_API_KEY=your_proxy_api_key
# n8n Webhooks
N8N_WEBHOOK_URL=http://fastgram_n8n:5678/webhook/alert-block
# Limits
DAILY_MESSAGE_LIMIT=20
MIN_DELAY_SECONDS=30
MAX_DELAY_SECONDS=60cp /path/to/your/credentials.json ./credentials.jsondocker compose up -dAPI is available at http://localhost:8003. n8n UI is available at http://localhost:5679.
In the n8n UI, import the four workflows from n8n/workflows/:
| File | Purpose |
|---|---|
outreach_trigger.json |
Daily cron at 10:00 β starts outreach batch |
warmup_trigger.json |
Daily cron at 00:01 β increments warm-up day |
reply_polling.json |
Every 30 min β polls replies and alerts on leads |
alert_on_block.json |
Webhook β fires Telegram alert on account block |
Set your YOUR_TELEGRAM_CHAT_ID in the Telegram Alert nodes.
All requests require the header: X-API-Key: your_secure_api_key_here
# Start outreach batch
POST http://localhost:8003/outreach/start
Content-Type: application/json
{"dry_run": false}
# Check for new replies and classify leads
GET http://localhost:8003/tracking/check-replies
# Increment warm-up day counter (also called by n8n cron)
POST http://localhost:8003/outreach/warmup/increment
# Health check
GET http://localhost:8003/health
# Warmup status
GET http://localhost:8003/admin/warmup-status
# Account health check
GET http://localhost:8003/admin/account-health
# Manual resume after pause
POST http://localhost:8003/admin/resume-pauseThe Contacts sheet must contain these columns:
| Column | Description |
|---|---|
Instagram Username |
Target account handle (without @) |
Instagram User ID |
Numeric user ID (populated after first contact) |
Status |
Pending / Sent / Replied / Error |
Tag |
Interested / Not Interested / Unclear (set by ReplyTracker) |
# Test Instagram authentication
docker compose exec api python scripts/test_instagram.py
# Test Google Sheets access
docker compose exec api python scripts/test_sheets.py| Days | Daily Message Limit |
|---|---|
| 1β3 | 5 |
| 4β6 | 10 |
| 7β9 | 15 |
| 10β12 | 25 |
| 13β14 | 35 |
| 15+ | 50 (warm-up deactivates) |
| Resource | Cost |
|---|---|
| VPS (n8n + FastAPI, e.g. Hetzner CX22) | $5β10 |
| 4G Mobile Proxy (1 slot with rotation) | $30β80 |
| Google Sheets API | Free |
| Domain + SSL (optional) | $0β5 |
| Total | $35β95 |
- The
X-API-Keyheader is required on all endpoints; unauthorized requests return HTTP 401 - Instagram credentials and session data are never exposed via the API
credentials.jsonis mounted read-only inside the container- Pre-commit hooks block accidental commits of private keys (via
detect-private-key) sessions/session.jsonand.envare listed in.gitignore
- Phase 1 β PostgreSQL migration (replace Google Sheets)
- Phase 2 β Sentry integration for error tracking
- Phase 3 β LLM-based reply classification (replace keyword matching)
- Phase 4 β Playwright fallback for API-blocked scenarios
The project ships with 82 tests across 9 modules and achieves 84% overall coverage.
Run the full test suite with coverage report:
poetry run pytest --cov=app --cov-report=term-missingLatest results (Python 3.13.11):
tests/test_fastapi.py 11 passed
tests/test_instagram_client.py 17 passed
tests/test_notification_service.py 3 passed
tests/test_outreach_engine.py 13 passed
tests/test_pause_manager.py 6 passed
tests/test_proxy_rotator.py 11 passed
tests/test_reply_tracker.py 5 passed
tests/test_sheets_client.py 11 passed
tests/test_warmup_manager.py 5 passed
βββββββββββββββββββββββββββββββββββββββββββββ
82 passed in 2.72s
Coverage summary:
Name Stmts Miss Cover
-----------------------------------------------------------
+app/config.py 30 0 100%
+app/services/notification_service.py 20 0 100%
+app/services/proxy_rotator.py 88 0 100%
+app/services/reply_tracker.py 63 1 98%
+app/services/warmup_manager.py 56 1 98%
+app/services/pause_manager.py 67 5 93%
app/routers/health.py 20 2 90%
app/services/outreach_engine.py 140 18 87%
app/services/sheets_client.py 134 19 86%
app/routers/outreach.py 59 10 83%
app/dependencies.py 43 9 79%
app/routers/tracking.py 19 5 74%
-app/services/instagram_client.py 220 72 67%
-app/utils/delay.py 25 10 60%
-app/main.py 29 13 55%
-----------------------------------------------------------
TOTAL 1028 165 84%
instagram_client.py(67%) andmain.py(55%) have lower coverage due to live Instagram API calls and app-startup side effects that require integration-level testing.
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature - Install pre-commit hooks:
pre-commit install - Make changes and ensure linting passes:
ruff check . && ruff format . - Submit a pull request with a clear description
[INSERT LICENSE TYPE]