25% off Server GTM for 12 months

Claim 25% off
Server GTM Containers

COD Order Protection for Server-Side GTM

Hold cash-on-delivery purchases at checkout and send them to Meta, GA4, Google Ads and TikTok only when the order is really confirmed.

9 min readUpdated Nov 13, 2026TagLinc docs
Browse documentation

With cash on delivery, a purchase at checkout is not a sale yet. Some orders are fake, some are cancelled on the confirmation call, and some come back with the courier. If your purchase tags fire at checkout, the ad platforms learn from all of them, and they go looking for more people who order and never pay.

COD Order Protection holds a cash-on-delivery purchase in Taglinc when it happens. When you confirm the order, Taglinc sends it back into your server container as a purchase with the original order time and the original ad click, and your own tags send it on. Orders you reject are never sent. It works on every plan.

How it works

  1. Your web container sends the GA4 purchase as usual, with one extra parameter, cod_hold, that is true for cash-on-delivery orders.
  2. In your server container, the Taglinc COD Hold tag sends that purchase to Taglinc. Your other purchase tags skip it (an exception), so nothing reaches the ad platforms yet.
  3. The order waits on the COD Order Protection page of your container. You confirm or reject it there, or your shop does it for you (WooCommerce or a webhook, see below).
  4. A confirmed order goes back into your server container through the Taglinc COD Client, as a purchase event with is_delayed set to true. Your Meta, GA4, Google Ads and TikTok tags fire on it with the order's own ID, value, items, customer details and click IDs.

If Taglinc cannot hold an order (for example while Taglinc is down, or after you switch the power-up off), the hold tag sends the purchase straight back into your container through the same client, so your tags fire at once as they did before. You do not lose a sale because of Taglinc.

Set it up

You need a server container on Taglinc with a GA4 client, and a web container that sends the GA4 purchase event to it.

1. Switch it on

Open your container, go to Power-Ups and turn on COD Order Protection. Your container restarts once.

Do this before step 2. Until the power-up has been on once, the hold tag does not know where to send an order, so it cannot hold it or pass it on. With the exceptions from step 2 already on your purchase tags, a COD purchase would then go nowhere.

Easiest: let Taglinc set it up

If your container is connected to Google Tag Manager (Overview, Setup), Taglinc does steps 2 and 3 below for you:

  1. On Power-Ups, in COD Order Protection, pick your web container. Taglinc lists the purchase tags it found in your published containers.
  2. Click Set it up for me. Taglinc makes a Taglinc COD setup workspace in each container with the templates, the client, the hold tag, the triggers and the variables, and adds the COD exception to every purchase tag it found. Your GA4 purchase event tag gets the cod_hold and payment_type parameters. Cookie tags (such as Cookie Monster) are left as they are.
  3. Open each workspace (the buttons link to it), check the changes and press Submit, then Publish. Web container first, then the server container.

Nothing goes live until you publish. To undo, delete the workspaces in Tag Manager. Purchase tags that fire on a thank-you page view instead of the purchase event are not found: add the exception to those by hand (step 3). If the container already has the COD items from an earlier import, delete them first or follow the steps below.

Prefer to do it yourself? Follow steps 2 and 3 below.

2. Server container

The quickest way is the ready-made container from the power-up: in your server container open Admin, Import Container, choose taglinc-cod-server-container.json, pick your workspace and Merge (rename conflicting items). It adds:

  • the two templates, Taglinc COD Hold (tag) and Taglinc COD Client (client),
  • a Taglinc COD Client client, which answers on /taglinc-cod,
  • a Taglinc COD Hold tag with the trigger Taglinc - COD purchase to hold (Client Name is GA4, Event Name is purchase, cod_hold is true),
  • a trigger Taglinc - COD confirmed purchase (Client Name is Taglinc COD Client, Event Name is purchase).

Then, on every other purchase tag in the server container (Meta Conversions API, GA4, Google Ads, TikTok and so on):

  1. add Taglinc - COD purchase to hold as an exception, so the tag skips a COD order at checkout;
  2. add Taglinc - COD confirmed purchase as a second firing trigger, so the tag sends the order when it is confirmed.

If you would rather build it by hand: download both templates from the power-up, import them under Templates (the three-dot menu, Import), and create the client, tag and triggers as listed above.

3. Web container

Import taglinc-cod-web-container.json the same way (Merge). It adds a variable Taglinc - payment type (the data layer value ecommerce.payment_type), a variable Taglinc - cod_hold (true for cod, cash_on_delivery or cash on delivery) and a trigger Taglinc - COD purchase. Then:

  1. In your GA4 purchase event tag, add two event parameters: cod_hold with the value {{Taglinc - cod_hold}}, and payment_type with {{Taglinc - payment type}}.
  2. On every browser purchase tag that goes straight to an ad platform (Meta Pixel, Google Ads, TikTok Pixel), add Taglinc - COD purchase as an exception. Otherwise the browser still reports the order at checkout.

If your data layer keeps the payment method under another name, change Taglinc - payment type to read it. If your shop sends something other than cod for cash on delivery, add it to the list in Taglinc - cod_hold and in the hold tag's Payment methods field.

4. Publish both containers

Then test, below, before you rely on it.

Confirm or reject orders

On the COD Order Protection page

Pending orders show the order ID, value, customer name, phone and city, and whether the order came with a Google click or a Meta browser ID. Approve & fire sends the order now; Reject drops it for good. You can tick several and do them at once. If other orders came from the same phone number, the row says so, which helps spot fake orders.

From WooCommerce (no plugin)

  1. On the power-up, under Confirm orders automatically, copy the Delivery URL and the Webhook secret.
  2. In WordPress open WooCommerce, Settings, Advanced, Webhooks, Add webhook. Status Active, Topic Order updated, API version WP REST API Integration v3, and paste the Delivery URL and the secret (into Secret). Save.

By default an order is sent on when its status becomes Completed, because WooCommerce marks every cash-on-delivery order Processing as soon as it is placed. If your shop only moves an order to Processing after the confirmation call, choose Processing on the power-up. Cancelled, Refunded and Failed reject the order. Taglinc matches the order by its number or its ID, so it works whichever one your data layer sends as the transaction ID.

From any other shop, n8n or a CRM

POST JSON to the Webhook URL with the secret in the X-Taglinc-Webhook-Secret header:

curl -X POST https://api.taglinc.com/taglinc-api/cod/YOUR_WEBHOOK_ID \
  -H 'Content-Type: application/json' \
  -H 'X-Taglinc-Webhook-Secret: fnwh_...' \
  -d '{"order_id":"1234","status":"completed"}'

These statuses send the order: confirmed, processing, completed, paid, shipped, delivered, approved. These reject it: cancelled, failed, refunded, returned, rejected, fake. Anything else is ignored. Send up to 100 orders at once as {"orders":[{"order_id":"1","status":"delivered"}, ...]}. The answer says what happened to each order.

The webhook secret starts with fnwh_. It is not the key Taglinc uses inside your container; if you send that by mistake, the answer tells you. If a status arrives before the order was held (a fast shop, a slow page), Taglinc keeps it for 7 days and applies it when the order comes in.

Test it

  1. Turn on the Preview Header power-up with your Tag Manager preview header, so the requests Taglinc sends into your container show up in Preview.
  2. Place one prepaid test order. It must go out at once, as before.
  3. Place one cash-on-delivery test order. In Preview, the GA4 purchase fires only the Taglinc COD Hold tag, and the order appears as Pending on the power-up.
  4. Press Approve & fire. In Preview you see a new purchase from the Taglinc COD Client with is_delayed true, and your purchase tags fire on it.
  5. Check the browser side too: the Meta Pixel and Google Ads purchase tags must not fire for the COD test order.
  6. Turn the Preview Header off again when you are done.

Timing: send confirmations soon

  • Meta accepts the original order time for 7 days. An order confirmed later is sent with the time it is sent.
  • GA4 keeps the original time only for about 72 hours.
  • Google Ads needs a Google click ID (gclid, wbraid or gbraid) on the order, and the click must be within about 90 days.

The page warns about pending orders that are close to these limits. A pending order that nobody confirms or rejects becomes Expired after 30 days; you can still approve it later.

How many orders

Holding orders is free and not limited. What counts is each order sent on (a fire): 50 a month on Free, 5,000 on Pro, 10,000 on Business and Enterprise. The power-up shows how many you have used this month, and Taglinc emails you at 80% and at 100%. Over the limit, confirmed orders wait and go out when the next month starts or when you upgrade.

Good to know

  • Taglinc cannot see inside your tags. The page shows whether your container took the order and, when Tag Manager reports it, which tags ran. Use Preview to check a tag's own result.
  • If your container does not answer, Taglinc tries again for 24 hours, then marks the order Send failed with a Retry button. The usual cause is that the Taglinc COD Client is not published.
  • Held orders, including the customer details, are kept encrypted by Taglinc and shown only to you and your team. They are never shown to other Taglinc customers.
  • Only requests signed by Taglinc are accepted on /taglinc-cod, so nobody else can push purchases into your container through it.
  • Turning the power-up on or off restarts the container once. When it is off, cash-on-delivery purchases go out at checkout again (the fallback); you can leave the tags in place.

Still stuck?

Open a support ticket from your dashboard and include the container name.

Contact support