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