Personalizing Push Notifications for Maximum Impact in Braze

Commuter on a train holding a phone showing two notification banners, with a cup and tote beside them, for personalised push notifications

To personalise push notifications in Braze, insert profile data with Liquid, give every attribute a default value, and write a conditional for each state a user can be in. Use abort_message() only when no acceptable message exists. Then preview as a user for each state before you send.

‍

Key Takeaways

  • Give every attribute a default value, because a missing field is blank in the message.
  • A default shows for empty values but not for blank ones, so a field that holds only a space slips past it.
  • Use abort_message() only when no acceptable message exists, because an else branch that aborts stops the send for every user without that data.
  • iOS push titles display as a single line, so apply the strip_newlines filter to Liquid output.
  • targeted_device values can be null for push, so add an else branch to device-specific copy.
  • Preview as a user for each state, and enable Override recipients' attributes on test sends when abort logic depends on profile data.

‍

How do you personalize push notifications in Braze?

Braze uses Liquid, a template language, to personalise messages. Each tag is replaced with data for that recipient before the push goes out, so one template can change its content based on a user's profile data, behaviour or language.

Inserting a first name takes one tag. The harder decisions are what the push says when the name is missing, and whether it should send at all. We build those two answers first and the clever copy last.

The mechanics below come from Braze documentation, which is linked in the sources. Where we add judgement of our own, the text says so.

‍

What data can you pull into a push message?

Standard attributes such as first name use the tag form {{${first_name}}}. Custom attributes need the custom_attribute namespace, as in {{custom_attribute.${reward_points}}}. Braze Connected Content can also insert information from an API into the message.

Push has one extra source. The targeted_device tags carry attributes of the device that receives the message, and they work for push, in-app messages and Banners but not for Content Cards or emails.

If a user has the app on several devices, Braze sends to all devices with a valid push token by default. Each send attempt uses the corresponding device identifier.

‍

How should you handle missing data in a push?

If you give no default and the field is missing or not set on the user, the field is blank in the message. A push that reads "Hi , your order is ready" looks like a mistake on a lock screen. The default filter fixes this: {{ ${first_name} | default: 'there' }}.

Braze's own example uses "Valued User" as the fallback. We prefer a default that reads as an ordinary greeting, because a short push with a formal placeholder reads like a mail merge.

Defaults have an edge. Braze documents that the default value shows for empty values but not for blank values, where a blank value holds whitespace and nothing else. An attribute set to a single space slips past the default, so test any field where whitespace is plausible.

When a default can't express the logic, use a conditional. Braze uses a rewards balance as the case where a default can't cover both low and null balances, and says conditional logic can abort for null or blank values.

Operators work in if, elsif and unless tags but filters don't, so assign a filtered value to a variable first. Braze also advises keeping a default on first name inside a conditional, so a customer doesn't see raw Liquid if something goes wrong.

Defaults and conditionals handle a gap after it appears. Where attributes are missing because customer records are split across systems, our customer data management service covers identity resolution, schema design and validation rules.

‍

When should a push abort instead of falling back?

The abort_message() tag, placed inside a conditional, stops a message going to a user. The aborted send won't appear on the user's profile or count toward deliveries or frequency capping. It shows in Messaging Observability with the outcome Liquid abort, and it is evaluated at send time.

We reserve abort for pushes where every fallback would be worse than silence. A push that states something untrue about someone's account is worse than no push. A greeting without a name is not.

The failure mode is a silent loss of reach. An else branch that aborts when a value is missing stops the send for every user without that data.

Braze names abort logic as a common cause when many users enter a campaign or Canvas step but few sends result. In a Canvas the user doesn't exit when a step aborts, and moves to the next step.

‍

Which push details can break personalised copy?

Each row below is a documented behaviour, with the check we run against it.

SituationWhat Braze documentsCheck we run
Message bodyPush messages must be formatted in plain textKeep Liquid output free of markup
iOS titleTitles display as a single line, so text after a line break may not show; apply the strip_newlines filterWrap title output in a capture and strip newlines
Image from Liquid or Connected ContentThe image URL must begin with https://; http:// will crash your appRead the rendered URL in preview
Device-specific copytargeted_device values can be null, for example when the push token was imported through APIAlways add an else branch
Personalisation tag inside single quotes in an assign tagStrings in single quotes are literal, so tags inside them are not interpolated; use variables or the append filterLook for raw braces in every preview
Message that renders to a single spaceA message containing only a single space is sent as a silent pushPreview each state for empty output

‍

We treat a push whose entire title comes from Liquid as high risk. If every attribute in it can be missing, the title can render as nothing, so we keep one fixed word in it. Braze recommends a unique name for any variable you create, since a name close to a supported tag such as language may affect your logic.

Liquid can pull consented information from a user's account. We keep anything sensitive out of a push body, because it lands on a device screen, and what you may insert depends on the consent you hold. This post doesn't settle that legal question.

‍

How do you test personalised push before it goes out?

Braze recommends testing all messages that use Liquid before sending, to reduce the risk of errors or unsupported Liquid. This sequence builds the safety net in the order we use it.

  1. Write the generic message first, one that reads correctly with no personal data.
  2. Add a default to every attribute you insert.
  3. Add a conditional for each state, with an else branch that holds the generic message.
  4. Add an abort only where no generic message is acceptable.
  5. Use Preview message as user for a random user, an existing user, a custom user or a multi-language user.
  6. For test sends where abort logic depends on profile data, enable Override recipients' attributes with current preview user's attributes.
  7. If the push uses Connected Content, open the Connected Content Debugger in Preview & Test to see each request and response.

‍

Remember that a cached result reflects an earlier response, not necessarily your endpoint's current state. Check the cache note in the debugger before you trust what a preview shows.

‍

What does a hypothetical streak reminder look like?

Take a hypothetical language-learning app that sends a daily reminder to protect a learning streak. This is an illustration. It isn't client work, and it uses no figures.

There are three states. A new learner has no streak recorded, a returning learner has a streak above zero, and a lapsed learner has a streak of zero.

The Liquid below is ours, built from the documented tags, and it needs a preview for each state before use. We check the blank branch first, because Braze says blank values should be checked before other variables.

{% if {{custom_attribute.${current_streak}}} == blank %}
Hi {{ ${first_name} | default: 'there' }}, your first lesson is ready.
{% elsif {{custom_attribute.${current_streak}}} > 0 %}
Hi {{ ${first_name} | default: 'there' }}, keep your {{custom_attribute.${current_streak}}}-day streak going.
{% else %}
Hi {{ ${first_name} | default: 'there' }}, pick up where you left off.
{% endif %}

‍

Nothing in this example aborts, because every state has an acceptable message. We would test two failure modes first.

One is a first name that holds only a space, which the default won't catch. The other is a streak of zero, since we haven't confirmed how it compares with blank and the preview is where to find out.

‍

How does this connect to the rest of the programme?

Good personalisation depends on the data behind it. Our guide to hyper-personalisation in Braze covers the wider approach. The post on using Braze Connected Content covers pulling in data from your own systems.

For other patterns, see seven ways to deliver dynamic content in Braze. Who should receive the push is covered in push notification segmentation. A specific push journey is in push notifications for onboarding completion, and language handling is in internationalising Braze campaigns.

Our case study on unifying fragmented customer profiles covers consolidating tier, language and consent data into one profile, which is the data personalised push draws on.

As a Braze implementation partner, CustomerIK recommends writing the fallback message before any personalised variant. A push that reads well with no data is the one that survives a missing attribute.

‍

Frequently Asked Questions
‍

1. Can I use Liquid in a push title?

Braze says you can include Liquid to make your push personalised and targeted. iOS titles display as a single line, so apply the strip_newlines filter when Liquid output could contain a line break.

2. What happens if an attribute is missing and I set no default?

The field is blank in the message. Add a default value with the default filter, or use a conditional to send a different message.

3. Does a default value cover an attribute that holds only a space?

It doesn't. Braze documents that the default value shows for empty values but not for blank values, so test fields where whitespace is possible.

4. What does abort_message() do to a push?

It stops the send for users who don't meet your condition. The message won't appear on their profile or count toward deliveries or frequency capping, and the outcome shows in Messaging Observability as Liquid abort.

5. How do I preview a personalised push?

Use Preview message as user in the composer, then enable Override recipients' attributes on test sends when abort logic depends on profile data. Braze recommends testing all messages that use Liquid before you send them.

‍

Sources

‍

CustomerIK is a Braze implementation partner working across onboarding, technical integration, marketing operations and customer data management.

If you are planning personalised push and want a second pair of eyes on fallbacks and abort logic, let's talk.

‍

Preferences

Privacy is important to us, so you have the option of disabling certain types of storage that may not be necessary for the basic functioning of the website. Blocking categories may impact your experience on the website.

Accept all cookies
Accept all cookies

These items are required to enable basic website functionality.

Always active

These items are used to deliver advertising that is more relevant to you and your interests.

These items allow the website to remember choices you make (such as your user name, language, or the region you are in) and provide enhanced, more personal features.

These items help the website operator understand how its website performs, how visitors interact with the site, and whether there may be technical issues.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.