Analytics & data
Events, webhooks, exports, dashboard discrepancies, third-party forwarding and subscriber base import.
What data does Purchasely produce, and how do I get it out?
Three channels, in decreasing order of completeness:
| Channel | What it gives you |
|---|---|
| S2S webhooks | Real-time JSON on the whole subscription lifecycle — entitlement events, 27 lifecycle events, offer events, TRANSACTION_PROCESSED. The most complete channel: you replicate the data on your side continuously. |
| Third-party forwarding | Automatic forwarding of server events and subscription attributes to your analytics and CRM tools. |
| CSV exports | Download CSV on the Dashboards, respecting the active filters and granularity. |
📚 Purchasely Analytics overview
What is the difference between Server Events and UI / SDK Events?
| Family | Where it comes from | What it is for |
|---|---|---|
| Server Events | Our backend | Entitlements, subscription lifecycle, offers, revenue. Reliable, retried, and the source of truth. |
| UI / SDK Events | The SDK, inside the app | Paywall views, interactions, conversion funnels, quiz answers. |
The distinction matters when a number looks wrong: revenue and subscription counts come from Server Events, while everything about paywall exposure and conversion comes from UI / SDK Events emitted by the app.
📚 Entitlement events · Lifecycle events · Offer events · Transactional event · UI / SDK events list
Can I configure several webhook URLs for one app?
No — one webhook endpoint per app. If you need to fan out, receive the event on a single endpoint of yours and dispatch downstream, or use the third-party integrations for tools we already support.
Our platform retries any event you do not acknowledge with an HTTP 200, so a temporary outage on your side does not lose data.
📚 Webhook
Why does a dashboard number not match what I compute myself?
Before assuming a bug, check these in order:
- Which event family the metric is built on. Paywall views, conversion rates and A/B test exposure come from UI / SDK events. If those events are not being collected — for example because
revokeDataProcessingConsent([.analytics])is set — the numbers are structurally incomplete while revenue stays correct. - Unknown users. Purchases that arrive only through store notifications appear in subscription listings but not in paywall dashboards, and generate no webhook. See Understanding user types.
- Time zone and granularity. Dashboards aggregate on their own period boundaries; a daily comparison against your own UTC-based query will drift at the edges.
- Unique viewer counts. Unique-user metrics are approximate by construction at scale, so they will not reconcile to the exact row count of a raw event export.
- Filters still applied. Exports respect the filters visible on screen, which is easy to miss when comparing two exports.
If the gap survives all five, open a support request with the dashboard, the date range, the filters and your own figure — a screenshot of the dashboard plus the query you compared it against is what makes it reproducible.
Why doesn't my revenue match the store's own report?
Because the two measure different things. The Purchasely Revenue chart shows gross revenue:
- it is what the user paid, VAT included,
- before the store commission (typically 15–30%) is deducted,
- attributed to the transaction date,
- and it is not MRR — a yearly subscription shows its full amount on the day of the transaction, not spread over 12 months.
A Google Play or App Store payout report is net of commission and often net of tax, and it is attributed to a settlement period rather than a transaction date. Those two numbers are not supposed to be equal.
Before opening a ticket, reconcile in this order: same date range → same platform filter → gross vs net → transaction date vs payout period → refunds (which land in a later period on the store side).
📚 Revenue · MRR · Subscription refunds
Why aren't my A/B test variants split 50/50?
Several reasons, and most of them are by design:
- Weights are configurable. Each variant carries a weight, and the total must equal 100. Use Equalize in the Console if you want an even split — the defaults are not necessarily what you want.
- Assignment is deterministic, not balanced in real time. A user is bucketed by a hash of their identifier (0–99), so a given user always sees the same variant. Over a small sample that hash does not produce an exactly even split.
- Unique Viewers counts
PRESENTATION_VIEWEDevents, not assignments. If one variant is a Flow and the other a single Screen, or if one variant is slower to render, exposure counts can diverge even with identical weights. - Anonymous users reinstalling get a new identifier, and therefore a new bucket.
A large, persistent imbalance that none of the above explains is worth reporting with the test ID, the weights configured and the observed counts.
How do I run an A/B test with a real control group?
Two structures, depending on what you want to measure:
- Screen A vs Screen B — the standard case. Keep the test type consistent: a UI test changes the Screen, a Price test changes the Plans. Mixing the two makes the result uninterpretable.
- Paywall vs no paywall — the variant serves no Screen, so the SDK returns a deactivated presentation and your app shows nothing. That is how you measure the paywall's own impact rather than one design against another.
Constraints to know up front:
- One Placement per test. A Placement already used by another test cannot be reused.
- One test per Audience + Placement combination.
- An Audience ID cannot be changed once it has been associated with an A/B test or a transaction.
📚 A/B test configuration · A/B test results
When can I read an A/B test result?
The Console computes Bayesian significance, so wait for it rather than eyeballing the numbers. Practically:
- run for 1 to 2 weeks minimum, to cover a full weekly cycle,
- aim for 95%+ significance,
- watch View to Paid (subscriptions started + trials converted, over unique viewers) rather than raw counts,
- remember that Trial Ongoing users have not resolved yet — a test read before the trials mature will overstate whichever variant pushed trials hardest.
Revenue, ARPU and ARPPU stay live even after the test is stopped.
Can I export subscriptions or automate reporting?
- Ad hoc — every Dashboard has a Download CSV on its data table.
- Continuous — the webhook is the right channel. Replicate the events into your own warehouse and you can build any report without depending on our UI.
- Programmatic — there is no API to pull subscription datasets or aggregated statistics on a schedule today. The Client API covers configuration and audience operations, not reporting. If you need a scheduled export, raise it with your account team so it is prioritized against the API roadmap.
Which dashboards should I look at?
| Question | Dashboard |
|---|---|
| Is my subscriber base growing? | Subscription base evolution · Paid subscription movements |
| How healthy is my base? | Subscription status · Subscription retention |
| How much revenue am I making? | MRR · Revenue |
| Do my paywalls convert? | Screens and conversions · Funnel |
| Which SDK versions are actually in the wild? | SDK versions |
| Is the platform healthy right now? | Platform health |
| How many active users do I have? | Active users and app sessions |
Do you forward events to my analytics and CRM tools?
Yes, natively:
- Attribution / MMPs — Adjust, AppsFlyer, Branch
- Analytics — Amplitude, Mixpanel, Google Analytics for Firebase, Piano (AT Internet), Segment, CleverTap
- Engagement / CRM — Airship, Braze, Batch, Customer.io, Iterable, MoEngage, OneSignal, Brevo
- Other — Firebase, Slack, RevenueCat
Most integrations are server-side (S2S), which means they keep working even if the app is closed. Check the specific integration page for whether it also uses client-side SDK events.
You can disable all forwarding with revokeDataProcessingConsent([.thirdPartyIntegrations]) — see Managing user privacy.
📚 Analytics integrations · Engagement & CRM integrations
Why is my S2S integration not receiving anything?
The usual causes, in order:
- Store server notifications are not configured. Purchasely needs to be the notification target on the store side. See App Store S2S and Play Store server-to-server notifications.
- The events concern unknown users, for which no webhook is sent by default (this can be enabled on request).
- Your endpoint is not returning HTTP 200, so the events are being retried rather than delivered.
- The integration is enabled on a different app than the one generating the transactions.
Can I import my existing subscriber base?
Yes — that is how most migrations onto Purchasely start, so that historical subscribers get entitlements and appear in dashboards from day one.
📚 Subscribers base import · Catalogue import
How do I delete or export the data of one specific user?
Through the user deletion request API, and through the webhook stream for export. See Privacy, security & compliance and User deletion request.
Updated 18 minutes ago

