picked 0.0.101-next.2 → 0.0.101
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/README.md +27 -12
- package/docs/explanation/conditions-and-the-logic-engine.md +94 -0
- package/docs/explanation/content-references.md +99 -0
- package/docs/explanation/feature-flag-allocation.md +218 -0
- package/docs/explanation/how-picked-works.md +124 -0
- package/docs/explanation/how-pickedql-works.md +76 -0
- package/docs/explanation/pages-and-flows.md +64 -0
- package/docs/explanation/the-content-model.md +87 -0
- package/docs/explanation/the-two-apis.md +68 -0
- package/docs/explanation/why-server-side-rendering.md +76 -0
- package/docs/explanation/workspaces-and-versions.md +71 -0
- package/docs/how-to/add-a-step-field-or-action.md +56 -0
- package/docs/how-to/analytics/index.md +324 -0
- package/docs/how-to/archive-or-delete-a-workspace.md +59 -0
- package/docs/how-to/authenticate-the-cli.md +101 -0
- package/docs/how-to/authenticate-with-a-magic-link.md +56 -0
- package/docs/how-to/authenticate-with-a-password.md +68 -0
- package/docs/how-to/authenticate-with-an-api-key.md +60 -0
- package/docs/how-to/authenticate-with-oauth.md +49 -0
- package/docs/how-to/build-a-flow.md +106 -0
- package/docs/how-to/call-an-external-api-from-a-workflow.md +116 -0
- package/docs/how-to/connect-the-mcp-server.md +46 -0
- package/docs/how-to/create-a-content-entry.md +58 -0
- package/docs/how-to/create-a-project.md +40 -0
- package/docs/how-to/create-an-experience.md +51 -0
- package/docs/how-to/create-and-revoke-an-api-key.md +54 -0
- package/docs/how-to/debug-with-the-chrome-extension.md +57 -0
- package/docs/how-to/define-a-page-layout.md +54 -0
- package/docs/how-to/fill-and-publish-a-page.md +82 -0
- package/docs/how-to/install-the-gtm-template.md +84 -0
- package/docs/how-to/install-the-sdk.md +93 -0
- package/docs/how-to/install-the-vite-plugin.md +69 -0
- package/docs/how-to/invite-and-remove-members.md +45 -0
- package/docs/how-to/point-one-entry-at-another.md +75 -0
- package/docs/how-to/preview-a-workspace.md +39 -0
- package/docs/how-to/publish-a-workspace.md +42 -0
- package/docs/how-to/read-a-feature-flag.md +113 -0
- package/docs/how-to/read-a-referenced-entry.md +109 -0
- package/docs/how-to/register-a-component.md +55 -0
- package/docs/how-to/register-an-action-handler.md +85 -0
- package/docs/how-to/register-an-api-that-uses-oauth2.md +107 -0
- package/docs/how-to/render-a-step-form.md +131 -0
- package/docs/how-to/render-an-unpublished-preview.md +41 -0
- package/docs/how-to/retry-a-failed-call-with-a-loop.md +81 -0
- package/docs/how-to/reuse-a-section.md +64 -0
- package/docs/how-to/reuse-a-step-field-or-action.md +39 -0
- package/docs/how-to/roll-back-a-published-version.md +39 -0
- package/docs/how-to/run-an-ab-test.md +59 -0
- package/docs/how-to/run-code-on-a-form-submission.md +125 -0
- package/docs/how-to/server-render-a-page.md +81 -0
- package/docs/how-to/set-a-content-security-policy.md +32 -0
- package/docs/how-to/set-up-mfa.md +126 -0
- package/docs/how-to/switch-workspaces.md +122 -0
- package/docs/how-to/upload-and-use-an-asset.mdx +87 -0
- package/docs/how-to/validate-a-field.md +52 -0
- package/docs/how-to/wait-for-an-action-response.md +182 -0
- package/docs/how-to/write-a-condition.md +57 -0
- package/docs/how-to/write-a-predicate.md +60 -0
- package/docs/index.md +59 -0
- package/docs/reference/dashboard/actions.mdx +65 -0
- package/docs/reference/dashboard/api-keys.mdx +47 -0
- package/docs/reference/dashboard/conditions.mdx +51 -0
- package/docs/reference/dashboard/content/asset-library.mdx +74 -0
- package/docs/reference/dashboard/content/blocks.mdx +66 -0
- package/docs/reference/dashboard/content/content-entries.mdx +109 -0
- package/docs/reference/dashboard/content/models.mdx +119 -0
- package/docs/reference/dashboard/content/pages.mdx +72 -0
- package/docs/reference/dashboard/experiences.mdx +61 -0
- package/docs/reference/dashboard/external-apis.md +182 -0
- package/docs/reference/dashboard/features.mdx +165 -0
- package/docs/reference/dashboard/fields.mdx +120 -0
- package/docs/reference/dashboard/flow-builder/canvas.mdx +58 -0
- package/docs/reference/dashboard/flow-builder/condition-builder.md +69 -0
- package/docs/reference/dashboard/flow-builder/keyboard-shortcuts.md +72 -0
- package/docs/reference/dashboard/flow-builder/nodes.md +74 -0
- package/docs/reference/dashboard/labels.md +321 -0
- package/docs/reference/dashboard/lead-search.md +235 -0
- package/docs/reference/dashboard/projects.mdx +53 -0
- package/docs/reference/dashboard/reports.mdx +53 -0
- package/docs/reference/dashboard/steps.mdx +47 -0
- package/docs/reference/dashboard/team-management.md +38 -0
- package/docs/reference/dashboard/workflow-runs.md +157 -0
- package/docs/reference/dashboard/workflow-templates.md +182 -0
- package/docs/reference/dashboard/workflow-test-runs.md +85 -0
- package/docs/reference/dashboard/workspace-versioning.mdx +42 -0
- package/docs/reference/dashboard/workspaces.mdx +91 -0
- package/docs/reference/delivery-api/experience-content.md +152 -0
- package/docs/reference/delivery-api/index.md +45 -0
- package/docs/reference/delivery-api/preview-caching-crawling.md +79 -0
- package/docs/reference/delivery-api/project-config.md +65 -0
- package/docs/reference/delivery-api/workspace-schema.md +107 -0
- package/docs/reference/glossary.md +201 -0
- package/docs/reference/management-api/authentication.md +87 -0
- package/docs/reference/management-api/authorization-and-scopes.md +291 -0
- package/docs/reference/management-api/error-handling.md +232 -0
- package/docs/reference/management-api/pagination.md +192 -0
- package/docs/reference/management-api/schema/action.md +261 -0
- package/docs/reference/management-api/schema/analytics-session.md +363 -0
- package/docs/reference/management-api/schema/analytics.md +73 -0
- package/docs/reference/management-api/schema/api-key.md +170 -0
- package/docs/reference/management-api/schema/auth.md +1177 -0
- package/docs/reference/management-api/schema/cms-fields.md +954 -0
- package/docs/reference/management-api/schema/cms-models.md +1155 -0
- package/docs/reference/management-api/schema/common.md +362 -0
- package/docs/reference/management-api/schema/condition.md +254 -0
- package/docs/reference/management-api/schema/design-system.md +199 -0
- package/docs/reference/management-api/schema/experience.md +1098 -0
- package/docs/reference/management-api/schema/external-api.md +637 -0
- package/docs/reference/management-api/schema/feature.md +350 -0
- package/docs/reference/management-api/schema/feedback.md +103 -0
- package/docs/reference/management-api/schema/field.md +400 -0
- package/docs/reference/management-api/schema/index.md +243 -0
- package/docs/reference/management-api/schema/integration.md +272 -0
- package/docs/reference/management-api/schema/label.md +349 -0
- package/docs/reference/management-api/schema/lead.md +340 -0
- package/docs/reference/management-api/schema/mcp-server.md +299 -0
- package/docs/reference/management-api/schema/metric.md +223 -0
- package/docs/reference/management-api/schema/operation.md +96 -0
- package/docs/reference/management-api/schema/organization.md +749 -0
- package/docs/reference/management-api/schema/project.md +607 -0
- package/docs/reference/management-api/schema/report.md +243 -0
- package/docs/reference/management-api/schema/saved-view.md +288 -0
- package/docs/reference/management-api/schema/shopify.md +795 -0
- package/docs/reference/management-api/schema/step.md +273 -0
- package/docs/reference/management-api/schema/tenant-branding.md +185 -0
- package/docs/reference/management-api/schema/workbench.md +246 -0
- package/docs/reference/management-api/schema/workflow-run.md +263 -0
- package/docs/reference/management-api/schema/workflow.md +1110 -0
- package/docs/reference/management-api/schema/workspace-version.md +823 -0
- package/docs/reference/management-api/schema/workspace.md +917 -0
- package/docs/reference/pickedql/data-sources.md +174 -0
- package/docs/reference/pickedql/dimensions.md +103 -0
- package/docs/reference/pickedql/filtering.md +64 -0
- package/docs/reference/pickedql/index.md +18 -0
- package/docs/reference/pickedql/schema.md +172 -0
- package/docs/reference/pickedql/virtual-functions.md +248 -0
- package/docs/reference/sdk/actions.md +154 -0
- package/docs/reference/sdk/analytics-events.md +453 -0
- package/docs/reference/sdk/conditions.md +147 -0
- package/docs/reference/sdk/content-security-policy.md +21 -0
- package/docs/reference/sdk/content.md +253 -0
- package/docs/reference/sdk/experiences.md +51 -0
- package/docs/reference/sdk/features.md +256 -0
- package/docs/reference/sdk/fields.md +255 -0
- package/docs/reference/sdk/index.md +68 -0
- package/docs/reference/sdk/plugins/create-experience.md +123 -0
- package/docs/reference/sdk/plugins/dynamic-experiences.md +74 -0
- package/docs/reference/sdk/plugins/fingerprintjs.md +39 -0
- package/docs/reference/sdk/plugins/hotjar.md +60 -0
- package/docs/reference/sdk/plugins/index.md +33 -0
- package/docs/reference/sdk/plugins/sentry.md +51 -0
- package/docs/reference/sdk/plugins/shopify.md +109 -0
- package/docs/reference/sdk/plugins/window-object.md +25 -0
- package/docs/reference/sdk/predicates.md +43 -0
- package/docs/reference/sdk/react.md +61 -0
- package/docs/reference/sdk/ssr/index.md +33 -0
- package/docs/reference/sdk/ssr/rendering-and-hydration.md +103 -0
- package/docs/reference/sdk/ssr/serialize.md +80 -0
- package/docs/reference/sdk/ssr/slots-and-placements.md +113 -0
- package/docs/reference/sdk/steps.md +86 -0
- package/docs/reference/sdk/svelte.md +74 -0
- package/docs/reference/sdk/type-generation.md +265 -0
- package/docs/reference/tools/admin-api-client.md +89 -0
- package/docs/reference/tools/chrome-extension.md +16 -0
- package/docs/reference/tools/cli.md +319 -0
- package/docs/reference/tools/delivery-api-client.md +60 -0
- package/docs/reference/tools/image-optimisation-service.md +104 -0
- package/docs/reference/tools/mcp-run.md +121 -0
- package/docs/reference/tools/mcp.md +391 -0
- package/docs/reference/tools/vite-plugin.md +163 -0
- package/docs/tutorials/first-api-call.md +253 -0
- package/docs/tutorials/first-experience-in-the-dashboard.mdx +160 -0
- package/docs/tutorials/first-experience.mdx +254 -0
- package/docs/tutorials/first-server-rendered-page.mdx +186 -0
- package/package.json +8 -7
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: reference
|
|
3
|
+
layout: docs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Fields
|
|
7
|
+
|
|
8
|
+
Define your fields in code with `createField()`. Check the input with JSON Logic.
|
|
9
|
+
Read the values that a user sends through the step context.
|
|
10
|
+
|
|
11
|
+
## Define a field
|
|
12
|
+
|
|
13
|
+
Define a field with `createField()` from the
|
|
14
|
+
`@picked/client/plugins/create-experience` package. Each field needs a unique
|
|
15
|
+
identifier, a name, a type, a label, and a count of the values that it takes:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { createField } from '@picked/client/plugins/create-experience'
|
|
19
|
+
|
|
20
|
+
// A text input that the user must fill in.
|
|
21
|
+
export const emailField = createField({
|
|
22
|
+
id: 'email-address',
|
|
23
|
+
name: 'email-address',
|
|
24
|
+
type: 'text',
|
|
25
|
+
label: 'Email Address',
|
|
26
|
+
multiple: false,
|
|
27
|
+
required: true,
|
|
28
|
+
placeholder: 'you@example.com',
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
// A dropdown that takes more than one choice, with fixed options.
|
|
32
|
+
export const communicationMethods = createField({
|
|
33
|
+
id: 'communication-methods',
|
|
34
|
+
name: 'communication-methods',
|
|
35
|
+
type: 'text',
|
|
36
|
+
label: 'Preferred contact methods',
|
|
37
|
+
multiple: true,
|
|
38
|
+
required: true,
|
|
39
|
+
options: [
|
|
40
|
+
{
|
|
41
|
+
id: 'email',
|
|
42
|
+
label: 'Email',
|
|
43
|
+
value: 'email',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: 'phone',
|
|
47
|
+
label: 'Phone',
|
|
48
|
+
value: 'phone',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 'sms',
|
|
52
|
+
label: 'SMS',
|
|
53
|
+
value: 'sms',
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
})
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Register fields on the client
|
|
60
|
+
|
|
61
|
+
Register fields when you create the Picked client. Pass a `fields` object. The key of an
|
|
62
|
+
entry becomes the field `key` when the definition does not set one. A definition with its
|
|
63
|
+
own `key` keeps it. Pass a function to build a definition once during the client setup:
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import { createClient } from 'picked'
|
|
67
|
+
|
|
68
|
+
const client = createClient({
|
|
69
|
+
projectId: 'your-project-id',
|
|
70
|
+
fields: {
|
|
71
|
+
email: {
|
|
72
|
+
id: 'email',
|
|
73
|
+
name: 'email',
|
|
74
|
+
label: 'Email Address',
|
|
75
|
+
type: 'text',
|
|
76
|
+
multiple: false,
|
|
77
|
+
required: true,
|
|
78
|
+
},
|
|
79
|
+
age: () => ({
|
|
80
|
+
id: 'age',
|
|
81
|
+
name: 'age',
|
|
82
|
+
label: 'Age',
|
|
83
|
+
type: 'number',
|
|
84
|
+
multiple: false,
|
|
85
|
+
required: false,
|
|
86
|
+
}),
|
|
87
|
+
},
|
|
88
|
+
})
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Field types
|
|
92
|
+
|
|
93
|
+
A field has one of four basic types: `text`, `number`, `boolean`, or `object`.
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
// One text input.
|
|
97
|
+
const nameField = createField({
|
|
98
|
+
type: 'text',
|
|
99
|
+
multiple: false,
|
|
100
|
+
// ...
|
|
101
|
+
})
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Give an `options` array to let the user choose more than one value:
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
const nameField = createField({
|
|
108
|
+
type: 'text',
|
|
109
|
+
multiple: true,
|
|
110
|
+
options: [
|
|
111
|
+
{
|
|
112
|
+
id: 'option-one',
|
|
113
|
+
label: 'Option One',
|
|
114
|
+
value: 'product-id-one',
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
id: 'option-two',
|
|
118
|
+
label: 'Option Two',
|
|
119
|
+
value: 'product-id-two',
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
id: 'option-three',
|
|
123
|
+
label: 'Option Three',
|
|
124
|
+
value: 'product-id-three',
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
})
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Conditions
|
|
131
|
+
|
|
132
|
+
A field and a field option both work with condition logic:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
const conditionalField = createField({
|
|
136
|
+
id: 'conditional-field',
|
|
137
|
+
type: 'text',
|
|
138
|
+
condition: {
|
|
139
|
+
invoke: {
|
|
140
|
+
var: 'responses.has-answered-question',
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
options: [
|
|
144
|
+
{
|
|
145
|
+
id: 'conditional-option',
|
|
146
|
+
label: 'Conditional Label',
|
|
147
|
+
condition: {
|
|
148
|
+
invoke: {
|
|
149
|
+
var: 'responses.eligible-for-option',
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
],
|
|
154
|
+
})
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Field policies
|
|
158
|
+
|
|
159
|
+
A field captures nothing until you permit it. Use a privacy policy to let Picked track
|
|
160
|
+
or store the data of a field:
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
const colourField = createField({
|
|
164
|
+
id: 'favourite-colour',
|
|
165
|
+
name: 'favourite-colour',
|
|
166
|
+
type: 'text',
|
|
167
|
+
label: 'Favourite colour',
|
|
168
|
+
multiple: false,
|
|
169
|
+
required: true,
|
|
170
|
+
policies: {
|
|
171
|
+
trackValue: true, // Send the value to analytics.
|
|
172
|
+
storeValue: true, // Keep the value in browser storage.
|
|
173
|
+
},
|
|
174
|
+
})
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**Privacy policies**:
|
|
178
|
+
|
|
179
|
+
- `trackValue`: set it to `true` to put the value of the field in your analytics events.
|
|
180
|
+
At `false`, and when the policy is absent, the events carry the field ID only.
|
|
181
|
+
- `storeValue`: set it to `true` to let the SDK put the value in browser storage. At
|
|
182
|
+
`false`, and when the policy is absent, the SDK keeps the value out of storage.
|
|
183
|
+
|
|
184
|
+
Both policies keep the value in the browser by default. A field with no `policies`
|
|
185
|
+
object sends no value to your analytics and writes no value to browser storage. Keep
|
|
186
|
+
the default for sensitive data such as a tax number, a credit card number, or a
|
|
187
|
+
password. That data stays in the browser:
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
const sensitiveField = createField({
|
|
191
|
+
id: 'ssn',
|
|
192
|
+
name: 'ssn',
|
|
193
|
+
type: 'text',
|
|
194
|
+
label: 'Social Security Number',
|
|
195
|
+
multiple: false,
|
|
196
|
+
required: true,
|
|
197
|
+
})
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Neither policy stops the flow from the use of the value inside the page. A field that
|
|
201
|
+
captures nothing still holds its value there, for step validation and for the conditions
|
|
202
|
+
after the step. The policies control what leaves the page: your analytics, and browser
|
|
203
|
+
storage.
|
|
204
|
+
|
|
205
|
+
## Field metadata
|
|
206
|
+
|
|
207
|
+
Add more text to help the user:
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
const passwordField = createField({
|
|
211
|
+
id: 'password',
|
|
212
|
+
name: 'password',
|
|
213
|
+
type: 'text',
|
|
214
|
+
label: 'Password',
|
|
215
|
+
multiple: false,
|
|
216
|
+
required: true,
|
|
217
|
+
placeholder: 'Enter a strong password',
|
|
218
|
+
description: 'Your password must be at least 8 characters',
|
|
219
|
+
helpText: 'Use a mix of letters, numbers, and symbols for better security',
|
|
220
|
+
})
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**Metadata fields**:
|
|
224
|
+
|
|
225
|
+
- `placeholder`: the hint text that an empty input shows.
|
|
226
|
+
- `description`: a short explanation below the label.
|
|
227
|
+
- `helpText`: more guidance, or the requirements, next to the field.
|
|
228
|
+
|
|
229
|
+
## Read a field value
|
|
230
|
+
|
|
231
|
+
The SDK stores each field response in the experience state. Read a response through
|
|
232
|
+
the `responses` object:
|
|
233
|
+
|
|
234
|
+
:::code-group
|
|
235
|
+
|
|
236
|
+
```ts [In Conditions]
|
|
237
|
+
// Point at the value from a later field condition.
|
|
238
|
+
const sensitiveField = createField({
|
|
239
|
+
condition: {
|
|
240
|
+
'==': [
|
|
241
|
+
{
|
|
242
|
+
var: 'responses.field-name',
|
|
243
|
+
},
|
|
244
|
+
'expected-value',
|
|
245
|
+
],
|
|
246
|
+
},
|
|
247
|
+
})
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
:::
|
|
251
|
+
|
|
252
|
+
## Related
|
|
253
|
+
|
|
254
|
+
- [How to validate a field](/how-to/validate-a-field)
|
|
255
|
+
- [Fields](/reference/dashboard/fields) — the dashboard privacy controls.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: reference
|
|
3
|
+
layout: docs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Picked SDK
|
|
7
|
+
|
|
8
|
+
The Picked SDK lets you add a dynamic, personalized experience to your web
|
|
9
|
+
application with very little code.
|
|
10
|
+
|
|
11
|
+
:::tip
|
|
12
|
+
The SDK is framework-agnostic. It works with React, Svelte, Vue, and plain
|
|
13
|
+
JavaScript.
|
|
14
|
+
:::
|
|
15
|
+
|
|
16
|
+
## Precondition and condition
|
|
17
|
+
|
|
18
|
+
| Category | Question | Description |
|
|
19
|
+
| ------------ | ---------------------- | --------------------------------------------------------------------------------------------- |
|
|
20
|
+
| Precondition | Must Picked start? | Use it to check the environment, to filter by page, or for a feature flag that turns the SDK off completely. |
|
|
21
|
+
| Condition | Is this user eligible? | Use it to divide your users into groups, to enter a user into an A/B test, or to reach one group of users. |
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
const picked = createClient({
|
|
25
|
+
precondition: {
|
|
26
|
+
and: [
|
|
27
|
+
{
|
|
28
|
+
or: [
|
|
29
|
+
{
|
|
30
|
+
invoke: {
|
|
31
|
+
var: 'features.aa-test',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
true,
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
{ invoke: { var: 'predicates.shopify-is-product-page' } },
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
condition: {
|
|
41
|
+
invoke: {
|
|
42
|
+
var: 'features.convincely-enabled',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
// The rest of the Picked options go here.
|
|
46
|
+
})
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
:::warning
|
|
50
|
+
A precondition or a condition that points at a feature flag reads the bucket of that
|
|
51
|
+
feature flag. That read allocates the visitor at that moment.
|
|
52
|
+
|
|
53
|
+
A precondition runs at startup. Picked therefore allocates every visitor to a feature
|
|
54
|
+
flag that a precondition points at, before anything else happens. This includes a
|
|
55
|
+
visitor who never reaches the experience that the feature flag controls.
|
|
56
|
+
|
|
57
|
+
See [Allocation and exposure](/explanation/feature-flag-allocation) before you point a
|
|
58
|
+
precondition at a flag.
|
|
59
|
+
:::
|
|
60
|
+
|
|
61
|
+
See [conditions](/reference/sdk/conditions) for more detail.
|
|
62
|
+
|
|
63
|
+
## Related
|
|
64
|
+
|
|
65
|
+
- [How to install the SDK](/how-to/install-the-sdk)
|
|
66
|
+
- [How to register a component](/how-to/register-a-component)
|
|
67
|
+
- [About conditions and the logic engine](/explanation/conditions-and-the-logic-engine) —
|
|
68
|
+
what the difference is between a precondition and a condition.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: reference
|
|
3
|
+
layout: docs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Create Experience Plugin
|
|
7
|
+
|
|
8
|
+
This plugin registers an array of experiences on the Picked client.
|
|
9
|
+
|
|
10
|
+
## Define a step
|
|
11
|
+
|
|
12
|
+
Define a step with `createStep()`. Add it directly to an experience with
|
|
13
|
+
`experience.addStep()`.
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { createExperience, createStep } from '@picked/client/plugins/create-experience'
|
|
17
|
+
|
|
18
|
+
// Define the steps on their own.
|
|
19
|
+
const welcomeStep = createStep({
|
|
20
|
+
id: 'welcome',
|
|
21
|
+
name: 'Welcome',
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const contactStep = createStep({
|
|
25
|
+
id: 'contact',
|
|
26
|
+
name: 'Contact Details',
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
// Define the experience, then add the steps to build the flow.
|
|
30
|
+
const onboardingExperience = createExperience({
|
|
31
|
+
id: 'onboarding',
|
|
32
|
+
name: 'User Onboarding',
|
|
33
|
+
targets: [{ selector: 'body', placement: 'after' }],
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
onboardingExperience.addStep(welcomeStep)
|
|
37
|
+
onboardingExperience.addStep(contactStep)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Each step needs a `name`, and your analytics events use that name to identify the
|
|
41
|
+
step. An `id` is optional. Picked makes one for you when you give none.
|
|
42
|
+
|
|
43
|
+
You can use the same step on more than one experience.
|
|
44
|
+
|
|
45
|
+
### Add a field to a step
|
|
46
|
+
|
|
47
|
+
Define a field with `createField()`.
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { createStep, createField } from '@picked/client/plugins/create-experience'
|
|
51
|
+
|
|
52
|
+
const emailField = createField({
|
|
53
|
+
id: 'email-address',
|
|
54
|
+
name: 'email-address',
|
|
55
|
+
type: 'text',
|
|
56
|
+
label: 'Email Address',
|
|
57
|
+
multiple: false,
|
|
58
|
+
required: true,
|
|
59
|
+
placeholder: 'you@example.com',
|
|
60
|
+
})
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Add a field to a step with `step.addField()`. You can also pass an array of
|
|
64
|
+
`fieldIds` when you create the step:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
const contactStep = createStep({
|
|
68
|
+
id: 'contact',
|
|
69
|
+
label: 'Contact Details',
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
contactStep.addField(emailField)
|
|
73
|
+
|
|
74
|
+
// Or:
|
|
75
|
+
|
|
76
|
+
const contactStep = createStep({
|
|
77
|
+
id: 'contact',
|
|
78
|
+
label: 'Contact Details',
|
|
79
|
+
fieldIds: [contactStep.id],
|
|
80
|
+
})
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Use a condition in an experience
|
|
84
|
+
|
|
85
|
+
A [condition](/reference/sdk/conditions) defines when an experience becomes active for the user.
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { createExperience, createStep } from '@picked/client/plugins/create-experience'
|
|
89
|
+
|
|
90
|
+
const productPageFunnel = createExperience({
|
|
91
|
+
id: 'product-page-funnel',
|
|
92
|
+
name: 'Product Page Funnel',
|
|
93
|
+
condition: {
|
|
94
|
+
and: [
|
|
95
|
+
{
|
|
96
|
+
'==': [
|
|
97
|
+
{
|
|
98
|
+
var: 'location.pathname',
|
|
99
|
+
},
|
|
100
|
+
'/product/:id',
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
var: 'actions.isSaleActive',
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
targets: [{ selector: 'body', placement: 'after' }],
|
|
109
|
+
})
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
A [condition](/reference/sdk/conditions) also controls the move from one step to the next.
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
import { createExperience, createStep } from '@picked/client/plugins/create-experience'
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Related
|
|
119
|
+
|
|
120
|
+
- [Plugins](/reference/sdk/plugins)
|
|
121
|
+
- [SDK experiences](/reference/sdk/experiences)
|
|
122
|
+
- [Dynamic Experiences](/reference/sdk/plugins/dynamic-experiences) — the dashboard-driven
|
|
123
|
+
alternative.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: reference
|
|
3
|
+
layout: docs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Dynamic Experiences Plugin
|
|
7
|
+
|
|
8
|
+
This plugin reads the configuration of your project from the Picked API at runtime. You can
|
|
9
|
+
therefore control your experiences, feature flags, steps, fields, and conditions from
|
|
10
|
+
the [dashboard](/reference/dashboard/experiences) alone.
|
|
11
|
+
|
|
12
|
+
The plugin reads the configuration of your project and the CMS content of your
|
|
13
|
+
experiences from one source. It does not mix them. Picked gives a configuration and its
|
|
14
|
+
content the same version.
|
|
15
|
+
|
|
16
|
+
## Options
|
|
17
|
+
|
|
18
|
+
| Option | Type | Default | Description |
|
|
19
|
+
| --- | --- | --- | --- |
|
|
20
|
+
| `mode` | `'bundle' \| 'api'` | see below | Where to read the configuration and the content from. |
|
|
21
|
+
| `apiUrl` | `string` | `https://api.picked.app` | Your own API URL, for a self-hosted or local API. |
|
|
22
|
+
| `projectConfig` | `ProjectConfig` | none | A configuration that you give. The plugin makes no request for it. |
|
|
23
|
+
| `getContent` | `function` | none | A function that you give. The plugin calls it for each experience that uses CMS content. |
|
|
24
|
+
|
|
25
|
+
### mode
|
|
26
|
+
|
|
27
|
+
| Value | Source | Use it when |
|
|
28
|
+
| --- | --- | --- |
|
|
29
|
+
| `'bundle'` | The data that the [Vite plugin](/reference/tools/vite-plugin) puts in your build | You want no API request when the page loads. |
|
|
30
|
+
| `'api'` | The Picked API, read when the client starts | You want a workspace publish to reach users without a new deployment. |
|
|
31
|
+
|
|
32
|
+
:::code-group
|
|
33
|
+
|
|
34
|
+
```ts [app.ts]
|
|
35
|
+
import { createClient } from 'picked'
|
|
36
|
+
import { dynamicExperiencesPlugin } from '@picked/client/plugins/dynamic-experiences'
|
|
37
|
+
|
|
38
|
+
const client = createClient({
|
|
39
|
+
projectId: 'your-project-id',
|
|
40
|
+
plugins: [dynamicExperiencesPlugin({ mode: 'bundle' })],
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
client.start()
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
:::
|
|
47
|
+
|
|
48
|
+
If you do not set `mode`, the plugin uses the build data when the Vite plugin gave it
|
|
49
|
+
some. In every other case it uses the API.
|
|
50
|
+
|
|
51
|
+
### projectConfig and getContent
|
|
52
|
+
|
|
53
|
+
These two replace the source for you. Keep the configuration and the content at the same
|
|
54
|
+
version when you use them. The plugin cannot make that check for you.
|
|
55
|
+
|
|
56
|
+
## Preview mode
|
|
57
|
+
|
|
58
|
+
After you [enter preview mode from the dashboard](/how-to/preview-a-workspace), the SDK
|
|
59
|
+
receives a preview token and starts preview mode:
|
|
60
|
+
|
|
61
|
+
- The plugin reads fresh options from the API with that token, for any value of `mode`.
|
|
62
|
+
It does not read the build-time configuration, a `projectConfig` that you give, or the
|
|
63
|
+
cached options.
|
|
64
|
+
- A feature flag decision uses session storage. The decision resets when you close
|
|
65
|
+
the tab.
|
|
66
|
+
|
|
67
|
+
A `getContent` function keeps its place in a preview session, and it receives the token.
|
|
68
|
+
You therefore decide what a preview means for your own content.
|
|
69
|
+
|
|
70
|
+
## Related
|
|
71
|
+
|
|
72
|
+
- [About how Picked works](/explanation/how-picked-works) — how the plugin resolves your
|
|
73
|
+
options at startup.
|
|
74
|
+
- [About feature flag allocation](/explanation/feature-flag-allocation)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: reference
|
|
3
|
+
layout: docs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# FingerprintJS
|
|
7
|
+
|
|
8
|
+
`@picked/fingerprintjs` adds the FingerprintJS visitor ID to the Picked session.
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { createClient } from 'picked'
|
|
12
|
+
import { fingerprintjsPlugin } from '@picked/fingerprintjs'
|
|
13
|
+
|
|
14
|
+
const client = createClient({
|
|
15
|
+
projectId: 'your-project-id',
|
|
16
|
+
plugins: [fingerprintjsPlugin()],
|
|
17
|
+
})
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The plugin has no options.
|
|
21
|
+
|
|
22
|
+
## Visitor ID
|
|
23
|
+
|
|
24
|
+
The plugin reads `window.FingerprintJS`, which your own FingerprintJS script gives. The
|
|
25
|
+
plugin does not load FingerprintJS.
|
|
26
|
+
|
|
27
|
+
| Case | Result |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| `window.FingerprintJS` is there in 10 seconds | The plugin calls `load()` and `get()`. It sets the `fingerprintjs_visitor_id` session identifier to the `visitorId`. |
|
|
30
|
+
| `window.FingerprintJS` is not there after 10 seconds | The plugin removes the `fingerprintjs_visitor_id` session identifier. |
|
|
31
|
+
|
|
32
|
+
The SDK sends `fingerprintjs_visitor_id` in the `session` context of each analytics event.
|
|
33
|
+
See [Analytics events](/reference/sdk/analytics-events).
|
|
34
|
+
|
|
35
|
+
The plugin does nothing outside a browser.
|
|
36
|
+
|
|
37
|
+
## Related
|
|
38
|
+
|
|
39
|
+
- [Plugins](/reference/sdk/plugins)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: reference
|
|
3
|
+
layout: docs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Hotjar
|
|
7
|
+
|
|
8
|
+
`@picked/hotjar` sends the events of the Picked client to Hotjar. Each event becomes a
|
|
9
|
+
Hotjar event, and the session ID identifies the Hotjar user.
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { createClient } from 'picked'
|
|
13
|
+
import { hotjarPlugin } from '@picked/hotjar'
|
|
14
|
+
|
|
15
|
+
const client = createClient({
|
|
16
|
+
projectId: 'your-project-id',
|
|
17
|
+
plugins: [hotjarPlugin({ siteId: 1234567 })],
|
|
18
|
+
})
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Options
|
|
22
|
+
|
|
23
|
+
| Option | Type | Default | Description |
|
|
24
|
+
| --- | --- | --- | --- |
|
|
25
|
+
| `siteId` | `number` | required | The ID of your Hotjar site. |
|
|
26
|
+
| `snippetVersion` | `number` | `6` | The version of the Hotjar script. |
|
|
27
|
+
| `trackedEvents` | `string[]` | See [Events](#events) | The client events that the plugin sends to Hotjar. |
|
|
28
|
+
| `getUserAttributes` | `() => Record<string, string \| number \| boolean>` | none | Gives more attributes for the Hotjar user. |
|
|
29
|
+
| `autoStartRecording` | `boolean` | `true` | Sends `recordingStartEvent` on the first `experience_initialize` event. |
|
|
30
|
+
| `recordingStartEvent` | `string` | `'hotjar_start'` | The name of the Hotjar event that starts a recording. |
|
|
31
|
+
|
|
32
|
+
## Events
|
|
33
|
+
|
|
34
|
+
The default value of `trackedEvents` is:
|
|
35
|
+
|
|
36
|
+
- `step_enter`
|
|
37
|
+
- `step_complete`
|
|
38
|
+
- `step_submit`
|
|
39
|
+
- `field_validation_error`
|
|
40
|
+
- `experience_complete`
|
|
41
|
+
- `experience_initialize`
|
|
42
|
+
- `session`
|
|
43
|
+
|
|
44
|
+
The plugin starts Hotjar on the first tracked event. The name of each Hotjar event is the
|
|
45
|
+
event type, the experience name, and the step name, joined by `>`. An example is
|
|
46
|
+
`step_enter > Quiz > Question 1`. An event without an experience has only its type.
|
|
47
|
+
|
|
48
|
+
The plugin keeps each event until Hotjar is ready, and then sends the events in order.
|
|
49
|
+
|
|
50
|
+
## User attributes
|
|
51
|
+
|
|
52
|
+
On the `session` event, the plugin calls `Hotjar.identify` with the session ID. The
|
|
53
|
+
attributes are `projectId` and the return value of `getUserAttributes`.
|
|
54
|
+
|
|
55
|
+
The plugin does nothing outside a browser.
|
|
56
|
+
|
|
57
|
+
## Related
|
|
58
|
+
|
|
59
|
+
- [Plugins](/reference/sdk/plugins)
|
|
60
|
+
- [Analytics events](/reference/sdk/analytics-events)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: reference
|
|
3
|
+
layout: docs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Plugins
|
|
7
|
+
|
|
8
|
+
A plugin adds behaviour to the Picked client. Pass one to the `plugins` array of
|
|
9
|
+
`createClient()`.
|
|
10
|
+
|
|
11
|
+
| Plugin | Import | What it does |
|
|
12
|
+
| --- | --- | --- |
|
|
13
|
+
| [Dynamic Experiences](/reference/sdk/plugins/dynamic-experiences) | `@picked/client/plugins/dynamic-experiences` | Reads the published configuration of your project at runtime and registers every experience, step, field, condition, and feature flag. |
|
|
14
|
+
| [Create Experience](/reference/sdk/plugins/create-experience) | `@picked/client/plugins/create-experience` | Registers an experience, a step, and a field that you define in code. |
|
|
15
|
+
| [Window Object](/reference/sdk/plugins/window-object) | `@picked/client/plugins/window-object` | Puts the client on `window.Picked`, which helps when you debug. |
|
|
16
|
+
| Single Page App | `@picked/client/plugins/single-page-app` | Starts the client again on a history event. |
|
|
17
|
+
| [React framework](/reference/sdk/react) | `@picked/react/plugins/framework` | Lets the client render a React component. |
|
|
18
|
+
| [Svelte framework](/reference/sdk/svelte) | `@picked/svelte/plugins/framework` | Lets the client render a Svelte component. |
|
|
19
|
+
| [Devtools](/reference/sdk/svelte#devtools-plugin) | `@picked/svelte/plugins/devtools` | Connects the client to the Chrome extension. |
|
|
20
|
+
| [Hotjar](/reference/sdk/plugins/hotjar) | `@picked/hotjar` | Sends the events of the client to Hotjar. |
|
|
21
|
+
| [FingerprintJS](/reference/sdk/plugins/fingerprintjs) | `@picked/fingerprintjs` | Adds the FingerprintJS visitor ID to the session. |
|
|
22
|
+
| [Sentry](/reference/sdk/plugins/sentry) | `@picked/sentry` | Sends the errors of the client to Sentry, and adds Picked tags. |
|
|
23
|
+
| [Shopify](/reference/sdk/plugins/shopify) | `@picked/shopify/plugins/shopify` | Adds Shopify predicates, and writes Picked data to the cart. |
|
|
24
|
+
|
|
25
|
+
Most applications need a framework plugin and **one** of Dynamic Experiences or Create
|
|
26
|
+
Experience. Dynamic Experiences puts your options in the dashboard; Create Experience
|
|
27
|
+
puts them in code.
|
|
28
|
+
|
|
29
|
+
## Related
|
|
30
|
+
|
|
31
|
+
- [How to install the SDK](/how-to/install-the-sdk) — where the plugins go.
|
|
32
|
+
- [SDK installation](/reference/sdk) — every client option.
|
|
33
|
+
- [How to debug with the Chrome extension](/how-to/debug-with-the-chrome-extension)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: reference
|
|
3
|
+
layout: docs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Sentry
|
|
7
|
+
|
|
8
|
+
`@picked/sentry` sends the errors of the Picked client to Sentry, and adds Picked tags to
|
|
9
|
+
the Sentry scope.
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import * as Sentry from '@sentry/browser'
|
|
13
|
+
import { createClient } from 'picked'
|
|
14
|
+
import { sentryPlugin } from '@picked/sentry'
|
|
15
|
+
|
|
16
|
+
Sentry.init({ dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0' })
|
|
17
|
+
|
|
18
|
+
const client = createClient({
|
|
19
|
+
projectId: 'your-project-id',
|
|
20
|
+
plugins: [sentryPlugin()],
|
|
21
|
+
})
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The plugin has no options. It uses the global Sentry scope of your application.
|
|
25
|
+
|
|
26
|
+
## Requirements
|
|
27
|
+
|
|
28
|
+
| Peer dependency | Version |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| `@sentry/browser` | `^10` |
|
|
31
|
+
| `@picked/client` | The version of your Picked SDK |
|
|
32
|
+
|
|
33
|
+
All the Sentry packages in your application must have the same version, for example `10.x`. A
|
|
34
|
+
different version makes a different Sentry scope, and the plugin then sends nothing.
|
|
35
|
+
|
|
36
|
+
## Events
|
|
37
|
+
|
|
38
|
+
| Client event | Sentry result |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| `exception` with `level: 'info'` | `captureMessage`, with the tag `picked: true`. |
|
|
41
|
+
| `exception` with a different `level` | `captureException`, with the tag `picked: true`. |
|
|
42
|
+
| `session` | The tag `picked.id`, with the session ID as its value. |
|
|
43
|
+
| `feature_decide` | The tag `picked.feature.<feature ID>`, with the bucket of the feature as its value. |
|
|
44
|
+
| `user_decide` | The tag `picked.is_user`, with the decision as its value. |
|
|
45
|
+
|
|
46
|
+
The plugin does nothing outside a browser.
|
|
47
|
+
|
|
48
|
+
## Related
|
|
49
|
+
|
|
50
|
+
- [Plugins](/reference/sdk/plugins)
|
|
51
|
+
- [About feature flag allocation](/explanation/feature-flag-allocation)
|