---
title: "Custom triggers - build your own Shopify Flow trigger"
description: "Build a Flow trigger of your own: pick a Shopify event, capture a real payload, write a few lines of JavaScript to filter and reshape it, and test it before you switch it on."
canonical: "https://docs.workflow-trigger-extensions.app/custom-triggers"
---

# Custom triggers

> [!NOTE]
> **Coming soon**
> Custom triggers are in active development and not yet available on production stores. This page describes how they will work so you can plan ahead. We will announce it in the changelog the moment it ships.

The built-in triggers cover the changes most stores care about. A **custom trigger** covers the rest: you pick a Shopify event, write a few lines of JavaScript to decide whether it matters and what to send, and it becomes a trigger you can use in Shopify Flow.

Two things it solves that a built-in trigger cannot:

- **Fire only on your condition.** "Only when an order over 500 EUR gets the `vip` tag" is one line of code, instead of a workflow that runs on every order and then filters.
- **Send exactly the fields you want.** Reshape the event into the values your workflow actually uses, rather than reading them back out one by one.

## How it works

1. **Pick the event** it listens to - any Shopify event the app already receives.
2. **Capture a real payload.** Make that change in your store and the app grabs the exact event body.
3. **Write a transform** - return an object to fire, return `null` to skip.
4. **Test it** against the captured event, and see precisely what your workflow would receive.
5. **Switch it on.**

> [!NOTE]
> **Why we capture a real event instead of generating one**
> A generated sample would not match reality. Shopify's webhook bodies are trimmed to the fields we subscribe to, and event history keeps only the resource ID for high-volume events. Capturing the real thing means the payload you write against is byte-for-byte the payload your trigger will receive - so a passing test genuinely predicts production.

## Writing the transform

Your code receives `payload` (the raw event body), plus `topic` and `shop`.

- **Return an object** and the trigger fires, carrying that object.
- **Return `null`** and the event is skipped. This is how filtering works - there is no separate filter language to learn.
- **Leave the code empty** and it fires on every event of that type.

```javascript
const total = parseFloat(payload.total_price || "0");
const tags = (payload.tags || "").split(",").map(t => t.trim());

if (total < 500) return null;
if (!tags.includes("vip")) return null;

return {
  orderId: payload.admin_graphql_api_id,
  orderNumber: payload.name,
  total,
  currency: payload.currency,
  customerEmail: payload.email,
};
```

## Using it in Shopify Flow

Every custom trigger arrives in Flow as the same trigger: **Custom Trigger**. Add it to a workflow, then add a condition on **Trigger handle** equals your trigger's handle.

That handle is shown on the trigger's page and **never changes**, even if you rename the trigger - so your workflow keeps working.

Each key your transform returns becomes a field on the trigger, and the whole object is also available as JSON if you would rather parse it yourself.

### Does a custom trigger use my plan allowance?

Yes - each time it fires it counts as one event, exactly like a built-in trigger. Events your code skips by returning `null` do **not** count, so a well-filtered custom trigger can use far less of your allowance than a broad built-in one.

### Can I change the handle later?

No, and that is deliberate. Your Flow workflow filters on the handle, so changing it would silently stop that workflow running. You can rename the trigger freely - the handle stays put.

### What happens if my code has a bug?

The event is skipped and the error is recorded on the trigger, so you can see what went wrong. A failing transform never blocks anything else - your other triggers, custom or built-in, carry on unaffected.

### Where does my code run?

In an isolated sandbox, separate from the rest of the app, with a short time limit and no access to your store's credentials. It only ever sees the event payload you captured.

### Can it fire on events the app does not already receive?

Not at first. A custom trigger listens to the events the app already subscribes to for your store, which depends on the permissions you have granted. Broader event coverage is planned.

## Next steps

- [Developer API, MCP and trigger simulation](https://docs.workflow-trigger-extensions.app/developer-api-and-mcp.md) - manage and test triggers from your own code or an AI assistant.
- [How triggers work](https://docs.workflow-trigger-extensions.app/how-triggers-work.md) - the built-in triggers and how they fire.
