Experiment lifecycle commands
Create, list, inspect, read results, pause, complete, and delete Apex experiments from the CLI.
Human results output names each goal’s counting basis. See Metric definitions for the exact rules.
The experiments group covers experiment CRUD and lifecycle actions. Use IDs or slugs for reads and lifecycle commands. The alias apex exp is available for the group, and apex experiments list also has the ls alias.
List and inspect
apex experiments list --status draft --limit 20
apex experiments list --url https://shop.example/products/example --json
apex experiments get homepage-hero-test
apex experiments results homepage-hero-test --currency EUR| Command | Arguments | Flags | Notes |
|---|---|---|---|
apex experiments list | None | --status <status>, --url <absolute-url>, --limit <n>, --include-archived, --fields <list>, --full | Summary by default; status and effective URL targeting are filtered server-side. Experiments without URL rules match every URL. Select columns with --fields or request full details with --full. |
apex experiments get | <id-or-slug> | None beyond global flags | A plain slug and slug:<slug> both resolve by slug. |
apex experiments results | <id-or-slug> | --currency <code>, --wait <seconds> | Returns experiment totals, arms, decision, metrics, series, computed time/source, and warnings. Cold results builds retry for up to 120 seconds by default; use --wait 0 to disable retries. |
Use JSON mode for scripts:
apex experiments results homepage-hero-test --currency EUR --jsonLifecycle readback
Create and get JSON always include these keys; they are never omitted. All three
are null on a fresh draft. Set values are ISO-8601 UTC timestamps in the exact
YYYY-MM-DDTHH:mm:ss.sssZ form.
| Key | Set by | Cleared by |
|---|---|---|
started_at | Dashboard launch | Revert to draft |
scheduled_start_at | Launch scheduling | Schedule cancellation or QA reopen |
qa_approved_at | QA approval | QA reopen |
Integrations reading a schedule field must read scheduled_start_at.
Create a draft
apex experiments create \
--name "Homepage hero trust copy" \
--slug homepage-hero-trust-copy \
--description "Tests clearer proof copy in the homepage hero." \
--page-url "https://shop.example/products/hero-bundle" \
--audience segment_vip \
--goal "new:type=click,selector=.hero-cta,name=Hero CTA click,page=<page-id>" \
--traffic 25 \
--preview| Flag | Required | Behavior |
|---|---|---|
--name <name> | Headless: yes | Experiment display name. In a terminal the wizard asks for it when omitted. |
--slug <slug> | No | URL-safe slug for GitOps and slug-based lookup. |
--description <desc> | No | Draft description. |
--counting-type <type> | No | standard (default), setup_test, aa_test, or non_program. |
--type <type> | No | mutation (default) or flag-gated redirect. |
--source-url <pattern> | Redirect: yes | Positive source URL targeting rule. Repeat for multiple exact URLs, paths, or wildcard patterns. The first absolute HTTP(S) value also becomes the preview/store URL. |
--page-url <pattern> | No | Page URL targeting rule. Repeat for multiple patterns. This is additive with the existing --source-url spelling. |
--audience <segment-id|new:@file.json> | No | Include an existing segment, or create one first from the same JSON body accepted by apex segments create. Repeat for multiple audiences. |
--goal <goal-id|new:fields> | No | Attach an existing goal, or create one from comma-separated type, name, and goal fields such as selector. Field keys are the v1 goal fields; page is accepted for page_id and hyphenated spellings such as text-match and url-pattern are accepted too. Click goals are page-scoped in v1, so an inline type=click goal needs page=<page-id> (list them with apex pages list); in a terminal the wizard asks for the page when it is missing. Wrap a value that contains commas in double quotes, for example selector=".buy,.checkout". Custom goals cannot use reserved event names such as pageview or purchase (add_to_cart and checkout_started are allowed). Every inline goal and audience file is checked before anything is created. Repeat for multiple goals; the first is primary. |
--destination <url> | Redirect: yes | HTTP(S) destination for one treatment variation. Repeat to create multiple equally weighted treatments. Invalid or missing redirect destinations fail validation. |
--traffic <pct> | No | Percentage input converted to API traffic allocation. Defaults to 100. |
--preview | No | Print a QA URL pinned to the first non-control variation. Needs an absolute HTTP(S) --page-url/--source-url to build the link, checked before anything is created, so a run that cannot be previewed fails validation instead of leaving an experiment behind. JSON output includes it as preview_url. |
--yes | No | Disable wizard prompts. Missing required values then return validation exit code 3. |
In an interactive terminal without --yes, omitted values are collected by a wizard that lists available audiences and goals and permits none. Headless callers should provide --name and use flags for the desired targeting and goals. New audiences are created first, then new goals, followed by a single experiment request. If that final request fails, the error lists resource IDs that were already created so callers can clean them up deliberately.
JSON output's data payload has the shape { experiment, segments, goals, preview_url, preview_note }; segments and goals contain resources created by this invocation. Inline goal bodies are parsed and completed before the first write, so a malformed or page-less new: goal fails validation without creating anything. When the created experiment has no treatment variation yet, the command still succeeds and reports why the link is missing in preview_note.
Create a redirect experiment with a control on the source page and one treatment on the destination:
apex experiments create \
--name "Product page split URL" \
--type redirect \
--source-url "https://shop.example/products/source" \
--destination "https://landing.example/products/treatment"Redirect creation preserves the public v1 gates: the shop must have redirect
tests enabled, at least one positive source rule and treatment destination are
required, and destinations must be HTTP(S). A destination must not match the
source targeting unless it is the same page with added or changed query
parameters, such as ?view=alternate. API gate failures use the standard JSON
error envelope and exit codes.
The filesystem and public v1 contracts permit a redirect treatment to retain mutations, CSS, or JavaScript. Those artifacts are source-page-only; Apex keeps the assignment active on the destination for attribution but does not apply the source-authored artifacts there. Filesystem plans warn when a treatment mixes these artifacts with a destination.
Update
apex experiments update homepage-hero-trust-copy --counting-type aa_test --json
apex experiments update homepage-hero-trust-copy --counting-type non_program --results-weekdays mon,tue --results-timezone Europe/Berlin --json--counting-type accepts standard, setup_test, aa_test, or non_program.
It works alone or with the results weekday window. When setting a window,
--results-weekdays and --results-timezone must travel together; use
--clear-results-weekdays to clear it. Omitting classification leaves it unchanged.
Text output reports the classification stored by the server. API edits are draft-only;
the CLI passes through the server error for other statuses.
Lifecycle verbs
apex experiments pause homepage-hero-trust-copy
apex experiments complete homepage-hero-trust-copy| Command | Arguments | Behavior |
|---|---|---|
apex experiments pause | <id-or-slug> | Requests the API to pause a running experiment. |
apex experiments complete | <id-or-slug> | Requests the API to complete or stop the experiment. |
Starting traffic is dashboard-only so the approval gates remain visible. Lifecycle validation for pause and complete is owned by Apex; if the API rejects a state transition, the CLI reports the API error and exits non-zero.
Delete
apex experiments delete homepage-hero-trust-copy
apex experiments delete homepage-hero-trust-copy --force --jsonapex experiments delete prompts before deleting in an interactive terminal. In non-TTY mode, deletion returns confirmation-required exit code 4 unless you pass --force.
Launch in the dashboard
The CLI has no experiments start command. Launch is dashboard-only so Apex can keep approval and readiness gates visible; CLI lifecycle commands cannot bypass QA or business approval.
Experiment references accept an ID, slug, or test key (for example BIO-085). Test keys resolve within the selected shop; use --shop <shop-id> to change it. Bare lowercase references remain slugs.
Create and get JSON include dashboard_url (null when no shop is known), and text output
prints a Dashboard line. The link opens the experiment in the right shop, requires a
signed-in dashboard user, and switches that user's active shop. The response's
shop_id takes precedence over the CLI's pinned shop context.
Troubleshooting
Results verification: When publishing or interpreting material results changes, require revision-specific live-model comparison evidence and an author explanation.
- Experiment not found: check whether you passed an ID, slug, or
slug:<slug>. - Lifecycle action rejected: inspect the API error in JSON mode for readiness, status, or permission details.
- Delete fails in automation: rerun with
--forceonly after confirming the target experiment.
Related pages
- Template tests on Shopify
- Experiment filesystem and QA commands
- Push and GitOps with
.drip.config.ts - CLI commands, JSON, and exit codes
List summaries and selected fields
apex experiments list --json returns code-free summaries with targeting_urls
and variation_count. It omits targeting objects, variations, and goals.
Use --full --json when you need the full configuration, including code.
apex experiments list --fields id,test_key,name,status --json
apex experiments list --fields status,name
apex experiments list --full --fields id,name,targeting --json--fields selects top-level keys. Requesting a field outside the summary view
automatically switches the server to full details, so --full is not required.
Table columns follow the requested order; JSON always retains id. Unknown keys
return an error listing allowed keys. --full leaves the default table columns unchanged.
The existing CR-011 filters remain the way to narrow the experiment set;
view and field selection change row content, not which experiments match.
Direct API consumers retain the full view by default; the CLI sends view=summary.
Summary timestamps include created_at and archived_at; experiments have no updated_at field.
Explaining a number
Run apex experiments results GET-023 --explain --samples to compare raw events
with reported results. Use --goal <id-or-event-key> for a specific attached goal,
--currency EUR for money, or --order <order-key> for an order's label trail
across arms. --json preserves the API body, including its data envelope.
Each row gets one label, in this order: bot, qa_traffic, outside_window,
duplicate, before_exposure, exposed_before_window_only, filtered_by_goal,
or counted. These mean bot traffic, QA traffic, events outside the result window,
repeated event/order identity, conversions before the first in-window exposure,
visitors exposed only before the window, unmatched or unevaluable goal conditions,
and included events respectively. Non-purchase events without an eligible exposure,
and placeholder visitor IDs on exposures and non-purchase goals, are also
filtered_by_goal; purchases keep placeholder IDs, as the results pipeline does. An
order belongs to the variation on its earliest row; if that variation is no longer
part of the test, the order appears under other_variations. An order without any
tracked exposure carries arm_only: true when counted.
The table shows counted, reported, and residual (counted minus reported) for each
arm. This is a diagnostic classifier, not the canonical results pipeline. A nonzero
residual exposes a disagreement between the diagnostic rules and the results
pipeline; it is never forced to zero. Unavailable reported values or currency conversion
produce an unavailable residual. The scan includes 30 days before the result window;
older sightings cannot be diagnosed. Exposure rows are aggregated without a raw-row
cap, so visitor counts remain exact; visitor samples are not provided. Variations
missing from the results model appear in other_variations and are excluded from
the arm diagnostics.
Conversion scans above 100,000 rows return diagnostic_row_limit with the observed
row count and a hint to narrow by --order. An order lookup restricts candidates to
that order and exposures to its visitors. Because it covers one order, it shows
no reported value or residual; run without --order to compare with the reported
numbers.
Timeouts and oversized candidate scans return errors, never partial results. See metric definitions.
Profit per visitor for commerce tests and checkout-owned tests
apex experiments results includes Profit per visitor (CM1) for commerce tests and checkout-owned tests with attributed orders. It reports exposed visitors, attributed orders, CM1
per visitor, the range versus control, the verdict, cost coverage, and failed
trust checks. Unsupported money is -, not zero. A pending or unavailable
analytics read prints its degraded reason instead of an empty results table.
Checkout-owned tests measure orders from visitors who saw the checkout message and receive the supplementary CM1 section when they have attributed orders. Other non-commerce tests return commerce_results: null. An unavailable supplementary section on a checkout-owned test does not mark the analytics as degraded.