How to Roll Up Multi-Store Shopify Sales into One Weekly Email

Build a scheduled Spojit workflow that loops over several Shopify store connections, pulls each store's orders for the past week, aggregates revenue and order count per store with the math connector, and emails a single league-table comparison to your regional managers.

What This Integration Does

If you run more than one Shopify storefront, comparing them usually means logging into each admin separately and copying numbers into a spreadsheet. This workflow does that for you on a fixed weekly cadence. It walks through a list of store connections, fetches each store's paid orders from the last seven days, sums the order totals and counts the orders, and then assembles one ranked table so a regional manager can see every store side by side in a single email. No dashboards to open, no per-store logins.

The workflow is driven by a Schedule trigger, so it runs on its own without anyone pressing a button. Each run is self-contained: it reads live order data from Shopify, builds the rollup in memory, sends the email, and leaves no records behind. Because it only reads orders and never writes back to any store, re-running it is completely safe. If you run it twice in a week you simply get two emails covering the same window. The reporting window is computed at run time from the current date, so the same workflow keeps working week after week with no edits.

Prerequisites

  • One Shopify connection per store you want to report on, each added under Connections > Add connection > Shopify. Note the exact connection name for each store, as you will reference them in the loop.
  • Read access to orders on each Shopify store (the connection's API access must include reading orders).
  • The recipient email addresses for your regional managers added to the org allowlist under Settings > General > Email recipients, since the Send Email node only delivers to allowlisted addresses.
  • The math and csv connectors are built-in utility connectors and need no setup.
  • The timezone your business reports in (for example Australia/Sydney), used by the schedule and the date math.

Step 1: Add a Schedule trigger for the weekly run

Start a new workflow and set the Trigger node type to Schedule. A Schedule trigger uses a 5-field Unix cron expression plus an IANA timezone. To run every Monday at 8:00 AM in Sydney time, enter the cron 0 8 * * 1 and set the timezone to Australia/Sydney. The trigger output is { scheduledAt }, which gives you the moment the run started. A single Schedule trigger can hold more than one schedule if you want, for example, both a Monday morning run and an end-of-week run.

Step 2: Compute the reporting window with the date connector

Add a Connector node in Direct mode on the date connector and call subtract to get the start of your seven-day window. Subtract 7 days from {{ trigger.scheduledAt }} and store the result. You will use this lower bound to filter Shopify orders. Keeping the window calculation in its own step means the same expression drives every store, so the stores are always compared over an identical date range. Format the boundary as an ISO date so it slots cleanly into the Shopify query in the next step.

tool: subtract
date: {{ trigger.scheduledAt }}
amount: 7
unit: days
=> weekStart  (e.g. 2026-06-14)

Step 3: Define the list of stores and loop over them

Add a Transform node to hold the list of stores you want in the report. Build a small array where each entry carries a friendly store label and the name of its Shopify connection, for example:

[
  { "label": "Sydney Flagship", "connection": "shopify-sydney" },
  { "label": "Melbourne", "connection": "shopify-melbourne" },
  { "label": "Online AU", "connection": "shopify-online-au" }
]

Then add a Loop node set to ForEach and point it at that array. Inside the loop body, each iteration exposes the current store as {{ store }}, giving you {{ store.label }} and {{ store.connection }} to work with per store.

Step 4: Pull each store's orders with Shopify list-orders

Inside the Loop body, add a Connector node in Direct mode on the shopify connector and select the list-orders tool. Choose the store's connection for this node so each iteration reads from the right storefront. The list-orders tool accepts a Shopify search query in its query field plus a first page size (max 250). Filter to paid orders created within your window:

tool: list-orders
query: financial_status:paid created_at:>={{ weekStart }}
first: 250

The result is a paginated list of orders, each carrying its total price, currency, and creation date. If a busy store can exceed 250 orders in a week, use the returned cursor in the after field to fetch the next page (see Common Pitfalls).

Step 5: Aggregate revenue and order count per store with the math connector

Still inside the loop, first pull the per-order totals into a flat list. Add a Transform node that maps the orders from Step 4 down to an array of numbers, one total price per order. Then add a Connector node in Direct mode on the math connector and call sum over that array of totals to get the store's revenue. Add a second math Direct-mode node calling average over the same list for an average order value, and use a Transform (or the array connector's length tool) to capture the order count. Collect a small result object per store so the loop accumulates one row per store:

{
  "store": "{{ store.label }}",
  "orders": {{ orderCount }},
  "revenue": {{ revenueSum }},
  "avgOrderValue": {{ avgOrder }}
}

For clean currency display, you can pass revenueSum through the math connector's currency tool to format it as a money string before it reaches the email.

Step 6: Build the league table with the csv connector

After the Loop completes, you have an array of per-store rows. Add a Connector node in Direct mode on the csv connector and call from-json to turn that array into a CSV table with columns for store, orders, revenue, and average order value. Then call the csv connector's sort tool to order the rows by revenue descending, so the top-performing store sits at the top of the league table. The sorted CSV is your at-a-glance comparison. Keep the same row produced in Step 5 so every column lines up across stores.

Step 7: Email the rollup to your regional managers

Finish with a Send Email node, which sends from Spojit's built-in mail service with no connection required. Set Recipients to your managers' allowlisted addresses (comma-separated), give it a templated Subject like Weekly store sales rollup - week of {{ weekStart }}, and put the sorted table from Step 6 into the Body along with a short summary line. Set If sending fails to Fail the workflow so a delivery problem surfaces in your execution history rather than passing silently. Each delivery counts toward your monthly email allowance.

Recipients: regional-manager@yourbrand.com, ops@yourbrand.com
Subject: Weekly store sales rollup - week of {{ weekStart }}
Body:
Here is this week's store league table (paid orders, last 7 days):

{{ leagueTableCsv }}

Tips

  • Keep the store list in the Step 3 Transform node so adding a new store is a one-line change: add its label and connection name, and the loop picks it up automatically.
  • If you want the email to read like a table in plain text, the csv output already aligns columns; you can also add a header line summarising total revenue across all stores by running one more math sum over the per-store revenue values after the loop.
  • Ask Miraxa, the intelligent layer across your automation, to scaffold the skeleton for you with a prompt like "Add a Loop node over a list of stores, and inside it a Connector node on the shopify connector using list-orders, then a math connector sum on the order totals." Then fine-tune the fields in the properties panel.
  • To compare against the prior week, run a second pass with a window from 14 to 7 days back and include a week-over-week change column.

Common Pitfalls

  • Pagination: list-orders returns at most 250 orders per call. A high-volume store can exceed that in a week, so check whether the result includes a next-page cursor and loop on the after field until every page is collected, otherwise revenue will be understated.
  • Timezone drift: Shopify stamps created_at in UTC. If your reporting week is defined in local time, compute weekStart in your business timezone (Step 2) so orders near midnight on the boundary land in the correct week.
  • Mixed currencies: summing totals across stores that sell in different currencies produces a meaningless number. Either report each store in its own currency or convert to a single currency before the math step.
  • Wrong connection per store: every Shopify list-orders node inside the loop must use the connection named by {{ store.connection }}. Reusing one store's connection for all iterations will report the same store multiple times.

Testing

Before turning the schedule on, validate the logic on a small scope. Temporarily shorten the Step 2 window (for example one day) and limit list-orders to a small first value, then use the Run button to execute the workflow once. Open the run in your execution history and confirm the loop produced one row per store, the math totals match what you see in each Shopify admin for that window, and the csv league table is sorted by revenue. Once the numbers reconcile, restore the seven-day window and full page size, then enable the workflow so the Schedule trigger takes over.

Learn More

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.