How to Send Tracking Notifications via Slack When Orders Ship
Notify your team on Slack whenever an order is shipped with tracking details.
What This Integration Does
Customer-success and fulfillment teams need to know in real time when an order ships - to update customers proactively, to verify SLAs, and to celebrate big orders going out. Rather than asking the team to refresh ShipStation or Shopify all day, this workflow posts a formatted Slack message to a shared channel every time a shipment is created. The message includes the order number, customer name, carrier, tracking number, and a clickable tracking URL.
The workflow is webhook-driven, fires once per shipment, and uses Slack Block Kit formatting so the message renders cleanly with sections, a tracking button, and the carrier's logo as a status accessory. Errors are non-blocking - if Slack is down, the shipment still ships; the workflow just retries the post.
Prerequisites
- A Shopify or WooCommerce connection (with the order webhook configured to call into Spojit), or a ShipStation connection if you ship outside the store.
- A Slack connection with permission to post to your fulfillment channel.
- The Slack channel ID (not the name) where notifications should land - look it up with the slack
list-channelstool once during setup.
Step 1: Webhook Trigger
Add a Trigger node and set its type to Webhook. Wire it into your store's fulfillment webhook (fulfillments/create on Shopify). The trigger payload contains the tracking number, carrier, and the order ID.
Step 2: Hydrate the Order
Add a Connector node on shopify with the get-order tool (or woocommerce get-order) using {{ trigger.body.order_id }}. This gets you the customer name, order total, and line items for the Slack message.
Step 3: Build the Slack Block Kit Payload
Add a Transform node that constructs the Block Kit blocks. Block Kit gives you headers, fields, buttons, and dividers, which read far better in-channel than a wall of text:
{
"blocks": [
{
"type": "header",
"text": {"type": "plain_text", "text": "Order {{ order.name }} shipped"}
},
{
"type": "section",
"fields": [
{"type": "mrkdwn", "text": "*Customer*\n{{ order.customer.first_name }} {{ order.customer.last_name }}"},
{"type": "mrkdwn", "text": "*Total*\n{{ order.total_price }} {{ order.currency }}"},
{"type": "mrkdwn", "text": "*Carrier*\n{{ trigger.body.tracking_company }}"},
{"type": "mrkdwn", "text": "*Tracking*\n{{ trigger.body.tracking_number }}"}
]
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {"type": "plain_text", "text": "Track parcel"},
"url": "{{ trigger.body.tracking_url }}"
}
]
}
]
}
Step 4: Post to Slack
Add a Connector node on slack and pick the send-message tool. Configure:
channel:C0123456789(your channel ID)text:"Order {{ order.name }} shipped"(fallback for notifications)blocks: the array from Step 3
The text field is the preview shown in mobile notifications and accessibility tools, so keep it short and informative.
Step 5: Add Reactions or Threading (Optional)
For VIP orders or expedited shipments, add a Condition node on the order total. If order.total_price > 500, fan out to a second slack call using add-reaction with "star" on the freshly-posted message timestamp. Threading follow-up updates (status changes, delivery confirmation) under the original message keeps the channel tidy.
Step 6: Handle Failures
Add a Condition node on the Slack send result. On failure, log to a fallback mongodb collection or post to an error channel via a backup webhook. Spojit's per-node retries cover transient Slack 5xx errors automatically; this Condition catches the rarer permanent failures (bad channel ID, missing scope).
Tips
- Use channel IDs, not names -
#shippingcan be renamed;C0123456789cannot. - Block Kit Builder - Slack's online Block Kit Builder lets you preview your payload before wiring it into the workflow.
- Mention humans sparingly -
@hereon every shipment will get the workflow muted in a week. Reserve mentions for failures or VIP orders.
Common Pitfalls
- Webhook fires before tracking populates - some stores send
fulfillments/createbefore the carrier label is generated. Guard the workflow with a Condition ontracking_numberbeing non-empty; if it's missing, wait and use a Schedule trigger to re-check. - Rate limits - Slack's
chat.postMessagecaps at 1 message/sec per channel. Bursting from a backfill will throttle; pace with a Loop and small delays. - Scope gaps - the Slack connection needs the
chat:writescope and (if posting to a private channel) must be invited to that channel. - Mismatched JSON in blocks - a single trailing comma in your Block Kit payload silently downgrades to a plain-text message. Validate with the json connector's
validatetool before sending.
Testing
Fulfill a test order in your store with a real tracking number. The Slack message should appear in the configured channel within seconds, with the tracking button linking to the carrier. Click through and confirm the URL is live. Once that round-trips cleanly, leave the webhook subscribed.