Member webhooks

When exactly does Ghost's member-updated webhook fire?

Member webhooks
If you read nothing else, read this: The best way to debug webhooks is to send them over to, which nicely displays everything it receives for you. Highly recommended.

I asked ChatGPT to explain webhooks for me. Here's what it said:

So, imagine you've got two apps, like App A and App B, doing their thing. Now, let's say something important (an event) happens in App A, like a new purchase or a user signing up. Instead of App A constantly bothering App B with, "Hey, anything new?" messages, we've got webhooks to handle the communication.
Here's how it works: When something noteworthy (an event) happens in App A, it shoots a quick message (a webhook payload) over to a special URL in App B. Think of it like sending a formal letter announcing the news.
App B knows exactly what to do when it gets this message. It's like having a secret code between the two apps.
You can set up webhooks to handle all sorts of tasks, like updating data or triggering actions. It's like having your own little team of automated assistants taking care of business quietly in the background. Pretty handy, right?

Yes, I asked it for something a little less formal. I think it got a bit carried away. The rest of this post is all me, typos included!

So with that background, let's talk about webhooks in Ghost. Ghost lets you control what events to send webhook payloads for, and what URL to send those payloads to. It doesn't let you control what's actually in the webhook payload. Generally, the sites receiving webhooks have opinions about what payloads they receive. The discrepancies between the two tend to require some translating glue, like a cloud function, or Zapier, or Make, or Integromat, or.... So yeah, the third paragraph ChatGPT wrote is mighty optimistic. But having said that, webhooks are the best way to accomplish many commonly-requested additions to Ghost, including (but definitely not limited to):

  • Take a payment through another provider besides Stripe and create a member (or add a complimentary subscription) in Ghost
  • Use a more full-featured sign-up form and then create the member in Ghost
  • Send new users an email drip
  • Update Algolia's full text search whenever a post is added of modified
  • Publicize your new posts on social media
  • Email a post through some provider other than Mailgun.

One of the webhook events Ghost supports is the "member-updated" event. I couldn’t find exactly what triggers it documented, so I’ve dropped my test results below while trying to debug a client’s member-updated webhook behavior.

Actions that produce a fire of the member-updated webhook:

  • Creating a new paying user (three fires, actually)
  • Unsubscribing or subscribing to a newsletter
  • Moving between tiers
  • Comping a member to a paid tier/removing the comp subscription
  • Adding/removing a newsletter subscription using the admin panel

Actions that do not trigger the member-updated webhook:

  • Cancelling a paying subscription (at least, not immediately). It should fire when the subscription cancellation date arrives, although I haven't tested this yet.
  • Changing a user between yearly/monthly on the same tier
  • Switching from pending cancellation to will renew.
  • Adding a new member manually in the admin panel (even though they’re getting a newsletter subscription). This triggers the member-added webhook instead.
  • Importing a member via csv upload (even if adding subscriptions or a Stripe subscriber ID)

Super important discovery: Importing a CSV file does NOT seem to trigger the member-added webhook, nor the member-updated webhook. If you are counting on the member-added webhook to fire when you import some members, you're going to be unhappy. [Why you might want to import Ghost members via CSV in the first place is the topic of another post, but yes, you might want to....]