Skip to main content

Datadog Synthetics

Convert recorded proxymock traffic into a Datadog Synthetics test suite — one multistep API test per snapshot, with all auth headers redacted into global variables and automatic variable chaining between steps.


Quick Start

# Export and publish directly to Datadog
proxymock export datadog-synthetics \
--in ./proxymock/snapshot-<id> \
--publish

# Output:
# Variables: datadog/snapshot-<id>.vars.md
# View: https://app.datadoghq.com/synthetics/details/<public-id>
# Run: datadog-ci synthetics run-tests --public-id <public-id>

Set your Datadog keys once via environment variables and they are picked up automatically:

export DATADOG_API_KEY=...
export DATADOG_APP_KEY=...

How It Works

Each export run targets one snapshot directory and writes three files into datadog/ alongside it:

FilePurpose
datadog/snapshot-<id>.jsonDatadog Synthetics bundle (the test definition)
datadog/snapshot-<id>.vars.mdGlobal variables to create before running

The bundle defaults to multistep mode: one Synthetics API test with one step per recorded request, ordered by capture time. Sensitive headers (Authorization, Cookie, etc.) are automatically replaced with {{ AUTHORIZATION_1 }} placeholders; the sidecar lists the values.

Output path

The output path is derived from --in automatically:

--in ./proxymock/snapshot-e77c31c9-fc5a-48c8-ad22-2000c9ce4574
→ datadog/snapshot-e77c31c9.json
datadog/snapshot-e77c31c9.vars.md

Each snapshot gets its own files, so re-exporting a different snapshot never overwrites previous work. Override with --out if needed.


Publish to Datadog

Add --publish to create or update the tests directly in your Datadog account:

proxymock export datadog-synthetics \
--in ./proxymock/snapshot-e77c31c9-fc5a-48c8-ad22-2000c9ce4574 \
--publish

On success the command prints the exact Datadog UI link and CLI run command:

multistep test with 8 step(s) written to datadog/snapshot-e77c31c9.json

Variables: datadog/snapshot-e77c31c9.vars.md
View: https://app.datadoghq.com/synthetics/details/abc-def-ghi
Run: datadog-ci synthetics run-tests --public-id abc-def-ghi

Keys

Pass keys via environment variables (recommended) or flags:

# via env (recommended)
export DATADOG_API_KEY=...
export DATADOG_APP_KEY=...

# or via flags
proxymock export datadog-synthetics --datadog-api-key ... --datadog-app-key ...

Global variables

By default --publish also creates or updates Datadog Synthetics global variables for any redacted headers. Disable with --publish-variables=false if you manage variables separately.

Re-publishing

Use --force to overwrite the local bundle file on subsequent runs:

proxymock export datadog-synthetics \
--in ./proxymock/snapshot-e77c31c9-fc5a-48c8-ad22-2000c9ce4574 \
--publish --force

Bundle Layouts

Multistep (default)

One Synthetics API test, one step per recorded request. Steps are ordered by capture time. The exporter wires automatic variable extraction between steps (see Automatic variable chaining).

proxymock export datadog-synthetics \
--in ./proxymock/snapshot-<id> \
--bundle multistep

Limit: Datadog caps multistep API tests at 10 steps. If the snapshot has more eligible requests, the first 10 are used and a warning is printed. Narrow the input with --limit or --service.

Single

One independent Synthetics API test per recorded request. No step cap.

proxymock export datadog-synthetics \
--in ./proxymock/snapshot-<id> \
--bundle single

When published, the output shows a --search command that finds all tests from the export by tag:

View: https://app.datadoghq.com/synthetics/tests?search=tag:proxymock_export_id:20260501t120000z
Run: datadog-ci synthetics run-tests --public-id id1 --public-id id2 ...

Global Variables

Sensitive headers are replaced with placeholders like {{ AUTHORIZATION_1 }}. The sidecar .vars.md lists the variable names, source headers, hosts, and sample values:

| Variable | Source header | Hosts | Sample value |
|---|---|---|---|
| `AUTHORIZATION_1` | `Authorization` | api.example.com | `Bearer eyJhbGci...` |
| `COOKIE_1` | `Cookie` | api.example.com | `session=abc123...` |

Default redacted headers: Authorization, Cookie, X-Api-Key, X-Auth-Token, Proxy-Authorization

Add more with --auth-header:

proxymock export datadog-synthetics --auth-header "X-My-Token"

If --publish is used, global variables are created automatically in Datadog. Otherwise, create them manually:

  1. Go to Synthetics → Settings → Global Variables → New Global Variable
  2. Name: AUTHORIZATION_1, mark Secure
  3. Value: the actual value from the sidecar

Automatic Variable Chaining

In multistep mode, the exporter scans each step's JSON response for string values that appear verbatim in a later step's request. Those values are automatically extracted and reused:

  • Step 1: POST /login → response contains "token": "abc123"
  • Step 2: GET /profile with Authorization: Bearer abc123
  • Result: Step 1 gets a $.token extractor named EXTRACTED_1; Step 2's header becomes Bearer {{ EXTRACTED_1 }}

Isolate a Single User Session

Use --filter to narrow the export to one session before building the test:

proxymock export datadog-synthetics \
--in ./proxymock/snapshot-<id> \
--bundle multistep \
--filter '(header[X-Session-ID] IS "alice-abc123")' \
--publish

Common filter predicates:

SourceFilter
Session header(header[X-Session-ID] IS "abc123")
Sticky cookie(header[Cookie] CONTAINS "sessionid=abc123")
JWT subject(header[Authorization] CONTAINS "sub=abc123")
Query param(query_param[session] IS "abc123")
HTTP method(command IS "POST")
URL path(url CONTAINS "/checkout")

Combine with AND / OR:

--filter '(header[X-Session-ID] IS "abc123") AND (url CONTAINS "/checkout")'

After export, the Skipped during export section in the .vars.md sidecar shows how many RRPairs were filtered. If all were skipped, the predicate matched nothing.


Flag Reference

FlagDefaultDescription
--in.Snapshot directory containing RRPair files
--outdatadog/<snapshot-id>.jsonOutput bundle path
--formatjsonjson or yaml
--bundlemultistepmultistep (one test, N steps) or single (one test per request)
--limit10Max requests to include (-1 for unlimited)
--inbound-onlytrueSkip outbound (proxied) requests
--serviceFilter by HTTP Host header (case-insensitive)
--filterSpeedscale traffic filter expression
--schemeForce http or https on all URLs
--name-prefixbasename of --inPrefix added to every test name
--tagExtra Datadog tags (repeatable)
--locationaws:us-east-1Datadog test location(s) (repeatable)
--tick-every0 (manual)Scheduled run interval (e.g. 60s, 1h)
--redact-headerstrueReplace sensitive headers with placeholders
--auth-headerExtra headers to redact (repeatable)
--allow-insecurefalseAllow self-signed certificates
--assert-response-timefalseAdd a soft 2000 ms response-time assertion
--publishfalseCreate/update tests directly in Datadog
--publish-variablestrueCreate/update global variables when publishing
--datadog-sitedatadoghq.comDatadog site (e.g. datadoghq.eu, us3.datadoghq.com)
--datadog-api-key$DATADOG_API_KEYDatadog API key
--datadog-app-key$DATADOG_APP_KEYDatadog application key
--forcefalseOverwrite existing output file

Common Patterns

Export a specific snapshot and publish

proxymock export datadog-synthetics \
--in ./proxymock/snapshot-e77c31c9-fc5a-48c8-ad22-2000c9ce4574 \
--publish --force

Export one service's traffic only

proxymock export datadog-synthetics \
--in ./proxymock/snapshot-<id> \
--service api.example.com \
--publish

Capture a customer-reported bug as a runnable test

proxymock export datadog-synthetics \
--in ./proxymock/snapshot-<id> \
--bundle multistep \
--filter '(header[X-Session-ID] IS "alice-abc123")' \
--publish

Schedule the test to run hourly

proxymock export datadog-synthetics \
--in ./proxymock/snapshot-<id> \
--tick-every 1h \
--publish

CI/CD pipeline

proxymock export datadog-synthetics \
--in ./proxymock/snapshot-<id> \
--name-prefix "$SERVICE_NAME-" \
--tag "env:$ENVIRONMENT" \
--tag "build:$CI_BUILD_NUMBER" \
--publish --force

Limitations

ConstraintValueNotes
Steps per multistep test10Datadog API limit; use --limit or --service to stay under
Request body size50 KBLarger bodies are omitted with tag body-omitted:too-large
Supported body typesJSON, XML, form-urlencoded, GraphQLBinary bodies are omitted

Troubleshooting

SymptomCauseFix
no eligible RRPairs to exportAll traffic was filteredCheck --service; try --inbound-only=false; inspect sidecar skip counts
warning: multistep test capped at 10 stepsSnapshot has >10 eligible requestsUse --limit or --service
Test fails with 401/403Missing global variablesCreate variables from .vars.md in Datadog
connection refusedWrong URL schemeUse --scheme https or --scheme http
400 Bad Request on publishStale/partial bundleRe-export with --force