Email Personalization in Ghost

Jannis Fedoruk-Betschki
Jannis Fedoruk-Betschki
5 min read

Today I woke up to a post on the Ghost forum that piqued my interest:

Can you insert Member ID’s into newsletters
We have a need to send out a combination of static content and then per-member customized content. We know how to do this on the website using some JS and cookies and modifying themes but we don’t know how to make this work in the newsletters themselves due to a seeming lack of ability to insert system variables. Note that we’re hosted currently with Ghost Pro and would like to avoid moving the site so that we could hack it to make it do what we need for it to do. That’s just more work for no…

Can you insert a member's ID into emails that are sent by Ghost? Should be easy, right?

Most people using Ghost's newsletter feature have probably used an email card. That's the nifty little tool that lets you add email-specific content that won't show up when the post is rendered in a browser:

A screenshot of the email card from the Ghost editor showing "Hey `{first_name, "there"}" as content.

This email card introduces the concept of email personalization. You can address your subscriber by their first name – and if that's not available, it falls back to saying "Hey there". Cool!

When I read the post from the Ghost forum, I wanted to link to some sort of documentation that Ghost has published. Yet, there is none. The email personalization is kind of a black hole.

There are a few old threads on the forum, each diving into one personalization option or another – or "merge tags", as they're sometimes called. But there's no comprehensive list.

So, uhh...here you go. A little bit of a deep dive into Ghost's email personalization.

How Does Ghost's Email Personalization Work?

When you're writing in an email card, you use simple curly braces with certain keywords:

{property_name}

For each of these, you can also add a fallback value, in case the property you're trying to display isn't available (e.g., the member hasn't added a name):

{property_name, "fallback text"}

Behind the scenes, Ghost converts these and merges them with actual member data..

The entire code responsible for this is in the EmailRenderer.js:

Ghost/ghost/core/core/server/services/email-service/EmailRenderer.js at 31119e81d126f685f75a92848eb54eee0aef7228 · TryGhost/Ghost
Independent technology for modern publishing, memberships, subscriptions and newsletters. - TryGhost/Ghost

And these are the personalizations that are available:

Personal Information

  • {first_name} - Just the first name (extracts from full name)
  • {name} - Full name
  • {email} - Email address

Member Status & Subscription

  • {status} - Shows: free, paid, complimentary, or trialing
  • {status_text} - Human-readable status with dates like "Your subscription will renew on August 15, 2025"
  • {created_at} - When they became a member

Account Management

  • {unsubscribe_url} - Unsubscribe link
  • {manage_account_url} - Link to account portal

Technical Helpers

  • {key} - Validation key for secure operations
  • {name_class} - CSS helper (returns "hidden" if no name provided)

Getting The Member ID Into An Email

There's one gotcha. If you've read the EmailRenderer.js, you might have spotted that there's also a uuid property in there. For the initial question on the Ghost forum that started this quest for me, this would have been all they needed.

But...it's not that easy. The EmailRenderer.js has this comment:

// We don't allow the usage of the %%{uuid}%% replacement in the email body 
// (only in links and special cases)
html = html.replace(/%%{uuid}%%/g, '{uuid}');

Why? Security. Member UUIDs are sensitive identifiers that Ghost only uses internally for tracking links and unsubscribe URLs.

Quick update: Cathy correctly pointed out that the uuid is actually exposed in Ghost's comments. So uhh...make of that what you want 🙃

However, if you try to use {uuid} in your email content, it'll just show up as literal text {uuid}.

Bummer.

And while we're at it...

Email Cards Only

Yes, personalizations only work in email cards. It kinda makes sense. But it's also quite a big limitation. You can't use them in HTML cards to render something like <img> tags.

And well, email cards themselves cannot render images or HTML at all. They are just...text. Again, this makes sense, since emails should be able to render in both HTML and plain text.

So, that defeats the solution the original poster from the forum set out to implement.

What you can do, however, is adding links in there. Most email clients would make these clickable. This way, you could generate unique links that lead to some sort of dashboard.

Option 1: Use Email Address

This is probably your best bet because email addresses are unique per member. They're always available and stay up to date. Inside an email card you could add:

Your personalized content:
https://example.com/content?member={email}

Option 2: Use the Validation Key as a Unique Identifier

While you can't reverse the key to get the UUID, you can use it as a unique identifier on its own. Each member gets a unique key that's consistent. You could store a mapping of key -> member preferences on your custom server, though you'd first need to calculate all the keys.

Your personalized content:
https://example.com/content?key={key}

Option 3: Get Creative With Multiple Parameters

You could even combine multiple member attributes for more sophisticated personalization:

Your personalized content:
https://example.com/content?member={email}&status={status}&joined={created_at}

What Doesn't Work

Here's what I tried that doesn't work, so you don't have to:

❌ HTML Cards

<!-- This stays as literal text -->
<img src="https://example.com/content?user={email}">
<p>Hello {first_name}</p>

❌ Pasted Images

Images (and image URLs) pasted directly into Ghost become static HTML and can't use personalizations.

❌ Using %%{property}%% Directly

Even if you try to use Ghost's internal %%{property}%% format, it won't work in anything except email cards.

The bottom line: Only email cards process personalizations. Everything else treats them as literal text 🙃


I came to realize that Ghost's email personalization system is more limited than you might expect, but also more powerful within those limits. The email-cards-only restriction is a significant gotcha, but hey...developers love to be creative with constraints, right? 😄

Share:
Jannis Fedoruk-Betschki

About Jannis Fedoruk-Betschki

I'm the founder of Magic Pages, providing managed Ghost hosting that makes it easy to focus on your content instead of technical details.

You might also like

Customer Showcase

Websites powered by Magic Pages

See what real publishers have built with Ghost CMS and Magic Pages hosting.

Start Your 14-Day Free Trial

No credit card required • Set up in minutes