@picked/client 0.0.56-next.1 → 0.0.56
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.
- package/dist/api-BfVRVGAR.cjs +1 -0
- package/dist/{api-CNxyQeRM.js → api-CTjJzTQT.js} +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/plugins/dynamic-experiences/index.js +1 -1
- package/dist/docs/actions.md +58 -0
- package/dist/docs/api/index.md +32 -0
- package/dist/docs/api-keys.md +33 -0
- package/dist/docs/conditions.md +52 -0
- package/dist/docs/experiences.md +33 -0
- package/dist/docs/features.md +51 -0
- package/dist/docs/fields.md +70 -0
- package/dist/docs/flow-builder/building-flows.md +61 -0
- package/dist/docs/flow-builder/condition-builder.md +54 -0
- package/dist/docs/flow-builder/keyboard-shortcuts.md +66 -0
- package/dist/docs/flow-builder/nodes.md +43 -0
- package/dist/docs/flow-builder/overview.md +43 -0
- package/dist/docs/index.md +79 -0
- package/dist/docs/pickedql/data-sources.md +39 -0
- package/dist/docs/pickedql/dimensions.md +23 -0
- package/dist/docs/pickedql/examples.md +165 -0
- package/dist/docs/pickedql/filtering.md +31 -0
- package/dist/docs/pickedql/index.md +34 -0
- package/dist/docs/pickedql/schema.md +95 -0
- package/dist/docs/pickedql/virtual-functions.md +84 -0
- package/dist/docs/projects.md +30 -0
- package/dist/docs/reference/index.md +11 -0
- package/dist/docs/reports.md +11 -0
- package/dist/docs/sdk/actions.md +7 -0
- package/dist/docs/sdk/conditions.md +131 -0
- package/dist/docs/sdk/content-security-policy.md +31 -0
- package/dist/docs/sdk/experiences.md +41 -0
- package/dist/docs/sdk/features.md +213 -0
- package/dist/docs/sdk/fields.md +263 -0
- package/dist/docs/sdk/index.md +74 -0
- package/dist/docs/sdk/plugins/create-experience.md +133 -0
- package/dist/docs/sdk/plugins/dynamic-experiences.md +59 -0
- package/dist/docs/sdk/plugins/index.md +9 -0
- package/dist/docs/sdk/plugins/window-object.md +20 -0
- package/dist/docs/sdk/predicates.md +113 -0
- package/dist/docs/sdk/steps.md +411 -0
- package/dist/docs/steps.md +35 -0
- package/dist/docs/team-management.md +40 -0
- package/dist/docs/tooling/chrome-extension.md +29 -0
- package/dist/docs/tooling/gtm-template.md +69 -0
- package/dist/docs/tooling/index.md +19 -0
- package/dist/docs/tooling/mcp.md +120 -0
- package/dist/docs/tooling/vite-plugin.md +82 -0
- package/dist/docs/workspaces.md +35 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/plugins/dynamic-experiences/index.js +1 -1
- package/package.json +2 -2
- package/dist/api-CtE-gT1L.cjs +0 -1
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: docs
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Picked SDK
|
|
6
|
+
|
|
7
|
+
The Picked SDK enables you to add dynamic, personalized experiences to your web applications with minimal code.
|
|
8
|
+
|
|
9
|
+
:::tip
|
|
10
|
+
The SDK is framework-agnostic and works with React, Svelte, Vue, and vanilla JavaScript.
|
|
11
|
+
:::
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
:::code-group
|
|
16
|
+
|
|
17
|
+
```typescript [Browser]
|
|
18
|
+
import { createClient } from '@picked/client'
|
|
19
|
+
import { windowObjectPlugin } from '@picked/client/plugins/window-object'
|
|
20
|
+
import { singlePageAppPlugin } from '@picked/client/plugins/single-page-app'
|
|
21
|
+
|
|
22
|
+
const picked = createClient({
|
|
23
|
+
organizationId: 'your-organization-id',
|
|
24
|
+
projectId: 'your-project-id',
|
|
25
|
+
plugins: [windowObjectPlugin(), singlePageAppPlugin()],
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
picked.init()
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```ts [Server]
|
|
32
|
+
Coming Soon...
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
:::
|
|
36
|
+
|
|
37
|
+
:::tip
|
|
38
|
+
If you’re running Picked in a browser environment, access the Picked client in the console with `window.Picked`
|
|
39
|
+
:::
|
|
40
|
+
|
|
41
|
+
## Precondition & Condition
|
|
42
|
+
|
|
43
|
+
| Category | Question | Description |
|
|
44
|
+
| ------------ | ---------------------- | --------------------------------------------------------------------------------------------- |
|
|
45
|
+
| Precondition | Should Picked start? | Use for environment checks, page filtering, or feature flags that completely disable the SDK. |
|
|
46
|
+
| Condition | Is this user eligible? | Use for user segmentation, A/B test enrollment, or targeting specific user groups. |
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
const picked = createClient({
|
|
50
|
+
precondition: {
|
|
51
|
+
and: [
|
|
52
|
+
{
|
|
53
|
+
or: [
|
|
54
|
+
{
|
|
55
|
+
invoke: {
|
|
56
|
+
var: 'features.aa-test',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
true,
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
{ invoke: { var: 'predicates.shopify-is-product-page' } },
|
|
63
|
+
],
|
|
64
|
+
},
|
|
65
|
+
condition: {
|
|
66
|
+
invoke: {
|
|
67
|
+
var: 'features.convincely-enabled',
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
// rest of picked config
|
|
71
|
+
})
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
See [conditions](./conditions.md) for more detail
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: docs
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Create Experience Plugin
|
|
6
|
+
|
|
7
|
+
A plugin to register an array of experiences to the Picked client.
|
|
8
|
+
|
|
9
|
+
## Setup Plugin
|
|
10
|
+
|
|
11
|
+
:::code-group
|
|
12
|
+
|
|
13
|
+
```ts [app.ts]
|
|
14
|
+
import { createClient } from '@picked/client'
|
|
15
|
+
import { createExperiencePlugin } from '@picked/client/plugins/create-experience'
|
|
16
|
+
import { funnelExperience } from '../experiences/funnel-experience'
|
|
17
|
+
import { widgetExperience } from '../experiences/widget-experience'
|
|
18
|
+
|
|
19
|
+
const client = createClient({
|
|
20
|
+
organizationId: 'your-org-id',
|
|
21
|
+
projectId: 'your-project-id',
|
|
22
|
+
plugins: createExperiencePlugin({
|
|
23
|
+
experiences: [funnelExperience, widgetExperience],
|
|
24
|
+
}),
|
|
25
|
+
})
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
:::
|
|
29
|
+
|
|
30
|
+
## Defining Steps
|
|
31
|
+
|
|
32
|
+
Steps are defined using `createStep()`. They are added directly to an experience using `experience.addStep()`.
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { createExperience, createStep } from '@picked/client/plugins/create-experience'
|
|
36
|
+
|
|
37
|
+
// Define standalone steps
|
|
38
|
+
const welcomeStep = createStep({
|
|
39
|
+
id: 'welcome',
|
|
40
|
+
name: 'Welcome',
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
const contactStep = createStep({
|
|
44
|
+
id: 'contact',
|
|
45
|
+
name: 'Contact Details',
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
// Define the experience and add steps to build the flow
|
|
49
|
+
const onboardingExperience = createExperience({
|
|
50
|
+
id: 'onboarding',
|
|
51
|
+
name: 'User Onboarding',
|
|
52
|
+
targets: [{ selector: 'body', placement: 'after' }],
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
onboardingExperience.addStep(welcomeStep)
|
|
56
|
+
onboardingExperience.addStep(contactStep)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Each step requires a `name` that identifies it in analytics events. An `id` is optional — one will be generated automatically if omitted.
|
|
60
|
+
|
|
61
|
+
Steps can be used on multiple experiences.
|
|
62
|
+
|
|
63
|
+
### Adding Fields to Steps
|
|
64
|
+
|
|
65
|
+
Fields are defined with `createField()`.
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import { createStep, createField } from '@picked/client/plugins/create-experience'
|
|
69
|
+
|
|
70
|
+
const emailField = createField({
|
|
71
|
+
id: 'email-address',
|
|
72
|
+
name: 'email-address',
|
|
73
|
+
type: 'text',
|
|
74
|
+
label: 'Email Address',
|
|
75
|
+
multiple: false,
|
|
76
|
+
required: true,
|
|
77
|
+
placeholder: 'you@example.com',
|
|
78
|
+
})
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Fields are added to a step with `step.addField()`, or an array of `fieldIds` when creating a step:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
const contactStep = createStep({
|
|
85
|
+
id: 'contact',
|
|
86
|
+
label: 'Contact Details',
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
contactStep.addField(emailField)
|
|
90
|
+
|
|
91
|
+
//Or
|
|
92
|
+
|
|
93
|
+
const contactStep = createStep({
|
|
94
|
+
id: 'contact',
|
|
95
|
+
label: 'Contact Details',
|
|
96
|
+
fieldIds: [contactStep.id],
|
|
97
|
+
})
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Using conditions in an experience
|
|
101
|
+
|
|
102
|
+
[Conditions](../conditions) are used to define when an experience will become active for the user.
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import { createExperience, createStep } from '@picked/client/plugins/create-experience'
|
|
106
|
+
|
|
107
|
+
const productPageFunnel = createExperience({
|
|
108
|
+
id: 'product-page-funnel',
|
|
109
|
+
name: 'Product Page Funnel',
|
|
110
|
+
condition: {
|
|
111
|
+
and: [
|
|
112
|
+
{
|
|
113
|
+
'==': [
|
|
114
|
+
{
|
|
115
|
+
var: 'location.pathname',
|
|
116
|
+
},
|
|
117
|
+
'/product/:id',
|
|
118
|
+
],
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
var: 'actions.isSaleActive',
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
},
|
|
125
|
+
targets: [{ selector: 'body', placement: 'after' }],
|
|
126
|
+
})
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Navigation between steps is handled with [conditions](../conditions). Use the `create`
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
import { createExperience, createStep } from '@picked/client/plugins/create-experience'
|
|
133
|
+
```
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: docs
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Dynamic Experiences Plugin
|
|
6
|
+
|
|
7
|
+
A plugin that fetches your project configuration from the Picked API at runtime, letting you manage experiences, features, steps, fields, and conditions entirely from the [dashboard](/experiences).
|
|
8
|
+
|
|
9
|
+
## Setup Plugin
|
|
10
|
+
|
|
11
|
+
:::code-group
|
|
12
|
+
|
|
13
|
+
```ts [app.ts]
|
|
14
|
+
import { createClient } from '@picked/client'
|
|
15
|
+
import { dynamicExperiencesPlugin } from '@picked/client/plugins/dynamic-experiences'
|
|
16
|
+
|
|
17
|
+
const client = createClient({
|
|
18
|
+
organizationId: 'your-org-id',
|
|
19
|
+
projectId: 'your-project-id',
|
|
20
|
+
plugins: [dynamicExperiencesPlugin()],
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
client.start()
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
:::
|
|
27
|
+
|
|
28
|
+
:::tip
|
|
29
|
+
Unlike [createExperiencePlugin](./create-experience.md), you do not define experiences, steps, or fields in code. All configuration is managed from the [Picked dashboard](/experiences).
|
|
30
|
+
:::
|
|
31
|
+
|
|
32
|
+
## How It Works
|
|
33
|
+
|
|
34
|
+
When the client starts, the plugin resolves your project configuration using a three-tier strategy:
|
|
35
|
+
|
|
36
|
+
1. **Preview mode** — When you [enter preview mode from the dashboard](/workspaces#preview), the plugin fetches fresh config from the API. Feature decisions use session storage so they are not persisted beyond the current tab.
|
|
37
|
+
|
|
38
|
+
2. **Build-time config** — If `projectConfig` was passed as a plugin option, or the [Vite Plugin](/tooling/vite-plugin) injected config at build time, the plugin uses that config with no network request.
|
|
39
|
+
|
|
40
|
+
3. **Runtime fetch** — Otherwise, the plugin fetches config from the API when the client starts.
|
|
41
|
+
|
|
42
|
+
Once resolved, the plugin registers all features, conditions, fields, steps, and experiences with the client. Experiences then initialize according to their [conditions](/sdk/conditions) and [target selectors](/sdk/experiences).
|
|
43
|
+
|
|
44
|
+
:::note
|
|
45
|
+
The [Vite Plugin](/tooling/vite-plugin) eliminates the runtime API request in production by embedding your project config at build time. This is the recommended setup for Vite-based applications.
|
|
46
|
+
:::
|
|
47
|
+
|
|
48
|
+
## Feature Allocation
|
|
49
|
+
|
|
50
|
+
Each [feature](/sdk/features) in your project has an `enabled` state and a `weight` (0–100) that controls the percentage of traffic allocated to it. The plugin uses a deterministic hash of the user's session ID to produce a stable allocation value. A user whose value falls below the feature weight is allocated to that feature — the same user always gets the same result.
|
|
51
|
+
|
|
52
|
+
Feature decisions are cached in `localStorage` by default, or `sessionStorage` when in [preview mode](#preview-mode).
|
|
53
|
+
|
|
54
|
+
## Preview Mode
|
|
55
|
+
|
|
56
|
+
When you [enter preview mode from the dashboard](/workspaces#preview), the SDK receives a preview token and activates preview mode:
|
|
57
|
+
|
|
58
|
+
- The plugin fetches fresh config from the API using the token, bypassing any build-time or cached config
|
|
59
|
+
- Feature decisions use session storage, so closing the tab resets them
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: docs
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Window Object
|
|
6
|
+
|
|
7
|
+
A plugin to add the Picked client to the window object
|
|
8
|
+
|
|
9
|
+
## Setup Plugin
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { createClient } from '@picked/client'
|
|
13
|
+
import { windowObjectPlugin } from '@picked/client/plugins/window-object'
|
|
14
|
+
|
|
15
|
+
const client = createClient({
|
|
16
|
+
organizationId: 'your-org-id',
|
|
17
|
+
projectId: 'your-project-id',
|
|
18
|
+
plugins: [windowObjectPlugin()],
|
|
19
|
+
})
|
|
20
|
+
```
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: docs
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Predicates
|
|
6
|
+
|
|
7
|
+
Predicates enable reusable condition logic based on current application state. Each predicate is a pure function that receives a state snapshot containing responses, fields, browser context, and optional arguments.
|
|
8
|
+
|
|
9
|
+
## Defining Predicates
|
|
10
|
+
|
|
11
|
+
Define predicates when creating the Picked client by passing a `predicates` object. Each predicate requires a unique identifier and a function that receives a state snapshot:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { createClient } from '@picked/client'
|
|
15
|
+
|
|
16
|
+
const client = createClient({
|
|
17
|
+
organizationId: 'your-org-id',
|
|
18
|
+
projectId: 'your-project-id',
|
|
19
|
+
predicates: {
|
|
20
|
+
'is-example-page': ({ location }) => {
|
|
21
|
+
return location?.pathname === '/example'
|
|
22
|
+
},
|
|
23
|
+
'get-account-tier': async () => {
|
|
24
|
+
const data = await fetch('/api/get-account-tier').then((r) => r.json())
|
|
25
|
+
return data.result // returns "trial"
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
})
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## How Predicates Work
|
|
32
|
+
|
|
33
|
+
When a predicate is registered and used in conditions, the SDK follows this execution flow:
|
|
34
|
+
|
|
35
|
+
1. **Registration**: Predicates are registered to the Picked client during initialization
|
|
36
|
+
2. **State Snapshot Creation**: When invoked, predicates receive a frozen state snapshot containing current responses, fields, and browser context
|
|
37
|
+
3. **Condition Evaluation**: Experience conditions invoke predicates with a fresh snapshot whenever called
|
|
38
|
+
4. **Return Flexibility**: Predicates can return boolean, string, string array, undefined, or promises that resolve to these types
|
|
39
|
+
|
|
40
|
+
## Using Predicates in Conditions
|
|
41
|
+
|
|
42
|
+
Predicates are most commonly used within condition logic via the `invoke` operator:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
const myExperience = createExperience({
|
|
46
|
+
// ... other config
|
|
47
|
+
condition: {
|
|
48
|
+
and: [
|
|
49
|
+
{
|
|
50
|
+
'==': [
|
|
51
|
+
{
|
|
52
|
+
invoke: {
|
|
53
|
+
var: 'predicates.is-example-page', // Reference predicate that calls user endpoint
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
true, // Check if return value is true
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
'==': [
|
|
61
|
+
{
|
|
62
|
+
invoke: {
|
|
63
|
+
var: 'predicates.account-tier',
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
'/trial', // If string matches, evaluate to true
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
})
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
:::tip
|
|
75
|
+
Predicates can also be used in `validation` logic
|
|
76
|
+
:::
|
|
77
|
+
|
|
78
|
+
## Using the State Snapshot
|
|
79
|
+
|
|
80
|
+
Each predicate receives a `StateSnapshot` object with the following properties:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
interface StateSnapshot {
|
|
84
|
+
client: Picked // The Picked client instance
|
|
85
|
+
responses?: Array<{
|
|
86
|
+
// All user responses
|
|
87
|
+
fieldId: string
|
|
88
|
+
value: FieldValue | undefined
|
|
89
|
+
}>
|
|
90
|
+
args?: unknown[]
|
|
91
|
+
fields?: Field[] // All registered fields
|
|
92
|
+
location?: Location // Browser location (URL, pathname, search, etc.)
|
|
93
|
+
document?: Document // Browser document object
|
|
94
|
+
sessionStorage?: Storage // Browser sessionStorage API
|
|
95
|
+
localStorage?: Storage // Browser localStorage API
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
:::warning
|
|
100
|
+
In server-side rendering or non-browser environments, `location`, `document`, `sessionStorage`,
|
|
101
|
+
and `localStorage` will be `undefined`.
|
|
102
|
+
:::
|
|
103
|
+
|
|
104
|
+
## Best Practices
|
|
105
|
+
|
|
106
|
+
- **Keep predicates pure**: Predicates should be deterministic and side-effect free. Given the same snapshot, they should always return the same result
|
|
107
|
+
- **Handle missing data gracefully**: Always check if responses or fields exist before accessing their values. Return `undefined` when data is unavailable rather than throwing errors
|
|
108
|
+
- **Avoid heavy computations**: Predicates may be invoked frequently. Keep logic lightweight and fast
|
|
109
|
+
- **Use async sparingly**: While async predicates are supported, they can delay experience rendering. Prefer synchronous logic when possible
|
|
110
|
+
- **Return consistent types**: Don't mix return types (e.g., sometimes boolean, sometimes string) for the same predicate
|
|
111
|
+
- **Use meaningful names**: Predicate IDs should clearly describe what they evaluate (e.g., `is-premium-user`, `has-items-in-cart`)
|
|
112
|
+
- **Consider caching expensive operations**: If a predicate needs to perform expensive operations, consider caching the result in `localStorage` or `sessionStorage` within the predicate logic
|
|
113
|
+
- **Don't mutate the snapshot**: The state snapshot is frozen. Any attempt to modify it will throw an error in strict mode
|