Build a Daily Publishing Engine Using Reflect and Ghost

Why I Wanted Reflect Plus Ghost to Work

This whole setup started after three skipped newsletters and a very long walk where I kept thinking “Should I just use Notion again?” I was trying to publish daily, genuinely trying, using Ghost for the actual website and Reflect for writing. It should’ve worked. Reflect is honestly my favorite note app right now — fast, markdown-y where I want it to be, not markdown-y where I don’t, and the new linking engine doesn’t totally hijack my thoughts. I’ll be mind-dumping in Reflect anyway, so the idea was: clean up a highlight, tag it, and then have that auto-populate a draft in Ghost. Just enough automation to stay out of my way.

But two minutes into building it, the whole thing got weird. Zapier only kind of sees Reflect. Draft links kept vanishing. Ghost accepts markdown, but Reflect exports something in that uncanny valley between text and HTML. At some point, the Zap fired six times in a row, publishing broken copies of the same post. It felt like trying to plug a hairdryer into a soup.

Anyway, this is what I ended up doing and what didn’t work at all 😅

Setting the Trigger in Reflect Without Chaos

Reflect uses tags, not folders. That mattered more than I thought. My first idea was to say: “when I tag something #publish, zap it.” Simple, right? Turns out the Reflect-Zapier integration doesn’t support tag-based triggers. Like… at all. The only reliable trigger is “New or Updated Note.” That means Zaps will fire on literally every edit you make — even if you’re just fixing a comma.

So here’s the workaround I found:

1. Create a new page in Reflect specifically for publishing-ready notes. I called mine “Live Queue.”
2. Use the “New Note in Folder” Zap trigger (Reflect calls these folders, but they’re really just top-level notes).
3. Set your Zap to listen *only* to notes created inside that page.

Any time I finish writing something and want it published, I drag or paste it into Live Queue. This solves the tagging limitation without relying on unsupported triggers.

🐞 At one point, I tried using filters in Zapier to control this based on note content or metadata, but Reflect doesn’t expose any of that in the Zap. You can’t filter by tag, modified time, or even title reliably. So don’t bother — trigger on that one location and move on.

Dealing With Reflects Markdown Formatting Issues

This was a rabbit hole I didn’t want to crawl into, but here we are 🙃

Reflect lets you write in Markdown, but what Zapier pulls from Reflect is not clean Markdown. You’ll probably get weird line breaks, occasional junk HTML like
tags, and stress-inducing quote formatting that breaks your layout when moved into Ghost.

Here’s what worked best:

– Instead of using Zapier’s built-in content fields like “Note Body,” grab the “Markdown Export” version of the content. This shows up in the dropdown if you dig under Custom Value > Note > Markdown.
– Run a formatter step via Zapier’s Text action — use Replace to clean out any weird
tags or duplicate spaces.
– Pad the start and end of the exported note yourself. I ended up sandwiching each article with a triple dash — to delineate metadata when it gets to Ghost. That also helped when debugging — I could see exactly where my content actually started.

If you skip this, you’ll end up with smart quotes that get turned into those black diamonds with question marks 😵‍💫 or line breaks that break whole paragraphs just because Reflect interpreted a return differently.

Sending to Ghost Without Accidentally Publishing

The first time I pushed a test post into Ghost, it published instantly. No warning, no preview, just boom — live on my homepage, typos and all. That’s because Ghost’s API default is “publish” unless you explicitly set the status to “draft.” I learned that… after the fact.

To avoid this, here’s what I changed:

– In Zapier, use the Webhooks module, not the Ghost integration. The Ghost app in Zapier doesn’t let you customize post status.
– Set up a POST webhook to https://yourdomain.com/ghost/api/content/posts/ — but swap in your actual Ghost Admin API endpoint.
– In the body, send:

“`json
{
“posts”: [
{
“title”: “{{title_from_reflect}}”,
“markdown”: “{{cleaned_markdown}}”,
“status”: “draft”
}
]
}
“`

– Include the Admin API key in the header as Authorization: Ghost {{your_token}}

Once I did that, it stopped prematurely publishing half-written nonsense. The drafts started appearing exactly as expected, and from there I could go in and hit publish manually with the correct tags.

Auto Filling the Title Without Embarrassing Mistakes

Reflect doesn’t explicitly separate the title from the body. If the first line looks like a title, it kind of works, but if you accidentally start with anything else — a quote, a bullet, your grocery list — your Ghost draft ends up titled “Grocery eggs oatmilk.”

There are two ways around this:

1. **Force a consistent title format**: I now always write the first line in Reflect like this:

`# Title of the Thing`

If a note starts with a heading tag in Markdown, that translates cleanly into Ghost. Then in Zapier, I extract just that first line using a Formatter step → Text → Split at line breaks → Keep Line 1.

2. **Fallback title logic:** If for some reason someone (often me 😅) forgets to add the heading, I added a second formatter step that sets the title to “Untitled Draft from Reflect” if the extracted line is blank.

Sounds overkill, but after reading back two Ghost drafts titled “Hi” and “Hmm” — yeah. Not overkill.

Why Images and Links Still Break Almost Every Time

Short answer? Because neither Ghost nor Reflect handle media embedding in a friendly way when coming from midstream copy-paste automations.

If you include an image in Reflect, it’s technically uploaded to a private Reflect asset URL. But that link will throw a 403 error if you try to access it outside of the original session. So when you publish that into Ghost — broken image icon. Every time.

The only sustainable fix I found was to re-upload images manually in Ghost before publishing. I tried building a custom parser to download the image attachments, save them to Cloudinary, and replace links via regex… but about halfway through I remembered I’m still just one person trying to hit “publish once a day,” not build ZapierGPT for content sanitation.

As for links — Reflect sometimes grabs smart link previews that conflict with Ghost embeds. So I try really hard to never auto-paste a link preview. Just raw URLs or predictable Markdown links like:

`[Link text](https://domain.com)`

You do this wrong, and Ghost turns it into a card you didn’t ask for.

How I Organize Reflect So I Never Miss a Publish Day

Here’s the meta-structure that actually keeps this running. Nothing automated here — just personal rules I stick to that make this fragile system usable:

– **Inbox**: Everything starts here — random ideas, links, fragments, overheard quotes.
– **Draft**: When an idea becomes real, I move it here and add a title line.
– **Queue** (aka the Live Queue Reflect page): This is the trigger zone. Once here, it autosyncs to Ghost.
– **Published**: Manually archive this once I hit publish on Ghost.

This setup makes Reflect act like a writing pipeline: messy at the front, clean at the gate, logbook at the end.

I also started numbering entries like: `691 Some quick automation fail` so I don’t lose track when I reuse titles. That number becomes the slug for Ghost and makes internal links less confusing.

One Random Thing That Keeps Breaking for No Reason

Once a week, Reflect updates its internal sync and Zapier stops firing. No errors, no warnings. The webhook just… doesn’t trigger. Best guess: Reflect rate-limits something when you edit notes too quickly in succession.

My fix? Every morning, I open Zapier, turn the Zap off and on again. That’s it. Primitive fix, but effective. It’s the digital version of unplugging the router 😑

I added a checkbox item in my Reflect morning checklist: “Refresh Zapier connection.” Takes 10 seconds and prevents 3 hours of wondering why my post didn’t show up today.

I’ll eventually move this to Make or build a Ghost-native shortcut to write in iA Writer or something equally dramatic, but not today. Today the duct tape’s holding

Leave a Comment