Notification templates
Reusable push copy with variables.
#What a notification template is
A notification template is a single push title + body pair drawn from a curated corpus of real push notifications documented from growth-stage apps. Templates give you a starting point — tested copy patterns you can adapt to your brand — without writing from scratch.
The corpus contains 180 entries spanning habit-forming, win-back, trial conversion, social, and transactional patterns. Each entry carries attribution (the real app it was documented from), a verbatim flag, and links to the public sources used to verify the copy.
#Categories
Templates are organised into ten categories:
| Category | What it covers |
|---|---|
| habit | Daily reminders and routine-building nudges. |
| streak | Streak protection, milestone celebration, and loss-aversion warnings. |
| winback | Re-engagement after extended inactivity — escalating emotional tone. |
| reactivation | Return prompts for recently lapsed users (shorter lapse than win-back). |
| trial | Trial start, midpoint, expiry warning, and post-expiry upgrade prompts. |
| promo | Time-limited offers, discount codes, and event-based promotions. |
| social | Friend activity, kudos, league standings, and community events. |
| progress | Milestone completions, goal achievements, and metric summaries. |
| transactional | Confirmations, payment receipts, and status updates. |
| onboarding | First-session, feature discovery, and account setup prompts. |
#Variables and personalisation
Notification title and body text can contain personalisation tokens. The flow engine resolves them against the receiving user's stored attributes at send time — not at flow-activation time. Any attribute name you have written via the SDK or the HTTP API is valid.
| Syntax | Meaning |
|---|---|
{{ name }} | Resolves to the user's current value for attribute name. If the attribute is not set and no fallback is written, the send is suppressed (see Honesty policy below). |
{{ name | fallback }} | Same resolution, but uses fallback text when the attribute is unset. The fallback is trimmed. {{ name | }} is an explicit empty-string fallback. |
[bracket text] | Literal placeholder — rendered exactly as written. Replace it with your own copy before activating (e.g. [product_name], [Feature X]). |
// Fallback — sends even when first_name is not yet set
"Hey {{ first_name | friend }}, your streak ends tonight."
// No fallback — the send is skipped when plan is unset (see Honesty policy)
"Your {{ plan }} plan renews tomorrow."
// Bracket placeholder — static copy you fill in before activating
"Unlock [Feature X] with a plan upgrade."suppress entry appears in the decision_log with suppress_reason="missing_variable" and the missing attribute names. Literal {{ … }} braces are never delivered to a device and a value is never invented. Add an inline fallback ({{ first_name | friend }}) to any token where the attribute may not yet be populated.Resolution sources — at send time the engine looks up tokens against:
- User attributes written via
Pushlane.setAttributes(SDK / drop-ins) orPOST /v1/attributes(HTTP). Most-recent value wins. - Four auto-populated system attributes:
app_version,os_version,install_env, andlocale— projected from every event context automatically, no SDK call required. Treat these names as reserved: writing them viasetAttributesoverwrites the auto-populated value (forlocalethat is a supported override — see Localization — but never reuse them for unrelated data). external_id— the user's own identifier, always available once identified.
placement on a paywall_viewed) are not available as tokens. Only user attributes survive deferred sends — delays, schedule windows, STO waits — because the engine does not persist event properties in the Durable Object. To use a value that was present at trigger time, write it as an attribute first (e.g. Pushlane.setAttributes({ last_paywall: 'home' })).Four ways to feed a variable:
- SDK / drop-in — call
Pushlane.setAttributes({ first_name: user.firstName })afterPushlane.identifyon any platform. See the quickstart for your platform. - HTTP API —
POST /v1/attributesfrom your server for attributes you know server-side (plan, LTV, subscription status…). See the HTTP API reference. - Flow Update node — an Update attributes step inside a flow sets attributes mid-journey (e.g. stamp
onboarding_completed_atwhen the user reaches that node). - Auto-populated —
app_version,os_version,install_env, andlocaleare written automatically from every event context.
#Localization
A template gives you copy in one language. To reach users in their own language, translate the message: a flow can carry a title and body per language, and each user receives the one that matches their device locale — with an honest fallback to the default language when a locale is not covered. The same personalisation tokens work in every language.
See Localization for the Localization table, auto-translate, and how the language is picked at send time.
#Verbatim vs. reconstructed
Each template carries a verbatim flag:
| Flag | Meaning |
|---|---|
| verbatim: true | The copy was confirmed word-for-word by at least one public source (linked in the sources field). Use as-is or adapt. |
| verbatim: false | The copy was reconstructed from a documented notification pattern. The tone and structure are accurate but the exact wording may differ from the original. |
The sourceApp field names the real app the template was documented from. This is attribution only — no app logos are displayed.
#Using a template
Notification templates surface in two places in the product:
- Message editor — "Use as template": Open a Message node in the flow builder and click the template library icon. Browse by category, select a template, and its title and body are loaded into the editor. Edit the copy before saving.
- New flow seed — "Start from this notification": From the template library, start a new single-step flow pre-populated with the chosen notification. Add delays, branches, or additional messages around it.
channel to push. Pushlane is a push-only platform — in-app and SMS channels are not available.#Deeplinks
Some templates carry a deeplink hint — a URL scheme or universal link to a specific screen in your app. When present it populates the deeplink field of the message variant. Replace the hint with your own scheme before activating.
{
"content": {
"title": "Your streak ends in 10 minutes",
"body": "One lesson saves your {{ days_left }}-day streak.",
"deeplink": "myapp://lesson/daily"
}
}The deeplink is passed through to the APNs payload as-is. Your app must register the scheme or associated domain and handle the URL in your notification delegate.
Next: Audiences — build the segment of users a flow targets.