Appearance
Are you an LLM? You can read better optimized documentation at /docs/custom-widgets/v2/dynamic-options.md for this page in Markdown format
Dynamic Options
This page documents the dynamicOptions object and the autocomplete field type, which let configuration fields load their choices from an external API instead of a hardcoded options array.
Field Types
| Type | Static options | Dynamic options | Multi-value |
|---|---|---|---|
select | Yes — via options array | Yes — via dynamicOptions | Optional — set multiple: true |
autocomplete | No | Required — via dynamicOptions | Optional — set multiple: true |
A select field declares exactly one of options (static) or dynamicOptions (dynamic) — never both. An autocomplete field always requires dynamicOptions.
When to Use Each Pattern
| Pattern | Type | isAsyncSearch | When to use |
|---|---|---|---|
| Fixed dropdown | select + options | — | Fixed enum: sort order, layout style |
| Load-once dropdown | select + dynamicOptions | — | Bounded list (up to ~200 items): categories, regions |
| Search-as-you-type | autocomplete + dynamicOptions | true | Unbounded list: 10 000+ courses, users, products |
| Single-fetch typeahead | autocomplete + dynamicOptions | false | Small list with chip UI |
dynamicOptions Object
| Field | Type | Required | Description |
|---|---|---|---|
endpoint | object | Yes | API endpoint to fetch the list of options — see API Endpoint Object |
valuesEndpoint | object | No | API endpoint to resolve stored IDs back to fresh labels — see API Endpoint Object |
mapping | object | Yes | How to extract value and label from the API response — see Options Mapping Object |
isAsyncSearch | boolean | No | When true, the API is called on every keystroke. Only valid on autocomplete fields. |
API Endpoint Object
Naming
The field on dynamicOptions is also named endpoint — the URL string lives one level deeper inside it: dynamicOptions.endpoint.endpoint.
Used for both endpoint and valuesEndpoint.
| Field | Type | Required | Description |
|---|---|---|---|
endpoint | string | Yes | HTTPS URL for the API call. Supports URL template tokens. Must start with https://. |
method | string | Yes | HTTP method — "GET" or "POST" |
headers | object | No | Additional HTTP headers. See Disallowed Headers. |
body | object | No | Request body, for POST requests. |
params | object | No | Query parameters appended to the URL after template interpolation. |
URL Template Tokens
Embed these tokens in endpoint URLs to make requests dynamic:
| Token | Replaced with | Used in |
|---|---|---|
{q} | Current search query (URL-encoded) | endpoint on autocomplete fields with isAsyncSearch: true |
{value} | Stored IDs, comma-joined; each ID is individually URL-encoded | valuesEndpoint |
Example: "https://api.example.com/courses?q={q}" sends the current search term as a query parameter.
Disallowed Headers
The following headers cannot be declared in headers (case-insensitive): Authorization, Cookie, Set-Cookie, Proxy-*, X-Forwarded-*. The registry is not the right place to store credentials — use a Connector for authenticated external API calls.
params Serialization
Entries in params are appended to the URL as a query string after template interpolation:
- Strings, numbers, and booleans are converted to strings.
- Arrays become repeated entries:
tag=a&tag=b. - Objects are JSON-stringified.
nullandundefinedvalues are skipped.
Example: { "page": 1, "tag": ["a", "b"] } → ?page=1&tag=a&tag=b
Options Mapping Object
Maps an API response array to { value, label } pairs.
| Field | Type | Required | Description |
|---|---|---|---|
path | string | No | Dot-path to the array within the response (e.g. "data.items"). Defaults to the response root. |
valueKey | string | Yes | Property name to use as the stored value (e.g. "id"). |
labelKey | string | Yes | Property name to use as the display label (e.g. "name"). |
path accepts dot-paths like "data.items". A leading $. is stripped for JSONPath compatibility; filters and wildcards are not supported.
Multi-select (multiple)
Add "multiple": true to any select or autocomplete field to allow the user to pick more than one option:
json
{
"name": "tags",
"type": "autocomplete",
"label": "Tags",
"multiple": true,
"dynamicOptions": { ... }
}1
2
3
4
5
6
7
2
3
4
5
6
7
Content Endpoint Wire Format
When the platform forwards saved widget configuration to your content endpoint, dynamic selection values are normalized:
| Saved shape | Sent as (GET) | Sent as (POST) |
|---|---|---|
| Single value | ?field=id | {"field": "id"} |
| Multiple values | ?field=id1,id2 | {"field": ["id1", "id2"]} |
| Empty selection | ?field= | {"field": []} |
The cachedLabel is never sent to the content endpoint. If your widget needs a display name, fetch it from your API using the ID.
Examples
Load-once dropdown (select with dynamicOptions)
json
{
"name": "category",
"type": "select",
"label": "Category",
"dynamicOptions": {
"endpoint": {
"endpoint": "https://api.example.com/categories",
"method": "GET"
},
"mapping": {
"valueKey": "id",
"labelKey": "name"
}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Search-as-you-type multi-select (autocomplete)
json
{
"name": "courses",
"type": "autocomplete",
"label": "Courses",
"multiple": true,
"rules": { "required": true },
"dynamicOptions": {
"endpoint": {
"endpoint": "https://api.skilljar.com/v1/courses?q={q}",
"method": "GET"
},
"valuesEndpoint": {
"endpoint": "https://api.skilljar.com/v1/courses?ids={value}",
"method": "GET"
},
"mapping": {
"path": "results",
"valueKey": "id",
"labelKey": "title"
},
"isAsyncSearch": true
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
The valuesEndpoint is optional but recommended: when the configurator reloads, it calls valuesEndpoint with the stored IDs to display fresh labels. Without it, the cached label is shown until the user searches again.
Limitations
- Authentication —
dynamicOptionsendpoints must be publicly accessible or rely on existing B2B authentication. Per-request auth headers are not supported; use a Connector for endpoints that require credentials. - Caching — the platform does not cache
dynamicOptionsresponses. For large datasets, preferisAsyncSearch: trueto limit the volume of results returned. - Pagination — not supported. Your endpoint should return a usable page size or all items for bounded lists.
- Cascading fields — one field's selection cannot drive another field's endpoint. Each field's
endpointis fixed at registration time. - Response shape — only flat dot-paths and
valueKey/labelKeylookups are supported. Filters, computed fields, and wildcard paths are not.
Next Steps
- Widget Configuration — how to define configuration fields and read them in widget code
- Widget Definition Reference — full reference for all widget fields
- Connectors — proxy authenticated external API calls securely

