> For the complete documentation index, see [llms.txt](https://docs.appfarm.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.appfarm.io/library/action-nodes/streaming-web-request.md).

# Streaming web request

The Streaming web request action node sends an HTTP request and processes the response incrementally as chunks arrive, rather than waiting for the complete response. This lets you update the UI in real time as data is received — for example, displaying AI-generated text word by word as a language model streams its response, instead of making the user wait for the full reply.

The node is designed for cases where a user is watching the output as it arrives. A typical use case is integrating with AI APIs that return streaming responses via Server-Sent Events (SSE), but it works with any API that sends a chunked or streamed response.

### Request settings

The request configuration is the same as on the [Web request](/library/action-nodes/web-request.md) action node: **Base URL**, **Path**, **Path Parameters**, **Query Parameters**, **Request Headers**, **Authorization**, **Method**, **Body Type**, **Body Content**, and **Content Type** all work the same way. See the Web request page for details on each setting.

As on the Web request action node, the **Timeout** setting controls how long the node waits for the response to complete. The default is `30 000` ms.

### Chunk handler

The chunk handler is a JavaScript function that runs each time a chunk of data is received from the streaming response. It is authored in the standard function editor and is where you define how incoming data should be parsed and processed.

#### Built-in function params

The following parameters are available automatically in the chunk handler:

| Parameter          | Description                                                                                                                                                                                                                                                                                                          |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `rawChunk`         | The raw chunk of data received from the stream, as a string.                                                                                                                                                                                                                                                         |
| `buffer`           | A persistent array that survives across chunk handler invocations. Use it to accumulate partial data that spans chunk boundaries — for example, an incomplete line that continues in the next chunk.                                                                                                                 |
| `memory`           | A persistent Map for storing custom values between chunk handler invocations. Use it to keep track of state that does not fit the `buffer` array — for example, counters, flags, or accumulated results. Values set with `memory.set(key, value)` in one invocation are available via `memory.get(key)` in the next. |
| `responseCode`     | The HTTP status code of the response.                                                                                                                                                                                                                                                                                |
| `responseHeaders`  | The response headers.                                                                                                                                                                                                                                                                                                |
| `generateObjectId` | A utility function for generating object IDs.                                                                                                                                                                                                                                                                        |
| `DOMParser`        | The standard DOMParser, available for parsing XML or HTML content.                                                                                                                                                                                                                                                   |

In addition to the built-in params, you can add custom function params from the left pane — action data, app data, app variables, and other data sources — just like in any other function editor in Appfarm Create.

#### How the chunk handler works

The chunk handler is called once for each chunk the server sends. A chunk is a fragment of the response body — it may contain a complete message, part of a message, or multiple messages depending on the streaming protocol and network conditions.

Because chunks may split data at arbitrary points, the built-in `buffer` array is provided for reassembling data across invocations. A typical pattern is to push the raw chunk onto the buffer, join and split on a delimiter (such as a newline), and keep any incomplete trailing fragment in the buffer for the next call.

{% tabs %}
{% tab title="Example: parsing SSE using an action" %}
This example parses Server-Sent Events from an AI Messages API. Each SSE event is a line starting with `data:` followed by a JSON payload. The handler extracts text deltas and passes each one to an action called `updateStreamingResponse`.

```javascript
buffer.push(rawChunk);
const combined = buffer.join('');
const lines = combined.split('\n');
buffer.length = 0;
buffer.push(lines.pop()); // keep incomplete last line

lines
  .filter(line => line.startsWith('data: '))
  .map(line => line.slice(6).trim())
  .filter(jsonStr => jsonStr && jsonStr !== '[DONE]')
  .map(jsonStr => {
    try { return JSON.parse(jsonStr); }
    catch (e) { return null; }
  })
  .filter(parsed =>
    parsed &&
    parsed.type === 'content_block_delta' &&
    parsed.delta?.type === 'text_delta' &&
    parsed.delta?.text
  )
  .map(parsed => () => updateStreamingResponse({ input: parsed.delta.text }))
  .reduce((chain, fn) => chain.then(fn), Promise.resolve());
```

{% endtab %}

{% tab title="Example: parsing SSE using a data item" %}
This example uses the same SSE parsing logic, but writes each text delta to a data item called `streamedText` instead of calling an action. The data item targets an action variable with **Append to values** mode, so the full response accumulates token by token.

```javascript
buffer.push(rawChunk);
const combined = buffer.join('');
const lines = combined.split('\n');
buffer.length = 0;
buffer.push(lines.pop()); // keep incomplete last line

for (const line of lines) {
  if (!line.startsWith('data: ')) continue;
  const jsonStr = line.slice(6).trim();
  if (!jsonStr || jsonStr === '[DONE]') continue;

  try {
    const parsed = JSON.parse(jsonStr);
    if (
      parsed.type === 'content_block_delta' &&
      parsed.delta?.type === 'text_delta' &&
      parsed.delta?.text
    ) {
      streamedText({ responseBody: parsed.delta.text });
    }
  } catch (e) {
    // skip malformed JSON
  }
}
```

{% endtab %}
{% endtabs %}

### Data items

The **Data Items** section on the Streaming web request node lets you write streamed data directly to data sources from within the chunk handler, without calling a separate action. Each data item maps a name to a target data source and an operation that controls how data is written.

#### Configuring a data item

Each entry has three settings:

* **Name** — the identifier you use to call the data item from within the chunk handler. The name must start with a letter and contain only letters, digits, and underscores. It must be unique across all data items and cannot use a reserved name (`rawChunk`, `buffer`, `memory`, `responseCode`, `responseHeaders`, `generateObjectId`, or `DOMParser`).
* **Data Source** — the target data source to write to. This can be a local data source, an action variable, or other runtime state.
* **Operation** — how the data is applied to the target. The available operations depend on the data source's cardinality:
  * Single-cardinality sources: **Update single cardinality object** (default) or **Replace all objects**.
  * Multi-cardinality sources: **Add to Data Source** (default) or **Replace**.

#### Calling a data item from the chunk handler

Each configured data item becomes a callable function parameter in the chunk handler, similar to the built-in params. Call it by name and pass an object whose keys are the property names of the target data source:

```javascript
myDataItem({ propertyName: value })
```

You shape the data yourself in JavaScript — the data item is bound to the data source as a whole, not to an individual property. For single-cardinality sources, pass a single object. For multi-cardinality sources, pass an array of objects. The runtime merges the object into the data source according to the configured operation.

#### Action variables

When a data item has [action variables](/reference/actions/action-variables.md) as its **Data Source**, the **Operation** property behaves a bit differently:

* **Replace values** (default) — overwrites the action variable with the new value on each call.
* **Append to values** — concatenates the new value onto the current value. For text, values are joined; for lists, items are appended.

The append mode is designed for token-by-token AI streaming. When an AI API returns text one token at a time, each chunk handler invocation appends the latest token to the action variable, so the full response accumulates naturally as the stream progresses.

Note that **Action Variables** is treated as a data source, where each variable is treated as a property of that data source.

### Actions

The **Actions** section on the Streaming web request node lets you wire up actions that the chunk handler can call during processing. Each entry has two settings: **Function Name**, which is the name you use to call the action from within the chunk handler, and **Action**, which selects the Appfarm action to run.

Invoking an action from the chunk handler returns a Promise that resolves when the action finishes. To execute actions in sequence safely, see the [Promise composition guide](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#composition). For actions with parameters, select **Code Function Param** on each action param you want to pass from code, then call the function with an object of key/value pairs. For example, if the function name is `updateStreamingResponse` and the action has a code function param named `input`:

```javascript
updateStreamingResponse({ input: "some text" })
  .then(() => console.log('done!'))
  .catch(console.error)
```

Actions are called explicitly from within the chunk handler — they do not run automatically. This gives you full control over when and how often each action is invoked. In the SSE example above, the action is called once per text delta, and the calls are chained sequentially using `.reduce()` to ensure they execute in order.

### Other settings

| Property                     | Description                                                                                                                                                                                                                                                                                 |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Disabled**                 | Disables the action node. The node is skipped when the action runs.                                                                                                                                                                                                                         |
| **Disabled in Dev and Test** | Disables the action node in the Development and Test environments only.                                                                                                                                                                                                                     |
| **Send from Client**         | Sends the request directly from the client instead of routing it through the Appfarm server. When enabled, the hostname must be added to **Allowed web request targets** in **Environment Config**, and [Secrets](/reference/security/secrets.md) are not available for use in the request. |

### Properties

The request-side properties (**Base URL**, **Path**, **Path Parameters**, **Query Parameters**, **Request Headers**, **Authorization**, **Method**, **Timeout**, **Body Type**, **Body Content**, **Content Type**) are the same as on the [Web request](/library/action-nodes/web-request.md) action node. The following properties are specific to the Streaming web request:

| Property          | Description                                                                                                             |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------- |
| **Chunk Handler** | A JavaScript function that runs on each chunk of the streaming response. See [Chunk handler](#chunk-handler).           |
| **Data Items**    | Named bindings that write streamed data directly to data sources from the chunk handler. See [Data items](#data-items). |
| **Actions**       | Actions that can be called from within the chunk handler. See [Actions](#actions).                                      |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.appfarm.io/library/action-nodes/streaming-web-request.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
