What you need before you build a Postscript message
Building a working postscript message starts before you open the message editor. You need a Postscript account connected to your Shopify store with the sync running, so customer and order fields actually exist to merge into the message. You need a registered sending number (a shortcode or toll-free number, provisioned and approved, not a number still in review). And you need to know which type of message you’re building, because a campaign, an automation step, and a keyword reply each expose different settings in the editor.
This guide is written for a team already running Postscript, building or fixing an actual message, not evaluating whether to buy the platform. If you’re still deciding between SMS platforms, that’s a different question with a different answer. And if your store is under the published floor for managed lifecycle work — call it under $3M in revenue, or running on a non-Plus, non-subscription platform, a lot of this guide is still useful reading, but the operational weight of quiet-hours tuning and merge-field QA won’t pay for itself yet at your volume.
Step 1: choose the message type and trigger
Every Postscript message starts life as one of three types: a Campaign (a scheduled one-off send to a segment), an Automation (a message or sequence fired by a Shopify or Postscript event, such as checkout started or subscriber joined), or a Keyword reply (a message sent when a subscriber texts a specific word to your number).
The type you pick changes which settings appear later in the editor. A Campaign gets a send-time picker and an audience filter. An Automation gets a trigger event, a delay field, and, critically, an exit condition, so a subscriber who completes checkout doesn’t keep receiving a message written for someone who hasn’t. A Keyword message gets none of that; it fires immediately on the matching reply, so quiet hours become the only thing standing between a 3am text and a compliance problem.
Pick the trigger before you write a word of body copy. A message written for “24 hours after cart abandonment” reads differently from one written for “immediately on checkout started,” and rewriting a message to fit a trigger you chose afterwards causes most of the copy problems a team runs into.
Step 2: structure the message body
A Postscript message body is plain text (or text plus one image for MMS), capped at 160 characters per segment under GSM-7 encoding. The moment you add an emoji, a curly apostrophe, or most non-Latin characters, the encoding switches to UCS-2 and the segment limit drops to 70 characters: the same message can silently double or triple in billed segments because of one smart quote.
Structure the body in three parts: a one-line hook that states the reason for the text, the specific offer or information (a discount code, an order status, a restock notice), and the footer. Keep the hook first: SMS previews on a lock screen show roughly the first 40 characters, so a message that opens with a greeting and buries the reason for texting loses the recipient before they open the message.
Avoid writing the discount code or product name as a merge field you haven’t tested. A field name that’s correct in Postscript’s documentation but doesn’t match your actual Shopify metafield key returns blank, not an error; the message sends anyway, just wrong.
Step 3: add merge fields from Shopify data
Merge fields pull live values from the synced Shopify customer or order record into the message at send time, written in double curly braces: {{customer.first_name}}, {{customer.total_spent}}, {{shop.name}}, {{cart.total_price}}, {{discount_code}} on flows that generate one. Order-level fields are only available on automations triggered by an order or cart event: a general campaign has no order to pull from, so referencing {{order.number}} in a campaign either breaks the send or renders blank depending on your account’s fallback configuration.
Every merge field needs a fallback. Postscript lets you set a default value for a field in the syntax {{customer.first_name | default: "there"}}, so a blank name becomes “Hey there” instead of “Hey ,” with a visible gap. Shopify customer records created through guest checkout, POS, or a bulk import frequently have no first name populated. That gap isn’t rare; it’s routine, at a rate specific to your own checkout mix that only your data can tell you, so it belongs on your test list, not in a number quoted here.
Personalisation compounds when you combine fields: a message referencing both the customer’s name and the specific product left in cart reads as written for one person. A message with the name only, and a generic “items in your cart” line, reads as a template with a name inserted, the difference customers notice even if they can’t articulate it. For context on how much weight personalised, automated messaging carries relative to one-off sends, Klaviyo’s benchmark across 183,000+ brands attributes 41% of email revenue to automated flows rather than campaigns (vendor-reported); the same shape of finding, automation and personalisation doing more work than a blast, holds for SMS, though Postscript hasn’t published an equivalent figure to cite directly.
What the free plan is genuinely good for
The free plan has one legitimate use that gets skipped over in most complaints about it: proving a trigger actually fires before anyone commits time to building the real workflow. Before wiring conditional logic, error handling and a second or third action into a paid multi-step zap, it’s worth knowing the trigger app sends the event you think it sends, in the shape you expect, on the schedule you expect. A free single-step zap that dumps a raw payload into Slack or a spreadsheet answers that question directly: does a Shopify order-created event actually fire when a subscription renews, or only on a first purchase; does a Klaviyo list-add trigger fire on import as well as signup. Those are the kind of surprises that are far cheaper to find on a zero-cost single-step zap than after a paid, multi-step workflow has been built around a wrong assumption.
Used this way, the free plan is a prototyping tool, not a production one. The zap gets built to confirm the trigger, watched for a day or two, then either torn down or rebuilt properly on a tier that supports the filters and branching the real workflow needs. Treating it as a permanent home for a production order-sync workflow is where the plan starts costing more than it saves; treating it as a five-minute check before a real build is exactly what it’s for.
Step 4: set quiet hours and send-time limits
Quiet hours live under Postscript’s Compliance settings and block or delay outbound messages outside a window you define, evaluated against the recipient’s own time zone rather than the sender’s: a customer in a different zone than your warehouse gets the message held to their local window, not yours. This applies to automations as much as campaigns: an automation triggered at 11pm queues rather than sends, and fires once the window reopens rather than being dropped.
Two settings interact here and teams often set only one. The quiet-hours window itself controls when a message is allowed to leave. A separate frequency cap, where your account has one configured, controls how many messages a single subscriber can receive inside a rolling period regardless of time of day. A subscriber who triggers three automations in one afternoon (a back-in-stock alert, an abandoned-checkout nudge, and a shipping update) can hit a frequency cap and have the third message held even though it’s well inside quiet hours.
Exact time thresholds and what counts as an allowed exception are a compliance question, not a product-setting question, and the answer varies by the kind of message and the jurisdiction the recipient is in. Confirm the specifics, including whether your quiet-hours window meets whatever standard applies to your subscriber base, with counsel rather than a support article. What you can control directly in Postscript is the window itself, and testing that it actually holds.
Step 5: add the compliance footer
The compliance footer is the line, usually an opt-out instruction such as a reply-to-stop prompt, sometimes with sender identification, that Postscript can append automatically to outbound messages under the account’s Compliance settings. It counts toward the character limit like any other text, which is the most common reason a message you wrote to fit neatly in one segment spills into two: the footer was invisible in the editor’s live preview until you scrolled.
Some plan tiers expose a per-message toggle to turn the footer off for an individual send. Treat that toggle as a rare exception, not a formatting shortcut for tight messages; the underlying reason the footer exists doesn’t go away because you hid it on one campaign. If a message genuinely needs the space and you’re considering removing the footer, that’s a decision to run past whoever owns compliance for your programme, documented, not a call made alone in the editor at 4pm before a send.
The workarounds people try, and what they cost
Because the single-step ceiling is the real constraint, most attempts to get more out of the free plan aim at faking multi-step behaviour rather than buying it. Three show up repeatedly.
Chaining single-step zaps. Instead of one zap with a filter and two actions, the workaround is two or three separate zaps: one watches the same trigger and writes to a spreadsheet row or a lightweight database record, another polls that intermediate store and fires the next action if a condition looks right. It works, in the sense that the actions eventually happen. It also means the “workflow” now lives across multiple independent zaps with no shared error handling, each on its own polling schedule, so a failure in the middle step doesn’t stop the last one from firing on stale data. Debugging becomes a matter of checking three task histories instead of one, and nobody owns the intermediate spreadsheet as the source of truth until something in it goes wrong.
Routing through a free webhook or notification tool. A common pattern is sending the free zap’s single action to a webhook endpoint (a free tier of a tool like a webhook relay or a lightweight serverless function) that does the branching Zapier’s free plan won’t, then calls back into a second zap or another app directly. This does add real conditional logic, but it moves the maintenance burden onto a second free-tier tool with its own limits, its own outages and its own account to monitor, and it usually requires someone comfortable writing a small amount of code to stand up the webhook receiver in the first place. It’s a genuine capability gain, but it isn’t free in effort even though it’s free in dollars.
Manual replays. When a single-step zap without a filter fires on everything, including orders it shouldn’t have acted on, the workaround is often just cleaning up after it by hand: deleting the erroneous Slack message, voiding the duplicate tag, re-running the correct action manually for the order that should have been excluded. This is the cheapest-looking workaround because it uses no extra tools, but it’s also the one that scales worst — the cleanup time grows in direct proportion to order volume, which is exactly the metric a real automation is supposed to remove from a person’s plate.
None of these workarounds are free once time is counted. They trade a subscription cost for a standing maintenance cost that usually falls on whoever set the zap up in the first place, and that person is rarely tracking the hours against what a paid tier, or a purpose-built platform, would have cost instead.
The step most teams get wrong
The step almost every team skips is testing a merge field against a record that’s missing the value, not just one that has it. Sending a test message to your own phone, with your own name and order history populated, proves the happy path works. It proves nothing about the customer whose first name is blank, whose order has no discount code attached, or whose cart total field is null because they added items through a channel that doesn’t sync that field.
Build a second test contact deliberately missing the fields your message references, and send the same message to that contact before it goes live. If the fallback value you set in step 3 doesn’t show up cleanly (a stray comma, a double space, a literal blank), fix it there, in the test, where it costs nothing, rather than in a live send where it costs a reply asking why the text got their name wrong.
How to verify the message before it sends
Before turning a message live, run through four checks in the editor. First, send it to two test contacts: one complete record, one with your riskiest merge field blank, and read both results on an actual phone, not the desktop preview, since segment splitting and emoji rendering can differ. Second, check the character count against 160 for plain text or 70 if anything in the body could trigger UCS-2 encoding, including a curly apostrophe your editor may have auto-corrected. Third, confirm the quiet-hours setting is on and pointed at the correct time zone logic for the message type — campaign, automation, or keyword reply each need a separate check. Fourth, confirm the compliance footer rendered in the test send exactly as configured, not toggled off from a previous edit.
None of these four checks takes more than a few minutes, and none of them shows up as an error in Postscript’s interface if skipped; a broken merge field, a missed quiet-hours window, and a stripped footer all send successfully from the platform’s point of view. The only thing that catches them is a human reading the test message before a customer reads the real one.
A single test contact isn’t enough for a list with any real variety in how records were created. Build a seed list instead — a small set of test numbers, each pointing at a Shopify customer record with a different gap: one missing a first name, one with no order history to pull a last-purchase field from, one created through POS with no email captured, one with a currency or locale field that differs from your primary market. Send every candidate message to the full seed list before it reaches a real subscriber. A merge field can render correctly for nearly all of a list and still fail for the specific segment that happens to have been imported from a legacy platform, or created through a checkout flow that skips a field your newer signups always have. That failure is real but invisible until a record shaped like the gap actually gets tested, which is exactly what a single well-populated test contact can’t surface.
A single well-built postscript message rarely moves revenue on its own; what moves it is the sequence of messages a subscriber receives after a specific action, timed, personalised, and compliant end to end, which is a lifecycle problem more than a copywriting one. If your Postscript automations are built but the sequencing, the quiet-hours logic across message types, and the fallback handling haven’t been audited together, that’s the work Pointerflow’s lifecycle flows service does, and you can estimate what a fixed set of flows is worth to your store with the flow revenue calculator before you commit to the rebuild.
Sources
- Klaviyo, 183,000+ brands: 41% of email revenue from automated flows rather than one-off campaigns (vendor-reported figure, cited for context on automation versus campaign performance).