Examples

June 6, 2026 ยท View on GitHub

This guide provides practical examples for common Sarin use cases.

Table of Contents


Basic Usage

Send 1000 GET requests with 10 concurrent workers:

sarin -U http://example.com -r 1000 -c 10
YAML equivalent
url: http://example.com
requests: 1000
concurrency: 10

Send requests with a custom timeout:

sarin -U http://example.com -r 1000 -c 10 -T 5s
YAML equivalent
url: http://example.com
requests: 1000
concurrency: 10
timeout: 5s

Request-Based vs Duration-Based Tests

Request-based: Stop after sending a specific number of requests:

sarin -U http://example.com -r 10000 -c 50
YAML equivalent
url: http://example.com
requests: 10000
concurrency: 50

Duration-based: Run for a specific amount of time:

sarin -U http://example.com -d 5m -c 50
YAML equivalent
url: http://example.com
duration: 5m
concurrency: 50

Combined: Stop when either limit is reached first:

sarin -U http://example.com -r 100000 -d 2m -c 100
YAML equivalent
url: http://example.com
requests: 100000
duration: 2m
concurrency: 100

Headers, Cookies, and Parameters

Custom headers:

sarin -U http://example.com -r 1000 -c 10 \
  -H "Authorization: Bearer token123" \
  -H "X-Custom-Header: value"
YAML equivalent
url: http://example.com
requests: 1000
concurrency: 10
headers:
    Authorization: Bearer token123
    X-Custom-Header: value

Multiple values for the same header (all sent in every request):

Note: When the same key appears as separate entries (in CLI or config file), all values are sent in every request.

sarin -U http://example.com -r 1000 -c 10 \
  -H "X-Region: us-east" \
  -H "X-Region: us-west"
YAML equivalent
url: http://example.com
requests: 1000
concurrency: 10
headers:
    - X-Region: us-east
    - X-Region: us-west

Cycling headers from multiple values (config file only):

Note: When multiple values are specified as an array on a single key, Sarin starts at a random index and cycles through all values in order. Once the cycle completes, it picks a new random starting point.

url: http://example.com
requests: 1000
concurrency: 10
headers:
    X-Region:
        - us-east
        - us-west
        - eu-central

Query parameters:

sarin -U http://example.com/search -r 1000 -c 10 \
  -P "query=test" \
  -P "limit=10"
YAML equivalent
url: http://example.com/search
requests: 1000
concurrency: 10
params:
    query: "test"
    limit: 10

Dynamic query parameters:

sarin -U http://example.com/users -r 1000 -c 10 \
  -P "id={{ fakeit_Number 1 1000 }}" \
  -P "fields=name,email"
YAML equivalent
url: http://example.com/users
requests: 1000
concurrency: 10
params:
    id: "{{ fakeit_Number 1 1000 }}"
    fields: "name,email"

Cookies:

sarin -U http://example.com -r 1000 -c 10 \
  -C "session_id=abc123" \
  -C "user_id={{ fakeit_UUID }}"
YAML equivalent
url: http://example.com
requests: 1000
concurrency: 10
cookies:
    session_id: abc123
    user_id: "{{ fakeit_UUID }}"

Dynamic Requests with Templating

Dynamic URL paths:

Test different resource endpoints with random IDs:

sarin -U "http://example.com/users/{{ fakeit_UUID }}/profile" -r 1000 -c 10
YAML equivalent
url: http://example.com/users/{{ fakeit_UUID }}/profile
requests: 1000
concurrency: 10

Test with random numeric IDs:

sarin -U "http://example.com/products/{{ fakeit_Number 1 10000 }}" -r 1000 -c 10
YAML equivalent
url: http://example.com/products/{{ fakeit_Number 1 10000 }}
requests: 1000
concurrency: 10

Generate a random User-Agent for each request:

sarin -U http://example.com -r 1000 -c 10 \
  -H "User-Agent: {{ fakeit_UserAgent }}"
YAML equivalent
url: http://example.com
requests: 1000
concurrency: 10
headers:
    User-Agent: "{{ fakeit_UserAgent }}"

Send requests with random user data:

sarin -U http://example.com/api/users -r 1000 -c 10 \
  -M POST \
  -H "Content-Type: application/json" \
  -B '{"name": "{{ fakeit_Name }}", "email": "{{ fakeit_Email }}"}'
YAML equivalent
url: http://example.com/api/users
requests: 1000
concurrency: 10
method: POST
headers:
    Content-Type: application/json
body: '{"name": "{{ fakeit_Name }}", "email": "{{ fakeit_Email }}"}'

Use values to share generated data across headers and body:

sarin -U http://example.com/api/users -r 1000 -c 10 \
  -M POST \
  -V "ID={{ fakeit_UUID }}" \
  -H "X-Request-ID: {{ .Values.ID }}" \
  -B '{"id": "{{ .Values.ID }}", "name": "{{ fakeit_Name }}"}'
YAML equivalent
url: http://example.com/api/users
requests: 1000
concurrency: 10
method: POST
values: "ID={{ fakeit_UUID }}"
headers:
    X-Request-ID: "{{ .Values.ID }}"
body: '{"id": "{{ .Values.ID }}", "name": "{{ fakeit_Name }}"}'

Generate random IPs and timestamps:

sarin -U http://example.com/api/logs -r 500 -c 20 \
  -M POST \
  -H "Content-Type: application/json" \
  -B '{"ip": "{{ fakeit_IPv4Address }}", "timestamp": "{{ fakeit_Date }}", "action": "{{ fakeit_HackerVerb }}"}'
YAML equivalent
url: http://example.com/api/logs
requests: 500
concurrency: 20
method: POST
headers:
    Content-Type: application/json
body: '{"ip": "{{ fakeit_IPv4Address }}", "timestamp": "{{ fakeit_Date }}", "action": "{{ fakeit_HackerVerb }}"}'

For the complete list of 340+ template functions, see the Templating Guide.

Solving Captchas

Sarin can solve captchas through third-party services and embed the resulting token into the request. Three services are supported via dedicated template functions: 2Captcha, Anti-Captcha, and CapSolver.

Solve a reCAPTCHA v2 and submit the token in the request body:

sarin -U https://example.com/login -M POST -r 1 \
  -B '{"g-recaptcha-response": "{{ twocaptcha_RecaptchaV2 "YOUR_API_KEY" "SITE_KEY" "https://example.com/login" }}"}'

Reuse a single solved token across multiple requests via values:

sarin -U https://example.com/api -M POST -r 5 \
  -V 'TOKEN={{ anticaptcha_Turnstile "YOUR_API_KEY" "SITE_KEY" "https://example.com/api" }}' \
  -H "X-Turnstile-Token: {{ .Values.TOKEN }}" \
  -B '{"token": "{{ .Values.TOKEN }}"}'

See the Templating Guide for the full list of captcha functions and per-service support.

Request Bodies

Simple JSON body:

sarin -U http://example.com/api/data -r 1000 -c 10 \
  -M POST \
  -H "Content-Type: application/json" \
  -B '{"key": "value"}'
YAML equivalent
url: http://example.com/api/data
requests: 1000
concurrency: 10
method: POST
headers:
    Content-Type: application/json
body: '{"key": "value"}'

Multiple bodies (randomly cycled):

sarin -U http://example.com/api/products -r 1000 -c 10 \
  -M POST \
  -H "Content-Type: application/json" \
  -B '{"product": "laptop", "price": 999}' \
  -B '{"product": "phone", "price": 599}' \
  -B '{"product": "tablet", "price": 399}'
YAML equivalent
url: http://example.com/api/products
requests: 1000
concurrency: 10
method: POST
headers:
    Content-Type: application/json
body:
    - '{"product": "laptop", "price": 999}'
    - '{"product": "phone", "price": 599}'
    - '{"product": "tablet", "price": 399}'

Dynamic body with fake data:

sarin -U http://example.com/api/orders -r 1000 -c 10 \
  -M POST \
  -H "Content-Type: application/json" \
  -B '{
    "order_id": "{{ fakeit_UUID }}",
    "customer": "{{ fakeit_Name }}",
    "email": "{{ fakeit_Email }}",
    "amount": {{ fakeit_Price 10 500 }},
    "currency": "{{ fakeit_CurrencyShort }}"
  }'
YAML equivalent
url: http://example.com/api/orders
requests: 1000
concurrency: 10
method: POST
headers:
    Content-Type: application/json
body: |
    {
      "order_id": "{{ fakeit_UUID }}",
      "customer": "{{ fakeit_Name }}",
      "email": "{{ fakeit_Email }}",
      "amount": {{ fakeit_Price 10 500 }},
      "currency": "{{ fakeit_CurrencyShort }}"
    }

Multipart form data:

sarin -U http://example.com/api/upload -r 1000 -c 10 \
  -M POST \
  -B '{{ body_FormData "username" "john" "email" "john@example.com" }}'
YAML equivalent
url: http://example.com/api/upload
requests: 1000
concurrency: 10
method: POST
body: '{{ body_FormData "username" "john" "email" "john@example.com" }}'

Multipart form data with dynamic values:

sarin -U http://example.com/api/users -r 1000 -c 10 \
  -M POST \
  -B '{{ body_FormData "name" (fakeit_Name) "email" (fakeit_Email) "phone" (fakeit_Phone) }}'
YAML equivalent
url: http://example.com/api/users
requests: 1000
concurrency: 10
method: POST
body: '{{ body_FormData "name" (fakeit_Name) "email" (fakeit_Email) "phone" (fakeit_Phone) }}'

Note: body_FormData automatically sets the Content-Type header to multipart/form-data with the appropriate boundary.

File Uploads

File upload with multipart form data:

Upload a local file:

sarin -U http://example.com/api/upload -r 100 -c 10 \
  -M POST \
  -B '{{ body_FormData "title" "My Document" "document" "@/path/to/file.pdf" }}'
YAML equivalent
url: http://example.com/api/upload
requests: 100
concurrency: 10
method: POST
body: '{{ body_FormData "title" "My Document" "document" "@/path/to/file.pdf" }}'

Multiple file uploads (same field name):

sarin -U http://example.com/api/upload -r 100 -c 10 \
  -M POST \
  -B '{{ body_FormData "files" "@/path/to/file1.pdf" "files" "@/path/to/file2.pdf" }}'
YAML equivalent
url: http://example.com/api/upload
requests: 100
concurrency: 10
method: POST
body: |
    {{ body_FormData
       "files" "@/path/to/file1.pdf"
       "files" "@/path/to/file2.pdf"
    }}

Multiple file uploads (different field names):

sarin -U http://example.com/api/upload -r 100 -c 10 \
  -M POST \
  -B '{{ body_FormData "avatar" "@/path/to/photo.jpg" "resume" "@/path/to/cv.pdf" "cover_letter" "@/path/to/letter.docx" }}'
YAML equivalent
url: http://example.com/api/upload
requests: 100
concurrency: 10
method: POST
body: |
    {{ body_FormData
       "avatar" "@/path/to/photo.jpg"
       "resume" "@/path/to/cv.pdf"
       "cover_letter" "@/path/to/letter.docx"
    }}

File from URL:

sarin -U http://example.com/api/upload -r 100 -c 10 \
  -M POST \
  -B '{{ body_FormData "image" "@https://example.com/photo.jpg" }}'
YAML equivalent
url: http://example.com/api/upload
requests: 100
concurrency: 10
method: POST
body: '{{ body_FormData "image" "@https://example.com/photo.jpg" }}'

Note: Files (local and remote) are cached in memory after the first read, so they are not re-read for every request.

Base64 encoded file in JSON body (local file):

sarin -U http://example.com/api/upload -r 100 -c 10 \
  -M POST \
  -H "Content-Type: application/json" \
  -B '{"file": "{{ file_Base64 "/path/to/file.pdf" }}", "filename": "document.pdf"}'
YAML equivalent
url: http://example.com/api/upload
requests: 100
concurrency: 10
method: POST
headers:
    Content-Type: application/json
body: '{"file": "{{ file_Base64 "/path/to/file.pdf" }}", "filename": "document.pdf"}'

Base64 encoded file in JSON body (remote URL):

sarin -U http://example.com/api/upload -r 100 -c 10 \
  -M POST \
  -H "Content-Type: application/json" \
  -B '{"image": "{{ file_Base64 "https://example.com/photo.jpg" }}", "filename": "photo.jpg"}'
YAML equivalent
url: http://example.com/api/upload
requests: 100
concurrency: 10
method: POST
headers:
    Content-Type: application/json
body: '{"image": "{{ file_Base64 "https://example.com/photo.jpg" }}", "filename": "photo.jpg"}'

Using Proxies

Single HTTP proxy:

sarin -U http://example.com -r 1000 -c 10 \
  -X http://proxy.example.com:8080
YAML equivalent
url: http://example.com
requests: 1000
concurrency: 10
proxy: http://proxy.example.com:8080

SOCKS5 proxy:

sarin -U http://example.com -r 1000 -c 10 \
  -X socks5://proxy.example.com:1080
YAML equivalent
url: http://example.com
requests: 1000
concurrency: 10
proxy: socks5://proxy.example.com:1080

Multiple proxies (randomly cycled):

sarin -U http://example.com -r 1000 -c 10 \
  -X http://proxy1.example.com:8080 \
  -X http://proxy2.example.com:8080 \
  -X socks5://proxy3.example.com:1080
YAML equivalent
url: http://example.com
requests: 1000
concurrency: 10
proxy:
    - http://proxy1.example.com:8080
    - http://proxy2.example.com:8080
    - socks5://proxy3.example.com:1080

Proxy with authentication:

sarin -U http://example.com -r 1000 -c 10 \
  -X http://user:password@proxy.example.com:8080
YAML equivalent
url: http://example.com
requests: 1000
concurrency: 10
proxy: http://user:password@proxy.example.com:8080

Output Formats

Table output (default):

sarin -U http://example.com -r 1000 -c 10 -o table
YAML equivalent
url: http://example.com
requests: 1000
concurrency: 10
output: table

JSON output (useful for parsing):

sarin -U http://example.com -r 1000 -c 10 -o json
YAML equivalent
url: http://example.com
requests: 1000
concurrency: 10
output: json

YAML output:

sarin -U http://example.com -r 1000 -c 10 -o yaml
YAML equivalent
url: http://example.com
requests: 1000
concurrency: 10
output: yaml

No output (minimal memory usage):

sarin -U http://example.com -r 1000 -c 10 -o none
YAML equivalent
url: http://example.com
requests: 1000
concurrency: 10
output: none

Quiet mode (hide progress bar):

sarin -U http://example.com -r 1000 -c 10 -q
YAML equivalent
url: http://example.com
requests: 1000
concurrency: 10
quiet: true

Docker Usage

Basic Docker usage:

docker run -it --rm aykhans/sarin -U http://example.com -r 1000 -c 10

With local config file:

docker run -it --rm -v $(pwd)/config.yaml:/config.yaml aykhans/sarin -f /config.yaml

With remote config file:

docker run -it --rm aykhans/sarin -f https://example.com/config.yaml

Interactive mode with TTY:

docker run --rm -it aykhans/sarin -U http://example.com -r 1000 -c 10

Dry Run Mode

Test your configuration without sending actual requests:

sarin -U http://example.com -r 10 -c 1 -z \
  -H "X-Request-ID: {{ fakeit_UUID }}" \
  -B '{"user": "{{ fakeit_Name }}"}'
YAML equivalent
url: http://example.com
requests: 10
concurrency: 1
dryRun: true
headers:
    X-Request-ID: "{{ fakeit_UUID }}"
body: '{"user": "{{ fakeit_Name }}"}'

This validates templates.

Show Configuration

Preview the merged configuration before running:

sarin -U http://example.com -r 1000 -c 10 \
  -H "Authorization: Bearer token" \
  -s
YAML equivalent
url: http://example.com
requests: 1000
concurrency: 10
showConfig: true
headers:
    Authorization: Bearer token

Scripting

Transform requests using Lua or JavaScript scripts. Scripts run after template rendering, before the request is sent.

Add a custom header with Lua:

sarin -U http://example.com/api -r 1000 -c 10 \
  -lua 'function transform(req) req.headers["X-Custom"] = "my-value" return req end'
YAML equivalent
url: http://example.com/api
requests: 1000
concurrency: 10
lua: |
    function transform(req)
        req.headers["X-Custom"] = "my-value"
        return req
    end

Modify request body with JavaScript:

sarin -U http://example.com/api/data -r 1000 -c 10 \
  -M POST \
  -H "Content-Type: application/json" \
  -B '{"name": "test"}' \
  -js 'function transform(req) { var body = JSON.parse(req.body); body.timestamp = Date.now(); req.body = JSON.stringify(body); return req; }'
YAML equivalent
url: http://example.com/api/data
requests: 1000
concurrency: 10
method: POST
headers:
    Content-Type: application/json
body: '{"name": "test"}'
js: |
    function transform(req) {
        var body = JSON.parse(req.body);
        body.timestamp = Date.now();
        req.body = JSON.stringify(body);
        return req;
    }

Load script from a file:

sarin -U http://example.com/api -r 1000 -c 10 \
  -lua @./scripts/transform.lua
YAML equivalent
url: http://example.com/api
requests: 1000
concurrency: 10
lua: "@./scripts/transform.lua"

Load script from a URL:

sarin -U http://example.com/api -r 1000 -c 10 \
  -js @https://example.com/scripts/transform.js
YAML equivalent
url: http://example.com/api
requests: 1000
concurrency: 10
js: "@https://example.com/scripts/transform.js"

Chain multiple scripts (Lua runs first, then JavaScript):

sarin -U http://example.com/api -r 1000 -c 10 \
  -lua @./scripts/auth.lua \
  -lua @./scripts/headers.lua \
  -js @./scripts/body.js
YAML equivalent
url: http://example.com/api
requests: 1000
concurrency: 10
lua:
    - "@./scripts/auth.lua"
    - "@./scripts/headers.lua"
js: "@./scripts/body.js"