Reference
HTTP

HTTP Engine

Scenario actions

This section describes functionality available in scenarios described in the scenarios section of a test script.

GET / POST / PUT / PATCH / DELETE requests

An HTTP request object may have the following attributes:

  • url - The request URL; will be appended to the target URL set in config.target but can also be a fully qualified URL.
  • json - A JSON object to send in the request body.
  • body - Arbitrary data to send in the request body.
  • headers - A JSON object describing header key-value pairs.
  • cookie - A JSON object describing cookie key-value pairs.
  • capture - Set this to capture values from the response body of a request and store those in variables.

Example:

config:
  target: 'https://example.com'
  phases:
    - duration: 10
      arrivalRate: 1
scenarios:
  - flow:
      - get:
          url: '/'
      - post:
          url: '/resource'
          json:
            hello: 'world'

Configuration

TLS/SSL

By default, Artillery will reject SSL certificates that it's unable to validate. Typically, these errors occur when testing services with a self-signed certificate or an expired SSL certificate. You may see errors such as UNABLE_TO_GET_ISSUER_CERT_LOCALLY, UNABLE_TO_VERIFY_LEAF_SIGNATURE, CERT_UNTRUSTED or one of the other validation error codes (opens in a new tab) when that happens.

To get around these issues when using Artillery, you can disable certificate validation with one of the following two options:

  1. Pass the -k or --insecure flag to the artillery run or artillery quick commands.
  2. Set rejectUnauthorized: false under the config.tls setting in your test script:
config:
  target: 'https://myapp.staging:3002'
  tls:
    rejectUnauthorized: false
⚠️

Ignoring certificate errors can be useful for testing in a development or staging environment. However, you should never use this setting on a production environment. Ignoring certificate errors in a production system can lead to potential security vulnerabilities, like man-in-the-middle attacks.

Request timeouts

If a response to any request takes longer than 10 seconds, Artillery will abort the request and raise an ETIMEDOUT error.

To increase or decrease the default timeout period, set the config.http.timeout setting to the number of seconds for timing out the request.

config:
  target: 'http://my.app'
  http:
    # Responses have to be sent within 10 seconds, or an `ETIMEDOUT` error gets raised.
    timeout: 10

Max sockets per virtual user

By default, Artillery creates one TCP connection per virtual user. To allow for multiple sockets per virtual user (to mimic the behavior of a web browser, for example), specify the number of connections with the config.http.maxSockets setting.

config:
  target: 'http://my.app'
  http:
    # Set a max of five TCP connections per virtual user.
    maxSockets: 5

This setting is per virtual user, not for the total number of sockets. To limit the total number of sockets, use the config.http.pool setting.

Proxy support

Artillery can connect to the internet through a forward proxy (opens in a new tab), like a corporate proxy.

To send all traffic through a proxy, set the HTTP_PROXY environment variable to the proxy URL. The proxy URL itself may be HTTP or HTTPS. Both HTTP and HTTPS requests will be sent via the proxy.

HTTP_PROXY='http://my.proxy.app:3128' artillery run my-script.yaml

To send HTTPS traffic through a different proxy, set the HTTPS_PROXY environment variable. All HTTPS traffic will use this proxy.

HTTPS_PROXY='https://secure.proxy.app:3128' artillery run my-script.yaml

Additional performance metrics

The HTTP engine can be configured to track additional performance metrics by setting config.http.extendedMetrics to true:

config:
  http:
    extendedMetrics: true

The engine will then report the additional metrics listed below.

cookieJarOptions override

Added inv2.0.0-24

Cookie parsing behavior may be customized via config.http.cookieJarOptions by passing options to the underlying ToughCookie instance (opens in a new tab).

Default Configuration

Added inv2.0.0-36

You can set default configuration for the HTTP engine with config.http.defaults options.

For example, to set a default header:

config:
  http:
    defaults:
      headers:
        X-My-Header: '123'

You can set the following default configuration options:

NameValid OptionsDescription
headersany key:value pairDefault headers to be used in all requests.
cookieany key:value pairDefault cookies to be used in all requests.
strictCapture
  • true (default)
  • false
Whether to turn on strict capture by default for all captures.
thinkjitter: number or percentageSets jitter to simulate real-world random variance into think time pauses.

Logging

You can print messages to the console for each scenario using the log action:

config:
  target: 'https://example.com'
  phases:
    - duration: 10
      arrivalRate: 1
scenarios:
  - flow:
      - log: 'New virtual user running'
      - get:
          url: '/'
      - post:
          url: '/resource'
          json:
            hello: 'world'

In the example above, Artillery will print "New virtual user running" every time it generates a virtual user for the scenario.

The string argument to log may also include variables:

config:
  target: 'https://example.com'
  phases:
    - duration: 10
      arrivalRate: 1
scenarios:
  - flow:
      - log: 'Current environment is set to: {{ $environment }}'
      - get:
          url: '/'
      - post:
          url: '/resource'
          json:
            hello: 'world'

Debug messages will get printed to the console even when running the tests in "quiet" mode (using the --quiet or -q flag with the run command).

Setting Headers

Arbitrary headers may be sent under the headers option for a request:

- get:
    url: '/test'
    headers:
      X-My-Header: '123'

Compressed Responses (gzip)

Artillery automatically decompresses responses encoded with gzip, by adding an Accept-Encoding (opens in a new tab) header to the request.

Added inv2.0.0-28

Set gzip to false to disable automatic decompression if required to improve performance.

- post:
    url: '/test'
    json:
      foo: bar
    gzip: false

Basic Authentication

If your request requires Basic HTTP authentication (opens in a new tab), set your username and password under the auth option:

- get:
    url: '/protected/resource'
    auth:
      user: myusername
      pass: mypassword

Query Strings

Query strings (opens in a new tab) can be appended directly to the url or set with qs:

- get:
    url: '/products'
    qs:
      search_keyword: 'coffee'
      page_size: 25

The above request is identical to the following:

- get:
    url: '/products?search_keyword=coffee&page_size=25'

Redirects

Artillery follows redirects by default. To stop Artillery from following redirects, set the followRedirect option on a request to false:

- get:
    url: '/test'
    followRedirect: false

Forms

URL-encoded forms (application/x-www-form-urlencoded)

Use the form attribute to send an URL-encoded form (opens in a new tab):

- post:
    url: '/submit'
    form:
      name: 'Homer Simpson'
      favorite_food: 'donuts'

Multipart forms (multipart/form-data)

Use the formData attribute to send a multipart/form-data form (opens in a new tab) (forms containing files, non-ASCII data, and binary data).

formData is an object with fieldName: fieldValue pairs, each of them representing a form field:

- post:
    url: '/upload'
    formData:
      name: 'Homer Simpson'
      favorite_food: 'donuts'

Uploading files

Added inv2.0.17

To upload a file, set the value of the form field in formData to fromFile: './path/to/your-file'. The file path is resolved relative to the test script file.

- post:
    url: '/upload'
    formData:
      name: 'Homer Simpson'
      favorite_food: 'donuts'
      image:
        fromFile: './path/to/homer.jpg'

You can set content type for a file field explicitly with the contentType attribute:

- post:
    url: '/upload'
    formData:
      name: 'Homer Simpson'
      favorite_food: 'donuts'
      image:
        # Set content-type for this binary file explicitly
        fromFile: './path/to/binary-file'
        contentType: 'image/jpeg'

If you need to set contentType on a non-file field, use contentType and value attributes:

- post:
    url: '/upload'
    formData:
      name:
        value: '{"name":"Tiki","species":"pony","color":"brown","age":3}'
        contentType: 'application/json'

If you are running distributed tests on AWS Fargate or Lambda you need to provide the path to the file in the includeFiles section of the config.

config:
  target: "http://my.shop.app"
  phases:
    - duration: 1
      arrivalRate: 1
  includeFiles:
    - ./path/to/invoice.pdf
scenarios:
  - name: "order"
    flow:
      - post:
          url: '/upload'
          formData:
            id: abc123456
            item: 'donuts'
            invoice:
              fromFile: ./path/to/invoice.pdf
Setting the Content-Length header for file uploads

In some cases you may need to explicitly set the Content-Length header for a file upload (e.g. with S3/CloudFront pre-signed URLs). You can do this by setting the setContentLengthHeader attribute on the request level to true as seen below. This attribute will only work for file uploads.

- post:
    url: '/upload'
    setContentLengthHeader: true
    formData:
      name: 'Homer Simpson'
      favorite_food: 'donuts'
      image:
        fromFile: './path/to/homer.jpg'

Extracting and re-using parts of a response (request chaining)

You can parse responses and re-use those values in subsequent requests using the capture option in your requests.

Syntax

To tell Artillery to parse a response, add the capture option to a request:

- get:
    url: '/'
    capture:
      json: '$.id'
      as: 'id'

The capture option must always have an as attribute, which names the value for use in subsequent requests. It also requires one of the following attributes:

  • json - Allows you to define a JSONPath (opens in a new tab) expression.
  • xpath - Allows you to define an XPath (opens in a new tab) expression.
  • regexp - Allows you to define a regular expression that gets passed to a RegExp constructor (opens in a new tab). A specific capturing group (opens in a new tab) to return may be set with the group attribute (set to an integer index of the group in the regular expression). Flags (opens in a new tab) for the regular expression may be set with the flags attribute.
  • header - Allows you to set the name of the response header whose value you want to capture.
  • selector - Allows you to define a Cheerio (opens in a new tab) element selector. The attr attribute will contain the name of the attribute whose value we want. An optional index attribute may be set to a number to grab an element matching a selector at the specified index, "random" to grab an element at random, or "last" to grab the last matching element. If the index attribute is not specified, the first matching element will get captured.

Turn off strict capture

By default, captures are strict. If a capture rule fails because nothing matches, any subsequent requests in the scenario will not run, and that virtual user will stop making requests. This behavior is the default since subsequent requests typically depend on captured values and fail when one is not available.

In some cases, it may be useful to turn this behavior off. To make virtual users continue with running requests even after a failed capture, set strict to false:

- get:
    url: '/'
    capture:
      json: '$.id'
      as: 'id'
      strict: false # We don't mind if `id` can't be captured and the next requests 404s
- get:
    url: '/things/{{ id }}'

Capturing multiple values

Multiple values can be captured in a single request with an array of capture specs:

- get:
    url: '/journeys'
    capture:
      - xpath: '(//Journey)[1]/JourneyId/text()'
        as: 'JourneyId'
      - header: 'x-my-custom-header'
        as: 'headerValue'

Examples

The following example grabs a matching a element at random and uses the value of its href attribute in the next request:

- get:
    url: '/some/page'
    capture:
      - selector: 'a[class^=productLink]'
        index: 'random'
        attr: 'href'
        as: 'productUrl'
- get:
    url: '{{ productUrl }}'

Cookies

Cookies are remembered and re-used by individual virtual users. The cookie option can set custom cookies in individual requests.

The following example sets a cookie with the key saved with the value of tapir,sloth, which can be accessed in subsequent requests:

- get:
    url: '/pets/'
    cookie:
      saved: 'tapir,sloth'
- get:
    url: '/pets/saved'

Pausing execution with think

To pause the virtual user for N seconds, use a think action. The argument to think is the number of second to pause for. Floating numbers are supported, e.g. 0.5 pauses for half a second.

- post:
    url: '/pets'
    json:
      name: 'Mali'
      species: 'dog'
    capture:
      json: '$.id'
      as: 'id'
# wait for 5 seconds:
- think: 5
- get:
    url: '/pets/{{ id }}'

Using time units for think

Added inv2.0.1

As an alternative to using seconds, you can also provide any human-readable format from the ms package (opens in a new tab). For example:

- post:
    url: '/pets'
    json:
      name: 'Mali'
      species: 'dog'
    capture:
      json: '$.id'
      as: 'id'
# wait for two minutes:
- think: 2min
- get:
    url: '/pets/{{ id }}'

Conditional Requests

The ifTrue option can execute a request in a flow only when meeting a condition. ifTrue may take two forms:

  1. Set to a name of a scenario variable. If the variable is set (and is not explicitly set to false), the request will be executed.
  2. Set to a simple conditional expression, which may refer to any of the scenario variables and use one or more of:
    • A numeric operation with +, -, *, /, % (modulo), or ^ (power).
    • A comparison with ==, <, >, <=, or >=.
    • A boolean operation with or, and, or not. If the variable is explicitly set to a boolean, make sure to use this instead of comparison operators.

Examples

Make a GET request only if the keyword scenario variable is set to a value:

- get:
    url: '/search?keyword={{ keyword }}'
    ifTrue: 'keyword'

Make a GET request only if the pageNumber scenario variable is less than 10:

- get:
    url: '/pages/{{ pageNumber }}'
    ifTrue: 'pageNumber < 10'

Make a GET request only if the admin and user scenario variables are set to true:

- get:
    url: '/admin'
    ifTrue: 'admin and user'

Loops

You can use the loop construct to repeat through several requests in a scenario.

Looping through a number of requests

You can loop through a specific number of requests using the count attribute.

The following example sends 100 GET requests to / for each virtual user:

scenarios:
  - flow:
      - loop:
          - get:
              url: '/'
        count: 100

loop is an array - any number of requests can be specified. Variables, cookies, and response parsing will work as expected.

Accessing the loop count

You can access the current step of the loop by using the $loopCount variable, starting from 1. This variable is only available inside of the loop.

The following loop will first make a request to /pages/1, then /pages/2, and so on, up to /pages/100:

scenarios:
  - flow:
      - loop:
          - get:
              url: '/pages/{{ $loopCount }}'
        count: 100
⚠️

If the count option is omitted, the loop will run indefinitely.

Looping through an array

You can loop through an array of values by setting the over property to a specified array or by using the name of the variable containing an array of values. The loop can then access the value through the $loopElement variable.

In the following example, each value of the array defined in over will make one request for each value specified in the array, for a total of 3 requests:

scenarios:
  - flow:
      - loop:
          - get:
              url: '/products/{{ $loopElement }}'
        over:
          - id123
          - id456
          - id789

You can also iterate over different arrays defined as variables in the config section.

The following example uses the productIds variable inside of a loop. Each virtual user will make three requests for one of the arrays:

config:
  target: 'https://my.app.local'
  phases:
    - duration: 600
      arrivalRate: 10
  variables:
    productIds:
      - ['id1', 'id2', 'id3']
      - ['id4', 'id5', 'id6']
 
scenarios:
  - flow:
      - loop:
          - get:
              url: '/products/{{ $loopElement }}'
        over: productIds

In this example, a virtual user will make one of the following three requests in their loop:

  • /products/id1, /products/id2 and /products/id3
  • /products/id4, /products/id5 and /products/id6

Looping with custom logic

You can further control when to continue looping through a custom function defined in the whileTrue option.

For instance, let's say you want to poll an endpoint until it returns a JSON response with the top-level status attribute set to "ready":

config:
  target: 'https://my.app.local'
  phases:
    - duration: 600
      arrivalRate: 10
  processor: './my-functions.js'
 
scenarios:
  - flow:
      - loop:
          - think: 5
          - get:
              url: '/some/endpoint'
              capture:
                - json: $.status
                  as: 'status'
        whileTrue: 'statusReady'

The whileTrue option uses a JavaScript function loaded from my-functions.js containing the logic that determines when the loop stops:

module.exports = {
  statusReady: statusReady,
};
 
function statusReady(context, next) {
  const continueLooping = context.vars.status !== 'ready';
  // While `continueLooping` is true, the `next` function will
  // continue the loop in the test scenario.
  return next(continueLooping);
}

The whileTrue option takes precendence over count and over if either of those is specified.

Parallel requests

Added inv2.0.10

Artillery can send multiple requests in parallel. The following scenario sends three requests in parallel:

scenarios:
  - flow:
      - parallel:
          - get:
              url: '/resource1'
          - get:
              url: '/resource2'
          - get:
              url: '/resource3'
 

Writing custom logic in JS / TS

The HTTP engine has support for "hooks", which allow running custom code at specific points during the execution of a scenario.

  • beforeScenario and afterScenario - Called before/after a virtual user executes a scenario.
  • beforeRequest - Called before sending a request; request parameters like the URL, cookies, headers, and body can be customized here.
  • afterResponse - Called after a response has been received; the response can be inspected, and custom variables can be set here.

Custom functions may also be run at any point in a scenario with the function action.

Loading custom code

You can load custom code with config.processor attribute in your test script.

beforeRequest hooks

A beforeRequest hook gets the following arguments:

  • requestParams - Use this parameter to customize what to send in the request (headers, body, cookies, etc.).
  • 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. Added inv2.0.0-38
  • events - An event emitter that can be used to communicate with Artillery.

afterResponse hooks

A function invoked in an afterResponse gets the following arguments:

  • requestParams - Use this parameter to customize what to send in the request (headers, body, cookies, etc.).
  • response - Contains the response details (headers, body, etc.).
  • 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. Added inv2.0.0-38
  • events - An event emitter that can be used to communicate with Artillery.

function actions and beforeScenario / afterScenario hooks

A function invoked as an action in a scenario definition, either through function, beforeScenario and afterScenario gets the following arguments:

  • 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. Added inv2.0.0-38
  • events - An event emitter that can be used to communicate with Artillery.

Specifying a function to run

beforeRequest and afterResponse hooks can be set in a request:

- post:
    url: '/some/route'
    beforeRequest: 'setJSONBody'
    afterResponse: 'logHeaders'

In this example, Artillery runs the setJSONBody function before making the request and the logHeaders function after receiving the response.

Specifying multiple functions

You can also specify an array of function names, which run sequentially, one after another.

- post:
    url: '/products'
    beforeRequest:
      - 'setApiKey'
      - 'setJSONBody'
    afterResponse: 'logHeaders'

Setting scenario-level hooks

Similarly, a scenario definition can have beforeScenario and afterScenario attributes, which will make the specified functions run at the start, or the end of a scenario.

scenarios:
  - beforeScenario: 'setApiKey'
    afterScenario: 'logResults'
    flow:
      - get:
          url: '/search?q={{ query }}'
      - get:
          url: '/products'

Function steps in a flow

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

scenarios:
  - flow:
      - get:
          url: '/search?q={{ query }}'
      - function: 'setupSomeData'
      - get:
          url: '/some/url?q={{ query }}'

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

async function setupSomeData(context, events) {
  // Set the "query" variable for the virtual user.
  context.vars['query'] = 'foo';
}

Metrics reported by the engine

In addition to the default metrics reported by Artillery, the HTTP engine reports the following metrics:

MetricTypeDescription
http.requestsCounter

(count)

Number of HTTP requests made.
http.responsesCounter

(count)

Number of HTTP responses received.
http.codes.<status_code>Counter

(count)

Number of codes received for each specific status code.
http.downloaded_bytesCounter

(bytes)

Sum of downloaded_bytes of all responses received during this period.
http.response_time.<aggregation>Histogram

(milliseconds)

Response time (measured as TTFB - time-to-first-byte) aggregation for requests during this period.
http.request_rateRate

(req/sec)

Rate of http requests done over the time period.
http.response_time.2xx Available inv2.0.21Histogram

(milliseconds)

Response time distribution for 2xx responses
http.response_time.3xx Available inv2.0.21Histogram

(milliseconds)

Response time distribution for 3xx responses
http.response_time.4xx Available inv2.0.21Histogram

(milliseconds)

Response time distribution for 4xx responses
http.response_time.5xx Available inv2.0.21Histogram

(milliseconds)

Response time distribution for 5xx responses

Extended metrics

If extendedMetrics is enabled, the following additional metrics will be reported:

MetricTypeDescription
http.dns.<aggregation>Histogram

(milliseconds)

Time taken in the DNS phase of requests (i.e. time taken by DNS lookups).
http.tcp.<aggregation>Histogram

(milliseconds)

Time taken in the TCP phase of requests (i.e. time taken to establish TCP connections).
http.tls.<aggregation>Histogram

(milliseconds)

Time taken in the TLS phase of requests (i.e. time taken by completing TLS handshakes).
http.total.<aggregation>Histogram

(milliseconds)

Time for the entire response to be downloaded (i.e. time between when request started and it finished due to ending, aborting or erroring).

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.

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

DEBUG=http 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:

set DEBUG=http
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:

$Env:DEBUG = 'http'
artillery run my-script.yaml

The following examples use the macOS/Linux format for setting environment variables, but you can use any of the DEBUG values on Windows for your preferred command line interface.

Print request details, errors, and capture values

Set DEBUG=http when running your tests to view details about each request (URL, method, headers, etc.), values captured during a request, and any errors that occurred during the test run.

DEBUG=http artillery run my-script.yaml

Print request URL

Set DEBUG=http:request when running your tests to view the URL for each request made.

DEBUG=http:request artillery run my-script.yaml

Print response headers and body

Set DEBUG=http:response when running your tests to view each request's response headers and body.

DEBUG=http:response artillery run my-script.yaml

Combining debugging messages

You can combine different debugging modes in a single test run by setting a comma-separated list of values for DEBUG. For instance, to print the request URL and the response headers and body:

DEBUG=http:request,http:response artillery run my-script.yaml

You can also display all HTTP debugging messages with DEBUG=http*:

DEBUG=http* artillery run my-script.yaml