Can Shopify send its customers to Broadcast?

Yes, with a little plumbing you run yourself. Broadcast has no Shopify app and does not listen for Shopify events. What it has is a Subscribers API that takes tags and custom data. Shopify can call an HTTP endpoint when an order is paid. Put the two together and a paid order can tag a subscriber, store the order date, and start a sequence.

This page shows how. Read the limits section before you build anything.

What you can build today

  • A paid order adds the tags customer and ordered to the subscriber.
  • The order date goes into custom data as last_order_at, and the order number as last_order_name. An email can print it with {{ custom_data.last_order_name }}.
  • A sequence with the tag trigger ordered sends a post-purchase series.
  • A segment on last_order_at finds customers who have not ordered in 90 days, for a win-back sequence.

Post-purchase and win-back flows covers what to put in those sequences. This page is the plumbing.

What you cannot build today

Read these before you start:

  • Broadcast does not receive cart or checkout events. Abandoned checkout emails stay with Shopify. See Shopify abandoned checkout emails.
  • There are no product blocks. An email cannot show the items from an order with images and prices.
  • Custom data holds one value per key. You can store the last order number and print it, but the next order overwrites it.
  • A subscriber goes through a given sequence once. A second order does not run the post-purchase sequence again.
  • Broadcast cannot send SMS.

Native Shopify events are planned. Watch the roadmap for them.

Pick a route

Shopify gives you three ways to call an outside URL.

Route Shopify plan Can it send the Bearer token? Needs a server?
Admin webhooks (Settings > Notifications > Webhooks) Every plan No Yes, a small one
Shopify Flow, Send HTTP request Grow, Advanced, Plus Yes No, for simple calls
n8n, Make or Zapier Every plan Yes No, their service runs it

Broadcast’s API wants an Authorization: Bearer header and its own JSON shape. An admin webhook sends Shopify’s order JSON with a Shopify signature, so something has to sit in the middle and translate. That is the script below.

Shopify’s Customer events in the admin are for tracking pixels that run in a browser sandbox. They are not a server feed. For email, use webhooks or Flow.

Before you connect anything

  1. Create a channel access token in Broadcast with subscriber read and write permission. See API Authentication.
  2. Create the sequence and set its Tag trigger to ordered. Do this first: subscribers who already have the tag when you set the trigger are not added. See triggering a sequence.
  3. Import your existing customers once, so the API has people to tag. See bringing your Shopify list.

Route 1: admin webhook and a small script

In Shopify, open Settings > Notifications, click Webhooks, and click Create webhook. Pick the Order payment event, JSON format, and the URL of your script. Shopify shows the key it signs webhooks with on that page. Copy it.

The script does four things:

  1. Checks the X-Shopify-Hmac-SHA256 header against the raw body.
  2. Answers Shopify at once. Shopify waits five seconds at most and retries failures.
  3. Looks the buyer up with GET /api/v1/subscribers/find.json.
  4. Updates a known subscriber, or creates a new one only when the buyer ticked the marketing box at checkout.
// shopify-to-broadcast.mjs: Node 18 or later, no dependencies.
import { createServer } from "node:http";
import { createHmac, timingSafeEqual } from "node:crypto";

const { SHOPIFY_WEBHOOK_KEY, BROADCAST_URL, BROADCAST_TOKEN, PORT = 8080 } = process.env;

const api = (method, path, body) =>
  fetch(`${BROADCAST_URL}/api/v1/${path}`, {
    method,
    headers: { Authorization: `Bearer ${BROADCAST_TOKEN}`, "Content-Type": "application/json" },
    body: body && JSON.stringify(body),
  });

async function sync(order) {
  const email = order.email || order.customer?.email;
  if (!email) return;
  const data = { last_order_at: order.processed_at, last_order_name: order.name };

  const found = await api("GET", `subscribers/find.json?email=${encodeURIComponent(email)}`);
  if (found.ok) {
    await api("PATCH", "subscribers.json", { email, custom_data_mode: "merge", subscriber: { custom_data: data } });
    await api("POST", "subscribers/add_tag.json", { email, tags: ["customer", "ordered"] });
  } else if (found.status === 404 && order.buyer_accepts_marketing) {
    await api("POST", "subscribers.json", { subscriber: {
      email, first_name: order.customer?.first_name, last_name: order.customer?.last_name,
      tags: ["customer", "ordered"], custom_data: data } });
  }
}

createServer(async (req, res) => {
  const chunks = [];
  for await (const chunk of req) chunks.push(chunk);
  const raw = Buffer.concat(chunks);

  const expected = createHmac("sha256", SHOPIFY_WEBHOOK_KEY).update(raw).digest();
  const received = Buffer.from(req.headers["x-shopify-hmac-sha256"] || "", "base64");
  if (received.length !== expected.length || !timingSafeEqual(received, expected)) {
    return res.writeHead(401).end();
  }
  res.writeHead(200).end();
  sync(JSON.parse(raw)).catch(console.error);
}).listen(PORT);

Why the script looks the subscriber up first, and does not send one create call for everyone:

  • POST /api/v1/subscribers on an email that already exists replaces its tags and custom data, and resubscribes a person who unsubscribed. Never send it for a buyer who is already on your list.
  • PATCH with custom_data_mode: "merge" changes only the keys you send and keeps the rest.
  • add_tag adds tags and leaves the others alone. A tag does not start a sequence for an inactive or unsubscribed subscriber, so tagging a past unsubscriber is safe.

Run it on any small server or function host that has a public HTTPS URL. For production, put the work after the 200 on a queue so a slow call to Broadcast cannot be lost.

Route 2: Shopify Flow on Grow, Advanced or Plus

Flow’s Send HTTP request action can set headers, so it can call Broadcast directly. Store the token as a Flow secret and use it in the header value.

  1. Create a workflow with the Order paid trigger.
  2. Add Send HTTP request: method POST, URL https://your-broadcast-domain.com/api/v1/subscribers/add_tag.json, headers Authorization: Bearer <your secret> and Content-Type: application/json, body:
   { "email": "{{ order.email }}", "tags": ["customer", "ordered"] }
  1. Add a second Send HTTP request: method PATCH, URL https://your-broadcast-domain.com/api/v1/subscribers.json, body:
   {
     "email": "{{ order.email }}",
     "custom_data_mode": "merge",
     "subscriber": { "custom_data": { "last_order_at": "{{ order.processedAt }}" } }
   }
  1. Set 4XX responses to Ignore. Broadcast answers 404 for a buyer who is not a subscriber, and that is the right outcome.

This tags people who are already on your list. It does not add new buyers, because Flow cannot easily branch on Broadcast’s answer. To add buyers who opted in at checkout, point the Flow request at the script from route 1 instead.

Route 3: n8n, Make or Zapier

On a Basic plan without Flow’s HTTP action, an automation service does the same job. Start with the service’s Shopify trigger for orders, or with its own webhook URL that a Shopify webhook calls. Then add HTTP steps that copy the script’s logic: find the subscriber, then merge custom data and add tags, or create the subscriber only when buyer_accepts_marketing is true. These services hold your Broadcast token, so give them a token with subscriber permission only.

Check that it works

  1. Place a test order with an email that is already a subscriber.
  2. Open the subscriber in Broadcast. The tags show customer and ordered, and custom data shows last_order_at.
  3. Open the sequence. The subscriber is enrolled on the first step.

If nothing arrives, check the webhook delivery in Shopify first, then the response your script got from Broadcast. Write requests can succeed with a warnings array. See API Response Warnings.

Frequently asked questions

Do I need Shopify Plus to send webhooks to my email tool?

No. Webhooks under Settings > Notifications work on every plan. Flow’s Send HTTP request action needs Grow, Advanced or Plus.

Why not send the Shopify webhook straight to Broadcast?

Shopify sends its own order JSON with an HMAC signature. Broadcast expects a Bearer token and its own fields. A small script or an automation service translates between them.

Can Broadcast email abandoned checkouts from Shopify?

No. Broadcast does not receive checkout events today. Keep Shopify’s own abandoned checkout email turned on.

Does a repeat order start the post-purchase sequence again?

No. A subscriber goes through a sequence once. The last_order_at value still updates on every order, so segments stay current.

Is this the same as Broadcast’s general API guide?

This page is the Shopify recipe. For the API, CLI and MCP server in general, see connecting your app or an AI agent and the email marketing API overview.


The API reference for every call on this page: Subscribers API, Sequences API and Segments API. For events that go from Broadcast back to your own systems, see Webhooks. Comparing tools for a Shopify store? Read our Klaviyo alternative page and the e-commerce use case.

You may also be interested in

New to Broadcast?

Everything on this page is something you run yourself. Broadcast is self-hosted email marketing software you buy once and own: your server, your subscriber data, no per-contact pricing and nothing to renew.

One-time license, unlimited subscribers, and 30 days to change your mind.