EmailTimer.App

Merge tags and dynamic personalization

Where a merge tag can go, where it cannot, and the two ways a subscriber's own values reach an image.

How dynamic image parameters work

EmailTimer.App draws a subscriber's values into image layers at the moment the image is fetched: a name, a coupon code, a points balance, a deadline. What decides whether that works is how the values reach the image, because the obvious way does not.

Your email platform does not substitute these. This is the one thing on this page worth reading twice.

The image address is signed with an HMAC, and the signature covers every parameter in it. So the values have to be in place before the address is signed. If you paste a merge tag into the address and your platform replaces it at send time, the signature no longer matches what was signed, the image service rejects it, and every subscriber in that send receives the fallback graphic instead of your timer.

That failure is silent. The image service answers every request with HTTP 200 and a valid picture by design, because a broken image in a message that has already been delivered can never be fixed. So nothing errors, nothing retries, and no dashboard turns red. You find out when somebody asks why the countdown was a grey box.

The two ways a value actually gets into an image

One image for the whole send. The parameters are fixed when you publish, the address is signed once, and everybody requests the same one. The countdown is still different for every reader, because the time remaining is worked out at the moment they open rather than at send time. This is on every plan, including the free one, and it covers any campaign with a single deadline: a flash sale, a launch, a webinar, a shipping cut-off. Personalize the link around the image and its alt text, neither of which is signed.

One image per subscriber. Generate a signed address for each person, each with their own parameter values, using the batch endpoint or a CSV export. Import the column into your platform as a contact field, then set the image source to that field's merge tag. The merge tag is now the whole address rather than a fragment inside it, so nothing is substituted into a signed string. This is how a per-subscriber deadline works, and it needs Growth or Agency.

Whichever you use, the values fill the variables your template declares.

Where each merge tag goes, and what comes back
Where each merge tag goes, and what comes back In the email platform, the coupon code merge tag is in the link and the first name merge tag is in the alt text. The image source is a contact field holding an address signed for that subscriber. The render engine reads that subscriber's token and draws their name, their code, a countdown, a QR code and a VIP badge shown by a rule into one image. Your email platform Klaviyo syntax, for example: <a href="…?c={{ coupon }}"> <img src="{{ person.et_url }}" alt="{{ first_name }}, 20% off"> Filled in at send: Sarah's code, name, signed address Render engine Reads Sarah's recipient token Layer 1: Text, "Sarah, 20% off" Layer 2: Her code, "SARAH20" Layer 3: Countdown, 30 frames Layer 4: QR code, her claim link Rule: show the VIP badge by tier The image she sees Sarah, your exclusive pass SARAH20, 20% off 03 : 42 : 19 One file, drawn when she opens

Drawn for one image per subscriber, on Growth and Agency: the image source is a contact field holding an address signed for that subscriber. With one image for the whole send, the merge tags go in the link and the alt text, and the image carries what is the same for everybody.

Example variables

A template's variables are whatever you name them in the editor, so there is no fixed list. These are the names the examples on this site use, and the kind of value each layer takes.

Variable Type Description Example value
name string Subscriber first name or full name layer Sarah
coupon string Personalized voucher or discount code VIP25-SARAH
end ISO 8601 date and time Target deadline timestamp for countdown 2026-11-28T23:59:59Z
points integer Customer loyalty points or credit balance 1450
qr string (URL-encoded) Payload to rasterize into a scannable QR code https://brand.com/claim?id=982
progress integer, 0 to 100 Percentage fill for linear or circular progress bars 75

Handling fallback defaults

Not every subscriber has a first name recorded. Set a fallback in your template settings so an empty value draws something sensible rather than a gap. The platform-side fallbacks below apply to the link and the alt text, which your platform does substitute, and to the value you export when you are generating one address per subscriber.

Klaviyo fallback: {{ first_name|default:"Friend" }}
Mailchimp fallback: Set default merge value in Audience Settings
HubSpot fallback: {{ contact.firstname|default('there') }}

Each platform page carries that platform's full syntax, including the contact field that holds a per-subscriber address: Klaviyo, Mailchimp, HubSpot and Braze, with the rest on the integrations page.

URL encoding rules

When passing custom text containing spaces or special characters (such as ampersands or currency symbols), ensure values are URL-encoded.

The API encodes values for you when it mints an address, so this only matters if you are building the query yourself before signing. Use encodeURIComponent(), and encode before you sign rather than after, because the signature is taken over the address as it will be requested.

The API reference covers the endpoints, and pricing covers what each plan includes.