@picked/client 0.0.70-next.5 → 0.0.70

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 (78) hide show
  1. package/dist/{api-DQ1DqG_F.js → api-CPy9G49C.js} +1 -1
  2. package/dist/api-Ce6xYI--.cjs +1 -0
  3. package/dist/cjs/index.js +2 -2
  4. package/dist/cjs/plugins/dynamic-experiences/index.js +1 -1
  5. package/dist/cjs/server/index.js +1 -1
  6. package/dist/docs/actions.mdx +38 -18
  7. package/dist/docs/api/authentication.md +75 -48
  8. package/dist/docs/api/authorization-and-scopes.md +63 -47
  9. package/dist/docs/api/error-handling.md +70 -54
  10. package/dist/docs/api/index.md +41 -22
  11. package/dist/docs/api/pagination.md +30 -20
  12. package/dist/docs/api-keys.mdx +11 -6
  13. package/dist/docs/chrome-extension.md +22 -5
  14. package/dist/docs/conditions.mdx +32 -19
  15. package/dist/docs/content/asset-library.mdx +65 -34
  16. package/dist/docs/content/content-entries.mdx +8 -2
  17. package/dist/docs/content/layouts.mdx +45 -29
  18. package/dist/docs/content/pages.mdx +29 -14
  19. package/dist/docs/content/sections.mdx +19 -8
  20. package/dist/docs/delivery-api/experience-content.md +10 -5
  21. package/dist/docs/delivery-api/index.md +19 -12
  22. package/dist/docs/delivery-api/preview-caching-crawling.md +27 -14
  23. package/dist/docs/delivery-api/project-config.md +6 -4
  24. package/dist/docs/experiences.mdx +26 -10
  25. package/dist/docs/features.mdx +75 -20
  26. package/dist/docs/fields.mdx +42 -27
  27. package/dist/docs/flow-builder/building-flows.md +38 -20
  28. package/dist/docs/flow-builder/condition-builder.md +32 -21
  29. package/dist/docs/flow-builder/keyboard-shortcuts.md +18 -18
  30. package/dist/docs/flow-builder/nodes.md +26 -13
  31. package/dist/docs/flow-builder/overview.mdx +28 -15
  32. package/dist/docs/gtm-template.md +35 -26
  33. package/dist/docs/guides/build-a-personalized-page.mdx +36 -18
  34. package/dist/docs/image-optimisation-service.md +33 -17
  35. package/dist/docs/index.md +28 -17
  36. package/dist/docs/mcp.md +46 -38
  37. package/dist/docs/pickedql/data-sources.md +65 -43
  38. package/dist/docs/pickedql/dimensions.md +27 -12
  39. package/dist/docs/pickedql/examples.md +38 -26
  40. package/dist/docs/pickedql/filtering.md +10 -6
  41. package/dist/docs/pickedql/index.md +32 -14
  42. package/dist/docs/pickedql/schema.md +85 -76
  43. package/dist/docs/pickedql/virtual-functions.md +62 -36
  44. package/dist/docs/projects.mdx +14 -7
  45. package/dist/docs/reports.mdx +5 -3
  46. package/dist/docs/sdk/actions.md +33 -17
  47. package/dist/docs/sdk/conditions.md +8 -5
  48. package/dist/docs/sdk/content-security-policy.md +5 -4
  49. package/dist/docs/sdk/experiences.md +29 -11
  50. package/dist/docs/sdk/feature-allocation.md +79 -47
  51. package/dist/docs/sdk/features.md +130 -76
  52. package/dist/docs/sdk/fields.md +66 -42
  53. package/dist/docs/sdk/index.md +22 -13
  54. package/dist/docs/sdk/plugins/create-experience.md +18 -15
  55. package/dist/docs/sdk/plugins/dynamic-experiences.md +42 -16
  56. package/dist/docs/sdk/predicates.md +53 -37
  57. package/dist/docs/sdk/ssr/index.md +25 -8
  58. package/dist/docs/sdk/ssr/rendering-and-hydration.md +37 -16
  59. package/dist/docs/sdk/ssr/serialize.md +38 -20
  60. package/dist/docs/sdk/ssr/slots-and-placements.md +28 -10
  61. package/dist/docs/sdk/steps.md +100 -55
  62. package/dist/docs/steps.mdx +20 -11
  63. package/dist/docs/team-management.md +17 -11
  64. package/dist/docs/vite-plugin.md +26 -19
  65. package/dist/docs/workspace-versioning.mdx +14 -8
  66. package/dist/docs/workspaces.mdx +55 -24
  67. package/dist/esm/index.js +257 -238
  68. package/dist/esm/plugins/dynamic-experiences/index.js +2 -2
  69. package/dist/esm/server/index.js +1 -1
  70. package/dist/{plugin-EPx6sE_l.js → plugin-ChPkTj__.js} +58 -53
  71. package/dist/plugin-DHn11gn6.cjs +1 -0
  72. package/dist/types/entities/feature/feature.d.ts.map +1 -1
  73. package/dist/types/plugins/dynamic-experiences/hash.d.ts +40 -5
  74. package/dist/types/plugins/dynamic-experiences/hash.d.ts.map +1 -1
  75. package/dist/types/plugins/dynamic-experiences/plugin.d.ts.map +1 -1
  76. package/package.json +1 -1
  77. package/dist/api-B9koex39.cjs +0 -1
  78. package/dist/plugin-YbSSGrM7.cjs +0 -1
@@ -4,7 +4,10 @@ layout: docs
4
4
 
5
5
  # Image optimisation service
6
6
 
7
- The Picked image optimisation service is a hosted endpoint at `https://img.picked-content.com`. It fetches images from allowed source domains, resizes them, re-encodes to modern formats (WebP or AVIF), and caches the result.
7
+ The Picked service for image optimisation is a hosted endpoint at
8
+ `https://img.picked-content.com`. It reads an image from an allowed source domain and
9
+ resizes it. It then encodes the image again to a modern format, WebP or AVIF, and
10
+ caches the result.
8
11
 
9
12
  ## Endpoint
10
13
 
@@ -14,35 +17,39 @@ GET https://img.picked-content.com/_next/image?url={source}&w={width}&q={quality
14
17
 
15
18
  | Parameter | Description |
16
19
  |-----------|-------------|
17
- | `url` | URL-encoded URL of the source image. Must point to an allowed source domain (see below). |
18
- | `w` | Target width in pixels. Must match one of the supported widths. |
19
- | `q` | Target quality (`25`, `50`, `75`, or `100`). |
20
+ | `url` | The URL of the source image, URL-encoded. It must point at an allowed source domain. See below. |
21
+ | `w` | The width in pixels. It must be one of the supported widths. |
22
+ | `q` | The quality: `25`, `50`, `75`, or `100`. |
20
23
 
21
- The service performs content negotiation: if the requesting browser advertises `image/avif` or `image/webp` in its `Accept` header, the response uses that format. Otherwise the response uses the source format.
24
+ The service chooses the response format. When the browser advertises `image/avif` or
25
+ `image/webp` in its `Accept` header, the response uses that format. If it does not,
26
+ the response uses the source format.
22
27
 
23
28
  ## Allowed source domains
24
29
 
25
- The service only fetches from these hostnames:
30
+ The service reads only from these hostnames:
26
31
 
27
32
  - `**.picked.app`
28
33
 
29
- A request whose `url` parameter resolves to any other hostname returns `400 Bad Request`.
34
+ A request with a `url` parameter for any other hostname returns `400 Bad Request`.
30
35
 
31
36
  ## Supported widths
32
37
 
33
- Device sizes, for responsive images that span the viewport width:
38
+ Device sizes, for a responsive image that spans the width of the viewport:
34
39
 
35
40
  ```
36
41
  640, 750, 828, 1080, 1200, 1920, 2048, 3840
37
42
  ```
38
43
 
39
- Image sizes, for fixed-size UI elements such as icons, avatars, and thumbnails:
44
+ Image sizes, for a UI element of fixed size such as an icon, an avatar, or a
45
+ thumbnail:
40
46
 
41
47
  ```
42
48
  16, 32, 48, 64, 96, 128, 256, 384
43
49
  ```
44
50
 
45
- Requests with any other width return `400 Bad Request`. Pick the smallest width that covers your target rendering size at the user's device pixel ratio.
51
+ A request with any other width returns `400 Bad Request`. Choose the smallest width
52
+ that covers the size you render at the device pixel ratio of the visitor.
46
53
 
47
54
  ## Supported qualities
48
55
 
@@ -50,11 +57,13 @@ Requests with any other width return `400 Bad Request`. Pick the smallest width
50
57
  25, 50, 75, 100
51
58
  ```
52
59
 
53
- Lower values reduce bandwidth significantly. `75` is a good default for most images; use `25` or `50` for thumbnails on slow networks.
60
+ A lower value reduces the bandwidth by a large amount. `75` is a good default for
61
+ most images. Use `25` or `50` for a thumbnail on a slow network.
54
62
 
55
63
  ## Responsive images
56
64
 
57
- Combine the endpoint with the standard `srcset` attribute to let browsers pick the right width per viewport:
65
+ Use the endpoint together with the standard `srcset` attribute. The browser then
66
+ picks the correct width for each viewport:
58
67
 
59
68
  ```html
60
69
  <img
@@ -69,12 +78,19 @@ Combine the endpoint with the standard `srcset` attribute to let browsers pick t
69
78
  />
70
79
  ```
71
80
 
72
- ## Caching
81
+ ## Cache
73
82
 
74
- Optimised responses are cached by the upstream CDN. The minimum cache TTL is 60 seconds; the actual lifetime depends on the CDN's eviction policy. If you change the source image at the same URL, expect the optimised variant to remain cached for at least that interval.
83
+ The upstream CDN caches each optimised response. The smallest cache TTL is 60
84
+ seconds. The real lifetime depends on the eviction policy of the CDN. When you change
85
+ the source image at the same URL, the optimised copy stays in the cache for at least
86
+ that time.
75
87
 
76
88
  ## Security
77
89
 
78
- - SVG sources are not optimised. Requests for SVG return the original bytes if the source is allowed; the service never executes embedded scripts.
79
- - Optimised responses carry a strict `Content-Security-Policy` (`default-src *; script-src 'none'; sandbox;`) so even a compromised source cannot run scripts in a viewing browser.
80
- - The response uses `Content-Disposition: inline`, never `attachment`.
90
+ - The service does not optimise an SVG source. A request for an SVG returns the
91
+ original bytes when the source is allowed. The service never runs an embedded
92
+ script.
93
+ - Each optimised response carries a strict `Content-Security-Policy`
94
+ (`default-src *; script-src 'none'; sandbox;`). A compromised source therefore
95
+ cannot run a script in the browser that shows the image.
96
+ - The response uses `Content-Disposition: inline`, and never `attachment`.
@@ -2,25 +2,29 @@
2
2
  layout: docs
3
3
  ---
4
4
 
5
- # Getting Started
5
+ # Start here
6
6
 
7
- Picked lets you build personalized UI flows in a visual editor and deliver them to visitors on your site with a lightweight SDK.
7
+ Picked lets you build personalized UI flows in a visual editor. The SDK then serves
8
+ them to the visitors on your site.
8
9
 
9
10
  ## How it works
10
11
 
11
- You design experiences in the dashboard using a drag-and-drop flow builder. The SDK fetches your published experiences and renders them on your site.
12
+ You build experiences in the dashboard with a drag-and-drop flow builder. The SDK
13
+ reads your published experiences and renders them on your site.
12
14
 
13
15
  ## Quick start
14
16
 
15
17
  ### 1. Create a project
16
18
 
17
- Sign in to the dashboard and create a project. A project represents one website or app.
19
+ Sign in to the dashboard and create a project. A project is one site or one
20
+ application.
18
21
 
19
- See [Projects](/projects) for details.
22
+ See [Projects](/projects) for more detail.
20
23
 
21
24
  ### 2. Install the SDK
22
25
 
23
- Add the SDK to your site and initialize the client. Copy the snippet from your project home page.
26
+ Add the SDK to your site and start the client. Copy the snippet from your project
27
+ home page.
24
28
 
25
29
  ```typescript
26
30
  import { createClient } from '@picked/client'
@@ -33,11 +37,12 @@ const picked = createClient({
33
37
  picked.start()
34
38
  ```
35
39
 
36
- See [SDK Installation](/sdk) for full setup options.
40
+ See [SDK Installation](/sdk) for all setup options.
37
41
 
38
42
  ### 3. Register a component
39
43
 
40
- Register components when creating the client. Each key in the `components` object must match a component name you set in the dashboard.
44
+ Register your components when you create the client. Each key in the `components`
45
+ object must match a component name that you set in the dashboard.
41
46
 
42
47
  ```typescript
43
48
  import { createClient } from '@picked/client'
@@ -52,26 +57,32 @@ const picked = createClient({
52
57
  picked.start()
53
58
  ```
54
59
 
55
- See [SDK Experiences](/sdk/experiences) for targeting, conditions, and component adapters.
60
+ See [SDK Experiences](/sdk/experiences) for conditions, adapters, and the rules that
61
+ put an experience in a slot.
56
62
 
57
63
  ### 4. Create an experience
58
64
 
59
- In the dashboard, open your project and click **Experiences** > **New Experience**. Enter a name and set the component name to match your registered component (e.g., `welcome-survey`).
65
+ In the dashboard, open your project. Click **Experiences**, then **New Experience**.
66
+ Enter a name. Set the component name to match your registered component, for example
67
+ `welcome-survey`.
60
68
 
61
- See [Experiences](/experiences) for configuration options.
69
+ See [Experiences](/experiences) for the options.
62
70
 
63
71
  ### 5. Build the flow
64
72
 
65
- Open the flow builder and drag steps, actions, and conditions onto the canvas. Connect nodes to define the visitor's path through the experience.
73
+ Open the flow builder. Drag steps, actions, and conditions onto the canvas. Connect
74
+ the nodes to define the path that a visitor takes through the experience.
66
75
 
67
- See [Flow Builder](/flow-builder/overview) for a full walkthrough.
76
+ See [Flow Builder](/flow-builder/overview) for a full guide.
68
77
 
69
78
  ### 6. Save and publish
70
79
 
71
- Click **Save** in the flow builder toolbar. The SDK picks up the published experience and renders it to matching visitors on your site.
80
+ Click **Save** in the flow builder toolbar. The SDK reads the published experience
81
+ and renders it to each visitor who matches.
72
82
 
73
83
  ## Next steps
74
84
 
75
- - [Flow Builder](/flow-builder/overview) — Build experience flows visually
76
- - [Steps](/steps), [Fields](/fields), [Actions](/actions), [Conditions](/conditions) — Configure the building blocks of experiences
77
- - [SDK Installation](/sdk) — Full SDK setup and configuration
85
+ - [Flow Builder](/flow-builder/overview) — Build experience flows in a visual editor
86
+ - [Steps](/steps), [Fields](/fields), [Actions](/actions), [Conditions](/conditions)
87
+ — Set up the parts of an experience
88
+ - [SDK Installation](/sdk) — Full SDK setup and options
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`.