I run a thermal hunting repost page (@zerodarktactical, 28K followers) that posts thermal hog hunting content daily. For months I was manually curating, downloading, captioning, and posting videos every morning. It took 20-30 minutes per day.

Now my AI agent does it automatically at 8 AM Central. Every single day. Zero missed posts in the last 3 weeks.

Here's how the system works — and more importantly, how it never breaks.

The Architecture

1. Content Queue System

A JSON file (zdt-posting-queue.json) with 14-30 days of pre-approved content lined up.

Structure:

{
  "slot": 10,
  "date": "2026-02-22",
  "channel": "@Thermal Outdoors",
  "platform": "Facebook",
  "url": "https://www.facebook.com/reel/...",
  "caption": "Whole sounder lit up from the air...",
  "posted": false,
  "media_id": null,
  "permalink": null
}

How it gets filled:

  • I send videos to the agent throughout the week
  • Agent verifies thermal B&W only (no color, no night vision, no daylight)
  • Agent writes captions in my brand voice (no hashtags, no AI buzzwords, punchy one-liners)
  • Agent adds to queue with dates assigned sequentially

Failsafe #1: Queue never runs empty. Agent alerts me when it drops below 7 days.

2. Daily Cron Job (8:00 AM CT)

OpenClaw cron scheduler (not system cron — agent-native) triggers at 8 AM because Instagram engagement is highest 8-11 AM. Posts go out when people are scrolling on their commute.

Failsafe #2: Cron runs in isolated session (Sonnet model for cost savings). If it fails, the main agent session isn't affected.

3. Pre-Flight Checks (Before Any API Call)

A. Double-Post Guard

The problem: Race conditions, retry loops, or manual posts could cause duplicate posts on the same day.

The fix:

# Script: zdt-check-already-posted-today.sh
curl "https://graph.instagram.com/v21.0/$IG_USER_ID/media?fields=timestamp&limit=1"
# If latest post timestamp is today (America/Chicago), exit 1 and abort

Failsafe #3: This runs TWICE during every post attempt:

  1. Before creating the container
  2. Right before publishing

B. Token Auto-Refresh

Instagram Graph API long-lived tokens expire after 60 days. If the token dies at 8 AM, the post fails.

The fix:

# Step 0 of cron job (before anything else):
curl "https://graph.instagram.com/refresh_access_token?grant_type=ig_refresh_token&access_token=$OLD_TOKEN"
# Save new token to credentials/instagram-zdt.json

Failsafe #4: Token gets refreshed EVERY morning, regardless of expiry date. If refresh fails, tries posting with existing token anyway (might still work if not expired).

C. Token Health Check

Sometimes the token refresh succeeds but the new token is bad (race condition, API issue, etc.).

The fix:

# Quick validation call before attempting post
curl "https://graph.instagram.com/v21.0/$IG_USER_ID?fields=id,username&access_token=$TOKEN"
# If this fails, agent messages me and stops

Failsafe #5: Agent messages me on WhatsApp if token health check fails. Includes error details and what to check.

4. Video Download (Multi-Platform Support)

Platforms supported:

  • YouTube Shorts (via yt-dlp)
  • Instagram Reels (via browser + IG private API)
  • Facebook Reels (via yt-dlp)
  • TikTok (via yt-dlp, rarely used)

Instagram Reels are tricky. You can't just curl the video URL. The agent:

  1. Opens the reel in browser (OpenClaw browser profile)
  2. Extracts the video URL from page source using JavaScript eval
  3. Downloads via direct CDN link

Failsafe #6: If video download fails (404, dead link, account deleted):

  • Agent messages me on WhatsApp with the dead URL
  • Agent marks that queue entry as skipped
  • Agent moves to next available video in queue automatically

Fallback: If multiple videos fail in a row (rare), agent pulls from backup content sources (pre-vetted channels with recent uploads).

5. Video Processing

Instagram Graph API ONLY accepts H.264 video codec. Some source videos are VP9, AV1, or HEVC.

Transcoding check:

ffprobe -show_streams video.mp4 | grep codec_name
# If not H.264:
ffmpeg -i input.mp4 -c:v libx264 -c:a aac output.mp4

Cover frame extraction (every reel needs a thumbnail):

ffmpeg -ss 5 -i video.mp4 -frames:v 1 -q:v 2 cover.jpg

Failsafe #7: All temp video files are checked with ffprobe before upload. If corrupt or wrong codec, re-download and retry.

6. Bulletproof Upload System (The Big Fix)

Instagram Graph API can't accept direct video uploads. You have to give it a public URL where it can download the video from.

First Attempt (Free Services Only) — FAILED

Initially used free temp file hosts:

  • litterbox.catbox.moe
  • file.io
  • tmpfiles.org
  • 0x0.st

What went wrong: All 4 services went down simultaneously on Feb 22, 2026. Upload timeouts everywhere. Post failed 3 times in a row.

Current Solution (Vercel Blob + Fallbacks) — BULLETPROOF

Script: scripts/upload-temp-file.sh

Upload priority:

  1. Vercel Blob (primary) — 99.9% uptime SLA, 60-second timeout, $0.15/GB
  2. litterbox.catbox.moe (fallback)
  3. file.io (fallback)
  4. tmpfiles.org (fallback)
  5. 0x0.st (fallback)

How it works:

upload_vercel_blob() {
    for attempt in 1 2; do
        curl -X PUT "https://blob.vercel-storage.com/$FILENAME" \
          -H "authorization: Bearer $BLOB_READ_WRITE_TOKEN" \
          --data-binary "@$file" --max-time 60
        if success; then return URL; fi
        sleep $((2 ** attempt))  # exponential backoff
    done
    return 1  # failed, try next service
}

Failsafe #8: Multi-service retry with exponential backoff. 2 attempts per service = 10 total attempts before giving up.

Failsafe #9: Vercel Blob has 60-second timeout (vs 30s for free services). Large videos (3-5MB) don't timeout.

Cost: ~$0.60/month for video uploads ($0.15/GB storage + $0.30/GB egress). Basically free.

7. Instagram Graph API Posting (Three-Step Process)

Step 1: Create Container

curl -X POST "https://graph.instagram.com/v21.0/$IG_USER_ID/media" \
  -F "media_type=REELS" \
  -F "video_url=$VIDEO_URL" \
  -F "cover_url=$COVER_URL" \
  -F "caption=$CAPTION" \
  -F "access_token=$TOKEN"
# Returns container ID

Instagram downloads the video from your URL, transcodes it, and prepares it for publishing.

Step 2: Poll Container Status (Until FINISHED)

for i in 1..30; do
  curl "https://graph.instagram.com/v21.0/$CONTAINER_ID?fields=status_code"
  if status == "FINISHED"; then break; fi
  if status == "ERROR"; then abort; fi
  sleep 10
done

Typical wait time: 20-40 seconds for a 15-25 second video.

Failsafe #10: Max 30 polling attempts (5 minutes). If still IN_PROGRESS after 5 min, something's wrong — abort and alert me.

Step 3: Publish

# One more double-post guard check here
bash scripts/zdt-check-already-posted-today.sh
if safe; then
  curl -X POST "https://graph.instagram.com/v21.0/$IG_USER_ID/media_publish" \
    -F "creation_id=$CONTAINER_ID" \
    -F "access_token=$TOKEN"
fi

Failsafe #11: Final double-post guard right before publish. If another process posted in the last 5 minutes, this aborts.

8. Tracking & Verification

After successful publish, the agent updates THREE places:

A. Posting Queue (zdt-posting-queue.json)

{
  "posted": true,
  "media_id": "17939507331145396",
  "permalink": "https://www.instagram.com/reel/DVEaqwnE7KR/"
}

B. Posted Cache (zdt-posted-cache.json)

255 posts archived with full metadata:

  • Date, channel, platform, source URL
  • Caption, media ID, permalink
  • Used for duplicate detection across all past posts

C. Google Sheet (Video Queue tab)

  • Status column → "Posted"
  • Permalink column → Instagram URL
  • Syncs with the JSON files (sheet is secondary, JSON is source of truth)

Failsafe #12: If Google Sheets API fails (token expired, rate limit, etc.), the post still completes. Queue and cache are updated. Sheet sync happens on next successful run.

9. Error Handling & Recovery

Recoverable Errors (Retry with Backoff)

  • Rate limit exceeded → wait 2s, 4s, 8s
  • Service temporarily unavailable → retry 3 times
  • Network timeout → retry with longer timeout
  • Upload service down → try next service in fallback list

Fatal Errors (Stop, Alert, Don't Retry)

  • Invalid OAuth token → needs manual fix
  • Permissions revoked → account issue
  • User not found → IG account banned/deleted
  • Video violates IG content policy → skip this video, move to next

Failsafe #13: Agent distinguishes between recoverable and fatal errors. Doesn't waste time retrying when the problem needs human intervention.

Failed Post Recovery Queue

If all retries fail after 3 attempts over 3 hours:

  1. Agent saves post details to failed-posts.json
  2. Sends me a WhatsApp message with:
    • Video permalink (so I can review it)
    • Error logs
    • What it tried
  3. Tries again tomorrow at 8 AM before attempting the new daily post

Failsafe #14: Nothing gets lost. Every failed post gets queued for retry and I get notified.

10. Monitoring & Alerts

Daily Cron Status Report (8:30 AM CT)

Separate cron that runs 30 minutes after the posting cron. Checks:

  • Did the post go out? (Check IG API for today's post)
  • Any errors in the log?
  • Queue status (how many days left?)
  • Token expiry (when does it need manual refresh?)

Sends me a WhatsApp summary every morning:

✅ ZDT posted at 8:02 AM
📊 Queue: 14 days remaining
🔑 Token: 52 days until expiry

Failsafe #15: If the morning post failed, the 8:30 AM report tells me immediately. I can manually trigger a retry before noon.

Heartbeat Monitoring (Throughout the Day)

Agent checks queue status during heartbeat polls (every ~30 min):

  • If queue drops below 7 days → alert me to add content
  • If last post was >48 hours ago → something's wrong, alert me
  • If failed-posts.json has entries → remind me to review them

Failsafe #16: Passive monitoring catches problems I might miss if I don't check the 8:30 AM report.

The Results

Uptime since launch: 100% (21 consecutive days, zero missed posts)

Manual intervention required: ~5 minutes per week to:

  • Review and approve new content for the queue
  • Check the daily status reports

Time saved: ~2.5 hours per week (was spending 20-30 min/day manually)

Cost:

  • OpenClaw: $25-30/day (switched to Sonnet for non-critical tasks, was $48/day on Opus)
  • Vercel Blob: ~$0.60/month
  • IG Graph API: Free (Meta doesn't charge for publishing)

Total: ~$750-900/month for full automation

Is it worth it? Absolutely. The account generates ~$200-300/month in affiliate revenue (thermal scope links). But the real value is having a system I trust completely. I don't think about it anymore.

The Tech Stack

  • Agent: OpenClaw (self-hosted on Mac Mini)
  • Model: Claude Sonnet 4.5 (cron jobs), Opus 4 (complex tasks)
  • Hosting: Vercel Blob (temp file storage)
  • Secrets: 1Password (service account, "Ace" vault)
  • Scheduling: OpenClaw native cron (isolated sessions)
  • Monitoring: WhatsApp alerts + daily status reports
  • Code: Bash scripts + Python glue code
  • Video processing: ffmpeg + yt-dlp
  • Browser automation: OpenClaw browser (for IG private API)

Lessons Learned

1. Free services will let you down

Relying on 4 free temp file hosts seemed redundant until they ALL went down at once. Paid infrastructure (Vercel Blob) is worth the $0.60/month for reliability.

2. Double-post prevention is non-negotiable

I learned this the hard way when a retry loop posted the same video twice in one day. Now the guard runs twice per post attempt.

3. Token auto-refresh should happen proactively, not reactively

Don't wait for the token to expire. Refresh it every single day. Costs nothing and eliminates a failure mode.

4. Distinguish recoverable from fatal errors

Early versions would retry "Invalid OAuth token" errors 10 times before giving up. That's 5 minutes wasted when the problem needs manual intervention. Now fatal errors alert immediately.

5. The queue is the source of truth, not the Google Sheet

Initially I tried to keep the Sheet and JSON in perfect sync. Bad idea. The Sheet is for human viewing. The JSON is for the agent. Sheet sync can fail without breaking the system.

6. Monitoring matters as much as automation

The posting system is bulletproof, but I still need to know when something's wrong. Daily status reports + passive heartbeat checks catch edge cases.

7. Build in public, document everything

Writing this post forced me to review the entire system. I found 2 edge cases I hadn't thought about (what if the queue file is corrupted? what if the browser profile gets logged out?). Both now have failsafes.

What's Next?

Content sourcing automation: Right now I manually send videos to the agent. Next step: agent monitors 5-10 source channels for new uploads, filters for quality, and auto-adds to queue with my approval.

A/B testing captions: The agent writes captions in my brand voice, but I don't know if they perform better than my old manual captions. Could run experiments: half the posts get AI captions, half get my old style, track engagement.

Multi-account support: I have 2 other niche repost pages that could use this system. Should be easy to clone the scripts and point them at different IG accounts.

Sell it as a service: I'm already building "Agent Marketing Services" (productized consulting for business owners who want AI agents running their marketing). This Instagram automation could be one of the packages.

Questions I Get Asked

Q: Why not just use a scheduling tool like Buffer or Hootsuite?

A: They don't support Reels. And they can't download videos from other platforms, write captions in my voice, or handle multi-service upload fallbacks. This is a custom system built for my exact workflow.

Q: What if Instagram changes their API?

A: The Graph API is stable (v21.0 has been live for 6+ months with no breaking changes). But if it breaks, the agent alerts me immediately and I can switch to manual posting while I fix it.

Q: Can this get my account banned?

A: No. I'm using Instagram's official Graph API with a registered app. It's the same API that Buffer, Hootsuite, and every other scheduling tool uses. I'm not scraping, botting, or violating ToS.

Q: What about engagement (likes, comments, DMs)?

A: Still manual. The agent only handles posting. I respond to comments and DMs myself (takes 5-10 min/day). Could automate replies in the future but it feels less authentic.

Q: Why OpenClaw instead of Zapier/Make/n8n?

A: OpenClaw is an AI agent, not a workflow automation tool. It can make decisions, handle errors intelligently, and adapt when things go wrong. Zapier would just fail and send me an error email. OpenClaw retries, falls back, and messages me with context.

Final Thoughts

This isn't a "set it and forget it" system. It's a "set it and trust it" system.

I check the daily status report every morning. I review new content before it hits the queue. I keep an eye on engagement.

But I don't worry about it anymore. The system is bulletproof. When I wake up, the post is already live. When I travel, it keeps running. When free services go down, it routes around them.

That's the difference between automation and AI agents. Automation breaks. Agents adapt.


Want to build something similar?

I'm offering "done with you" setup for businesses that want AI agents running their marketing. This Instagram automation is part of the "Social Media Autopilot" package.

Learn more: raxdigital.com