Onboarding CRO
SKILL.md
HOW_TO_USE.md
sample_input.json
expected_output.json
skillscroSKILL.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
# Onboarding CRO
Signing up is not the win. A new user is only worth something once they reach the moment the product proves itself and they come back for more. This skill finds where new users stall on the way there, using the product's own analytics, and then designs the onboarding that moves them past that point.
It reads the data itself. Every number in the report comes from a call below, and every call shows what it returned.
## Before you start
You need the InsightfulPipe MCP connected to the GA4 property that records the product (the app or the site where people sign up and use it). A Klaviyo account is optional.
1. Call `query_contexts` with `request="accounts"` and `platform="google-analytics"`. Note `workspace_id`, `brand_id` and the `property_id`. If there are several properties, ask which one records the product.
2. Call `query_contexts` with `request="actions_details"` and `platform="google-analytics"` for `events`, `get_report`, `list_key_events`, `list_audiences`, `create_key_event` and `create_audience`, and follow the body shapes it returns. If Klaviyo is connected, do the same for `get_flows` and `get_flow_report` with `platform="klaviyo"`.
3. Ask the user these things, and use the defaults when they don't know:
- **What the product is and who it's for** (one line). This decides which onboarding model fits (see "Design the fix").
- **The signup event.** Default: `sign_up`, the name GA4 recommends.
- **The onboarding step events**, in order. Default: `tutorial_begin` then `tutorial_complete`, plus any event whose name contains `onboard`, `setup`, `connect`, `create`, `invite` or `import`.
- **The activation event:** the action that shows the user got real value (a first project, a first report, a first message sent and answered). Default: the first key event that fires and isn't the signup event. If none fires, activation is **unknown**; never pick one at random.
- **What onboarding looks like today:** the screens after signup, whether they change by role, goal or plan, and any human touch (a setup call, a named contact). This tells you which patterns are already in place. When the user doesn't say, recommend patterns without assuming any exist, and say so.
- **Where signup happens,** and the paths of the signup, onboarding and help pages. Default for the pages: paths containing `pricing`, `signup`, `sign-up`, `demo` or `onboarding`, plus paths starting with `/docs` (call 8). Add `register`, `get-started`, `welcome` or `/help` when the site uses them.
**Window.** Use the last 12 complete weeks, Monday to Sunday, ending on the last Sunday that is at least 2 days before today (GA4 is still processing the most recent days). Call the first day `START` and the last day `END`, and print both at the top of the report.
## How to run the calls
Every GA4 call goes through `query_data` with `platform="google-analytics"`. Add `workspace_id` and `brand_id` from step 1 to each body. Rules the API enforces, all seen on live runs:
- **Request keys are camelCase where GA4 defines them.** Filters go in `dimensionFilter`; `dimension_filter` is ignored without an error and quietly returns every row. The cohort spec goes in `cohortSpec`. After any filtered call, check that the rows that come back match the filter.
- **Only add up users where each user can sit in one row.** Each user has one `firstSessionDate` and one `firstUserDefaultChannelGroup`, so users in those rows can be summed. Users across devices, pages or days can't, because one person can be in several rows. Never add the `(not set)` first-session rows to the dated ones.
- **New users in the window** are the users of rows whose `firstSessionDate` falls between `START` and `END`. Rows with an earlier first-session date are people who first came before the window; leave them out of the journey.
- **GA4 doesn't know the order of steps.** A user who signed up in the window and did the activation event in the window counts for both, whatever the order. When a later step has more users than the step before it, say so: the earlier step is under-tracked, or users skip it.
- **Missing cohort cells are zeros.** The cohort report leaves out weeks in which nobody came back. A missing cell whose week ends on or before `END` is 0. A cell whose week ends after `END` is blank, even if GA4 returns a number for it, because that week isn't over.
- **Dates** come back as `YYYY-MM-DD` or `YYYYMMDD`. Read both.
- **Rate limits.** When a call is refused with "Retry in N seconds", tell the user how long that is, then wait or stop. Don't retry in a loop.
If a call fails, keep going. Mark the area it feeds **unknown**, say which call failed and why, and never fill the gap with a guess.
## The calls
**1. Key events configured.**
```json
{"action": "list_key_events", "property_id": "properties/<id>"}
```
**2. Existing audiences.** So the skill never offers an audience that already exists.
```json
{"action": "list_audiences", "property_id": "properties/<id>"}
```
**3. Event inventory.** Every event that fired in the window, with users.
```json
{"action": "events", "property_id": "properties/<id>",
"dimensions": ["eventName"], "metrics": ["eventCount", "totalUsers"],
"start_date": "START", "end_date": "END"}
```
**4. What the property can see.** If only the marketing site's host shows up, the product itself isn't tracked here, and everything after the signup click is invisible to this property.
```json
{"action": "get_report", "property_id": "properties/<id>",
"dimensions": ["hostName"], "metrics": ["sessions", "totalUsers"],
"start_date": "START", "end_date": "END"}
```
**5. The new-user journey, by first channel.** Users per event, per first-session date, per the channel that first brought them. Summed over the dated rows in the window, this is the journey funnel; per channel, it's the segment view.
```json
{"action": "get_report", "property_id": "properties/<id>",
"dimensions": ["firstSessionDate", "firstUserDefaultChannelGroup", "eventName"],
"metrics": ["totalUsers"], "start_date": "START", "end_date": "END", "limit": 100000}
```
**6. Journey events by device.** Only the signup, onboarding, activation and return events, so the rows stay few. Device rows can't be summed into a total (one person can use two devices); read each device's rate within its own rows, against that device's `first_visit` users.
```json
{"action": "get_report", "property_id": "properties/<id>",
"dimensions": ["firstSessionDate", "deviceCategory", "eventName"],
"metrics": ["totalUsers"], "start_date": "START", "end_date": "END", "limit": 100000,
"dimensionFilter": {"filter": {"fieldName": "eventName", "inListFilter": {"values": ["first_visit", "sign_up", "tutorial_begin", "tutorial_complete", "login"]}}}}
```
Put the user's own signup, step and activation events in `values`, and keep `first_visit` as the base.
**7. Time to value.** The same events by the day they happened. The gap between `date` and `firstSessionDate` is how many days after their first visit people got there.
```json
{"action": "get_report", "property_id": "properties/<id>",
"dimensions": ["firstSessionDate", "date", "eventName"],
"metrics": ["totalUsers"], "start_date": "START", "end_date": "END", "limit": 100000,
"dimensionFilter": {"filter": {"fieldName": "eventName", "inListFilter": {"values": ["sign_up", "tutorial_begin", "tutorial_complete", "login"]}}}}
```
Put the user's own signup, step and activation events in `values`. A user who does the event on 3 different days is counted on each of those days, so this gives the spread of "user-days", not of people. Report the share on day 0, days 1โ2, days 3โ7, days 8โ14 and day 15 or later, and say it counts user-days.
**8. Journey pages: evaluation, signup and help.** New users who reached the pricing, signup, onboarding or help pages.
```json
{"action": "get_report", "property_id": "properties/<id>",
"dimensions": ["firstSessionDate", "pagePath"],
"metrics": ["totalUsers"], "start_date": "START", "end_date": "END", "limit": 100000,
"dimensionFilter": {"orGroup": {"expressions": [
{"filter": {"fieldName": "pagePath", "stringFilter": {"matchType": "CONTAINS", "value": "pricing"}}},
{"filter": {"fieldName": "pagePath", "stringFilter": {"matchType": "CONTAINS", "value": "signup"}}},
{"filter": {"fieldName": "pagePath", "stringFilter": {"matchType": "CONTAINS", "value": "sign-up"}}},
{"filter": {"fieldName": "pagePath", "stringFilter": {"matchType": "CONTAINS", "value": "demo"}}},
{"filter": {"fieldName": "pagePath", "stringFilter": {"matchType": "CONTAINS", "value": "onboarding"}}},
{"filter": {"fieldName": "pagePath", "stringFilter": {"matchType": "BEGINS_WITH", "value": "/docs"}}}]}}}
```
Swap in the user's own paths. Drop pages that only mention the word, such as a blog post or a guide about signup forms. Leave out paths GA4 returns cut short (ending in `...`), and say how many. For one page, users can be summed over the dated first-session rows. Across pages they can't (one person can read three help pages), so a stage made of several pages is reported as "at least" its biggest page. Help pages read by new users are an early sign of where setup gets hard: name the most-read ones by what they cover (troubleshooting, a connection guide, account setup). Give every group an explicit rule; never let a catch-all group collect what's left. When one guide shows up at two paths, count the topics (platforms, features) as well as the pages.
**9. Hand-off clicks.** When signup lives on another domain, GA4's outbound-click event shows which links new visitors followed. A link to a subdomain of the same site is often not recorded as outbound; if the signup link never shows up here, the hand-off isn't measured.
```json
{"action": "get_report", "property_id": "properties/<id>",
"dimensions": ["linkDomain", "linkUrl"], "metrics": ["eventCount", "totalUsers"],
"start_date": "START", "end_date": "END",
"dimensionFilter": {"filter": {"fieldName": "eventName", "stringFilter": {"value": "click"}}}}
```
**10. Return by weekly cohort.** GA4's own cohort report: 12 weekly cohorts by first-session date, each followed for up to 11 weeks. Cohort calls take no `start_date` or `end_date`; the dates live in each cohort. `W01_START` is `START`, and each cohort is 7 days.
```json
{"action": "get_report", "property_id": "properties/<id>",
"dimensions": ["cohort", "cohortNthWeek"],
"metrics": ["cohortActiveUsers", "cohortTotalUsers"],
"cohortSpec": {"cohorts": [
{"name": "w01", "dimension": "firstSessionDate", "dateRange": {"startDate": "W01_START", "endDate": "W01_END"}},
{"name": "w02", "dimension": "firstSessionDate", "dateRange": {"startDate": "W02_START", "endDate": "W02_END"}},
{"name": "w03", "dimension": "firstSessionDate", "dateRange": {"startDate": "W03_START", "endDate": "W03_END"}},
{"name": "w04", "dimension": "firstSessionDate", "dateRange": {"startDate": "W04_START", "endDate": "W04_END"}},
{"name": "w05", "dimension": "firstSessionDate", "dateRange": {"startDate": "W05_START", "endDate": "W05_END"}},
{"name": "w06", "dimension": "firstSessionDate", "dateRange": {"startDate": "W06_START", "endDate": "W06_END"}},
{"name": "w07", "dimension": "firstSessionDate", "dateRange": {"startDate": "W07_START", "endDate": "W07_END"}},
{"name": "w08", "dimension": "firstSessionDate", "dateRange": {"startDate": "W08_START", "endDate": "W08_END"}},
{"name": "w09", "dimension": "firstSessionDate", "dateRange": {"startDate": "W09_START", "endDate": "W09_END"}},
{"name": "w10", "dimension": "firstSessionDate", "dateRange": {"startDate": "W10_START", "endDate": "W10_END"}},
{"name": "w11", "dimension": "firstSessionDate", "dateRange": {"startDate": "W11_START", "endDate": "W11_END"}},
{"name": "w12", "dimension": "firstSessionDate", "dateRange": {"startDate": "W12_START", "endDate": "W12_END"}}],
"cohortsRange": {"granularity": "WEEKLY", "startOffset": 0, "endOffset": 11}}}
```
**11. Repeat use of the activation event.** The same cohort report with a filter on one event. On a live run the filter shrank each cohort to the users who did that event (week 0 active users equal the cohort size), and each later week counted the cohort's users who did it in that week. Week-N users รท week-0 users over weeks 1โ4 shows whether the "aha" action turns into a habit.
```json
{"action": "get_report", "property_id": "properties/<id>",
"dimensions": ["cohort", "cohortNthWeek"],
"metrics": ["cohortActiveUsers", "cohortTotalUsers"],
"dimensionFilter": {"filter": {"fieldName": "eventName", "stringFilter": {"value": "ACTIVATION_EVENT"}}},
"cohortSpec": {"cohorts": [
{"name": "w01", "dimension": "firstSessionDate", "dateRange": {"startDate": "W01_START", "endDate": "W01_END"}},
{"name": "w02", "dimension": "firstSessionDate", "dateRange": {"startDate": "W02_START", "endDate": "W02_END"}},
{"name": "w03", "dimension": "firstSessionDate", "dateRange": {"startDate": "W03_START", "endDate": "W03_END"}},
{"name": "w04", "dimension": "firstSessionDate", "dateRange": {"startDate": "W04_START", "endDate": "W04_END"}},
{"name": "w05", "dimension": "firstSessionDate", "dateRange": {"startDate": "W05_START", "endDate": "W05_END"}},
{"name": "w06", "dimension": "firstSessionDate", "dateRange": {"startDate": "W06_START", "endDate": "W06_END"}},
{"name": "w07", "dimension": "firstSessionDate", "dateRange": {"startDate": "W07_START", "endDate": "W07_END"}},
{"name": "w08", "dimension": "firstSessionDate", "dateRange": {"startDate": "W08_START", "endDate": "W08_END"}},
{"name": "w09", "dimension": "firstSessionDate", "dateRange": {"startDate": "W09_START", "endDate": "W09_END"}},
{"name": "w10", "dimension": "firstSessionDate", "dateRange": {"startDate": "W10_START", "endDate": "W10_END"}},
{"name": "w11", "dimension": "firstSessionDate", "dateRange": {"startDate": "W11_START", "endDate": "W11_END"}},
{"name": "w12", "dimension": "firstSessionDate", "dateRange": {"startDate": "W12_START", "endDate": "W12_END"}}],
"cohortsRange": {"granularity": "WEEKLY", "startOffset": 0, "endOffset": 11}}}
```
Run it only when the activation event fires in the window. It shows repeat use of one action, not whether the action predicts staying; for that, see "Finding the activation metric".
**12. Onboarding emails (Klaviyo, optional).** Use `platform="klaviyo"`.
```json
{"action": "get_flows", "auto_paginate": true, "filter": "equals(archived,false)"}
```
```json
{"action": "get_flow_report", "body": {"data": {"type": "flow-values-report", "attributes": {
"timeframe": {"key": "last_90_days"},
"statistics": ["recipients", "delivered", "opens_unique", "open_rate", "clicks_unique", "click_rate", "conversions", "conversion_rate", "unsubscribes"],
"group_by": ["flow_id", "flow_message_id", "flow_name", "flow_message_name"]}}}}
```
Rates come back as fractions from 0 to 1. Klaviyo counts conversions against its "Placed Order" metric unless you pass `conversion_metric_id`; for a product without orders, pass the id of the activation or upgrade metric if the product sends one to Klaviyo, and otherwise read clicks, not conversions.
## Map the journey
Sort every event from call 3 and every page from call 8 into one of seven stages. Name an event's stage only from its name and what the user told you; when it's unclear, ask.
| Stage | What counts | Usual signals |
|---|---|---|
| 1. Arrive | first visit | `first_visit` (web) or `first_open` (app) |
| 2. Engage | the visit was more than a bounce | `user_engagement`, `scroll` |
| 3. Evaluate | looked at what it costs or how it works | pricing, demo and docs pages (call 8) |
| 4. Hand-off | started signing up | the signup page view, or a click to the signup domain (call 9) |
| 5. Sign up | account created | `sign_up` |
| 6. Onboard | the setup steps | `tutorial_begin`, `tutorial_complete`, the user's step events |
| 7. Activate and return | first value, then coming back | the activation event; week-1 return from call 10 |
For each stage, give the new users who reached it (call 5, dated rows in the window), the share of the stage before, and the share of all new users. Mark a stage **not tracked** when no event or page stands for it. The stage with the biggest drop from the one before it is the one to fix first, unless an earlier stage is not tracked; then the first fix is to track it, because a drop you can't see can't be ranked.
## The areas
Score each area **pass**, **warn**, **fail** or **unknown**. The thresholds are starting points. When the user has their own history or target, use that instead and say so.
### 1. Measurement: can the journey be seen?
From calls 1, 3 and 4.
| Check | Result |
|---|---|
| The product is tracked | fail when call 4 shows only the marketing site and no app host, and the user says the product lives elsewhere |
| Signup is tracked | fail when the signup event doesn't fire in the window |
| Activation is tracked | fail when no activation event fires; warn when one fires but isn't a key event |
| Onboarding steps are tracked | warn when signup and activation fire but no step event does |
| Key events are real | warn when key events are configured that never fired in the window; list how many |
| Tracking is steady | warn when one week's new users (call 5, summed by week) are 3 or more times the median of the other weeks: a tag change or a burst of automated visits. Read rates within the steady weeks too, and say which weeks those are |
| Test traffic is kept out | warn when `localhost`, a staging host or a preview host shows up in call 4 |
### 2. Hand-off: from visitor to signup
From calls 5, 8 and 9. The share of new users who reach the signup page or click to the signup domain. When neither is tracked, the area is **unknown**, and the evaluation pages (pricing, demo, docs) are reported as information. Show the split by first channel (call 5) for channels with 30 or more new users.
### 3. Onboarding completion
From calls 5 and 6. Users who finished the last onboarding step รท users who signed up. Pass at 70% or more, warn from 50% to 70%, fail under 50%. When a step has more users than the step before it, warn and say which step is under-tracked or skipped.
### 4. Activation and time to value
From calls 5 and 7. Activation rate = users who did the activation event รท users who signed up, both from dated rows in the window. Pass at 40% or more, warn from 20% to 40%, fail under 20%. These are rough starting points for a self-serve product; a product sold with hands-on setup should beat them, and the product's own trend matters more than any outside number.
Feature adoption, as information: for each other key event that fires, its users รท the activation event's users, both from call 5. GA4 doesn't know the order, so it shows how many activated users also use the feature, not when.
Time to value: the share of activation user-days that land on day 0. Warn when under half of them happen on the first day, because the first session is where most of the onboarding effort pays off.
### 5. Early return
From call 10 (and 11 when activation fires). Pool the cohorts whose week 1 is complete: week-1 return = cohort users active in week 1 รท cohort size. Do the same for week 4 with the cohorts old enough. Read one cohort on its own only when it has 30 or more users. When signup isn't tracked, these are site visitors, not product users: report them as information and leave the area **unknown**.
### 6. Segments: who gets stuck
From calls 5 and 6. The step rate of the stage to fix, by first channel and by device. When the stage to fix isn't tracked, use the deepest step that is (often first visit to engaged visit), and say so. A gap is worth reporting when both sides have 30 or more users and the rates differ by more than 2 ร โ(p(1โp)(1/n1 + 1/n2)), with p the pooled rate. Warn when a channel or device that brings 20% or more of new users converts at under half the rate of the rest. Below 30 users a side, say "too few users to compare".
### 7. Onboarding emails
From call 12. Fail when the account has no live flow for new users (a welcome or onboarding flow, or one triggered by signup or by a list join). Warn when the only onboarding flow is purely time-based, with no message triggered by what the user did or didn't do. When Klaviyo isn't connected, mark it **unknown** and ask what emails go out after signup.
## Scoring
- **Grade:** start at 100. Each **fail** costs 12 points, each **warn** 5. An **unknown** costs nothing, but list it.
- **No grade** when 3 or more areas are unknown: a grade over half the journey would mislead. Say "not graded" and why.
- **Rating:** 85 or above is healthy, 65โ84 needs work, under 65 is at risk.
- Print each area's result next to its deduction, so the grade can be checked.
## Finding the activation metric
The best activation event is the early action that best separates users who stay from users who leave. Compare, for each candidate action in the first week: week-4 retention of users who did it รท week-4 retention of users who didn't. The action with the biggest ratio, that enough users can reach in the first session, is the activation metric.
GA4's reporting API can't split one group of users by what they did and then follow them, so this comparison needs user-level data:
- **BigQuery export (untested until connected).** If the GA4 property is linked to BigQuery and the InsightfulPipe BigQuery connection is set up, run the comparison with `run_query` (`platform="bigquery"`) on the export's `events_*` tables: users by `user_pseudo_id`, first-week events, and whether they came back in week 4. Check the table name with `list_datasets` first. This path has not been run on a live account yet.
- **The product's own data.** Otherwise, ask the user for the same comparison from their product analytics or database, and mark every figure "from your data, not checked".
Typical candidates, to start the list: a first project with a first task in it (project tools), a first contact with a logged activity (CRMs), a first campaign sent (email tools), tracking installed and a first report opened (analytics), a first design made (design tools), a first message that gets a reply (chat tools).
Until it's found, use the user's best candidate and say that it hasn't been tested.
Later outcomes (paid conversion, lifetime value, satisfaction scores) sit in billing or survey data, not GA4. Ask for them when the user wants the onboarding tied to revenue, and mark them "from your data, not checked".
## Design the fix
Tie every recommendation to the stage that loses the most people, and to its numbers. A good onboarding gets each new user to the activation event by the shortest path, and gives them a reason to come back.
**Pick the onboarding model** from the product and its price:
- **Self-serve:** cheap or simple products with many signups. Everything happens in the product and by email, so the first-run screens and help content carry the load.
- **Assisted:** mid-priced products with some setup. Automate the basics, and send a person at the points where call 5 or 7 shows people stall.
- **Hands-on:** complex or expensive products. A named person runs the setup, with an agreed definition of "live" and a planned hand-over to support.
**Match the pattern to the drop:**
| Where people stall | Patterns that help |
|---|---|
| Between signup and the first step | ask one question at signup (role, goal or team size) and open on the matching first task; a screen that starts the first task instead of a tour |
| Inside the setup steps | a short guided setup that shows progress, saves partial work and lets people skip a step and come back; ask only for what the first result needs |
| After setup, before first value | empty screens that show what a full one looks like, with one clear first action and templates or sample data |
| Slow time to value | a checklist of 4 to 7 small, ordered tasks with visible progress; a hands-on walkthrough of the one key task, done in the real product in a few minutes |
| Feature confusion | reveal advanced features when they become relevant; a few dismissible hints, shown one at a time and remembered once closed |
| Week-1 return is low | messages triggered by what the user did or didn't do (below), and a visible next step after every success |
**The emails after signup.** Behaviour beats the calendar. Plan one message per trigger, each with one action:
- started signing up but didn't finish: you're almost done, with a link back to the step they left (needs an event when signup starts, or the email captured on the first step; without one, list it as a gap)
- right after signup: welcome, what to do first, one link that opens that task
- signed up but never came back: the account is ready, here's the one thing to do
- came back but didn't do the key action: why it matters, a direct link, and a short example from a similar user
- did the key action: well done, here's the next most useful thing
- still not active after about a week: ask what's in the way, and offer help or a call
- a deadline is coming (a plan or setup window) and the user isn't active: a summary of what they'd miss and a last offer of help
**Personalise** by role, goal, team size or the channel that brought them. Paid-ad visitors arrive with the ad's promise in mind, so their first screen should deliver that promise; organic visitors often need more explanation. If call 6 shows mobile users stall, the first-run must work on a phone.
**Avoid the usual mistakes:** a tour of every feature before the user has done anything; a pile of pop-ups, hints and emails at once; a finished setup with no obvious next step; the same path for every kind of user; a desktop-only first run; and changes shipped with no step tracked to show whether they worked.
**Ship it as a loop:** measure the biggest drop, write down why people might stop there, change one thing for a share of new users, compare the step rate, keep what wins and move to the next drop. Simplifying the first action, cutting setup steps, fixing empty screens and sending a welcome email with one clear action are usually quick wins; rebuilding the flow, personalising it and adding human touchpoints are bigger bets.
**Connect it to paid media.** Every user who never activates is acquisition spend with no return, so lifting activation from 25% to 40% gets 60% more active users from the same budget. Use the stage audiences below to bring stalled users back with the message for their stage, and check that each ad's promise is what the first screen delivers.
## Report format
1. **Header:** property, `START` to `END`, the activation event used (or "unknown"), and the grade or "not graded".
2. **Journey map:** the seven stages, users at each, the step rate and the share of new users; "not tracked" where it applies. Name the stage to fix first.
3. **Scorecard:** one row per area: result, the key number, one sentence on why.
4. **Top fixes,** up to 5. Tracking fixes for stages that aren't tracked come first, because they decide what can be ranked at all. The rest are ranked by the new users the stage loses each month: users lost over the window ร 30 รท the days in the window. A fix whose loss can't be counted yet goes after the ones that can, and says why. Each has what to change, the pattern or email it uses, the evidence (call and numbers), the expected impact (the stage it moves and the users a month it goes after; never a promised lift), the effort (low: a setting, tag or filter; medium: a product or flow change; high: rebuilding the flow), and who does it ("I can do this now" or "do this in the product or GA4").
5. **Measurement plan,** when stages aren't tracked: the exact events to add, with GA4's recommended names where one exists (`sign_up`, `tutorial_begin`, `tutorial_complete`, `login`), plus one activation event, and which to mark as key events.
6. **Onboarding emails:** what exists, what each trigger above should send, and the gaps.
7. **Personalisation opportunities:** up to 4 segments (first channel, device, or what users read or say at signup), each with its number and call, and the first screen or email tailored to it. A segment under 30 users gets "too few users to compare", not a tailored path.
8. **Unknowns:** what couldn't be checked, and why.
9. **Go deeper:** the next skill to run for each area.
## Fixes this skill can run
Only after the user says yes to the exact change. Each needs a Read & Write connection, and an owner, admin or operator can switch write actions off. Offer a fix only when the events it uses fired in the window; an audience built on an event that never fires stays empty.
**Mark the activation event as a key event** (`create_key_event`, `platform="google-analytics"`), only when the event fires in the window and isn't a key event yet:
```json
{"action": "create_key_event", "property_id": "properties/<id>",
"event_name": "ACTIVATION_EVENT", "counting_method": "ONCE_PER_SESSION"}
```
**Create a stage audience** (`create_audience`), for example "signed up, not activated in 14 days", to bring those users back with the message for their stage. Only when no audience in call 2 already does the same job. `membership_duration_days` can't be changed later.
```json
{"action": "create_audience", "property_id": "properties/<id>",
"display_name": "Signed up, not activated",
"description": "New signups who have not done the activation event; for onboarding re-engagement",
"membership_duration_days": 30,
"filter_clauses": [
{"clauseType": "INCLUDE", "simpleFilter": {"scope": "AUDIENCE_FILTER_SCOPE_ACROSS_ALL_SESSIONS",
"filterExpression": {"andGroup": {"filterExpressions": [{"orGroup": {"filterExpressions": [
{"eventFilter": {"eventName": "SIGNUP_EVENT"}}]}}]}}}},
{"clauseType": "EXCLUDE", "simpleFilter": {"scope": "AUDIENCE_FILTER_SCOPE_ACROSS_ALL_SESSIONS",
"filterExpression": {"andGroup": {"filterExpressions": [{"orGroup": {"filterExpressions": [
{"eventFilter": {"eventName": "ACTIVATION_EVENT"}}]}}]}}}}]}
```
Other stage audiences follow the same shape: "visited pricing, never signed up" (include a `pageLocation` filter, exclude the signup event) and "activated, not yet paying" (include activation, exclude the purchase or upgrade event).
It never changes the product, the site, tags, emails or flows. Those it writes up as recommendations.
## Without a connection
If GA4 isn't connected, or the product is tracked somewhere else, ask the user for:
- users at each stage over the last 12 weeks: new visitors, signups, each onboarding step, activation, and week-1 and week-4 return
- the days from signup to activation, if they have them
- the emails sent after signup, with what triggers each
- screenshots or a description of the first screens after signup
Run the same journey map, areas and design steps on their numbers, and mark every figure "from your data, not checked".
## Rules
- Every number comes from a call in this skill or from the user, and says which.
- Never guess the activation event, and never present a candidate as proven.
- When the journey isn't tracked, the most valuable output is the measurement plan. Say so plainly instead of padding the report with generic advice.
- Never present a share of user-days as a share of people.
- Name onboarding patterns only where the data points to the stage they fix.
- Don't run a write action without a yes to the exact payload.
## Go deeper
- **cro/signup-flow-cro:** the signup form and the steps before the account exists.
- **marketing/email-sequence-builder:** full copy for the onboarding emails.
- **marketing/funnel-dropoff-diagnostician:** the wider funnel beyond onboarding.
- **measurement/conversion-tracking-auditor:** checking that the events in the measurement plan fire and count as key events.
- **measurement/ga4-audience-retention** (if installed): retention by cohort, channel and device in more depth.
- **marketing/klaviyo-flow-auditor** (if installed): a full audit of the email flows.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# How to Use This Skill
Hey Claude, I just added the "onboarding-cro" skill. Map our new-user journey from first visit to activation and tell me where onboarding loses people.
## What you need
- **The InsightfulPipe MCP connected to Claude, with the GA4 property that records your product.** The skill pulls the events, pages, channels and weekly cohorts itself; you don't export anything.
- **Klaviyo connected (optional),** so it can check the emails that go out after signup.
- **Your signup event, onboarding step events and activation event,** if you know them. Without them it uses GA4's recommended names (`sign_up`, `tutorial_begin`, `tutorial_complete`) and the first key event that fires.
- **One line on the product and who it's for,** so it can pick the right onboarding model.
## Example requests
**Find the leak**
Hey Claude, I just added the "onboarding-cro" skill. Our signups are fine but few people stick around. Find the onboarding step that loses the most new users over the last 12 weeks.
**Map the journey**
Hey Claude, I just added the "onboarding-cro" skill. Map the journey from first visit to signup, setup and first value for our product, with the numbers at each step and where it goes dark.
**Time to value**
Hey Claude, I just added the "onboarding-cro" skill. How many days after their first visit do new users reach `project_created`, and how many come back the week after?
**Design the onboarding**
Hey Claude, I just added the "onboarding-cro" skill. Find our weakest onboarding step, then design the first-run screens and the emails after signup to fix it.
**Find the activation metric**
Hey Claude, I just added the "onboarding-cro" skill. Help me pick our activation metric. Our candidates are `report_created`, `teammate_invited` and `integration_connected`.
## What you get
1. **A journey map** in seven stages, from arrival to activation and return: new users at each stage, the step rate, and "not tracked" where the data stops.
2. **A scorecard** for seven areas: measurement, hand-off to signup, onboarding completion, activation and time to value, early return, segments, and onboarding emails. A grade out of 100 when enough of the journey is tracked, or "not graded" with the reason.
3. **Up to 5 fixes:** tracking fixes first, then the rest ranked by the new users each stage loses a month, each with the onboarding pattern or email it uses, the numbers behind it, the expected impact and the effort.
4. **A measurement plan** when stages aren't tracked: the exact events to add and which to mark as key events.
5. **An onboarding email plan** built on what the user did or didn't do, and what your current flows already cover.
6. **Personalisation opportunities:** the segments worth a tailored first screen or email, each with its number.
7. **What couldn't be checked,** and why.
## What it can change for you
With your yes on the exact change, it can:
- mark your activation event as a GA4 key event
- create a GA4 audience for a stage, such as "signed up, not activated", for re-engagement campaigns
It offers these only for events that actually fire. It never changes your product, site, tags or email flows; those come as recommendations.
## Good to know
- If your GA4 property only tracks the marketing site, the report shows the journey up to the signup click and gives you the tracking plan for the rest. That is often the most useful first result.
- Finding which early action predicts users staying needs user-level data: a GA4 BigQuery export connected through InsightfulPipe (not yet tested on a live account), or numbers from your own product analytics.
- Run it again a few weeks after a change to see whether the step rate moved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
{
"note": "Example data: an invented online booking software company with invented accounts, not a real business. Every number in expected_output.json follows from this input. Call 5 is shown summed over its dated first-session rows, which SKILL.md allows.",
"request": "Hey Claude, I just added the \"onboarding-cro\" skill. Map our new-user journey from first visit to activation and tell me where onboarding loses people. We sell online booking software to salons, clinics and studios, self-serve on monthly plans.",
"account": {
"business": "Example Booking Software, an online booking and scheduling app for small service businesses (invented example)",
"ga4_property": "properties/123456789",
"workspace_id": 1,
"brand_id": 1,
"tracks": "2 hosts: the marketing site and the app",
"klaviyo": "connected"
},
"window": "2026-08-03 to 2026-10-25",
"user_answers": {
"product": "online booking, reminders and payments for salons, clinics, studios and trainers; self-serve, monthly plans from $19",
"signup_event": "sign_up",
"onboarding_steps": "tutorial_begin (setup wizard opens), services_added, calendar_connected, tutorial_complete (booking page published)",
"activation_candidate": "booking_received: a first client booking through the business's booking page",
"current_onboarding": "A 4-step setup wizard after signup: add services, set opening hours, connect a calendar (required before the booking page can be published), publish the booking page. The same for every business type, no setup call or named contact.",
"where_signup_happens": "app.example.com/signup, linked from the site's Start free buttons; the site and the app send to the same GA4 property",
"pages": "defaults plus /help, where the help centre lives",
"own_targets": "flag hand-off under 12% of new users (usual level about 14%) and week-1 return under 10% (usual level about 12%)"
},
"data_pulled": {
"1_list_key_events": [
"sign_up",
"purchase"
],
"2_list_audiences": [
"All users",
"Purchasers",
"Pricing page visitors (30 days)"
],
"3_events": [
{
"eventName": "page_view",
"eventCount": 118400,
"totalUsers": 27310
},
{
"eventName": "session_start",
"eventCount": 64490,
"totalUsers": 27310
},
{
"eventName": "first_visit",
"eventCount": 25480,
"totalUsers": 25480
},
{
"eventName": "user_engagement",
"eventCount": 71200,
"totalUsers": 17620
},
{
"eventName": "scroll",
"eventCount": 30150,
"totalUsers": 11080
},
{
"eventName": "click",
"eventCount": 6420,
"totalUsers": 3910
},
{
"eventName": "sign_up",
"eventCount": 1668,
"totalUsers": 1662
},
{
"eventName": "tutorial_begin",
"eventCount": 1802,
"totalUsers": 1490
},
{
"eventName": "services_added",
"eventCount": 2210,
"totalUsers": 1361
},
{
"eventName": "calendar_connected",
"eventCount": 790,
"totalUsers": 752
},
{
"eventName": "tutorial_complete",
"eventCount": 721,
"totalUsers": 719
},
{
"eventName": "booking_received",
"eventCount": 9840,
"totalUsers": 1210
},
{
"eventName": "login",
"eventCount": 18900,
"totalUsers": 3650
},
{
"eventName": "purchase",
"eventCount": 402,
"totalUsers": 398
},
{
"eventName": "form_start",
"eventCount": 612,
"totalUsers": 540
},
{
"eventName": "form_submit",
"eventCount": 244,
"totalUsers": 236
}
],
"4_hostName": [
{
"hostName": "www.example.com",
"sessions": 41850,
"totalUsers": 27310
},
{
"hostName": "app.example.com",
"sessions": 22640,
"totalUsers": 3920
}
],
"5_journey_by_first_channel": {
"summed_over": "dated first-session rows 2026-08-03 to 2026-10-25",
"left_out": "14 (not set) rows and 3,880 rows with an earlier first-session date",
"events": [
"first_visit",
"user_engagement",
"sign_up",
"tutorial_begin",
"services_added",
"calendar_connected",
"tutorial_complete",
"booking_received",
"purchase"
],
"users_by_channel": {
"Organic Search": {
"first_visit": 9800,
"user_engagement": 6180,
"sign_up": 640,
"tutorial_begin": 572,
"services_added": 525,
"calendar_connected": 296,
"tutorial_complete": 284,
"booking_received": 190,
"purchase": 112
},
"Direct": {
"first_visit": 4200,
"user_engagement": 2690,
"sign_up": 330,
"tutorial_begin": 296,
"services_added": 272,
"calendar_connected": 160,
"tutorial_complete": 152,
"booking_received": 101,
"purchase": 62
},
"Paid Search": {
"first_visit": 3000,
"user_engagement": 1890,
"sign_up": 300,
"tutorial_begin": 266,
"services_added": 240,
"calendar_connected": 110,
"tutorial_complete": 105,
"booking_received": 62,
"purchase": 38
},
"Organic Social": {
"first_visit": 2100,
"user_engagement": 1040,
"sign_up": 86,
"tutorial_begin": 74,
"services_added": 63,
"calendar_connected": 36,
"tutorial_complete": 34,
"booking_received": 22,
"purchase": 14
},
"Referral": {
"first_visit": 1500,
"user_engagement": 980,
"sign_up": 140,
"tutorial_begin": 125,
"services_added": 115,
"calendar_connected": 68,
"tutorial_complete": 65,
"booking_received": 41,
"purchase": 26
},
"Email": {
"first_visit": 1000,
"user_engagement": 400,
"sign_up": 40,
"tutorial_begin": 37,
"services_added": 35,
"calendar_connected": 20,
"tutorial_complete": 20,
"booking_received": 14,
"purchase": 8
}
},
"first_visit_by_first_session_week": [
1712,
1764,
1690,
1825,
1801,
1748,
1866,
1902,
1835,
1779,
1840,
1838
]
},
"6_journey_by_device": {
"desktop": {
"first_visit": 11300,
"sign_up": 1150,
"tutorial_begin": 1046,
"tutorial_complete": 575,
"booking_received": 352
},
"mobile": {
"first_visit": 9700,
"sign_up": 420,
"tutorial_begin": 352,
"tutorial_complete": 92,
"booking_received": 74
},
"tablet": {
"first_visit": 700,
"sign_up": 24,
"tutorial_begin": 21,
"tutorial_complete": 7,
"booking_received": 6
}
},
"7_time_to_value_user_days_by_days_after_first_visit": {
"sign_up": {
"0": 891,
"1": 148,
"2": 89,
"3": 73,
"4": 67,
"5": 55,
"6": 43,
"7": 30,
"8": 28,
"9": 24,
"10": 17,
"11": 15,
"12": 13,
"13": 9,
"14": 7,
"15": 5,
"16": 4,
"17": 3,
"18": 3,
"19": 3,
"20": 2,
"21": 1,
"22": 1,
"23": 1,
"24": 1,
"25": 1,
"26": 0,
"27": 0,
"28": 0,
"29": 0,
"30": 0,
"31": 0,
"32": 0,
"33": 0,
"34": 0,
"35": 0,
"36": 0,
"37": 0,
"38": 0,
"39": 0,
"40": 0
},
"tutorial_complete": {
"0": 462,
"1": 65,
"2": 48,
"3": 36,
"4": 24,
"5": 19,
"6": 13,
"7": 9,
"8": 7,
"9": 5,
"10": 4,
"11": 3,
"12": 2,
"13": 1,
"14": 1,
"15": 1,
"16": 0,
"17": 0,
"18": 0,
"19": 0,
"20": 0,
"21": 0,
"22": 0,
"23": 0,
"24": 0,
"25": 0,
"26": 0,
"27": 0,
"28": 0,
"29": 0,
"30": 0,
"31": 0,
"32": 0,
"33": 0,
"34": 0,
"35": 0,
"36": 0,
"37": 0,
"38": 0,
"39": 0,
"40": 0
},
"booking_received": {
"0": 116,
"1": 136,
"2": 144,
"3": 101,
"4": 98,
"5": 100,
"6": 85,
"7": 98,
"8": 83,
"9": 69,
"10": 79,
"11": 61,
"12": 53,
"13": 49,
"14": 54,
"15": 47,
"16": 48,
"17": 42,
"18": 44,
"19": 39,
"20": 35,
"21": 35,
"22": 31,
"23": 31,
"24": 24,
"25": 22,
"26": 22,
"27": 21,
"28": 21,
"29": 20,
"30": 18,
"31": 16,
"32": 16,
"33": 14,
"34": 11,
"35": 11,
"36": 10,
"37": 10,
"38": 10,
"39": 9,
"40": 8
}
},
"8_journey_pages_new_users": {
"/pricing/": 3420,
"/signup": 2950,
"/demo/": 610,
"/help/connect-google-calendar/": 412,
"/help/calendar-not-syncing/": 236,
"/help/set-up-payments/": 198,
"/help/add-services-and-hours/": 151,
"/help/import-clients/": 88,
"/help/share-your-booking-link/": 64,
"/blog/salon-pricing-guide/": 520,
"/help/connect-outlook-calendar-and-share-your-availabi...": 12
},
"9_outbound_clicks": "not needed: the signup page is in this property, so call 8 counts its new users",
"10_weekly_cohorts": [
{
"cohort": "w01",
"cohortTotalUsers": 1712,
"cohortActiveUsers_by_week": {
"0": 1712,
"1": 202,
"2": 150,
"3": 124,
"4": 100,
"5": 76,
"6": 62,
"7": 57,
"8": 45,
"9": 35,
"10": 25,
"11": 23
}
},
{
"cohort": "w02",
"cohortTotalUsers": 1764,
"cohortActiveUsers_by_week": {
"0": 1764,
"1": 195,
"2": 170,
"3": 137,
"4": 114,
"5": 87,
"6": 62,
"7": 52,
"8": 45,
"9": 36,
"10": 29
}
},
{
"cohort": "w03",
"cohortTotalUsers": 1690,
"cohortActiveUsers_by_week": {
"0": 1690,
"1": 181,
"2": 149,
"3": 137,
"4": 98,
"5": 89,
"6": 65,
"7": 56,
"8": 44,
"9": 33
}
},
{
"cohort": "w04",
"cohortTotalUsers": 1825,
"cohortActiveUsers_by_week": {
"0": 1825,
"1": 208,
"2": 173,
"3": 128,
"4": 119,
"5": 93,
"6": 74,
"7": 56,
"8": 44
}
},
{
"cohort": "w05",
"cohortTotalUsers": 1801,
"cohortActiveUsers_by_week": {
"0": 1801,
"1": 218,
"2": 170,
"3": 124,
"4": 108,
"5": 79,
"6": 74,
"7": 52
}
},
{
"cohort": "w06",
"cohortTotalUsers": 1748,
"cohortActiveUsers_by_week": {
"0": 1748,
"1": 222,
"2": 170,
"3": 123,
"4": 111,
"5": 78,
"6": 71
}
},
{
"cohort": "w07",
"cohortTotalUsers": 1866,
"cohortActiveUsers_by_week": {
"0": 1866,
"1": 224,
"2": 167,
"3": 133,
"4": 123,
"5": 98
}
},
{
"cohort": "w08",
"cohortTotalUsers": 1902,
"cohortActiveUsers_by_week": {
"0": 1902,
"1": 210,
"2": 196,
"3": 149,
"4": 105
}
},
{
"cohort": "w09",
"cohortTotalUsers": 1835,
"cohortActiveUsers_by_week": {
"0": 1835,
"1": 200,
"2": 185,
"3": 139
}
},
{
"cohort": "w10",
"cohortTotalUsers": 1779,
"cohortActiveUsers_by_week": {
"0": 1779,
"1": 209,
"2": 184
}
},
{
"cohort": "w11",
"cohortTotalUsers": 1840,
"cohortActiveUsers_by_week": {
"0": 1840,
"1": 205
}
},
{
"cohort": "w12",
"cohortTotalUsers": 1838,
"cohortActiveUsers_by_week": {
"0": 1838,
"1": 110
}
}
],
"11_activation_repeat_cohorts": [
{
"cohort": "w01",
"week0": 13,
"by_week": {
"1": 10,
"2": 8,
"3": 7,
"4": 8,
"5": 6,
"6": 6,
"7": 6,
"8": 5,
"9": 5,
"10": 5,
"11": 4
}
},
{
"cohort": "w02",
"week0": 12,
"by_week": {
"1": 8,
"2": 9,
"3": 7,
"4": 7,
"5": 6,
"6": 6,
"7": 5,
"8": 5,
"9": 5,
"10": 5
}
},
{
"cohort": "w03",
"week0": 12,
"by_week": {
"1": 9,
"2": 8,
"3": 7,
"4": 7,
"5": 7,
"6": 6,
"7": 6,
"8": 5,
"9": 5
}
},
{
"cohort": "w04",
"week0": 14,
"by_week": {
"1": 9,
"2": 10,
"3": 8,
"4": 8,
"5": 8,
"6": 7,
"7": 6,
"8": 7
}
},
{
"cohort": "w05",
"week0": 12,
"by_week": {
"1": 8,
"2": 7,
"3": 7,
"4": 7,
"5": 7,
"6": 6,
"7": 5
}
},
{
"cohort": "w06",
"week0": 12,
"by_week": {
"1": 9,
"2": 8,
"3": 8,
"4": 7,
"5": 7,
"6": 5
}
},
{
"cohort": "w07",
"week0": 13,
"by_week": {
"1": 9,
"2": 8,
"3": 8,
"4": 8,
"5": 7
}
},
{
"cohort": "w08",
"week0": 14,
"by_week": {
"1": 10,
"2": 10,
"3": 9,
"4": 7
}
},
{
"cohort": "w09",
"week0": 13,
"by_week": {
"1": 10,
"2": 8,
"3": 9
}
},
{
"cohort": "w10",
"week0": 12,
"by_week": {
"1": 8,
"2": 8
}
},
{
"cohort": "w11",
"week0": 13,
"by_week": {
"1": 10
}
},
{
"cohort": "w12",
"week0": 13,
"by_week": {}
}
],
"12_klaviyo": {
"get_flows": [
{
"name": "Welcome series",
"status": "live",
"trigger": "added to list 'New accounts'"
},
{
"name": "Newsletter welcome",
"status": "live",
"trigger": "added to list 'Blog newsletter'"
}
],
"get_flow_report_last_90_days": [
{
"flow_name": "Welcome series",
"flow_message_name": "Welcome: set up your booking page",
"sent": "day 0",
"recipients": 1490,
"open_rate": 0.58,
"click_rate": 0.21
},
{
"flow_name": "Welcome series",
"flow_message_name": "Connect your calendar",
"sent": "day 2",
"recipients": 1420,
"open_rate": 0.46,
"click_rate": 0.09
},
{
"flow_name": "Welcome series",
"flow_message_name": "Share your booking link",
"sent": "day 5",
"recipients": 1380,
"open_rate": 0.41,
"click_rate": 0.07
},
{
"flow_name": "Newsletter welcome",
"flow_message_name": "Your reminder templates",
"sent": "day 0",
"recipients": 640,
"open_rate": 0.52,
"click_rate": 0.18
}
]
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
{
"header": {
"property": "properties/123456789",
"window": "2026-08-03 to 2026-10-25 (12 complete weeks, run 2026-10-28)",
"activation_event": "booking_received (the user's candidate, not yet tested against week-4 retention)",
"grade": 68,
"rating": "needs work",
"grade_math": "100 - 5 (Measurement, warn) - 12 (Onboarding completion, fail) - 5 (Activation and time to value, warn) - 5 (Segments, warn) - 5 (Onboarding emails, warn) = 68"
},
"headline": [
"Setup is the biggest drop: 43.0% of the 1,536 new signups finish the wizard and publish a booking page, and the calendar step loses the most of them (1,250 added services, 690 connected a calendar) (call 5).",
"On mobile, 21.9% of signups finish setup against 50.0% on desktop, and mobile brings 44.9% of new users (call 6).",
"28.0% of signups get a first client booking, and 6.0% of booking user-days fall on day 0 (calls 5 and 7). booking_received fires but isn't a key event yet (call 1)."
],
"journey_map": [
{
"stage": "1. Arrive",
"signal": "first_visit",
"source": "call 5",
"new_users": 21600,
"step_rate_pct": null,
"share_of_new_users_pct": 100
},
{
"stage": "2. Engage",
"signal": "user_engagement",
"source": "call 5",
"new_users": 13180,
"step_rate_pct": 61,
"share_of_new_users_pct": 61
},
{
"stage": "3. Evaluate",
"signal": "pricing and demo pages",
"source": "call 8",
"new_users": "at least 3,420",
"step_rate_pct": null,
"share_of_new_users_pct": 15.8,
"note": "At least, because pricing (3,420) and demo (610) users can't be added together. No step rate: a visitor can reach pricing without an engaged visit, so the two don't nest."
},
{
"stage": "4. Hand-off",
"signal": "signup page view (app.example.com/signup)",
"source": "call 8",
"new_users": 2950,
"step_rate_pct": null,
"share_of_new_users_pct": 13.7,
"note": "No step rate for the same reason: the signup page can be reached straight from an ad or a link."
},
{
"stage": "5. Sign up",
"signal": "sign_up",
"source": "call 5",
"new_users": 1536,
"step_rate_pct": 52.1,
"share_of_new_users_pct": 7.1,
"note": "Share of the signup page's new users; signup happens on that page, so the two nest."
},
{
"stage": "6. Onboard",
"signal": "tutorial_complete (booking page published)",
"source": "call 5",
"new_users": 660,
"step_rate_pct": 43,
"share_of_new_users_pct": 3.1
},
{
"stage": "7. Activate and return",
"signal": "booking_received; week-1 return from call 10",
"source": "calls 5 and 10",
"new_users": 430,
"step_rate_pct": 65.2,
"share_of_new_users_pct": 2,
"note": "Week-1 return is in the Early return area."
}
],
"fix_first": "Stage 6, Onboard: 43.0% of signups finish setup, the lowest step rate on the map. Inside the wizard, the step from services_added (1,250) to calendar_connected (690) loses 560 users, the most of any step.",
"setup_steps": {
"source": "call 5, in the order the user gave",
"users": {
"tutorial_begin": 1370,
"services_added": 1250,
"calendar_connected": 690,
"tutorial_complete": 660
},
"note": "GA4 doesn't know the order, so this reads the wizard order from the user's answer; no step has more users than the one before it."
},
"weekly_new_users": {
"source": "call 5: first_visit users summed by first-session week",
"weeks": [
1712,
1764,
1690,
1825,
1801,
1748,
1866,
1902,
1835,
1779,
1840,
1838
],
"flagged_weeks": "none: no week is 3 or more times the median of the others",
"rows_left_out": "14 (not set) first-session rows and 3,880 rows of users who first came before 2026-08-03"
},
"scorecard": [
{
"area": "Measurement",
"result": "warn",
"source": "calls 1, 3 and 4",
"key_number": "booking_received fires, not a key event",
"why": "The property sees both the site and the app (2 hosts, no test host), signup and all four setup steps fire, and weekly new users are steady. The activation event fired for 430 new users but isn't one of the 2 key events."
},
{
"area": "Hand-off",
"result": "pass",
"source": "call 8",
"key_number": "13.7% of new users reach the signup page",
"why": "2,950 of 21,600 new users opened the signup page, above your own floor of 12% (SKILL.md sets no threshold for this area, so your target is used)."
},
{
"area": "Onboarding completion",
"result": "fail",
"source": "calls 5 and 6",
"key_number": "43.0% finish setup",
"why": "660 of 1,536 signups published a booking page, under the 50% fail line."
},
{
"area": "Activation and time to value",
"result": "warn",
"source": "calls 5 and 7",
"key_number": "28.0% activation",
"why": "430 of 1,536 signups got a client booking, in the 20% to 40% warn band; only 6.0% of booking user-days are on day 0, so the first session rarely ends with value."
},
{
"area": "Early return",
"result": "pass",
"source": "calls 10 and 11",
"key_number": "week-1 return 11.5%",
"why": "2,274 of 19,762 new users in cohorts w01-w11 came back in week 1, above your floor of 10%; 6.1% came back in week 4 (cohorts w01-w08)."
},
{
"area": "Segments",
"result": "warn",
"source": "calls 5 and 6",
"key_number": "mobile 21.9% vs desktop 50.0%",
"why": "Mobile brings 44.9% of new users and finishes setup at under half the desktop rate; the gap (28.1 points) is far above the 5.6-point threshold."
},
{
"area": "Onboarding emails",
"result": "warn",
"source": "call 12",
"key_number": "3 welcome emails on fixed days",
"why": "'Welcome series' goes to every new account on day 0, 2 and 5 whatever they did; nothing is triggered by a step done or skipped."
}
],
"top_fixes": [
{
"rank": 1,
"kind": "drop",
"fix": "Let people publish the booking page before connecting a calendar",
"users_lost_per_month": 313,
"loss_counted_as": "signups who never finished setup (876), x 30 / 84 days",
"pattern": "inside the setup steps: a short guided setup that shows progress, saves partial work, lets people skip a step and come back, and asks only for what the first result needs",
"what": "Make calendar sync a skippable step that the app asks for again after the first booking, and show progress ('Step 3 of 4') with saved answers. Services and opening hours are all a booking page needs to go live.",
"evidence": "Call 5: services_added 1,250, calendar_connected 690, tutorial_complete 660. Call 8: the calendar connection guide is the most-read help page (412 new users) and calendar troubleshooting comes next (236).",
"expected_impact": "stage 6, going after about 313 signups a month who stop before the booking page is live",
"effort": "medium: a product change to the wizard",
"who": "do this in the product"
},
{
"rank": 2,
"kind": "drop",
"fix": "Trigger the setup emails on what people did, not on the day",
"users_lost_per_month": 313,
"loss_counted_as": "the same stage as fix 1: signups who never finished setup",
"pattern": "emails after signup triggered by what the user did or didn't do",
"what": "Replace the fixed day-2 and day-5 emails with: setup started but not finished after a day (a link back to the step they left, with the calendar guide), booking page live (share it now), and no booking after about a week (ask what's in the way). Send sign_up, tutorial_complete and booking_received to Klaviyo so the triggers work.",
"evidence": "Call 12: the day-2 'Connect your calendar' email reached 1,420 people in 90 days at a 9% click rate. It goes out on a fixed day, so it also reaches people who connected a calendar on day 0.",
"expected_impact": "stage 6, the same users as fix 1, reached by email when they leave the app",
"effort": "medium: a flow in Klaviyo plus the events sent to it",
"who": "do this in Klaviyo"
},
{
"rank": 3,
"kind": "drop",
"fix": "Make the setup wizard work on a phone",
"users_lost_per_month": 117,
"loss_counted_as": "mobile signups who never finished setup (328), x 30 / 84 days",
"pattern": "if mobile users stall, the first run must work on a phone",
"what": "Test each wizard step on a phone, starting with the calendar connection (it opens a sign-in window that is easy to lose on mobile), and let people finish setup on desktop with a 'send me a link' option.",
"evidence": "Call 6: mobile 92 of 420 signups finished setup (21.9%), desktop 575 of 1,150 (50.0%).",
"expected_impact": "stage 6 on mobile, about 117 signups a month",
"effort": "medium: product and design work",
"who": "do this in the product"
},
{
"rank": 4,
"kind": "drop",
"fix": "Turn the empty dashboard into a 'get your first booking' checklist",
"users_lost_per_month": 82,
"loss_counted_as": "users who published a booking page but got no booking (230), x 30 / 84 days",
"pattern": "after setup, before first value: one clear first action; slow time to value: a short checklist with visible progress",
"what": "After the page goes live, show 4 small tasks: copy the booking link, add it to the Instagram bio, add it to the Google Business profile, send it to 5 regular clients. Mark each as done.",
"evidence": "Call 5: 660 finished setup, 430 got a booking. Call 7: 6.0% of booking user-days on day 0, 24.8% on days 3 to 7.",
"expected_impact": "stage 7, about 82 users a month who are set up but have no client booking yet",
"effort": "medium: a product change",
"who": "do this in the product"
},
{
"rank": 5,
"kind": "tracking",
"fix": "Mark booking_received as a key event",
"users_lost_per_month": "can't be counted: it changes what GA4 reports, not what users do",
"what": "So activation shows up in GA4's standard reports and can be imported to the ad platforms as a conversion.",
"evidence": "Call 1: key events are sign_up, purchase; call 3: booking_received fired in the window.",
"expected_impact": "activation counted next to signups in every GA4 report",
"effort": "low: one setting",
"who": "I can do this now, with your yes"
}
],
"help_pages_read_by_new_users": {
"source": "call 8",
"rows": [
{
"type": "calendar connection guide",
"pages": 1,
"users_on_most_read_page": 412,
"most_read_page": "https://www.example.com/help/connect-google-calendar/"
},
{
"type": "troubleshooting",
"pages": 1,
"users_on_most_read_page": 236,
"most_read_page": "https://www.example.com/help/calendar-not-syncing/"
},
{
"type": "payments setup",
"pages": 1,
"users_on_most_read_page": 198,
"most_read_page": "https://www.example.com/help/set-up-payments/"
},
{
"type": "account setup (services, hours, client import)",
"pages": 2,
"users_on_most_read_page": 151,
"most_read_page": "https://www.example.com/help/add-services-and-hours/"
},
{
"type": "sharing the booking page",
"pages": 1,
"users_on_most_read_page": 64,
"most_read_page": "https://www.example.com/help/share-your-booking-link/"
}
],
"dropped_pages": "1 blog post that only mentions pricing in its path (/blog/salon-pricing-guide/), and 1 help path that GA4 returned cut short, so its page can't be told",
"reading": "The most-read help pages are about connecting and syncing a calendar, the step where the wizard loses the most people. Pages can't be added together, so each type shows its most-read page."
},
"time_to_value": {
"source": "call 7",
"counts": "user-days, not people: a user who does an event on 3 days counts 3 times, and booking_received repeats with every booking",
"by_event": {
"sign_up": {
"user_days": 1534,
"share_pct": {
"day 0": 58.1,
"days 1-2": 15.4,
"days 3-7": 17.5,
"days 8-14": 7.4,
"day 15 or later": 1.6
}
},
"tutorial_complete": {
"user_days": 700,
"share_pct": {
"day 0": 66,
"days 1-2": 16.1,
"days 3-7": 14.4,
"days 8-14": 3.3,
"day 15 or later": 0.1
}
},
"booking_received": {
"user_days": 1941,
"share_pct": {
"day 0": 6,
"days 1-2": 14.4,
"days 3-7": 24.8,
"days 8-14": 23.1,
"day 15 or later": 31.7
}
}
}
},
"feature_adoption": {
"source": "call 5",
"purchase_users_per_activated_user_pct": 60.5,
"note": "GA4 doesn't know the order, so this is how many activated users also bought a plan, not when."
},
"segments": {
"source": "calls 5 and 6",
"step": "signup to setup finished (the stage to fix)",
"by_device": [
{
"device": "desktop",
"first_visit_users": 11300,
"signups": 1150,
"finished_setup": 575,
"setup_rate_pct": 50
},
{
"device": "mobile",
"first_visit_users": 9700,
"signups": 420,
"finished_setup": 92,
"setup_rate_pct": 21.9
},
{
"device": "tablet",
"first_visit_users": 700,
"signups": 24,
"finished_setup": 7,
"setup_rate_pct": "too few users to compare"
}
],
"mobile_vs_desktop": {
"gap_points": 28.1,
"threshold_points": 5.6,
"verdict": "real",
"warn": true
},
"by_first_channel": [
{
"channel": "Organic Search",
"new_users": 9800,
"signups": 640,
"finished_setup": 284,
"setup_rate_pct": 44.4,
"share_of_new_users_pct": 45.4
},
{
"channel": "Direct",
"new_users": 4200,
"signups": 330,
"finished_setup": 152,
"setup_rate_pct": 46.1,
"share_of_new_users_pct": 19.4
},
{
"channel": "Paid Search",
"new_users": 3000,
"signups": 300,
"finished_setup": 105,
"setup_rate_pct": 35,
"share_of_new_users_pct": 13.9
},
{
"channel": "Organic Social",
"new_users": 2100,
"signups": 86,
"finished_setup": 34,
"setup_rate_pct": 39.5,
"share_of_new_users_pct": 9.7
},
{
"channel": "Referral",
"new_users": 1500,
"signups": 140,
"finished_setup": 65,
"setup_rate_pct": 46.4,
"share_of_new_users_pct": 6.9
},
{
"channel": "Email",
"new_users": 1000,
"signups": 40,
"finished_setup": 20,
"setup_rate_pct": 50,
"share_of_new_users_pct": 4.6
}
],
"paid_search_vs_rest": {
"paid_pct": 35,
"rest_pct": 44.9,
"gap_points": 9.9,
"threshold_points": 6.4,
"verdict": "real",
"warn": false,
"why_no_warn": "Paid Search brings 13.9% of new users, under the 20% the warn needs"
},
"device_note": "Device rows can't be added up: one person can sign up on a phone and finish on a laptop."
},
"early_return": {
"source": "calls 10 and 11",
"week_1": {
"cohorts": "w01-w11",
"cohort_users": 19762,
"returned": 2274,
"rate_pct": 11.5
},
"week_4": {
"cohorts": "w01-w08",
"cohort_users": 14308,
"returned": 878,
"rate_pct": 6.1
},
"blank_cell": "GA4 returned 110 for w12 week 1, but that week ends after the window, so it is left blank",
"missing_cells": "none inside the window: every cohort had people back in every finished week",
"activation_repeat_use": {
"base": "102 users who got a booking in their first week, cohorts w01-w08",
"share_with_a_booking_pct": {
"week 1": 70.6,
"week 2": 66.7,
"week 3": 59.8,
"week 4": 57.8
},
"reading": "Businesses that get one booking keep getting them, so the activation event turns into a habit once it happens."
}
},
"measurement_plan": "Not needed: every stage is tracked. The one change is marking booking_received as a key event (fix 5).",
"onboarding_emails": {
"source": "call 12",
"flows": [
{
"flow": "Welcome series",
"trigger": "added to list 'New accounts'",
"messages": [
{
"message": "Welcome: set up your booking page",
"sent": "day 0",
"recipients": 1490,
"open_rate_pct": 58,
"click_rate_pct": 21
},
{
"message": "Connect your calendar",
"sent": "day 2",
"recipients": 1420,
"open_rate_pct": 46,
"click_rate_pct": 9
},
{
"message": "Share your booking link",
"sent": "day 5",
"recipients": 1380,
"open_rate_pct": 41,
"click_rate_pct": 7
}
]
},
{
"flow": "Newsletter welcome",
"trigger": "added to list 'Blog newsletter'",
"messages": [
{
"message": "Your reminder templates",
"sent": "day 0",
"recipients": 640,
"open_rate_pct": 52,
"click_rate_pct": 18
}
]
}
],
"conversions": "not read: Klaviyo counts conversions against Placed Order, and the product doesn't send the activation event to Klaviyo yet",
"plan": [
"right after signup: welcome and one link that opens the setup wizard where they left it",
"setup started, not finished after a day: a link back to the step they left, with the calendar guide if that is the step",
"booking page live: share it now, with the link ready to copy",
"page live, no booking after about a week: ask what's in the way, and offer a short call",
"first booking received: well done, here's how to cut no-shows with reminders"
],
"gaps": "Every current message goes out on a fixed day. Nothing reacts to setup done, setup skipped or a first booking."
},
"personalisation_opportunities": [
{
"segment": "device: mobile",
"source": "call 6",
"number": "420 signups, 21.9% finished setup",
"tailored_experience": "a phone-first wizard, or a 'finish on your computer' email with a link straight back to the step they left"
},
{
"segment": "first channel: Paid Search",
"source": "call 5",
"number": "300 signups, 35.0% finished setup",
"tailored_experience": "open on the promise of the ad they clicked (most search ads sell online booking): the booking page preview first, with setup steps after it"
},
{
"segment": "read the calendar help pages",
"source": "call 8",
"number": "412 new users on the calendar connection guide",
"tailored_experience": "offer 'skip for now' at the calendar step and a one-click connection test, with the guide beside it"
},
{
"segment": "first channel: Organic Social",
"source": "call 5",
"number": "86 signups, 39.5% finished setup",
"tailored_experience": "none: its setup rate is 3.6 points below the rest, inside the 11.0-point threshold, so the gap isn't real"
}
],
"onboarding_model": "Self-serve: low monthly prices and many signups, so the wizard, the first screens and the emails carry the load. A short setup call for the Business plan is worth a test later.",
"fixes_offered": {
"source": "calls 1, 2 and 3",
"offered": [
{
"action": "create_key_event",
"body": {
"action": "create_key_event",
"property_id": "properties/123456789",
"event_name": "booking_received",
"counting_method": "ONCE_PER_SESSION"
},
"why": "booking_received fires and isn't a key event"
},
{
"action": "create_audience",
"display_name": "Signed up, not activated",
"why": "none of the 3 existing audiences covers it; 1,106 new signups in the window had no booking",
"membership_duration_days": 30
}
],
"status": "shown, not run: waiting for your yes on each exact body"
},
"unknowns": [
"Which first-week action predicts staying: needs user-level data (a BigQuery export or the product's own data); neither is connected, so booking_received stays an untested candidate.",
"Which wizard step people leave on mobile: the step events aren't split by device in call 6."
],
"go_deeper": [
"cro/signup-flow-cro: the 48% of signup page visitors who leave without an account",
"marketing/email-sequence-builder: copy for the triggered setup emails",
"measurement/conversion-tracking-auditor: check the new key event once it is created",
"measurement/ga4-audience-retention (if installed): retention by cohort, channel and device in more depth"
]
}
ReadyOnboarding CRO
MarkdownUTF-8