Docs

Test modes

Two settings decide whether a conversion really reaches a platform:

  1. the destination mode (per project and provider): live, test or dry_run;
  2. the deployment ceiling X3_CONVERSIONS_MODE – the effective mode is the lower of the two (dry_run < test < live).
X3_ENVX3_CONVERSIONS_MODE unsetEffective ceiling
productionliveas configured per destination
development, testdry_runnothing is sent unless you set the ceiling to test

X3_CONVERSIONS_DISABLED=1 forces dry_run everywhere (kill switch). live is only possible with X3_ENV=production.

What each mode does

ModeMetaLinkedInGoogle Ads APIGoogle feedTikTok
livesent (a testEventCode, if set, still routes to Test events)sentsentlisted (feed) ¹sent
testsent with the testEventCode; without one dry_run ("test mode without testEventCode")no test mode – dry_run unless the base URL is a local mockvalidateOnly: truelisted (feed) ¹sent with the testEventCode
dry_runpayload built, PII-free summary loggedsamesamelisted (feed) ¹same

¹ The feed is pull-based: rows are listed in every mode, and Google only imports them once you create the HTTPS schedule. Conversions of test sessions are never listed.

In test, conversions from test sessions are sent too (they are skipped in live), so you can test with your own visits marked as test traffic.

Local provider mocks

Outside live, base URLs can point to mocks so the full pipeline – payload, response handling, retries – runs locally:

X3_CONVERSIONS_MODE=test
X3_META_BASE_URL=http://127.0.0.1:4315
X3_LINKEDIN_BASE_URL=http://127.0.0.1:4316
X3_GOOGLE_ADS_BASE_URL=http://127.0.0.1:4317
X3_TIKTOK_BASE_URL=http://127.0.0.1:4318

The overrides are ignored in live. The API's integration tests use exactly this setup.

Test the destination

curl -s -X POST https://<api-host>/v1/projects/<project>/destinations/meta/test \
  -H "Authorization: Bearer $X3_SECRET_KEY"

returns {provider, ok, status, detail, test}. The synthetic event never counts in reports.

From the onboarding and Claude

The onboarding's step Conversions senden has a "Test-Event senden" button per configured destination (POST /v1/projects/{project}/setup/test-conversion with {provider, testEventCode?}, project admins). It runs the same destination test in the provider's test mode – Meta and TikTok need a test event code (Events Manager → Test events; the stored testEventCode is used when you pass none), Google Ads validates without uploading, LinkedIn checks token and conversion rule –, shows the provider's answer and stores the result, so the step turns green. The MCP tool conversions_send_test does the same (it needs project:admin, so the onboarding's Claude Code key asks you to click the button instead). At most 6 tests per minute and project. A destination left in test mode keeps the warning mode_test until you switch it live.

Conversions from test visits (?x3_test=1) are stored with isTest and skipped by providers in live mode – see Test visits and conversions.

Dry runs of single conversions

conversions.create with "dryRun": true (REST, server SDK) or MCP conversions_mark with dry_run: true resolves the session and returns what would be stored ({"result": "dry_run", "wouldStore": …}) without storing or sending anything – useful to check matching before marking a WhatsApp lead.