Add a Track order button to WhatsApp order messages

How dynamic URL buttons work in WhatsApp templates, why the link has to be a path, and how Beacon Messenger fills Track order and Finish checkout buttons from Shopify.

A shipping update that ends with a long tracking link is readable. A shipping update with a button that says Track order is better: it is one tap, it does not wrap across three lines, and it is what WhatsApp's own templates look like. The catch is that WhatsApp buttons do not accept a full URL per message. They accept a fixed URL with one variable at the end, and that single rule shapes everything about how a Shopify store can use them.

This post explains what Meta allows on a URL button, why the order status page is the link that works and carrier tracking links usually are not, how Beacon Messenger fills the button, and what to check before you rely on it.

What a URL button can and cannot contain

WhatsApp message templates can carry call-to-action buttons. One kind opens a website. Meta lets you make that URL either static, the same link every time, or dynamic, where the template holds a fixed base and a {{1}} placeholder at the very end. When a message is sent, the app supplies the text that replaces {{1}}, and WhatsApp appends it to the base. The base cannot change per message, and the placeholder cannot sit in the middle of the URL or appear twice. Meta's template guidelines cover the review side; the shape of the button is the part merchants usually find out about when a template is rejected or a link does not open.

The consequence for a store: a button can point at pages on one domain, your own, with a variable path. It cannot point at a different domain per message. That rules out one obvious use and makes another one easy.

Why the order status page is the right target

Every Shopify order has an order status page on your store's domain. Shopify documents it as the page customers reach from the confirmation email and the final step of checkout, showing items, shipping address, fulfillment and, once the order ships, tracking numbers and carrier links (Understanding order status pages). Its URL is always on your store's primary domain, with a path that identifies the order and carries a key so the customer does not need to log in.

That makes it a perfect fit for a dynamic URL button. The template holds https://yourstore.com/{{1}}, and the message supplies the path. The customer gets one button that works for confirmations, cash-on-delivery reminders and shipping updates alike, and when an order has two shipments the page lists both, which a single carrier link never does. The reasoning on that is in Split shipments and tracking added later.

Carrier tracking links are the obvious use that does not fit. A UPS link lives on ups.com, a DHL link on dhl.com, a Correos link somewhere else. Because the button's base is fixed in the approved template, one template cannot send the customer to whichever carrier shipped the order. The honest options are to put the carrier link in the body as text, where a full URL is allowed, or to use the Track order button for the order status page and let that page show the carrier link. Many stores do both: body text with the tracking number and carrier link, button for the status page.

How Beacon Messenger fills the button

When you pick an approved template in an automation, Beacon Messenger reads its components and lists every variable it finds: header variables, body variables and, for each URL button whose URL contains a placeholder, an entry labelled with the button's text and the word suffix. You map each entry to a Shopify merge field, exactly as you do for body variables.

Two merge fields exist for buttons. order_status_url_path is the order status page URL with the https://yourdomain/ part removed, so it is the path and query string only, ready to be appended to the template's base. checkout_url_path does the same for the abandoned checkout recovery link, for a Finish checkout button on that automation. The full-URL fields, order_status_url and checkout_url, are still there for body text. The automation screen shows a sample value next to each so the difference is visible before you send anything.

On send, the app builds the button component Meta expects: the button's position in the template and the suffix text as its single parameter. If a template has a URL button without a placeholder, it is static and nothing is sent for it; it just works. If a button has a placeholder and you leave it unmapped, the suffix is empty and the button opens your domain root, which is the one failure mode to watch for during setup.

Setting it up

  1. In Meta Business Suite or WhatsApp Manager, create or edit the template. Under Buttons add Call to action, Visit website, and set URL type to Dynamic. Enter your store's primary domain, the one shown in Shopify under Settings, Domains, followed by /{{1}}. Give the button a short label such as Track order or View order.
  2. Add a sample value for the button variable when Meta asks for one; a plausible path like 12345/orders/abc123 is fine. Submit and wait for approval. If the template is rejected, the usual causes are in Why WhatsApp templates get rejected.
  3. In Beacon Messenger open Automations, choose the trigger (order confirmation, shipping update or cash-on-delivery confirmation), select the approved template and map the body variables as described in the order notifications setup guide.
  4. Map the entry labelled with your button text and suffix to order_status_url_path. For the abandoned checkout automation map it to checkout_url_path instead, as covered in Abandoned checkout recovery on WhatsApp.
  5. Place a test order with your own number, wait for the message, and tap the button. It should open the order status page for that order without asking you to log in.

Things that break it

  • The template base and your Shopify primary domain disagree. If the template says https://shop.example.com/{{1}} and the order status URL is on https://example.com, the appended path lands on the wrong host. Use the primary domain and check again if you ever change it; editing the base means the template goes back through review.
  • A placeholder in the middle. Meta accepts a dynamic variable only at the end of the URL, so https://example.com/{{1}}/track will not be approved as a dynamic button.
  • Mapping the full URL field to the button. order_status_url contains https:// and the domain, which would be appended after your base and produce a nonsense link. Buttons take the _path fields; body text takes the full fields.
  • Expecting the button to carry the carrier link. It cannot, because the carrier domain changes per order. Put tracking_url in the body instead.
  • A redirect on the storefront. If your domain forwards www to non-www or the other way, the status page still opens, but test it: some redirect setups drop the query string and the key with it.

Is it worth the extra template work?

For a store sending a few hundred updates a month, a button changes little about delivery and a lot about how the message reads. It is also the cleaner way to keep a utility template looking like a utility template: a short body about the order and a single action, rather than a body stuffed with a long link. Approval takes the same minutes either way; the only real work is checking the domain once. Beacon Messenger's free tier covers the template mapping, and buttons do not change the per-message price. If you want to see how the mapping screen looks before you set anything up, the pricing and plan details are on the landing page.

Frequently asked questions

Can a WhatsApp template button open a different link for each customer?

Yes, within one domain. The template holds a fixed base URL ending in {{1}}, and each message supplies the suffix. The domain itself cannot change per message, so the link must be on your own site, such as the Shopify order status page.

Can I put a carrier tracking link on a WhatsApp button?

Not with a dynamic button, because carriers use different domains and the button's base is fixed. Put the tracking link in the message body as text, and use the button for the order status page, which lists the tracking numbers and carrier links.

Which merge field do I map to a URL button in Beacon Messenger?

order_status_url_path for order confirmation, cash-on-delivery and shipping update templates, or checkout_url_path for abandoned checkouts. They hold the path and query string without the domain, which is what Meta appends to the template's base.

Does adding a button change how the template is categorised or priced?

A website button on its own does not change the category; the body text decides whether Meta treats the template as utility or marketing. Pricing is per message by category, so a button adds nothing to the cost.

More guides