Skip to content

Repository files navigation

Power Your App's Analytics with Shopify's Stack

Starter app for the DotDev 2026 workshop, Power Your App's Analytics with Shopify's Stack. The app begins as a simple embedded Shopify app with a loyalty campaigns table. During the workshop you will seed real orders with order metafields, query those metafields in Shopify Analytics, then embed the same ShopifyQL queries in the app.

Before The Workshop

You only need this setup before the session:

  • A Shopify account with access to a Partner organization
  • A fresh Shopify development store where you can install an app and create real orders
  • Node.js 20.19+ or 22.12+
  • pnpm (tested with v10)
  • Shopify CLI
  • Comfort running commands in a terminal
  • Comfort using a code editor

You do not need any existing store data. The seed script creates orders and app-owned metafields for the workshop.

Workshop Walkthrough

Agenda

  1. Create a fresh app and verify its configuration.
  2. Seed real orders with app-owned order metafields.
  3. Verify the seeded data in Admin GraphQL and Shopify Analytics.
  4. Add Analytics UI to the embedded app.
  5. Render ShopifyQL metric cards from the same data.

Create The App With Shopify CLI

This is the workshop path. Create a new app even if you already have apps or demo stores; it keeps everyone on the same setup and avoids inherited configuration issues. You do not need to create the app from the Dev Dashboard first.

  1. Create a new app project from this workshop repo:
shopify app init \
  --template https://github.com/Shopify/dotdev-2026-shopify-analytics \
  --name analytics-workshop-app \
  --package-manager pnpm

In the prompts, select your Partner organization. Shopify CLI creates the app project, links it to a new app, and installs dependencies.

  1. Move into the app directory:
cd analytics-workshop-app
  1. Open shopify.app.toml and verify it includes the required scopes, direct Admin API access settings, and development URL override setting:
scopes = "read_orders,write_orders,read_reports"

[access.admin]
direct_api_mode = "online"
embedded_app_direct_api_access = true

[build]
automatically_update_urls_on_dev = true

If the CLI creates a new config file or overwrites the file, copy the settings above into the active config before continuing. If the seed script later says the app is not approved to access orders, come back to this file and verify the active app version has these scopes.

Use a development store from the same organization you select here. Shopify CLI's app dev command only finds app-development stores or Shopify Plus sandbox stores in the linked app's organization; a regular merchant store in the same organization will not appear.

The seed script uses Shopify CLI's app execute and app bulk execute commands, so you do not need to create or paste a direct Admin API access token. It uses the same development store Shopify CLI records when you run app dev.

Run The App

shopify app dev --use-localhost

When Shopify CLI asks whether to override your app URLs while running app dev, select Yes, automatically update. This lets the CLI point the app URL and redirect URLs at your local development server.

If Shopify CLI says it cannot find the store in the organization, the app is linked to an organization that does not contain that store as an app-development store or Plus sandbox store. Re-run pnpm shopify app config link --reset and choose an app in the organization that owns your development store, or use a development store from the currently linked organization.

Open the preview URL from Shopify CLI in your development store.

Keep this terminal running. Open a second terminal for the seed command in the next step.

Seed Orders

In a second terminal, run the following in the same project directory:

pnpm seed

The script creates:

  • App-owned order metafield definition $app:loyalty.reward_tier
  • App-owned order metafield definition $app:loyalty.campaign_name
  • Tags orders with dotdev-loyalty-seed

The script uses shopify app execute to prepare the metafield definitions and shopify app bulk execute to create real orders in small batches.

Rerunning the script creates more realistic sample orders; it does not reset old data.

Expected output:

Using Shopify CLI for linked-development-store.myshopify.com
Using shop currency USD
Preparing analytics-queryable order metafields...
- Created app--123456--loyalty.reward_tier
- Created app--123456--loyalty.campaign_name
Creating 24 loyalty sample orders with Shopify CLI bulk execute in batches of 4...
Development stores limit order creation, so this can take a few minutes.
1/24 #1001 Bronze / Summer Rewards / $72.43
Waiting 65 seconds before the next order batch...
...
Admin GraphQL verification query:
query SeedOrders {
  orders(first: 5, reverse: true, query: "tag:dotdev-loyalty-seed") {
    nodes {
      name
      rewardTier: metafield(namespace: "$app:loyalty", key: "reward_tier") {
        value
      }
      campaignName: metafield(namespace: "$app:loyalty", key: "campaign_name") {
        value
      }
    }
  }
}

The script prints a lightweight Admin GraphQL verification query, then the app-specific ShopifyQL field paths after it prepares the metafields. They look like order.metafields."app--123456--loyalty".reward_tier. Use the exact paths from your output or from the Analytics Exploration UI. It also prints an Analytics Exploration URL that opens a stacked campaign-by-tier report for the seeded data.

The orders are spread across the current month. If you inspect Analytics manually, without using the printed Exploration URL, make sure your report is not filtered to only today.

Verify In Admin GraphQL

Use Shopify CLI's local GraphiQL instance for this step:

  1. Keep shopify app dev running.
  2. Press g in that terminal window to open GraphiQL.
  3. Paste and run this query:
query SeedOrders {
  orders(first: 5, reverse: true, query: "tag:dotdev-loyalty-seed") {
    nodes {
      name
      rewardTier: metafield(namespace: "$app:loyalty", key: "reward_tier") {
        value
      }
      campaignName: metafield(namespace: "$app:loyalty", key: "campaign_name") {
        value
      }
    }
  }
}

Use the local GraphiQL instance instead of installing the separate Shopify GraphiQL app for this verification. The local instance connects as this workshop app, so it can resolve the $app:loyalty namespace and read the app-owned metafields created by the seed script. Shopify's standalone GraphiQL app is useful for general Admin API exploration, but it can't access data owned by other apps.

✅ Checkpoint: each returned order should include rewardTier.value and campaignName.value. If not, your orders weren't seeded correctly. Ask for help.

Use The Analytics Exploration Page

Start with the Analytics Exploration URL printed by the seed script. It opens a stacked campaign-by-tier report for the seeded data. You can also open /analytics/reports/explore in the Shopify Admin and use the ShopifyQL editor.

If you use the configuration panel dimension picker, search for the field name, such as campaign name and reward tier. The app-owned namespace can be easier to copy from the seed script output.

Reward tier performance:

FROM sales
  SHOW average_order_value
  GROUP BY order.metafields."app--YOUR_APP_ID--loyalty".reward_tier
  DURING this_month
VISUALIZE average_order_value TYPE bar

Top campaigns:

FROM sales
  SHOW total_sales
  GROUP BY order.metafields."app--YOUR_APP_ID--loyalty".campaign_name
  WITH TOTALS
  DURING this_month
VISUALIZE total_sales TYPE donut MAX 3

Embed Analytics In The App

The same ShopifyQL queries can render directly inside the embedded app.

  1. Add the Analytics UI script to app/root.tsx, directly after the Polaris script:
<script
  defer
  src="https://cdn.shopify.com/shopifycloud/analytics-ui.js"
></script>

✅ Checkpoint: in your browser devtools, inspect inside the embedded app iframe and confirm analytics-ui.js is loaded.

  1. At the top of app/routes/app._index.tsx, add your app-owned metafield namespace:
const LOYALTY_METAFIELD_NAMESPACE = "app--YOUR_APP_ID--loyalty";

Replace app--YOUR_APP_ID--loyalty with the exact namespace printed by the seed script.

  1. In the Index component, render the metric cards above <CampaignsTable /> when Analytics is available:
return (
  <s-page heading="Loyalty campaigns">
    {analyticsAvailable && (
      <div className={styles.analyticsGrid}>
        <div className={styles.metricCardFrame}>
          <s-shopifyql-metric-card
            heading="Reward tier performance"
            query={`FROM sales
SHOW average_order_value
GROUP BY order.metafields."${LOYALTY_METAFIELD_NAMESPACE}".reward_tier
DURING this_month
VISUALIZE average_order_value TYPE bar`}
          ></s-shopifyql-metric-card>
        </div>
        <div className={styles.metricCardFrame}>
          <s-shopifyql-metric-card
            heading="Top campaigns"
            query={`FROM sales
SHOW total_sales
GROUP BY order.metafields."${LOYALTY_METAFIELD_NAMESPACE}".campaign_name
WITH TOTALS
DURING this_month
VISUALIZE total_sales TYPE donut MAX 3`}
          ></s-shopifyql-metric-card>
        </div>
      </div>
    )}
    <CampaignsTable />
  </s-page>
);

✅ Checkpoint: the app should show two metric cards above the campaigns table. They should render in two columns above 550px and stack below that.

If a card cannot load data, verify:

  • read_reports is present in shopify.app.toml
  • embedded_app_direct_api_access = true is present in shopify.app.toml
  • The metafield namespace matches the seed script output exactly
  • Seeded data has appeared in Analytics

Already Have An App?

For the workshop, we recommend using a new app. If you already have an app you want to use outside the workshop flow, run:

shopify app config link

Select the existing app in the prompts, then run app dev against your development store so Shopify CLI records it for this app project:

shopify app dev --use-localhost

For an existing embedded app, the minimum integration is intentionally small: load analytics-ui.js, then add an <s-shopifyql-metric-card> with a ShopifyQL query. Ensure your app is configured with appropriate scopes and embedded_app_direct_api_access.

About

A repo for the Shopify Analytics workshop at DotDev

Resources

Code of conduct

Security policy

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages