@picked/client 0.0.70-next.6 → 0.0.71-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/api-CH2FNa6S.cjs +1 -0
  3. package/dist/api-CgqRvuKL.js +38 -0
  4. package/dist/cjs/form/index.js +1 -1
  5. package/dist/cjs/index.js +2 -2
  6. package/dist/cjs/plugins/dom-observer/index.js +1 -1
  7. package/dist/cjs/plugins/dynamic-experiences/index.js +1 -1
  8. package/dist/cjs/server/index.js +1 -1
  9. package/dist/docs/actions.mdx +38 -18
  10. package/dist/docs/api/authentication.md +75 -48
  11. package/dist/docs/api/authorization-and-scopes.md +63 -47
  12. package/dist/docs/api/error-handling.md +70 -54
  13. package/dist/docs/api/index.md +41 -22
  14. package/dist/docs/api/pagination.md +30 -20
  15. package/dist/docs/api-keys.mdx +11 -6
  16. package/dist/docs/chrome-extension.md +22 -5
  17. package/dist/docs/conditions.mdx +32 -19
  18. package/dist/docs/content/asset-library.mdx +65 -34
  19. package/dist/docs/content/content-entries.mdx +8 -2
  20. package/dist/docs/content/layouts.mdx +45 -29
  21. package/dist/docs/content/pages.mdx +29 -14
  22. package/dist/docs/content/sections.mdx +19 -8
  23. package/dist/docs/delivery-api/experience-content.md +10 -5
  24. package/dist/docs/delivery-api/index.md +19 -12
  25. package/dist/docs/delivery-api/preview-caching-crawling.md +27 -14
  26. package/dist/docs/delivery-api/project-config.md +6 -4
  27. package/dist/docs/experiences.mdx +26 -10
  28. package/dist/docs/features.mdx +66 -25
  29. package/dist/docs/fields.mdx +42 -27
  30. package/dist/docs/flow-builder/building-flows.md +38 -20
  31. package/dist/docs/flow-builder/condition-builder.md +32 -21
  32. package/dist/docs/flow-builder/keyboard-shortcuts.md +18 -18
  33. package/dist/docs/flow-builder/nodes.md +26 -13
  34. package/dist/docs/flow-builder/overview.mdx +28 -15
  35. package/dist/docs/gtm-template.md +35 -26
  36. package/dist/docs/guides/build-a-personalized-page.mdx +36 -18
  37. package/dist/docs/image-optimisation-service.md +33 -17
  38. package/dist/docs/index.md +28 -17
  39. package/dist/docs/mcp.md +46 -38
  40. package/dist/docs/pickedql/data-sources.md +65 -43
  41. package/dist/docs/pickedql/dimensions.md +27 -12
  42. package/dist/docs/pickedql/examples.md +38 -26
  43. package/dist/docs/pickedql/filtering.md +10 -6
  44. package/dist/docs/pickedql/index.md +32 -14
  45. package/dist/docs/pickedql/schema.md +85 -76
  46. package/dist/docs/pickedql/virtual-functions.md +62 -36
  47. package/dist/docs/projects.mdx +14 -7
  48. package/dist/docs/reports.mdx +5 -3
  49. package/dist/docs/sdk/actions.md +33 -17
  50. package/dist/docs/sdk/conditions.md +8 -5
  51. package/dist/docs/sdk/content-security-policy.md +5 -4
  52. package/dist/docs/sdk/experiences.md +29 -11
  53. package/dist/docs/sdk/feature-allocation.md +79 -47
  54. package/dist/docs/sdk/features.md +130 -76
  55. package/dist/docs/sdk/fields.md +66 -42
  56. package/dist/docs/sdk/index.md +22 -13
  57. package/dist/docs/sdk/plugins/create-experience.md +18 -15
  58. package/dist/docs/sdk/plugins/dynamic-experiences.md +42 -16
  59. package/dist/docs/sdk/predicates.md +53 -37
  60. package/dist/docs/sdk/ssr/index.md +25 -8
  61. package/dist/docs/sdk/ssr/rendering-and-hydration.md +37 -16
  62. package/dist/docs/sdk/ssr/serialize.md +38 -20
  63. package/dist/docs/sdk/ssr/slots-and-placements.md +28 -10
  64. package/dist/docs/sdk/steps.md +100 -55
  65. package/dist/docs/steps.mdx +20 -11
  66. package/dist/docs/team-management.md +17 -11
  67. package/dist/docs/vite-plugin.md +26 -19
  68. package/dist/docs/workspace-versioning.mdx +14 -8
  69. package/dist/docs/workspaces.mdx +55 -24
  70. package/dist/{dom-BwmTHeT7.js → dom-BqcToNL0.js} +1 -3
  71. package/dist/{dom-CDrHc_j9.cjs → dom-DlLH3FxV.cjs} +1 -1
  72. package/dist/esm/form/index.js +2 -4
  73. package/dist/esm/index.js +50 -45
  74. package/dist/esm/plugins/dom-observer/index.js +1 -1
  75. package/dist/esm/plugins/dynamic-experiences/index.js +2 -2
  76. package/dist/esm/preview/index.js +1 -1
  77. package/dist/esm/server/index.js +12 -10
  78. package/dist/{experience-instance-DOJShRk5.js → experience-instance-DGk11d8a.js} +3 -3
  79. package/dist/experience-instance-Dej3P1sE.cjs +1 -0
  80. package/dist/{plugin-BxMR7fOV.js → plugin-D2UqFikQ.js} +2 -2
  81. package/dist/plugin-DCW-tnjO.cjs +1 -0
  82. package/dist/{preview-channel-DW9J8t4B.js → preview-channel-CSr96XAo.js} +1 -1
  83. package/dist/{protocol-DSqOlW2r.js → protocol-C5KkkiZc.js} +1 -1
  84. package/dist/types/client.d.ts +7 -6
  85. package/dist/types/entities/action/action.d.ts +5 -4
  86. package/dist/types/entities/action/action.d.ts.map +1 -1
  87. package/dist/types/entities/component/component.d.ts +6 -5
  88. package/dist/types/entities/component/component.d.ts.map +1 -1
  89. package/dist/types/entities/condition/condition.d.ts +5 -5
  90. package/dist/types/entities/content/content.d.ts +4 -3
  91. package/dist/types/entities/experience/experience.d.ts +11 -10
  92. package/dist/types/entities/experience/experience.d.ts.map +1 -1
  93. package/dist/types/entities/experience-instance/experience-instance.d.ts +10 -9
  94. package/dist/types/entities/feature/feature.d.ts +3 -2
  95. package/dist/types/entities/feature/feature.d.ts.map +1 -1
  96. package/dist/types/entities/field/field.d.ts +7 -6
  97. package/dist/types/entities/framework/framework.d.ts +7 -6
  98. package/dist/types/entities/framework/framework.d.ts.map +1 -1
  99. package/dist/types/entities/history/history.d.ts +6 -6
  100. package/dist/types/entities/plugin/plugin.d.ts +3 -2
  101. package/dist/types/entities/plugin/plugin.d.ts.map +1 -1
  102. package/dist/types/entities/predicate/predicate.d.ts +4 -3
  103. package/dist/types/entities/predicate/predicate.d.ts.map +1 -1
  104. package/dist/types/entities/response/response-validation.d.ts +3 -2
  105. package/dist/types/entities/response/response.d.ts +12 -11
  106. package/dist/types/entities/session/session.d.ts +2 -1
  107. package/dist/types/entities/step/step.d.ts +6 -5
  108. package/dist/types/exports.d.ts +2 -1
  109. package/dist/types/exports.d.ts.map +1 -1
  110. package/dist/types/form/build-responses.d.ts +2 -1
  111. package/dist/types/form/create-field-evaluator.d.ts +4 -3
  112. package/dist/types/form/create-field-validation.d.ts +5 -4
  113. package/dist/types/form/create-form.d.ts +7 -6
  114. package/dist/types/form/create-submit-pipeline.d.ts +7 -6
  115. package/dist/types/form/get-step-fields.d.ts +3 -2
  116. package/dist/types/lifecycle/condition-selection.d.ts +14 -4
  117. package/dist/types/lifecycle/lifecycle.d.ts +4 -3
  118. package/dist/types/lifecycle/rules-logic.d.ts +4 -3
  119. package/dist/types/lifecycle/state-snapshot.d.ts +4 -3
  120. package/dist/types/picked.d.ts +64 -62
  121. package/dist/types/picked.d.ts.map +1 -1
  122. package/dist/types/ping.d.ts +1 -1
  123. package/dist/types/ping.d.ts.map +1 -1
  124. package/dist/types/plugins/create-experience/create-experience.d.ts +9 -8
  125. package/dist/types/plugins/create-experience/create-experience.d.ts.map +1 -1
  126. package/dist/types/plugins/create-experience/plugin.d.ts +3 -2
  127. package/dist/types/plugins/create-experience/plugin.d.ts.map +1 -1
  128. package/dist/types/plugins/create-experience/serialization.d.ts.map +1 -1
  129. package/dist/types/plugins/dom-observer/plugin.d.ts +1 -1
  130. package/dist/types/plugins/dynamic-experiences/plugin.d.ts +3 -3
  131. package/dist/types/plugins/dynamic-experiences/types.d.ts +8 -5
  132. package/dist/types/plugins/experience-browser-storage/plugin.d.ts +1 -1
  133. package/dist/types/plugins/experience-browser-storage/plugin.d.ts.map +1 -1
  134. package/dist/types/plugins/history-browser-storage/plugin.d.ts +1 -1
  135. package/dist/types/plugins/history-browser-storage/plugin.d.ts.map +1 -1
  136. package/dist/types/plugins/responses-browser-storage/plugin.d.ts +1 -1
  137. package/dist/types/plugins/responses-browser-storage/plugin.d.ts.map +1 -1
  138. package/dist/types/plugins/responses-indexeddb/plugin.d.ts +1 -1
  139. package/dist/types/plugins/single-page-app/plugin.d.ts +1 -1
  140. package/dist/types/plugins/single-page-app/plugin.d.ts.map +1 -1
  141. package/dist/types/plugins/web-components/plugin.d.ts +2 -1
  142. package/dist/types/plugins/window-object/plugin.d.ts +2 -2
  143. package/dist/types/preview-channel.d.ts +5 -1
  144. package/dist/types/preview-receiver/index.d.ts +18 -1
  145. package/dist/types/preview-receiver/protocol.d.ts +10 -1
  146. package/dist/types/server/index.d.ts +3 -3
  147. package/dist/types/server/serialize.d.ts +2 -2
  148. package/dist/types/utils/dom.d.ts +2 -1
  149. package/dist/types/utils/events.d.ts +6 -6
  150. package/dist/types/utils/events.d.ts.map +1 -1
  151. package/dist/types/utils/global-obj.d.ts +1 -1
  152. package/dist/types/utils/global-obj.d.ts.map +1 -1
  153. package/dist/types/utils/id.d.ts.map +1 -1
  154. package/dist/types/utils/logger.d.ts +2 -1
  155. package/dist/types/utils/logger.d.ts.map +1 -1
  156. package/dist/types/utils/node-tree/get-next-node-from-action.d.ts +2 -1
  157. package/dist/types/utils/node-tree/get-next-node-from-condition.d.ts +2 -1
  158. package/dist/types/utils/node-tree/get-next-node.d.ts +1 -1
  159. package/dist/types/utils/node-tree/get-next-node.d.ts.map +1 -1
  160. package/dist/types/utils/node-tree/get-origin-node.d.ts +1 -1
  161. package/dist/types/utils/node-tree/get-origin-node.d.ts.map +1 -1
  162. package/dist/types/utils/node-tree/min-max-steps-to-leaf.d.ts +1 -1
  163. package/dist/types/utils/node-tree/min-max-steps-to-leaf.d.ts.map +1 -1
  164. package/dist/types/utils/node-tree/min-max-steps-to-origin.d.ts +1 -1
  165. package/dist/types/utils/node-tree/min-max-steps-to-origin.d.ts.map +1 -1
  166. package/dist/types/utils/node-tree/next-reachable-step-nodes.d.ts +1 -1
  167. package/dist/types/utils/node-tree/next-reachable-step-nodes.d.ts.map +1 -1
  168. package/dist/types/utils/nodes.d.ts +1 -1
  169. package/dist/types/utils/picked-config.d.ts +2 -1
  170. package/dist/types/utils/rules-logic.d.ts +6 -2
  171. package/dist/types/utils/storage.d.ts +1 -1
  172. package/dist/types/utils/storage.d.ts.map +1 -1
  173. package/package.json +22 -23
  174. package/dist/api-CoUkIxIr.cjs +0 -1
  175. package/dist/api-ahdSBQ3Y.js +0 -40
  176. package/dist/experience-instance-DurC3pE-.cjs +0 -1
  177. package/dist/plugin-CASdGtTX.cjs +0 -1
package/dist/docs/mcp.md CHANGED
@@ -4,21 +4,23 @@ layout: docs
4
4
 
5
5
  # MCP server
6
6
 
7
- Manage your Picked workspace from AI coding tools using the Model Context Protocol (MCP).
7
+ Control your Picked workspace from an AI tool that writes code, with the Model
8
+ Context Protocol (MCP).
8
9
 
9
- ## Connecting
10
+ ## Connect
10
11
 
11
12
  The server URL is `https://api.picked.app/mcp`.
12
13
 
13
14
  ### Claude Desktop
14
15
 
15
- 1. Open **Settings > Connectors > Add custom connector**
16
- 2. Set **Name** to `Picked` and **URL** to `https://api.picked.app/mcp`
17
- 3. Click **Connect** and complete the authorization prompt
16
+ 1. Open **Settings > Connectors > Add custom connector**.
17
+ 2. Set **Name** to `Picked` and **URL** to `https://api.picked.app/mcp`.
18
+ 3. Click **Connect** and answer the authorization prompt.
18
19
 
19
- ### Project configuration (.mcp.json)
20
+ ### Project configuration in `.mcp.json`
20
21
 
21
- Add to your repository root. Works with Claude Code, Cursor, Windsurf, and other MCP-compatible tools.
22
+ Add this file to the root of your repository. It works with Claude Code, Cursor,
23
+ Windsurf, and other tools that support MCP.
22
24
 
23
25
  :::code-group
24
26
 
@@ -37,7 +39,7 @@ Add to your repository root. Works with Claude Code, Cursor, Windsurf, and other
37
39
 
38
40
  ### Cursor
39
41
 
40
- Add to `.cursor/mcp.json` in your project root:
42
+ Add this file to `.cursor/mcp.json` in the root of your project:
41
43
 
42
44
  ```json
43
45
  {
@@ -50,25 +52,25 @@ Add to `.cursor/mcp.json` in your project root:
50
52
  }
51
53
  ```
52
54
 
53
- ## Available tools
55
+ ## Tools
54
56
 
55
57
  ### Discovery
56
58
 
57
59
  | Tool | Description |
58
60
  | ------------------------ | ------------------------------------------------------------ |
59
- | `list_projects` | List organizations and projects |
60
- | `get_workspace_overview` | Full workspace state |
61
- | `get_schema_info` | Documentation for Picked concepts and data model |
62
- | `get_picked_docs` | Fetch the complete Picked documentation (LLM-optimized text) |
61
+ | `list_projects` | Lists your organizations and projects |
62
+ | `get_workspace_overview` | Reads the full workspace state |
63
+ | `get_schema_info` | Reads the documentation for Picked concepts and the data model |
64
+ | `get_picked_docs` | Reads the complete Picked documentation, as text for an agent |
63
65
 
64
66
  ### Experiences
65
67
 
66
68
  | Tool | Description |
67
69
  | ------------------------ | ----------------------------------------------------------------------------------------- |
68
- | `create_experience` | Create an experience |
69
- | `get_experience` | Get experience details including flow graph |
70
- | `list_experiences` | List experiences |
71
- | `update_experience_flow` | Atomically create, update, or delete steps, conditions, actions, fields, nodes, and edges |
70
+ | `create_experience` | Creates an experience |
71
+ | `get_experience` | Reads an experience, with its flow graph |
72
+ | `list_experiences` | Lists your experiences |
73
+ | `update_experience_flow` | Creates, updates, or deletes steps, conditions, actions, fields, nodes, and edges as one operation |
72
74
 
73
75
  ### Steps, fields, conditions, and actions
74
76
 
@@ -81,40 +83,46 @@ Add to `.cursor/mcp.json` in your project root:
81
83
 
82
84
  ### Feature flags
83
85
 
84
- | Tool | Description |
85
- | ---------------- | -------------------------------------------------- |
86
- | `create_feature` | Create a feature flag |
87
- | `get_feature` | Get feature flag details |
88
- | `list_features` | List feature flags |
89
- | `update_feature` | Update name, description, enabled state, or weight |
86
+ | Tool | Description |
87
+ | ---------------- | ---------------------------------------------------- |
88
+ | `create_feature` | Creates a feature flag |
89
+ | `get_feature` | Reads a feature flag |
90
+ | `list_features` | Lists your feature flags |
91
+ | `update_feature` | Updates the name, description, state, or weight |
90
92
 
91
93
  ### Analytics
92
94
 
93
95
  | Tool | Description |
94
96
  | ---------------- | ---------------------------------------------------------------- |
95
- | `query_pickedql` | Execute a PickedQL analytics query and return results as a table |
97
+ | `query_pickedql` | Runs a PickedQL analytics query and returns the rows as a table |
96
98
 
97
- Use `get_schema_info` with topic `pickedql` to see available tables, virtual functions, and dimension columns before writing queries.
99
+ Call `get_schema_info` with the topic `pickedql` to see the tables, the virtual
100
+ functions, and the dimension columns before you write a query.
98
101
 
99
- ### Publishing
102
+ ### Publish
100
103
 
101
104
  | Tool | Description |
102
105
  | ------------------- | ---------------------------------------------- |
103
- | `get_preview_url` | Generate a preview URL for unpublished changes |
104
- | `publish_workspace` | Publish the workspace |
106
+ | `get_preview_url` | Makes a preview URL for your unpublished work |
107
+ | `publish_workspace` | Publishes the workspace |
105
108
 
106
109
  ## Example prompts
107
110
 
108
- - "List my Picked projects and show me what's configured"
109
- - "Create a feature flag called 'new-checkout' enabled at 50% traffic"
110
- - "Create an experience with a step that collects email addresses"
111
- - "Show me control vs variant users by device for the last 30 days"
112
- - "Generate a preview URL for my workspace on https://example.com"
111
+ - "List my Picked projects and show me the options on each one"
112
+ - "Create a feature flag called 'new-checkout' at 50% traffic"
113
+ - "Create an experience with a step that collects an email address"
114
+ - "Show me control and variant users by the device type for the last 30 days"
115
+ - "Make a preview URL for my workspace on `https://example.com`"
113
116
 
114
117
  ## Tips
115
118
 
116
- - Ask your agent to list your projects first, then explore your workspace to see what's configured.
117
- - When building complex experiences, ask your agent about flow graphs and JSON Logic — it can look up the documentation for you.
118
- - Experience flow updates are atomic — your agent can create steps, fields, nodes, and edges in a single operation.
119
- - Preview your changes on your site before publishing to verify everything looks right.
120
- - Ask your agent to query analytics data with PickedQL — it can look up the schema, write the SQL, and explain the results.
119
+ - Ask your agent for a list of your projects first. Then ask it to read your
120
+ workspace and report the options on each record.
121
+ - For a large experience, ask your agent about flow graphs and JSON Logic. The agent
122
+ can read the documentation for you.
123
+ - An update to an experience flow is atomic. Your agent can create steps, fields,
124
+ nodes, and edges in one operation.
125
+ - See a preview of your work on your site before you publish, to check that each page
126
+ is correct.
127
+ - Ask your agent to run a PickedQL query on your analytics data. The agent can read
128
+ the schema, write the SQL, and explain the rows.
@@ -4,11 +4,14 @@ layout: docs
4
4
 
5
5
  # Data sources
6
6
 
7
- PickedQL provides four virtual tables (each optimized for different query patterns) plus three reference tables describing your Picked configuration.
7
+ PickedQL gives you four virtual tables. Each table is fast for one kind of work. It also gives you three reference tables, and those hold the options of your
8
+ Picked project.
8
9
 
9
- ## `metrics` — Pre-aggregated daily data
10
+ ## `metrics` — data that PickedQL aggregates each day
10
11
 
11
- Best for dashboards and trend analysis. One row per unique combination of dimensions per day. Dimension columns (like `device_category`, `country_code`, `utm_source`) are available directly — no joins needed.
12
+ Use it for a dashboard and to study a trend. There is one row for each unique set of
13
+ dimensions on each day. The dimension columns are there directly, and they need no
14
+ join. Examples are `device_category`, `country_code`, and `utm_source`.
12
15
 
13
16
  ```sql
14
17
  SELECT device_category, control_users(), variant_users()
@@ -17,9 +20,11 @@ WHERE project_id = 'your-project-id'
17
20
  GROUP BY device_category
18
21
  ```
19
22
 
20
- ## `events` — User-level event data
23
+ ## `events` — one row for each event of each user
21
24
 
22
- Best for deep analysis, funnels, and custom breakdowns. One row per event per user. Dimension columns (like `device_category` or `country_code`) are joined automatically when referenced.
25
+ Use it for a deep study, for a funnel, and for a breakdown of your own. There is one
26
+ row for each event of each user. PickedQL joins a dimension column, such as
27
+ `device_category` or `country_code`, when you point at it.
23
28
 
24
29
  ```sql
25
30
  SELECT user_canonical_id, device_category
@@ -28,9 +33,10 @@ WHERE project_id = 'your-project-id'
28
33
  AND variant_type = 'Control'
29
34
  ```
30
35
 
31
- ## `features` — Feature flag analysis
36
+ ## `features` — one row for each feature flag
32
37
 
33
- Best for querying user, session, and event counts per feature flag and bucket. Uses parameterized functions.
38
+ Use it to count the users, the sessions, and the events for each feature flag and
39
+ bucket. It uses parameterized functions.
34
40
 
35
41
  ```sql
36
42
  SELECT feature_users('homepage_test', 'control')
@@ -38,40 +44,48 @@ FROM features
38
44
  WHERE project_id = 'your-project-id'
39
45
  ```
40
46
 
41
- ## `experience_journey` — Sankey-ready step transitions
47
+ ## `experience_journey` — step transitions for a sankey chart
42
48
 
43
- Returns per-edge `source, target, users` rows ready to feed a sankey or funnel chart. Wraps the 8-CTE step-transition scaffold (lagInFrame, consecutive-step dedup, top-N path ranking) that cards used to carry inline.
49
+ It returns one `source, target, users` row for each edge. You can put those rows
50
+ directly into a sankey chart or a funnel chart. It holds the eight common table
51
+ expressions that a card carried before. Those call `lagInFrame`, remove a duplicate
52
+ between two steps that follow each other, and rank the top paths.
44
53
 
45
- All filters pass through the **outer `WHERE`** — PickedQL extracts them as parameters and substitutes them into the underlying scaffold. Only `project_id` is required; the rest are optional and default sensibly.
54
+ Every filter goes in the **outer `WHERE`** clause. PickedQL reads each one as a
55
+ parameter and puts it into the query below. Only `project_id` is necessary. The rest
56
+ are optional, and each has a sensible default.
46
57
 
47
- | Param (WHERE key) | Purpose |
58
+ | Parameter, as a WHERE key | What it does |
48
59
  |---|---|
49
- | `project_id` | Required tenant filter. |
50
- | `experience_id` | Restrict to one `fact_events.experience_id`. |
51
- | `starting_step` | Anchor edges at each user's first occurrence of this `step_id`. Absent → anchor at user's first step_enter event. |
52
- | `targeting_step` | Trim each user's window at their first occurrence of this `step_id`. Users who never reach it still contribute their journey up to `num_nodes_after_start`. |
53
- | `num_nodes_after_start` | Forward window size from the starting step (card 4129 semantics). |
54
- | `num_nodes_before_target` | Backward window size from the targeting step (card 2740 semantics). Requires `targeting_step`. |
55
- | `top_n_path` | Keep only the top-N distinct paths by user count. |
56
- | `user_cohort_event` | Restrict to users who have at least one `fact_events` row with this `event_type` (e.g., `'lead_capture'`). Useful for "paths taken by users who eventually converted". |
57
- | `client_local_date` | Date filter. Supports `=`, `<`, `<=`, `>`, `>=`, `BETWEEN`; pushed into the underlying `fact_events` scan. |
58
- | `event_timestamp` | Server-side timestamp filter. Same operators as `client_local_date`. |
59
-
60
- When `num_nodes_after_start` and `num_nodes_before_target` are both set, both predicates apply (intersection).
60
+ | `project_id` | The tenant filter. It is necessary. |
61
+ | `experience_id` | Limits the rows to one `fact_events.experience_id`. |
62
+ | `starting_step` | Anchors each edge at the first time that a user reaches this `step_id`. With no value, it anchors at the first `step_enter` event of that user. |
63
+ | `targeting_step` | Trims the window of each user at the first time that the user reaches this `step_id`. A user who never reaches it still gives a journey, up to `num_nodes_after_start`. |
64
+ | `num_nodes_after_start` | The size of the forward window from the start step. This is what card 4129 does. |
65
+ | `num_nodes_before_target` | The size of the backward window from the target step. This is what card 2740 does. It needs `targeting_step`. |
66
+ | `top_n_path` | Keeps the paths with the most users, and drops the rest. |
67
+ | `user_cohort_event` | Limits the rows to a user with at least one `fact_events` row of this `event_type`, such as `'lead_capture'`. Use it for the paths of the users who reached a goal. |
68
+ | `client_local_date` | A filter on the date. It takes `=`, `<`, `<=`, `>`, `>=`, and `BETWEEN`. PickedQL puts it into the `fact_events` read below. |
69
+ | `event_timestamp` | A filter on the timestamp from the server. It takes the same operators as `client_local_date`. |
70
+
71
+ When you set both `num_nodes_after_start` and `num_nodes_before_target`, both tests
72
+ apply. The result is the intersection of the two.
61
73
 
62
74
  ```sql
63
- -- "Overall user journey" sankey (card 4129 pattern) — forward window, target optional
75
+ -- The "overall user journey" sankey, as in card 4129.
76
+ -- It uses a forward window. The target step is optional.
64
77
  SELECT source, target, users FROM experience_journey
65
78
  WHERE project_id = 'your-project-id'
66
79
  AND starting_step = 'step-start'
67
80
  AND targeting_step = 'step-target'
68
81
  AND num_nodes_after_start = 10
69
- AND client_local_date >= '2026-04-01' -- optional date range
82
+ AND client_local_date >= '2026-04-01' -- An optional range of dates.
70
83
  AND client_local_date <= '2026-04-30'
71
84
  ```
72
85
 
73
86
  ```sql
74
- -- "Paths leading to target" sankey (card 2740 pattern) — backward window + top-N ranking
87
+ -- The "paths to a target" sankey, as in card 2740.
88
+ -- It uses a backward window and it ranks the top paths.
75
89
  SELECT source, target, users FROM experience_journey
76
90
  WHERE project_id = 'your-project-id'
77
91
  AND experience_id = 'exp-123'
@@ -82,7 +96,7 @@ WHERE project_id = 'your-project-id'
82
96
  ```
83
97
 
84
98
  ```sql
85
- -- "Drop-off" sankey (card 2744 pattern) — omit targeting_step
99
+ -- The "drop-off" sankey, as in card 2744. Leave the target step out.
86
100
  SELECT source, target, users FROM experience_journey
87
101
  WHERE project_id = 'your-project-id'
88
102
  AND experience_id = 'exp-123'
@@ -91,55 +105,63 @@ WHERE project_id = 'your-project-id'
91
105
  ```
92
106
 
93
107
  ```sql
94
- -- Cohort sankey: only users who eventually converted (card 3961 pattern)
108
+ -- A cohort sankey, as in card 3961. It holds the users who reached the goal only.
95
109
  SELECT source, target, users FROM experience_journey
96
110
  WHERE project_id = 'your-project-id'
97
111
  AND starting_step = 'step-start'
98
112
  AND targeting_step = 'step-target'
99
113
  AND num_nodes_after_start = 10
100
- AND user_cohort_event = 'lead_capture' -- restrict to users with ≥1 lead_capture event
114
+ AND user_cohort_event = 'lead_capture' -- Users with one or more of these events.
101
115
  ```
102
116
 
103
- Columns returned:
117
+ The columns that it returns:
104
118
 
105
119
  | Column | Type | Description |
106
120
  |---|---|---|
107
- | `source` | String | Edge start, formatted as `NN. <step title>` (e.g., `001. Welcome screen`). PickedQL joins `steps` to resolve the title. |
108
- | `target` | String | Edge end, formatted as `NN. <step title>`. |
109
- | `users` | UInt64 | Distinct `user_canonical_id` count that traversed this edge. |
121
+ | `source` | String | The start of the edge, in the form `NN. <step title>`, such as `001. Welcome screen`. PickedQL joins `steps` to find the title. |
122
+ | `target` | String | The end of the edge, in the form `NN. <step title>`. |
123
+ | `users` | `UInt64` | The number of different `user_canonical_id` values that went along this edge. |
110
124
 
111
125
  :::note
112
- `experience_journey` is aggregated output. Dimension filters (`variant_type`, `device_category`, `country_code`, …) are **not** supported — if you need those, query [`events`](#events--user-level-event-data) directly and build the transitions yourself.
126
+ `experience_journey` returns data that PickedQL aggregates first. It does **not**
127
+ support a dimension filter such as `variant_type`, `device_category`, or
128
+ `country_code`. To use one of those, query
129
+ [`events`](#events--one-row-for-each-event-of-each-user) directly and build the
130
+ transitions yourself.
113
131
  :::
114
132
 
115
133
  ## Reference tables — `steps`, `experiences`, `projects`
116
134
 
117
- Reference tables describing your Picked configuration. They serve two roles:
135
+ These reference tables hold the options of your Picked project. They have two uses:
118
136
 
119
- - **Auto-joined onto `events`** when their prefixed analyst columns (`step_title`, `experience_title`, `project_name`, `project_timezone`) are referenced.
120
- - **Queryable directly**, with a per-table tenant filter required so you only see rows belonging to a project you have access to.
137
+ - **PickedQL joins them onto `events`** when you point at one of their analyst
138
+ columns: `step_title`, `experience_title`, `project_name`, or `project_timezone`.
139
+ - **You can read them directly.** Each one then needs its own tenant filter, so that
140
+ you see only the rows of a project that you can reach.
121
141
 
122
- | Source | Tenant filter required |
142
+ | Source | The tenant filter that it needs |
123
143
  |---|---|
124
144
  | `steps` | `WHERE project_id = '<project_id>'` |
125
145
  | `experiences` | `WHERE project_id = '<project_id>'` |
126
146
  | `projects` | `WHERE id = '<project_id>'` |
127
147
 
128
148
  ```sql
129
- -- Direct query: list experiences for a project
149
+ -- A direct query that reads the experiences of a project.
130
150
  SELECT id, title FROM experiences WHERE project_id = 'your-project-id'
131
151
 
132
- -- Direct query: load metadata for one project
152
+ -- A direct query that reads the metadata of one project.
133
153
  SELECT id, name, timezone FROM projects WHERE id = 'your-project-id'
134
154
  ```
135
155
 
136
156
  ```sql
137
- -- Referenced from events: PickedQL auto-injects the LEFT JOINs
138
- -- (no separate tenant filter on the reference tables — the join is scoped via fact_events)
157
+ -- Pointed at from events. PickedQL adds each LEFT JOIN for you.
158
+ -- The reference tables need no separate tenant filter, because
159
+ -- the event table already limits the join.
139
160
  SELECT experience_title, step_title, count(*)
140
161
  FROM events
141
162
  WHERE project_id = 'your-project-id'
142
163
  GROUP BY experience_title, step_title
143
164
  ```
144
165
 
145
- See [Schema → reference tables](./schema#steps-experiences-projects) for the full column list and join keys.
166
+ See [Schema, reference tables](./schema#steps-experiences-projects) for the full
167
+ column list and the join keys.
@@ -4,9 +4,11 @@ layout: docs
4
4
 
5
5
  # Dimension columns
6
6
 
7
- Dimension columns are available on all data sources. On `metrics`, they are included directly in the table. On `events` and `features`, the required `LEFT JOIN` is added automatically when you reference them — you never write joins yourself.
7
+ Every data source has dimension columns. The `metrics` table holds them directly. On
8
+ `events` and on `features`, PickedQL adds the `LEFT JOIN` that it needs when you
9
+ point at one. You write no join.
8
10
 
9
- ## Available dimensions
11
+ ## The dimensions
10
12
 
11
13
  | Source | Columns |
12
14
  |---|---|
@@ -19,29 +21,42 @@ Dimension columns are available on all data sources. On `metrics`, they are incl
19
21
  | `experiences` | `experience_title` |
20
22
  | `projects` | `project_name`, `project_timezone` |
21
23
 
22
- The `steps`, `experiences`, and `projects` sources are reference tables sourced from the operational database. They are auto-joined onto `events`/`fact_events` when their analyst-facing columns are referenced, **and** they require their own tenant filter when queried directly:
24
+ The `steps`, `experiences`, and `projects` sources are reference tables, and they come
25
+ from the operational database. PickedQL joins them onto `events` and `fact_events`
26
+ when you point at one of their analyst-facing columns. Each one **also** needs its own
27
+ tenant filter when you query it directly:
23
28
 
24
- | Source | Tenant filter required |
29
+ | Source | The tenant filter that it needs |
25
30
  |---|---|
26
31
  | `steps`, `experiences` | `WHERE project_id = '<project_id>'` |
27
- | `projects` | `WHERE id = '<project_id>'` (the row's `id` IS the project id) |
32
+ | `projects` | `WHERE id = '<project_id>'`, because the `id` of the row is the project ID |
28
33
 
29
- When auto-joined, these reference tables also receive a tenant equality on the JOIN's `ON` clause (e.g. `AND st.project_id = '<project_id>'`, `AND pr.id = '<project_id>'`) so ClickHouse prunes the dim scan instead of reading the full table. The predicate is added to `ON` rather than `WHERE` to preserve `LEFT JOIN` semantics.
34
+ PickedQL also puts a tenant equality in the `ON` clause of each join that it adds.
35
+ Examples are `AND st.project_id = '<project_id>'` and `AND pr.id = '<project_id>'`.
36
+ ClickHouse then reads part of the dimension table and not all of it. PickedQL puts
37
+ the test in `ON` and not in `WHERE`, because a test in `WHERE` would change a
38
+ `LEFT JOIN` into an inner join.
30
39
 
31
- Analyst-facing column names are prefixed (`step_title`, `project_name`, etc.) to avoid collisions across sources — for example, `steps.title` and `experiences.title` both exist, but you reference them as `step_title` and `experience_title`.
40
+ Each analyst-facing column name carries a prefix, such as `step_title` and
41
+ `project_name`. The prefix stops a collision between two sources. Both `steps.title`
42
+ and `experiences.title` are there, and you point at them as `step_title` and
43
+ `experience_title`.
32
44
 
33
45
  ```sql
34
- -- Group events by experience and step name (auto-joins both `experiences` and `steps`)
46
+ -- Group the events by experience and by step name.
47
+ -- PickedQL joins both `experiences` and `steps` for you.
35
48
  SELECT experience_title, step_title, count(*)
36
49
  FROM events
37
50
  WHERE project_id = 'your-project-id'
38
51
  GROUP BY experience_title, step_title
39
52
  ```
40
53
 
41
- Auto-joins also work inside subqueries and CTEs — reference dimension columns wherever you need them and the required `LEFT JOIN` is injected at that level:
54
+ An automatic join also works inside a subquery and inside a common table expression.
55
+ Point at a dimension column where you need it, and PickedQL adds the `LEFT JOIN` at
56
+ that level:
42
57
 
43
58
  ```sql
44
- -- Dimension columns inside a CTE
59
+ -- Dimension columns inside a common table expression.
45
60
  WITH per_step AS (
46
61
  SELECT step_title, count(*) AS n
47
62
  FROM events
@@ -50,7 +65,7 @@ WITH per_step AS (
50
65
  )
51
66
  SELECT * FROM per_step ORDER BY n DESC
52
67
 
53
- -- Dimension columns inside a nested SELECT
68
+ -- Dimension columns inside a nested query.
54
69
  SELECT step_title, n FROM (
55
70
  SELECT step_title, count(*) AS n FROM events
56
71
  WHERE project_id = 'your-project-id'
@@ -60,6 +75,6 @@ SELECT step_title, n FROM (
60
75
 
61
76
  ## Native event columns
62
77
 
63
- These columns are available directly on `events` and require no join:
78
+ These columns are on `events` directly, and they need no join:
64
79
 
65
80
  `event_type`, `interaction_type`, `experience_id`, `step_id`, `event_id`, `user_canonical_id`, `session_id`, `client_local_date`, `is_purchase`, `is_cart_add`, `event_meta`.
@@ -51,7 +51,9 @@ ORDER BY project_local_date
51
51
 
52
52
  ## Custom conversion rate definition
53
53
 
54
- Override the default purchase conversion with your own numerator and denominator. Useful when conversion is defined by a form submission, lead capture, or any custom event.
54
+ Override the default conversion, which counts a `purchase` event, with your own
55
+ numerator and denominator. Use this when a form submission, a lead capture, or
56
+ another event of your own defines a conversion.
55
57
 
56
58
  ```sql
57
59
  -- Lead capture conversion: form submissions / lead-capture step entries
@@ -75,7 +77,7 @@ ORDER BY project_local_date
75
77
  You can also combine multiple events with `OR` and group with parentheses:
76
78
 
77
79
  ```sql
78
- -- Either checkout_complete or order_create counts as a conversion
80
+ -- A `checkout_complete` event or an `order_create` event counts as a conversion.
79
81
  SELECT
80
82
  control_conversion_rate(
81
83
  'event_type=checkout_complete OR event_type=order_create'
@@ -87,12 +89,15 @@ FROM events
87
89
  WHERE project_id = '{{ your project ID }}'
88
90
  ```
89
91
 
90
- ## Custom segment with `control_users` / `variant_users`
92
+ ## Your own segment with `control_users` and `variant_users`
91
93
 
92
- On `events`, `control_users` / `variant_users` / `control_sessions` / `variant_sessions` accept an optional filter string to count only users/sessions matching the given expression in addition to the implicit `variant_type` filter.
94
+ On `events`, four functions take an optional filter string: `control_users`,
95
+ `variant_users`, `control_sessions`, and `variant_sessions`. The filter counts only a
96
+ user or a session that matches your expression. It applies together with the
97
+ `variant_type` filter that PickedQL adds.
93
98
 
94
99
  ```sql
95
- -- Control users who fired app_initialize, broken down by step
100
+ -- The control users who fired an `app_initialize` event, by step.
96
101
  SELECT
97
102
  step_id,
98
103
  control_users('event_type=app_initialize') AS control_initialized,
@@ -113,10 +118,13 @@ WHERE project_id = '{{ your project ID }}'
113
118
 
114
119
  ## Conversion rate from nested virtual functions
115
120
 
116
- When numerator and denominator come from different segments — e.g., Control users who fired a custom event divided by **all** users (not just Control) — pass virtual function calls directly as conversion-rate args:
121
+ The numerator and the denominator can come from different segments. An example is the
122
+ control users who fired an event of your own, divided by **all** users and not by the
123
+ control users alone. For that, pass a virtual function call directly as an argument
124
+ of the conversion rate:
117
125
 
118
126
  ```sql
119
- -- (Control users who fired app_initialize) / (all users, regardless of variant)
127
+ -- The control users who fired `app_initialize`, over all users of every variant.
120
128
  SELECT
121
129
  control_conversion_rate(
122
130
  control_users('event_type=app_initialize'),
@@ -188,9 +196,9 @@ GROUP BY utm_source
188
196
 
189
197
  | utm_source | users | purchasers |
190
198
  | ---------- | ------ | ---------- |
191
- | meta | 12031 | 101 |
192
- | fb | 3656 | 31 |
193
- | an | 100366 | 299 |
199
+ | `meta` | 12031 | 101 |
200
+ | `fb` | 3656 | 31 |
201
+ | `an` | 100366 | 299 |
194
202
 
195
203
  ## Step funnel for variant users
196
204
 
@@ -211,18 +219,20 @@ ORDER BY variant DESC
211
219
 
212
220
  | step_id | variant |
213
221
  | ------------------------------ | ------- |
214
- | who-are-you-protecting-step | 1093 |
215
- | about-yourself-step | 533 |
216
- | date-of-birth-step | 435 |
217
- | employment-status-step | 408 |
218
- | nicotine-usage-step | 407 |
219
- | coverage-motivation-step | 405 |
220
- | lead-capture-step | 398 |
222
+ | `who-are-you-protecting-step` | 1093 |
223
+ | `about-yourself-step` | 533 |
224
+ | `date-of-birth-step` | 435 |
225
+ | `employment-status-step` | 408 |
226
+ | `nicotine-usage-step` | 407 |
227
+ | `coverage-motivation-step` | 405 |
228
+ | `lead-capture-step` | 398 |
221
229
 
222
230
 
223
231
  ## Sankey — overall user journey
224
232
 
225
- Forward window from the starting step. Non-reachers of `targeting_step` still contribute edges up to `num_nodes_after_start`. Mirrors dashboard 1156 card 4129's semantics.
233
+ A forward window from the starting step. A user who never reaches `targeting_step`
234
+ still gives edges, up to `num_nodes_after_start`. This does what card 4129 on
235
+ dashboard 1156 does.
226
236
 
227
237
  ```sql
228
238
  SELECT source, target, users FROM experience_journey
@@ -236,13 +246,15 @@ WHERE project_id = '{{ your project ID }}'
236
246
 
237
247
  | source | target | users |
238
248
  | ------------------------- | ------------------------- | ----- |
239
- | 001. step-start | 002. step-questionnaire-1 | 182 |
240
- | 002. step-questionnaire-1 | 003. step-quote | 144 |
241
- | 003. step-quote | 004. step-target | 121 |
249
+ | `001. step-start` | `002. step-questionnaire-1` | 182 |
250
+ | `002. step-questionnaire-1` | `003. step-quote` | 144 |
251
+ | `003. step-quote` | `004. step-target` | 121 |
242
252
 
243
- ## Sankey — top paths leading to a target step
253
+ ## Sankey — the top paths to a target step
244
254
 
245
- Backward window anchored at the target, plus top-N path ranking. Mirrors dashboard 1156 card 3961 / dashboard 991 card 2740 semantics.
255
+ A backward window anchored at the target. It also ranks the paths and keeps the ones
256
+ with the most users. This does what card 3961 on dashboard 1156 and card 2740 on
257
+ dashboard 991 do.
246
258
 
247
259
  ```sql
248
260
  SELECT source, target, users FROM experience_journey
@@ -284,6 +296,6 @@ WHERE project_id = '{{ your project ID }}'
284
296
 
285
297
  | device_category | user_canonical_id |
286
298
  | --------------- | ------------------------------------ |
287
- | Mobile | 019cc336-5a6a-7c32-b638-cdcc983b3e70 |
288
- | Mobile | 019cc336-5a6a-7d8f-994c-69bc28e5f550 |
289
- | Mobile | 019cc80f-503c-7181-b2c6-986b1f76d496 |
299
+ | Mobile | `019cc336-5a6a-7c32-b638-cdcc983b3e70` |
300
+ | Mobile | `019cc336-5a6a-7d8f-994c-69bc28e5f550` |
301
+ | Mobile | `019cc80f-503c-7181-b2c6-986b1f76d496` |
@@ -2,17 +2,19 @@
2
2
  layout: docs
3
3
  ---
4
4
 
5
- # Filtering
5
+ # Filters
6
6
 
7
- Add `WHERE` clauses as usual. Every query must include a `project_id` filter — PickedQL extracts it and verifies you have permission to access that project. Queries without a `project_id` filter are rejected.
7
+ Add a `WHERE` clause in the usual way. Every query must hold a `project_id` filter.
8
+ PickedQL reads that filter and checks that you have permission for the project.
9
+ PickedQL rejects a query with no `project_id` filter.
8
10
 
9
11
  ```sql
10
- -- Date range
12
+ -- A range of dates.
11
13
  SELECT control_users() FROM metrics
12
14
  WHERE project_id = 'your-project-id'
13
15
  AND project_local_date BETWEEN '2026-03-01' AND '2026-03-31'
14
16
 
15
- -- By experience
17
+ -- By experience.
16
18
  SELECT step_enter_users() FROM events
17
19
  WHERE project_id = 'your-project-id'
18
20
  AND experience_id = 'my-experience'
@@ -30,9 +32,11 @@ WHERE project_id = 'your-project-id'
30
32
  Each query can only filter on a single `project_id`. Queries that reference multiple projects will be rejected.
31
33
  :::
32
34
 
33
- ## Reference tables (per-table tenant filter)
35
+ ## Reference tables, each with its own tenant filter
34
36
 
35
- Queries against the reference tables (`steps`, `experiences`, `projects`) require their own tenant filter so you only see rows belonging to a project you have access to:
37
+ A query against a reference table needs its own tenant filter. The reference tables
38
+ are `steps`, `experiences`, and `projects`. The filter makes sure that you see only
39
+ the rows of a project that you can reach:
36
40
 
37
41
  | Source | Tenant filter |
38
42
  |---|---|