Analytics and drop-off points
Mistok records an event at every step — from order creation to payment — and shows exactly where, and how much money, went off the rails.
What is collected
| Event | When | Attributes |
|---|---|---|
order_created | orders/create webhook (our methods and cash on delivery) | country, region, city from the shipping address, amount, method |
pay_click | the buyer pressed the button (/pay) | + device (mobile/desktop), country by IP (Cloudflare/nginx), language |
redirected | invoice created, redirect to the PSP | gateway, amount, prepayment rule |
returned | came back from the PSP page | |
paid / prepaid / failed / expired / cancelled / reversed / refunded / reminder_sent / link_opened | the corresponding transitions | decline reason from the gateway |
Drop-off points
- Did not press “Pay” — the order exists, the button was not touched for 30+ min. Most often: the block is not enabled or not noticeable.
- Went to the payment page and did not come back — the classic “I’ll think about it”; cured by reminders.
- Declined by the bank/PSP — with the reason from the gateway response (insufficient funds, 3DS, limit).
- Expired, cancelled, amount mismatch.
For each point the dashboard shows the count and the amount of money lost, and the “stuck today” table lists the specific orders that can still be nudged with a call or a message.
Anomalies that get highlighted
- ≥ 30% declines in a gateway (with ≥ 5 attempts) — check the token/limits.
- ≥ 40% of orders without a button click — check the block on the Thank you page.
- ≥ 5 buyers did not come back — enable reminders.
- Country conversion < 30% — a local method is needed (BLIK for PL, Stripe for the rest).
- Mobile conversion noticeably below desktop — check Apple/Google Pay and the payment page on a phone.
Geography
Country/region/city come from the Shopify shipping address (more reliable than IP); country by IP is added as a separate attribute to spot buyers abroad ordering to Ukraine. Tables: countries (conversion, revenue), regions/voivodeships, cities.
Dashboard: /admin/dashboard?key=…&days=7|30|90. JSON: /admin/api/stats. Telegram: /today.
Analytics module (/admin/analytics)
The dashboard answers “where do we lose money”; the analytics module answers “where does the money come from and do buyers come back”. Same Mistok data, no GA, no cookie banners.
| Block | Data | Shows |
|---|---|---|
| 📣 Traffic sources | landing_site / referring_site / source_name from the orders/create webhook and customerJourneySummary from the Admin API | utm_source / utm_medium (e.g. google / cpc), else the referrer host (instagram.com), else the Shopify source (POS, draft). Orders, paid, conversion, revenue, AOV per source; UTM campaigns separately. |
| 🔁 New vs repeat | customer.numberOfOrders + paid history by email/phone | repeat share, AOV of new vs repeat, top-10 buyers by revenue. |
| 📦 Products | line-item snapshot taken at payment | top-15 by revenue, units, average basket. |
| ⏱️ Time to pay | order created → paid | histogram (< 2 min … > 3 days), median, p90 — tells you when to send reminders. |
| 🔔 Reminders | reminder counter on the invoice | orders reminded, paid afterwards, recovered revenue. |
| 🌍×💳 Country × provider | shipping address + gateway | paid / orders per cell — shows where a local method is missing. |
| 🧑🤝🧑 Cohorts | week of first payment | share of buyers who bought again (12 weeks). |
Top KPIs are compared with the previous period of the same length (▲▼). Insights are generated automatically: conversion drop ≥ 15 %, a weak source, reminder effectiveness, repeat share, too-long time to pay. Export: /admin/analytics.csv?days=30 (sections source / campaign / product / weekday / country_provider / cohort), JSON: /admin/api/analytics?days=30.
💸 Provider fees and 📬 the weekly digest
The “Provider fees” block shows what acquiring costs: the actual fee comes from the mono statement (/api/merchant/statement, once per poll), from LiqPay (receiver_commission), WayForPay (fee) and Fondy statuses; the rest is estimated by rate (FEE_RATE_<PROVIDER> in .env). The “net” KPI = revenue − fees; an insight highlights the most expensive gateway.
new Where the PSP does not report the fee, FEE_RULES (Settings → “Acquiring fees”, or .env) refine the estimate: an array of {provider, country, currency, minAmount, maxAmount, rate, fixed, note}, first match wins; provider is a code, a comma list or *; rate in %, fixed in minor units per transaction. Example: [{"provider":"stripe","currency":"PLN","rate":1.5,"fixed":100},{"provider":"*","country":"PL","rate":2.9}]. Below the provider table — fees by market (country × currency).
Every Monday at 09:00 (Kyiv) the bot sends the weekly digest: revenue, conversion, AOV and buyers with arrows vs last week, sources, losses, providers, reminders, insights. DIGEST=off disables it, DIGEST_DOW/DIGEST_HOUR change the time, /digest in the bot sends it on demand.
Sources and items are stored for orders created after the upgrade; older orders show as “direct / unknown”. In the sandbox every block is filled with fictional data.