What tagging and classification actually mean in Ghost
Ok so first, Ghost has this whole thing where posts can have tags and authors and are sorted by collections and routes. Sounds clean and simple. Until you try to actually automate it.
Tags are split into two types in Ghost — regular tags (just called tags) and internal tags, which are the ones that start with a # and don’t show up in your post metadata on the front end. You can use these to filter on collections or do fancy logic in the theme. But also… they don’t always work the way you expect when added via automation. 😐
When I started trying to use GPT to automatically add tags for me, I just wanted a way to label blog drafts quickly. Like, if I dump five half-written posts into Ghost in a rush (totally not my morning today), I don’t have time to sit down and properly tag each one. I wanted GPT to read the content, figure out if it was about Zapier, Make, Airtable vs Notion, etc — and apply the right labels so I can filter what’s worth finishing.
Simple enough in theory. But Ghost’s admin API doesn’t quite give you built-in magic for content classification. You actually have to do some pre-processing yourself and then feed the tags in along with a PATCH or PUT request. And if you send the wrong format (like using IDs instead of names accidentally), Ghost just silently ignores it. No error. No warning. It just… doesn’t tag. 😐
Setting up a Zap to run GPT on blog content
Here’s the Zap I built the first time:
– New row in a Google Sheet (which I use as a dumb inbox for post drafts)
– Get content from the row or the linked doc
– Use OpenAI in Zapier to summarize and suggest 1–3 tags
– Format those tags as an array of strings
– Update the post in Ghost using Zapier’s custom webhook with the tags
Getting the outputs from GPT to work in a way Ghost accepted wasn’t straightforward. GPT loves to give styled lists like:
“Suggested tags:\n- Automation\n- Airtable\n- Productivity”
But Ghost wants just the array: `[“Automation”,”Airtable”,”Productivity”]`
So I had to clean that with a formatter step in the Zap: text parser to remove line breaks and dashes, then a code step to build proper JSON. It felt like overkill for something this small. ¯\_(ツ)_/¯
Also had to double-check every time that the post ID from Ghost matched the one I thought I was editing. If you create posts via the Admin API from Zapier, they can get weird default IDs and sometimes fetch-as-draft fails. Better to create the post manually first, then update it via Zap.
Handling internal tags and filtering logic
Here’s where things got annoying: I use internal tags in my Ghost theme to filter certain categories into the homepage feed differently. For example, posts with #workflow go into their own section. GPT doesn’t know about my tags. So I needed it to sometimes apply internal tags like #tooling or #bugreport instead of just plain “Airtable.”
But if you just write `”#workflow”` in the tag list, Ghost sometimes accepts it, sometimes not. I seriously don’t know what makes it fail — I suspect it’s about whether the internal tag already existed in your system. If not, adding it via the API just silently doesn’t do anything. 🙂
Fix was to pre-create all my internal tags manually once in the Ghost Admin. Then using them in API calls seemed to actually apply them. I did a dumb test where I tried adding “#madeupinternaltag” — nothing happened. Then created that tag in Ghost, ran the same Zap again, and bam — it stuck.
Moral of the story: pre-register your internal tags if you want automation to actually use them.
What I tried when Ghost stopped saving tags
At one point, my GPT tagging Zap was running fine for like a week, then… stopped applying any tags. Exact same payload, same formatting. Posts updated normally, tags didn’t change. After a very unfun hour of debugging, I found this:
Turns out if you send tags as part of a PATCH request but your Zap accidentally includes the “tags”: null field somewhere (which Zapier sometimes does if the field is blank), Ghost refuses to overwrite tags. You have to *not* include the tags field at all if you’re not actively replacing them.
However, in my case, GPT *was* returning tags, but the formatting fell apart because I moved to a multi-line output and forgot to clean it. Literally just changing the quotation marks fixed it. Text parser step again. 😛
Also: Ghost doesn’t merge tags from your input. It replaces them entirely. So if your post already had “Notion” and you only send “Airtable,” now it just has one — “Airtable.” So beware of overwrites. I now fetch the existing tags in Ghost first, then merge them with GPT’s output before sending the update *unless* I want to clean-sweep.
Temporarily using Google Sheets to debug tags
To figure out which posts were getting the wrong tags or no tags at all, I made a quick table like this in Google Sheets:
| Post Title | GPT Tags Output | Cleaned Tag JSON | Ghost Tags Result |
|————|——————|——————|——————|
| Airtable Form Automations | Automation, Form, Airtable | [“Automation”,”Form”,”Airtable”] | 🟢 Applied |
| Broken Webhook Madness | #bugreport, #zapier | [“#bugreport”,”#zapier”] | ❌ Not applied |
| Advanced Notion Filters | Notion, Views | [“Notion”,”Views”] | 🟢 Applied |
Then I’d run the Zap, wait a second, refresh Ghost, and check which tags actually showed up. It was low-tech but helpful. I found that internal tags were the ones most likely to fail unless they already existed — again confirming the earlier behavior. Normal tags were mostly fine once the JSON cleaned up.
Why I still don’t trust my own automation
Even after getting it to work reliably (for now…), I still do spot-checks. GPT sometimes attaches tags that feel abstract (“Time Management”) when I’d rather it just said “Notion Templates.” Or it mixes up general topics vs actual software names. Like tagging something as “Forms” when it was literally about Google Forms.
Also, Ghost itself isn’t transparent here. Tags don’t log changes. You won’t see an activity log like “This tag was added by an API call at 10 AM.” So if your Zap quietly fails or overwrites something wrong, there’s no paper trail.
I added a second sheet where I log every predicted tag, cleaned tag array, and published URL (post gets tagged after publish). It’s still manual to diagnose, but better than discovering broken tag filters a month later.
The tagging script I now run with ChatGPT
The newest version of this workflow doesn’t rely on Zapier anymore. I paste my draft blog text into ChatGPT and run this prompt:
> Based on the content below, what are 3–5 tags I should apply in Ghost CMS? Use both primary and internal-type tags. Suggested tags must be formatted as a JSON array of strings. Internal tags start with a # in Ghost.
GPT then gives me something like:
[“Ghost”,”#meta”,”Automation”,”#workflow”]
I copy that into my post settings manually, or submit it through a curl call if I’m feeling fancy. Occasionally I tweak the list myself. This setup adds friction, sure — but I caught too many issues with batch automation and trust my manual brain more than Zaps now 🙂
It’s dumb, but it works. At least until I break it again
What to do if Zapier keeps overwriting tag updates
Final problem I ran into: when trying to make tag classification part of my publish flow (automatically tagging just before posting), the Zap would overwrite any manual tags I added an hour before. 🙃
That’s because I didn’t pull in newly added tags — my Zap was using old data. Even though Ghost was saving the tags right, Zapier’s trigger step was caching the outdated info.
Fix was to swap from “New Post in Ghost” to “New Row in Sheet” as the trigger, and then query the post live using Ghost’s API just before sending updates. That way I merge tags correctly.
Also had to add a delay step in Zapier so that edits could finish saving before tags were pushed. Without the delay, publishing and tagging competed with each other, and sometimes the tag update won… over the actual post content. 🤷
Still not sure if I trust those magic AI tags
When this all works, it’s beautiful. A blog post drops into the system, AI suggests clean relevant tags, Ghost updates itself, and I don’t touch anything. But when it glitches, debugging takes longer than just tagging the post by hand.
And yes, I could be using something like ghost.org to manage more centralized tagging rules, but for personal or small ops? It’s usually simpler just to fix things manually, tag your high-value posts deliberately, and let GPT help for drafts only.
I still use GPT to quickly brainstorm tags when I’m blanking. But at the end of the day, I always read them myself before publishing — because otherwise I’ll end up with internal tags like #blog and external ones like “Stuff I Should Edit Later.” 🤦