20 KiB
Examples
This guide provides practical examples for common Sarin use cases.
Table of Contents
- Basic Usage
- Request-Based vs Duration-Based Tests
- Headers, Cookies, and Parameters
- Dynamic Requests with Templating
- Solving Captchas
- Request Bodies
- File Uploads
- Using Proxies
- Output Formats
- Runtime Logging
- Docker Usage
- Dry Run Mode
- Show Configuration
- Scripting
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_FormDataautomatically sets theContent-Typeheader tomultipart/form-datawith 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
Hide the progress bar:
sarin -U http://example.com -r 1000 -c 10 -p none
YAML equivalent
url: http://example.com
requests: 1000
concurrency: 10
progress: none
Runtime Logging
--log-level selects which runtime logs Sarin emits (comma-separated info and error, default error). error covers request and generation errors, info covers every completed response (status, duration, headers, body). Logs appear in the progress log box on an interactive terminal, go to stderr when piped, or go to a file with --log-file.
Log responses and errors:
sarin -U http://example.com -r 1000 -c 10 -l info,error
Write logs to a file (the progress bar stays on screen):
sarin -U http://example.com -r 1000 -c 10 -l info --log-file ./run.log
Capture logs while keeping results on stdout:
sarin -U http://example.com -r 1000 -l info -o json > stats.json 2> run.log
YAML equivalent
url: http://example.com
requests: 1000
concurrency: 10
logLevel: info,error
logFile: ./run.log
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"