How I Automated Instagram Direct Publishing (Without Paying for a Scheduler)

How I Automated Instagram Direct Publishing
Manual posting is a soul-crushing bottleneck. I spent hours fighting Meta's documentation just to get a single image to post from my CLI. I finally got it working.
> TL;DR: Meta's API is a nightmare. Expiring tokens, hidden settings, and vague error messages will kill your momentum. This guide covers the exact settings I used to bypass the "Invalid Platform" errors and set up a reliable "Swiss Style" carousel generator.
What it actually looks like
I moved away from generic Canva templates because they look like "AI slop." I wanted something bold, readable, and editorial. Here is the actual output generated by the script:

---
The Stack (The "Good Enough" Version)
- Next.js (Edge Runtime): To generate the 1080x1080 cards.
- Puppeteer: To take the screenshots.
- Cloudinary: A staging hack. Instagram needs a public URL to "pull" the image, so I use Cloudinary as a 30-second host.
- Meta Graph API: The final boss.
---
Critical Config: The "Invalid Platform" Trap
If you see "Invalid platform app" in the login popup, you're missing a hidden redirect setting.
1. Go to Facebook Login > Settings (or Instagram Graph API > Settings).
2. Find "Valid OAuth Redirect URIs".
3. Add your site URL here (e.g., https://realaiexamples.com/).
4. Without this, Meta blocks the handshake. No error message, just a broken popup.
---
The Token Guide: User vs. Page
This is where I wasted the most time.
- User Token (IGAF...): Good for reading data, but cannot publish.
- Page Access Token (EAA...): This is the one you need.
The Workflow:
1. Generate a User Token with instagram_content_publish and pages_show_list.
2. Use the "User or Page" dropdown to switch to your Facebook Page.
3. This generates the EAA... token. Copy it.
---
Design System: The "Swiss" CSS
I kept it simple: Off-white background, massive black text, and a single accent bar. It’s built to be read on a small phone screen while scrolling fast.
```css
body {
margin: 0; padding: 100px; width: 1080px; height: 1080px;
background-color: #F5F5F0;
font-family: 'Inter', sans-serif;
display: flex; flex-direction: column; justify-content: center;
border-top: 30px solid #F04E30; /* International Orange */
}
.title {
font-size: 150px; font-weight: 900; line-height: 0.85; letter-spacing: -0.06em;
}
```
---
Step 5: The Implementation
1. Screenshot: Puppeteer hits a local URL and captures the card.
2. Upload: Push to Cloudinary.
3. Container: Post to /media to create an Instagram "item."
4. Publish: Post to /media_publish to make it live.
---
Conclusion
It's not perfect, but it works. Direct publishing from the CLI is way faster than using a scheduler, and it lets me scale my "build-in-public" without spending 20 minutes on a phone every morning.
Now, adding a new blueprint to the site is just one command away from being an Instagram carousel.
Useful Tools: