# Reference > Engines > Websocket

# WebSocket Engine

## Enabling WebSocket support

To use the WebSocket engine in an Artillery scenario, set the `engine` attribute of a scenario definition to `ws`.

```yaml
scenarios:
  - name: My WebSocket test
    engine: ws # Enable the Socket.io engine
    flow:
      - send: 'Hello world!'
```

## WebSocket-specific configuration

### Subprotocols

[WebSocket subprotocols](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers#subprotocols) may be configured with `config.ws.subprotocols` option:

```yaml
config:
  target: 'wss://echo.websocket.org'
  phases:
    - duration: 20
      arrivalRate: 10
  ws:
    # Set WebSocket subprotocols:
    subprotocols:
      - json
      - soap
```

### Headers

[Connection headers](https://tools.ietf.org/rfc6455#section-11.3) may be specified via the `config.ws.headers` object.

The following example shows how you can set a custom subprotocol called `my-protocol` via the [`Sec-WebSocket-Protocol` header](https://tools.ietf.org/rfc6455#section-11.3.4):

```yaml
config:
  target: 'wss://echo.websocket.org'
  phases:
    - duration: 20
      arrivalRate: 10
  ws:
    # Set a custom WebSocket subprotocol:
    headers:
      Sec-WebSocket-Protocol: my-protocol
```

### Proxies

> **Info:** The `config.ws.proxy` object is only available in Artillery v2

Proxy settings may be specified via the `config.ws.proxy` object:

```yaml
config:
  target: 'wss://echo.websocket.org'
  phases:
    - duration: 20
      arrivalRate: 10
  ws:
    proxy:
      url: 'https://proxy:port'
```

Any additional property will be passed to the underlying [HTTP(s) proxy agent](https://www.npmjs.com/package/https-proxy-agent).

### Other configuration options

You can configure the underlying WebSocket client via additional objects under `config.ws`.

For example, to change the number of maximum redirects allowed, use the `config.ws.maxRedirects` object:

```yaml
config:
  target: 'wss://echo.websocket.org'
  phases:
    - duration: 20
      arrivalRate: 10
  ws:
    maxRedirects: 25
```

For a list of available options, please see [WebSocket library docs](https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketaddress-protocols-options).

## Scenario actions and configuration

The WebSocket engine supports five types of actions: `connect`, `send`, `think`, `loop`, and `function`.

### Configuring the WebSocket connection with `connect`:

> **Info:** The `connect` action is only available in Artillery v2

`connect` *must* be the first step in the flow and it can be a string, a function or an object.

As a string:

```yaml
config:
  target: 'wss://echo.websocket.org'
  phases:
    - duration: 20
      arrivalRate: 10
  variables:
    token: 'mytoken'

scenarios:
  - engine: ws
    name: Echo a string
    flow:
      - connect: '{{ target }}/?token={{ token }}'
      - send: 'Hello from Artillery'
```

As a function:

```yaml
config:
  target: 'wss://echo.websocket.org'
  phases:
    - duration: 20
      arrivalRate: 10
  variables:
    token: 'mytoken'

scenarios:
  - engine: ws
    name: Echo a string
    flow:
      - connect:
          function: 'connectHandler'
      - send: 'Hello from Artillery'
```

The function should have the following signature:

```js
function connectHandler(params, context, next) {
  // This is the same as the "string" example above
  params.target = '${params.target}/?token=${context.vars.token}';

  next();
}
```

Where:

* `params` - An object whose properties will be passed to the underlying WebSocket constructor.
* `context` - The virtual user's context. `context.vars` is a dictionary containing all defined variables. `context.scenario` is the scenario definition for the scenario currently being run by the virtual user.
* `next` - The callback which *must* be called for the scenario to continue. If a value is passed to it, the execution fails.

As an object:

`connect` accepts all the parameters of the `config.ws` section plus a target property:

```yaml
config:
  target: 'wss://echo.websocket.org'
  phases:
    - duration: 20
      arrivalRate: 10
  variables:
    token: 'mytoken'

scenarios:
  - engine: ws
    name: Echo a string 1
    flow:
      - connect:
          target: 'ws://echo.websocket.org/?token={{ token }}'
          proxy:
            url: 'http://proxy1:3000'
      - send: 'Hello from Artillery'
  - engine: ws
    name: Echo a string 2
    flow:
      - connect:
          target: '{{ target }}/?token={{ token }}'
          proxy:
            url: 'http://proxy2:3000'
      - send: 'Hello from Artillery, through a different proxy'
```

### Sending data with `send`

Use `send` to send data to the server:

```yaml
config:
  target: 'wss://echo.websocket.org'
  phases:
    - duration: 20
      arrivalRate: 10
  ws:
    maxRedirects: 25

scenarios:
  - engine: ws
    name: Echo a string
    flow:
      - send: 'Hello from Artillery'
```

If the argument is an object, it will get converted to a string with [`JSON.stringify`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) before being sent to the target:

```yaml
config:
  target: 'wss://echo.websocket.org'
  phases:
    - duration: 20
      arrivalRate: 10

scenarios:
  - engine: ws
    name: Echo an object
    flow:
      # the following will be stringified and sent as '{"x":5,"y":6}'
      - send:
          x: 5
          y: 6
```

### Pausing execution with `think`

To pause the virtual user for N seconds, use a `think` action:

```yaml
config:
  target: 'wss://echo.websocket.org'
  phases:
    - duration: 20
      arrivalRate: 10

scenarios:
  - engine: ws
    flow:
      - send: 'Hello from Artillery'
      - think: 5 # Pause for 5 seconds.
      - send: 'Hello again'
```

### Repeating actions with `loop`

You can use the `loop` construct to loop through a number of requests in a scenario.

For example, the following send 100 messages to the target from each virtual user:

```yaml
config:
  target: 'wss://echo.websocket.org'
  phases:
    - duration: 20
      arrivalRate: 10

scenarios:
  - engine: ws
    flow:
      - loop:
          - send: 'Hello from Artillery'
        count: 100
```

See the [Loops section](/docs/reference/engines/http#loops) of the Testing HTTP guide for a detailed description of the `loop` action.

### Running custom code with `function`

A function may be run at any point in a scenario with a `function` action:

```yaml
config:
  target: 'wss://echo.websocket.org'
  processor: './my-functions.mjs'
  phases:
    - duration: 20
      arrivalRate: 10

scenarios:
  - engine: ws
    flow:
      - function: 'createTimestampedObject'
      - send: '{{ data }}'
```

JS functions invoked with the `function` action have full access to the virtual user's context:

```js
export async function createTimestampedObject(userContext, events) {
  const data = { timestamp: Date.now(), hello: 'world' };
  // set the "data" variable for the virtual user to use in the subsequent action
  userContext.vars.data = data;
}
```

## Examples

### Sending data

Send a string to a WebSocket server:

```yaml
config:
  target: 'wss://echo.websocket.org'
  phases:
    - duration: 20
      arrivalRate: 10

scenarios:
  - engine: 'ws'
    flow:
      - send: 'Hello from Artillery'
```

Send an object to a WebSocket server, which will get automatically converted to a JSON string:

```yaml
config:
  target: "wss://echo.websocket.org"
  phases:
    - duration: 20
      arrivalRate: 10

scenarios:
  - engine: "ws"
    flow:
      - send:
          id: 1
          name: "Artillery
```

Use the [WAMP](https://wamp-proto.org/) and [XMPP](https://datatracker.ietf.org/doc/rfc7395) subprotocols:

```yaml
config:
  target: 'wss://echo.websocket.org'
  phases:
    - duration: 20
      arrivalRate: 10
  ws:
    subprotocols:
      - wamp
      - xmpp

scenarios:
  - engine: 'ws'
    flow:
      - send: 'Hello from Artillery'
```

Configure the underlying [WebSocket client](https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketaddress-protocols-options):

```yaml
config:
  target: 'wss://echo.websocket.org'
  phases:
    - duration: 20
      arrivalRate: 10
  ws:
    protocolVersion: 8
    origin: 'https://websocket.org'
    followRedirects: true
    maxPayload: 2048

scenarios:
  - engine: 'ws'
    flow:
      - send: 'Hello from Artillery'
```

### Connecting Without Sending Any Data

You can use `think` to emulate clients connecting to the WebSocket server and listening without sending anything themselves:

```yaml
config:
  target: 'wss://echo.websocket.org'
  phases:
    - duration: 20
      arrivalRate: 10

scenarios:
  - engine: 'ws'
    flow:
      - think: 600 # do nothing for 10m and disconnect
```

## Metrics reported by the engine

In addition to the [default metrics](../reported-metrics#metrics-reported-by-artillery) reported by Artillery, the Websocket engine reports the following metrics:

| Metric                        | Type                                       | Description                                               |
| ----------------------------- | ------------------------------------------ | --------------------------------------------------------- |
| `websocket.messages_sent`     | Counter (count) | Number of messages sent.                                  |
| `websocket.messages_received` | Counter (count) | Number of messages received.                              |
| `websocket.send_rate`         | Rate (msg/sec)  | Rate of websocket messages sent over the time period.     |
| `websocket.receive_rate`      | Rate (msg/sec)  | Rate of websocket messages received over the time period. |

## Debugging

If you're having issues getting your test scenarios to complete successfully, you can print out helpful debugging messages using the `DEBUG` environment variable.

### Print data sent and errors

Set `DEBUG=ws` when running your tests to view details about the data sent to the WebSocket server and any errors that occurred during the test run.

On macOS and Linux systems, you can temporarily set the `DEBUG` environment variable by setting its value when running your Artillery test script:

```sh
DEBUG=ws artillery run my-script.yaml
```

For the Windows Command Prompt, you first need to set the `DEBUG` environment variable using the `set` command before running the test script:

```sh
set DEBUG=ws
artillery run my-script.yaml
```

If you use PowerShell on Windows, you can set the `DEBUG` environment variable using `$Env:DEBUG` before running the test script:

```powershell
$Env:DEBUG = 'ws'
artillery run my-script.yaml
```
