---
title: Run
---

An action can do one of the following things:

- Execute a function on the server (most common)
- If block is followed by a streamable variable, stream the variable on the client. Otherwise, execute a function on the server.
- Execute a function on the client
- Display a custom embed bubble

## Server function

The most common action is to execute a function on the server. This is done by simply declaring that function in the action block.

Example:

```ts
export const sendMessage = createAction({
  // ...
  run: {
    server: async ({
      credentials: { apiKey },
      options: { botId, message, responseMapping, threadId },
      variables,
      logs,
    }) => {
      const res: ChatNodeResponse = await got
        .post(apiBaseUrl + botId, {
          headers: {
            Authorization: `Bearer ${apiKey}`,
          },
          json: {
            message,
            chat_session_id: isEmpty(threadId) ? undefined : threadId,
          },
        })
        .json()

      if (res.error)
        logs.add({
          status: 'error',
          description: res.error,
        })

      if (res.error)
        logs.responseMapping?.forEach((mapping) => {
          if (!mapping.variableId) return

          const item = mapping.item ?? 'Message'
          if (item === 'Message') variables.set(mapping.variableId, res.message)

          if (item === 'Thread ID')
            variables.set(mapping.variableId, res.chat_session_id)
        })
    },
  },
})
```

As you can see the function takes `credentials`, `options`, `variables` and `logs` as arguments.

The `credentials` are the credentials that the user has entered in the credentials block.

The `options` are the options that the user has entered in the options block.

The `variables` object contains helper to save and get variables if necessary.

The `logs` allows you to log anything during the function execution. These logs will be displayed as toast in the preview mode or in the Results tab on production.

## Server function + stream

If your block can stream a message (like OpenAI), you can implement a stream object to handle it.

```ts
export const createChatCompletion = createAction({
  // ...
  run: {
    server: async (params) => {
      //...
    },
    stream: {
      getStreamVariableId: (options) =>
        options.responseMapping?.find(
          (res) => res.item === 'Message content' || !res.item
        )?.variableId,
      run: async ({ credentials: { apiKey }, options, variables }) => {
        const config = {
          apiKey,
          baseURL: options.baseUrl,
          defaultHeaders: {
            'api-key': apiKey,
          },
          defaultQuery: options.apiVersion
            ? {
                'api-version': options.apiVersion,
              }
            : undefined,
        } satisfies ClientOptions

        const openai = new OpenAI(config)

        const response = await openai.chat.completions.create({
          model: options.model ?? defaultOpenAIOptions.model,
          temperature: options.temperature
            ? Number(options.temperature)
            : undefined,
          stream: true,
          messages: parseChatCompletionMessages({ options, variables }),
        })

        return OpenAIStream(response)
      },
    },
  },
})
```

The `getStreamVariableId` function defines which variable should be streamed.

The `run` works the same as the [server function](./run#server-function). It needs to return `Promise<ReadableStream<any> | undefined>`.

## Client function

If you want to execute a function on the client instead of the server, you can use the `client` object.

<Info>
  This makes your block only compatible with the Web runtime. It won't work on
  WhatsApp for example, the block will simply be skipped.
</Info>

Example:

```ts
export const shoutName = createAction({
  // ...
  run: {
    web: {
      parseFunction: ({ options }) => {
        return {
          args: {
            name: options.name ?? null,
          },
          content: `alert('Hello ' + name)`,
        }
      },
    },
  },
})
```

The web function needs to return an object with `args` and `content`.

`args` is an object with arguments that are passed to the `content` context. Note that the arguments can't be `undefined`. If you want to pass an not defined argument, you need to pass `null` instead.

`content` is the code that will be executed on the client. It can call the arguments passed in `args`.

## Display embed bubble

If you want to display a custom embed bubble, you can use the `displayEmbedBubble` object. See [Cal.com
block](https://github.com/baptisteArno/typebot.io/blob/main/packages/forge/blocks/calCom/actions/bookEvent.ts)
as an example.

The `displayEmbedBubble` accepts a `parseInitFunction` function. This function needs to return the same object as the [`web` function](./run#client-function). The function content can use the `typebotElement` variable to get the DOM element where the block is rendered.

Optionally you can also define a `waitForEvent` object. This object accepts a `getSaveVariableId` function that returns the variable id where the event data should be saved. It also accepts a `parseFunction` function that returns the same object as the [`web` function](./run#client-function). The function content can use the `continueFlow` function to continue the flow with the event data.
