Appearance
Composite Connectors
Chain multiple API calls into a single execution when your widget needs data that requires more than one request — for example, authenticating with one service, then fetching data from another. This guide covers how to define, execute, and debug composite connectors.
Prerequisites
- A repository with
connectors_registry.jsonalready set up. See Repository Registry. - Familiarity with regular connector configuration. See Build Your First Connector.
How execution flows
Steps run sequentially — step 2 waits for step 1 to complete. If any step fails with an HTTP 4xx/5xx or network error, execution stops immediately and the final response is an error. The response returned to the widget is always the last step's response.
Define a composite connector
To create a composite connector, add an entry under the composite_connectors array in your connectors_registry.json:
json
{
"connectors": [...],
"composite_connectors": [
{
"name": "Auth and Fetch User",
"permalink": "auth-and-fetch-user",
"steps": [
{
"name": "auth",
"url": "https://auth.example.com/oauth/token",
"method": "POST",
"headers": [
{"key": "Content-Type", "value": "application/json"}
],
"authentication": {
"type": "oauth_client_credentials",
"config": {
"client_id": "{{ get_secret('oauth_client_id') }}",
"client_secret": "{{ get_secret('oauth_client_secret') }}",
"token_url": "https://auth.example.com/oauth/token"
}
}
},
{
"name": "fetch-user",
"url": "https://api.example.com/users/me",
"method": "GET",
"headers": [
{
"key": "Authorization",
"value": "Bearer {{ steps.auth.body | from_json | attr('access_token') }}"
}
]
}
]
}
]
}Push the file to your watched branch. The platform syncs the composite connector automatically — the same way it syncs regular connectors.
Composite connectors have no admin UI
You can only create and edit composite connectors through your repository registry. There is no visual editor for them.
For the full list of step fields and variables, see Composite Connector Reference.
Pass data between steps
To use a value from a previous step, reference it with steps.<name>.body in any Jinja2 template field (URL, headers, request body). Parse JSON responses with from_json, then pick fields with attr():
jinja2
Bearer {{ steps.auth.body | from_json | attr('access_token') }}If the previous step's response is large and you only need one field, transform it once at the source by setting response_body on that step:
json
{
"name": "auth",
"url": "https://auth.example.com/oauth/token",
"method": "POST",
"response_body": "{{ response.body | from_json | attr('access_token') }}"
}After this, steps.auth.body holds just the token string, and later steps can reference it directly as Bearer {{ steps.auth.body }}.
Step names use slug format
Step names use slug format: lowercase letters, digits, and hyphens (for example, auth, fetch-user). For single-word names use dot notation: steps.auth.body. For hyphenated names use bracket notation: steps['fetch-user'].body.
Use incoming request data in steps
To drive step behavior from the client's request — for example, a user ID sent in the request body — reference the request object in any step template:
jinja2
{# In a step URL or request_body template #}
{{ request.body_text | from_json | attr('userId') }}The request object exposes the client's body, headers, and query parameters. See Composite Connector Reference for the full list.
Different from regular connectors
Regular connectors use body_text and body_raw directly in payload templates. Composite connectors use request.body_text and request.body_raw — the request. prefix distinguishes client data from step result data.
Execute a composite connector
To call a composite connector from widget code, use sdk.connectors.composite.execute():
html
<script>
(async () => {
const sdk = new window.WidgetServiceSDK();
try {
const data = await sdk.connectors.composite.execute({
permalink: "auth-and-fetch-user"
});
console.log("Result:", data);
} catch (error) {
console.error("Connector request failed:", error);
}
})();
</script>The HTTP method is always POST — it is not a configurable parameter. The SDK owns this detail so you do not need to specify it.
Path parameters are not supported on composite connectors
pathParams is a simple-connector concept only. Passing pathParams to sdk.connectors.composite.execute() throws ConnectorBoundaryError synchronously — no request is sent. If you need per-call path values inside a composite flow, embed them in the step URLs using template variables from previous steps' results. See Dynamic URL Path Segments for the simple-connector pattern.
To pass a request body, include the payload option as a plain object. The SDK handles serialisation. Use queryParams to append URL query parameters — these are available in step templates as request.query_parameters.<key>:
html
<script>
(async () => {
const sdk = new window.WidgetServiceSDK();
try {
const data = await sdk.connectors.composite.execute({
permalink: "auth-and-fetch-user",
payload: { userId: "usr_123" },
queryParams: { format: "json" }
});
console.log("Result:", data);
} catch (error) {
console.error("Connector request failed:", error);
}
})();
</script>Debug failing steps
When a step fails, the platform returns a single error response identifying which step failed:
- HTTP 4xx/5xx from a step — returns 502 with the failed step's name and index
- Network error on a step — returns 502 with step identification
- Template rendering error — returns 422 with the affected step and template error
No data from previous successful steps is included in the error response.
Example errors.scope value in the JSON error response: Composite step 'fetch-user' (index 1): Downstream (HTTP error)
To see per-step timing, inspect the response headers:
Server-Timing— includes astep.<name>;dur=<ms>entry per step, plustotalX-Connector-Timing— JSON with per-step breakdown
Server-Timing: step.auth;dur=120.5;desc="Step: auth", step.fetch-user;dur=85.3;desc="Step: fetch-user", total;dur=210.1;desc="Total"Next Steps
- Composite Connector Reference — Step fields, template variables, error types
- How Connectors Work — Understand the request and response pipeline
- Response Transformation — Per-step
response_bodyuses the same syntax - Template Variables — Variables, filters, and functions available in step templates

