Notion + Instagram: captions ready, posts publish
You write a solid post idea, then it disappears into a messy loop of rewrites, “final-final” drafts, and last-minute caption tweaks right before you publish. The worst part is the context switching. It drains your creative energy fast.
This hits social media managers first, because they’re the ones chasing approvals and formatting copy for every platform. But small business owners feel it too, and so do consultants running their own content. This Notion Instagram automation turns one raw idea into organized drafts and an Instagram post that can publish automatically.
Below, you’ll see how the workflow moves from a single webhook message to Notion storage, AI-written captions, and finally an Instagram publish (with an image URL that won’t break).
How This Automation Works
The full n8n workflow, from trigger to final output:
n8n Workflow Template: Notion + Instagram: captions ready, posts publish
flowchart LR
subgraph sg0["Instagram Caption Ge Flow"]
direction LR
n0["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>Webhook"]
n1["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/notion.dark.svg' width='40' height='40' /></div><br/>Notion Page Create"]
n2@{ icon: "mdi:robot", form: "rounded", label: "Instagram Caption Generate", pos: "b", h: 48 }
n3["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/notion.dark.svg' width='40' height='40' /></div><br/>Instagram Caption Save"]
n4@{ icon: "mdi:robot", form: "rounded", label: "Threads Caption Generate", pos: "b", h: 48 }
n5["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/notion.dark.svg' width='40' height='40' /></div><br/>Threads Caption Save"]
n6@{ icon: "mdi:robot", form: "rounded", label: "X Caption Generate", pos: "b", h: 48 }
n7["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/notion.dark.svg' width='40' height='40' /></div><br/>X Caption Save"]
n8@{ icon: "mdi:robot", form: "rounded", label: "Blog Draft Generate", pos: "b", h: 48 }
n9["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/notion.dark.svg' width='40' height='40' /></div><br/>Blog Draft Save"]
n10["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Upload to Cloudinary"]
n11["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Instagram Media Container"]
n12["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Instagram Publish"]
n0 --> n1
n7 --> n8
n9 --> n10
n1 --> n2
n6 --> n7
n8 --> n9
n5 --> n6
n10 --> n11
n3 --> n4
n4 --> n5
n11 --> n12
n2 --> n3
end
%% Styling
classDef trigger fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef ai fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef aiModel fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
classDef decision fill:#fff8e1,stroke:#f9a825,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef disabled stroke-dasharray: 5 5,opacity: 0.5
class n2,n4,n6,n8 ai
class n1,n3,n5,n7,n9 database
class n0,n10,n11,n12 api
classDef customIcon fill:none,stroke:none
class n0,n1,n3,n5,n7,n9,n10,n11,n12 customIcon
The Problem: Captions Get Rewritten, Lost, and Posted Late
Posting “consistently” sounds simple until you’re juggling idea capture, approvals, caption writing, image sourcing, and the actual publishing step. Most teams start in a notes app, move to a doc for edits, paste into Notion (or a spreadsheet), then copy again into Instagram. Somewhere in there, captions get tweaked without being saved back to the source. A week later, you can’t find what worked. Or worse, you publish the wrong version because the latest draft is buried in Slack.
The friction compounds. Here’s where it breaks down.
- One post idea can turn into 30 minutes of copy-paste and “where’s the latest?” messages.
- Captions written for Instagram don’t translate cleanly to Threads or X, which means more rewriting than you expected.
- If your drafts aren’t stored in one place, you can’t reuse winners or build a content library over time.
- Manual Instagram publishing often slips to “later,” and later becomes never.
The Solution: One Input, Notion Storage, Instagram Auto-Publish
This workflow starts with a single piece of raw text sent to a webhook (for example, from a chat tool or simple form). n8n immediately creates a new entry in your Notion database, so the idea is captured and searchable from the start. Then GPT-4 generates captions tailored to each platform: Instagram first (because it’s the one you want ready-to-publish), then Threads, X/Twitter, and even a longer blog draft. Those drafts are written back into Notion fields so your team can review them in the place you already use for content planning. Finally, the workflow fetches a relevant image from an external source, uploads it to Cloudinary for a clean hosted URL, and uses the Instagram Graph API to publish the post automatically with the generated caption.
The workflow begins when the webhook receives your idea. AI produces platform-specific copy and stores each version in Notion. Once the image is hosted through Cloudinary, Instagram publishing runs end-to-end via the Graph API.
What You Get: Automation vs. Results
| What This Workflow Automates | Results You’ll Get |
|---|---|
|
|
Example: What This Looks Like
Say you publish 5 Instagram posts a week and you also want Threads and X drafts ready for review. Manually, a typical flow is 10 minutes to clean up the idea, 15 minutes to write and tweak a caption, 10 minutes to format variants for other platforms, plus another 10 minutes to find an image and publish. That’s roughly 45 minutes per post, or close to 4 hours a week. With this workflow, you drop the raw text in once (a minute), then wait for the captions and publishing to finish. Your team reviews in Notion, and Instagram can go out automatically.
What You’ll Need
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- Notion for storing ideas and caption drafts
- Cloudinary to host images with stable URLs
- OpenAI (GPT-4) to generate platform-specific captions
- Instagram Graph API access token (get it from your Meta Developer app)
Skill level: Intermediate. You’ll mostly connect accounts and match Notion properties, but the Instagram token and permissions need careful setup.
Don’t want to set this up yourself? Talk to an automation expert (free 15-minute consultation).
How It Works
A webhook captures your raw idea. You send text from a bot, a lightweight form, or any system that can hit a webhook URL. n8n receives it instantly, so you’re not relying on someone to “remember to log it.”
Notion becomes the source of truth. The workflow creates a Notion database entry, then keeps updating the same record as new captions are generated. That single page becomes the place where drafts live, edits happen, and approvals are tracked.
GPT-4 writes captions for multiple platforms. Instagram copy is generated and saved first, then the workflow produces Threads text, X/Twitter copy, and a blog draft. Each one is written back to a dedicated Notion property, which keeps things organized even if you only publish some of them.
Images are fetched, hosted, and published to Instagram. The workflow pulls a relevant image (often a book cover or similar visual), uploads it to Cloudinary, then uses the Instagram Graph API to create a media container and publish the post with the stored Instagram caption.
You can easily modify the caption prompts to match your brand voice based on your needs. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Webhook Trigger
Set up the incoming endpoint that starts the workflow and captures the text payload used throughout the automation.
- Add and open Incoming Webhook Trigger.
- Set Path to
line-book-output. - Set HTTP Method to
POST. - Set Response Mode to
=onReceived. - Save the workflow to generate the webhook test URL.
body.events[0].message.text so the downstream Notion title expression resolves correctly.Step 2: Connect Notion and Create the Base Record
Create a Notion database page that will hold all generated captions and drafts, and reuse it for all updates.
- Add Create Notion Entry and set Resource to
databasePage. - Set Database ID to
[YOUR_ID]. - In Properties, set Title|title to
={{ $json.body.events[0].message.text }}. - Connect Create Notion Entry after Incoming Webhook Trigger.
- Credential Required: Connect your Notion credentials (required for Create Notion Entry and all Notion update nodes).
{{ $('Create Notion Entry').item.json.url }}. If the initial page creation fails, every subsequent update will fail too.Step 3: Set Up AI Caption and Draft Generation
Configure the OpenAI-powered nodes to generate Instagram, Threads, X, and blog content in sequence.
- Configure Generate IG Caption with Model set to
chatgpt-4o-latestand message=Summarize for Instagram (<=1000 chars, include hashtags): {{ $json.name }}. - Configure Produce Threads Caption with message
=Summarize for Threads (<=500 chars, include hashtags): {{ $json.name }}. - Configure Create X Copy with message
=Summarize for X/Twitter (<=280 chars, include hashtags): {{ $json.name }}. - Configure Generate Blog Draft with message
=Rewrite into blog article (<=1800 chars, include Title, TOC, Body): {{ $json.name }}. - Ensure the execution order follows the flow: Create Notion Entry → Generate IG Caption → Save IG Caption → Produce Threads Caption → Store Threads Caption → Create X Copy → Save X Copy → Generate Blog Draft.
- Credential Required: Connect your OpenAI credentials (required for Generate IG Caption, Produce Threads Caption, Create X Copy, and Generate Blog Draft).
Step 4: Configure Notion Update Outputs
Save each AI-generated output back into the same Notion page for centralized tracking.
- In Save IG Caption, set Page ID to
={{ $('Create Notion Entry').item.json.url }}and Instagram Caption|rich_text to={{ $json.message.content }}. - In Store Threads Caption, set Page ID to
={{ $('Create Notion Entry').item.json.url }}and Threads Caption|rich_text to={{ $json.message.content }}. - In Save X Copy, set Page ID to
={{ $('Create Notion Entry').item.json.url }}and X Caption|rich_text to={{ $json.message.content }}. - In Store Blog Draft, set Page ID to
={{ $('Create Notion Entry').item.json.url }}and Blog Draft|rich_text to={{ $json.message.content }}. - Connect the flow from Generate Blog Draft → Store Blog Draft so the draft is persisted before media publishing begins.
- Credential Required: Connect your Notion credentials (applies to all Notion update nodes).
Instagram Caption, Threads Caption, X Caption, and Blog Draft with rich_text types.Step 5: Upload Image and Publish to Instagram
Upload the image asset, build the Instagram media container, then publish the post using the generated caption.
- Configure Upload Image Asset with URL
https://api.cloudinary.com/v1_1/[YOUR_ID]/image/uploadand MethodPOST. - In Upload Image Asset body parameters, set file to binary field
data1, folder toig/books, public_id to=ig_books_{{ $json.isbn13 || Date.now() }}_cover, and upload_preset to[YOUR_ID]. - Configure Build IG Media with URL
https://graph.facebook.com/v23.0/[YOUR_ID]/mediaand query parameters: access_token={{$env.IG_ACCESS_TOKEN}}, image_url={{$('Upload Image Asset').item.json.secure_url}}, and caption={{ $('Save IG Caption').item.json["Instagram Caption|rich_text"][0].plain_text }}. - Configure Publish IG Post with URL
https://graph.facebook.com/v23.0/[YOUR_ID]/media_publishand query parameters: creation_id={{ $('Build IG Media').item.json.id }}and access_token={{$env.IG_ACCESS_TOKEN}}. - Ensure the flow continues Store Blog Draft → Upload Image Asset → Build IG Media → Publish IG Post.
- Credential Required: Add credentials as required by your Cloudinary and Meta Graph API setup (these HTTP Request nodes do not include built-in credential fields).
IG_ACCESS_TOKEN must be defined as an environment variable in n8n, and the Meta app must have permissions to publish media.Step 6: Test and Activate Your Workflow
Validate the end-to-end flow, confirm Notion updates, and verify the Instagram post is published.
- Click Execute Workflow and send a POST request to the Incoming Webhook Trigger test URL with a sample payload.
- Confirm a new Notion page is created and that Save IG Caption, Store Threads Caption, Save X Copy, and Store Blog Draft populate the expected properties.
- Verify Upload Image Asset returns a
secure_urland Build IG Media returns anid. - Check that Publish IG Post completes successfully and the post appears on Instagram.
- Turn on the workflow by toggling Active after tests pass.
Common Gotchas
- Notion credentials can expire or lack access to the database. If things break, check your n8n Notion connection and confirm the integration is shared with the right Notion workspace and database.
- If you’re using Wait nodes or external rendering, processing times vary. Bump up the wait duration if downstream nodes fail on empty responses.
- Cloudinary uploads fail quietly when the upload preset or cloud name is wrong. Double-check those values in the HTTP Request node before you blame the Instagram step.
Frequently Asked Questions
About 60–90 minutes if your Notion database and Instagram access are already in place.
No. You’ll connect accounts and paste a few IDs and keys into n8n.
Yes. n8n has a free self-hosted option and a free trial on n8n Cloud. Cloud plans start at $20/month for higher volume. You’ll also need to factor in OpenAI API usage and Cloudinary storage/bandwidth costs.
Two options: n8n Cloud (managed, easiest setup) or self-hosting on a VPS. For self-hosting, Hostinger VPS is affordable and handles n8n well. Self-hosting gives you unlimited executions but requires basic server management.
Yes, and you should. Update the prompt text inside the “Generate IG Caption” node (and the Threads/X/Blog generation nodes too) to include your tone, banned phrases, emoji rules, and hashtag style. Many teams also add a short “brand rules” field in Notion, then merge it into the prompt so every caption follows the same playbook. If you want approval before publishing, insert an If node after “Save IG Caption” that only continues to publishing when a Notion “Approved” checkbox is true.
Most of the time it’s an expired access token or missing permissions for the Instagram Business account in your Meta app. Regenerate the token, confirm the account is connected correctly, and update the IG_ACCESS_TOKEN environment variable in n8n. If the “Build IG Media” call succeeds but “Publish IG Post” fails, it can also be a media/container status issue or an image URL problem. Cloudinary URLs fix that more often than you’d think, honestly.
If you self-host n8n, there’s no hard execution limit (it depends on your server). On n8n Cloud, capacity depends on your plan and how often you run the workflow, but most small teams can handle daily posting without thinking about it.
Often, yes, because this is more than a simple 2-step zap. You’re generating multiple drafts, writing back into Notion several times, and calling the Instagram Graph API in sequence, which benefits from branching and tighter control. n8n also gives you the option to self-host, which is handy when you start running higher volume. Zapier or Make can still work, but complex Instagram publishing and multi-step AI flows tend to get fiddly and pricey. If you want help choosing, Talk to an automation expert.
Once this is running, your ideas stop getting lost and your drafts stop splintering across tools. Set it up, feed it one good input at a time, and let the workflow handle the repeatable parts.
Need Help Setting This Up?
Our automation experts can build and customize this workflow for your specific needs. Free 15-minute consultation—no commitment required.