Data sources Which connections are live right now.Each source reports its own status, and any problem is written in plain English.
Live, demo or off. Until Shopify is connected every panel shows demo data, and live and demo are never mixed.
- ShopifyDemoAdd SHOPIFY_STORE_DOMAIN, SHOPIFY_CLIENT_ID and SHOPIFY_CLIENT_SECRET to go live.
- Sessions and funnelDemoDemo sessions until Shopify is connected.
- Meta adsDemoDemo spend and creatives.
- Google AdsDemoDemo spend and creatives.
- TikTok adsOffNot in the demo. Add TIKTOK_APP_ID and TIKTOK_APP_SECRET in Vercel, then click Connect TikTok in Settings.
- RechargeDemoDemo subscriber counts.
- KlaviyoDemoDemo campaign sends and email revenue.
- Ticket storageOffIn memory only, so tickets reset on each deploy. Connect a Redis store to the Vercel project to keep them.
- PasswordOffNo DASHBOARD_PASSWORD set. Fine for the demo, required before live data.
Connect this demo brand's Shopify
A read-only app in the Shopify Dev Dashboard, inside the organisation that owns this demo brand's store. About fifteen minutes.
- In
dev.shopify.com, use the organisation switcher to pick the organisation that owns this demo brand's store, not another brand's. If it isn't listed, ask the store owner to invite you to it. - Open the Cross Street Coffee Dashboard app, or click Create app and call it that (app names can be 30 characters at most). Go to Versions, then Create version.
- Set App URL to
https://www.thatotheragency.co.ukand untick Embed app in Shopify admin. - Set Scopes to
read_reports,read_orders,read_customers,read_products, leave Optional scopes empty, and click Release. - Open the app's Home, scroll down, click Install app, choose this demo brand's store and click Install.
- Open Settings in the app and copy the Client ID and Client secret.
- In Vercel, open the dashboard-demo project, then Settings, Environment Variables. Add
SHOPIFY_STORE_DOMAIN,SHOPIFY_CLIENT_ID,SHOPIFY_CLIENT_SECRETandDASHBOARD_PASSWORDfor Production, then redeploy.
If the status above says shop_not_permitted, the app and the store are in different organisations in the Dev Dashboard. If a scope is missing, add it to a new version, release it, and click Install app again.
Connect Meta ads
A read-only system user token for this demo brand's ad account. About ten minutes.
- In
developers.facebook.com, create a Business app called Cross Street Coffee Dashboard with the Marketing API use case, and connect it to this demo brand's business portfolio. It can stay unpublished. - In Meta Business settings for Cross Street Coffee, open Users, then System users, and add a system user with the Employee role. Give it a different name from the app, for example Cross Street Coffee Reporting, or Meta won't save it.
- Click Assign assets: give it the Cross Street Coffee ad account with view performance access only, and the Cross Street Coffee Dashboard app. The ads_read permission only appears once the app is assigned.
- Click Generate new token, pick the Cross Street Coffee Dashboard app, set expiry to Never, tick only
ads_read, and copy the token. Meta only shows it once. - In Vercel add
META_ACCESS_TOKENandMETA_AD_ACCOUNT_ID(the number from Ads Manager's account menu) for Production, then redeploy.
Connect Google Ads
A read-only service account, so there's no sign-in to expire. About fifteen minutes. No manager account or developer token needed since September 2026.
- In
console.cloud.google.com, create a project called Cross Street Coffee Dashboard, then under APIs & Services, Library, enable the Google Ads API. Use a new project rather than another brand's, so either brand's access can be removed on its own. - On the Google Ads API Overview page, expand Apply for next access level and apply for Explorer access. Google usually approves it automatically.
- Under IAM & Admin, Service accounts, create one called dashboard-demo. On its Keys tab, add a key, create new key, JSON. Copy its email address.
- In this demo brand's Google Ads, go to Admin, Access and security, click +, paste the service account email and choose Read only.
- In Vercel add
GOOGLE_ADS_SERVICE_ACCOUNT_JSON(the whole key file) andGOOGLE_ADS_CUSTOMER_IDfor Production, redeploy, and delete the downloaded key file.
Google spend, conversions and conversion value count towards MER, CAC and ROAS. Ads named with script and hook tags (S07 H03) also appear in Creative performance.
Connect TikTok ads
Only needed if Cross Street Coffee runs TikTok ads. A developer app with read-only reporting; TikTok reviews the developer profile and the app, up to three business days each.
- At
business-api.tiktok.com/portal, click Become a Developer. Use a company email whose domain matches the website you enter; personal email addresses are rejected. - Once approved, go to My Apps, Create an App. Set the advertiser redirect URL to
https://www.thatotheragency.co.uk/api/tiktok/callbackand tick only Ad Account Management and Reporting. - Once the app is approved, copy the App ID and Secret from its Basic Information page into Vercel as
TIKTOK_APP_IDandTIKTOK_APP_SECRET, then redeploy. - Click Connect TikTok below, tick this demo brand's ad account, and confirm with the code TikTok emails.
Environment variables
Set these in Vercel. Nothing secret is stored in the repository.
| Variable | Purpose |
|---|---|
| SHOPIFY_STORE_DOMAINrequired for live | this demo brand's myshopify.com address (Shopify admin, Settings, Domains). Not northbank.example.com. another brand's stores are refused. |
| SHOPIFY_CLIENT_IDrequired for live | From the app's Settings page in the Dev Dashboard. |
| SHOPIFY_CLIENT_SECRETrequired for live | From the same page. Swapped for a 24 hour Admin API token automatically, so there's no token to copy or renew. |
| DASHBOARD_PASSWORDrequired for live | Password for the whole dashboard. Live data stays off until this is set. |
| REDIS_URL | Added automatically when you connect a Redis store to this Vercel project. Keeps tickets, feature counters and the report cache. Use a new store, not another brand's. Upstash REST credentials (KV_REST_API_URL and KV_REST_API_TOKEN) also work. |
| SHOPIFY_SALES_FILTER | Optional ShopifyQL condition applied to every sales query, for example is_b2b_order IS NOT TRUE to keep wholesale out of the numbers. |
| BUNDLE_MATCH | Regex for product titles that count as bundles. Defaults to the duos, kits, routines and collections. Shopify bundle line items always count. |
| GIFT_MATCH | Regex for free gift lines, shown in grey in Units sold so they don't read as best sellers. Defaults to the gift app's "(100% off)" copies. |
| META_ACCESS_TOKEN / META_AD_ACCOUNT_ID | System user token with only ads_read, plus this demo brand's ad account id. Spend, MER, CAC, ROAS and creative-level rows. another brand's ad account is refused. META_API_VERSION defaults to v25.0. |
| GOOGLE_ADS_SERVICE_ACCOUNT_JSON | The whole JSON key file of a Google Cloud service account added to this demo brand's Google Ads account as Read only. The Cloud project needs the Google Ads API enabled and Explorer access. |
| GOOGLE_ADS_CUSTOMER_ID | this demo brand's 10 digit Google Ads customer ID, dashes optional. another brand's account is refused. GOOGLE_ADS_LOGIN_CUSTOMER_ID is only needed if access goes through a manager account. |
| TIKTOK_APP_ID / TIKTOK_APP_SECRET | Only if Cross Street Coffee runs TikTok ads. From the TikTok developer app's Basic Information page, then click Connect TikTok above. |
| TIKTOK_ADVERTISER_ID | Only needed if the TikTok authorisation covers more than one ad account. another brand's ad accounts are always left out. |
| KLAVIYO_API_KEY | Private key from this demo brand's Klaviyo account (Settings, API keys) with Read Access on Accounts, Campaigns, Flows and Metrics. Keys can't be edited later, so pick all four. another brand's keys are refused. |
| RECHARGE_API_TOKEN | Only if subscriptions move to Recharge. Subscriptions sold through Seal or any app using Shopify subscription contracts are already counted from the sales reports. |
| FEATURE_TRACKING_KEY / STOREFRONT_ORIGIN | Bearer key the storefront uses to post feature events, and the origin allowed to post (https://northbank.example.com). |
| SHOPIFY_ADMIN_TOKEN | Only for a legacy custom app made in the Shopify admin before 2026. Leave blank when using the Dev Dashboard app. |
How the numbers are built
So nobody has to guess what a figure means.
- Sales, orders, units, new vs returning and product mix come from Shopify's own reports (ShopifyQL), so they line up with Shopify analytics.
- Net sales are after discounts and returns, before tax and shipping.
- Sessions, the funnel and conversion rate exclude bot sessions. Conversion rate is sessions that completed checkout divided by sessions.
- Channels use Shopify's traffic type and referring medium. AI Referral uses Shopify's AI agent tag plus referrer domains such as Perplexity and Claude.
- Duos, edits and collections count as bundles. Free gift lines are shown in grey so they don't read as best sellers.
- Subscription panels stay hidden until subscription orders appear in Shopify or a Recharge token is added.
- Recent ranges refresh every 15 minutes. Older ranges are cached for six hours.
Persistence
Tickets and feature counters need somewhere to live.
In the Vercel project open Storage, add a new Redis database on the free plan, and connect it to this project. Vercel adds REDIS_URL and the next deploy keeps everything. Don't connect another brand's store: each dashboard keeps its own tickets. Until then tickets live in memory and reset on each deploy.
Targets
Where the plan numbers come from.
No plan loaded yet, so the plan bars and Pace to plan stay hidden. Send the monthly plan (net sales and orders per month) and scripts/targets_from_csv.py turns it into data/targets.json.