Skip to main content

Create Experiment

POST/v2/project/{project_key}/create-experiment

Create a new A/B experiment for a project. The experiment is created in draft status by default.

Required fields

FieldTypeDescription
test_namestringDisplay name for the experiment
urlstringThe page URL being tested
variantsarrayOne or more treatment variant objects — do not include a "Control" entry (see Variants section)

Variants

The variants array contains only your treatment variants — the variations you want to test. Do not include a "Control" entry. The Control (the original, unmodified page) is always added automatically by the platform. Including a Control entry causes a duplicate Control to appear in the experiment setup UI.

data is always required

Every variant object must include "data": []. For code-based experiments, pass an empty array. Only visual editor experiments populate the data array with DOM mutations.

Code-based experiments (most common via API)

Use customCSS and/or customJS to inject changes. Pass data as an empty array.

[
{
"name": "Variant 1 - Red Button",
"customCSS": ".cta-button { background-color: #FF5733 !important; color: #fff !important; }",
"customJS": "document.querySelector('.cta').textContent = 'Get Started Free';",
"data": []
}
]

Visual DOM experiments

The data array holds DOM mutations produced by the Mida visual editor. Each entry replaces an element matched by a CSS selector with new HTML:

{
"name": "Variant 1",
"data": [
{
"target": "h1.hero-title",
"outerHTML": "<h1 class=\"hero-title\">New Headline Copy</h1>"
}
]
}

You can combine data mutations with customCSS/customJS in the same variant.

Goals

Pass primary_goal as an object to create the goal alongside the experiment. If a goal with the same goal_name and goal_type already exists for the project, it will be reused.

{
"primary_goal": {
"goal_name": "CTA Button Click",
"goal_type": "clickOnElement",
"goal_value": ".cta-button"
}
}

Reference an existing goal by key

{
"primary_goal_key": "my-existing-goal-key"
}

Goal types

goal_typeWhat it tracksgoal_value
clickOnElementClick on a CSS selector.buy-btn
clickOnTextClick on an element containing specific textAdd to cart
formSubmitForm submissionCSS selector of the <form>
pageviewURL path partial match/thank-you
pageviewExactExact URL matchhttps://example.com/thank-you
pageviewWildcardURL with * wildcards/products/*/confirm
pageviewRegexRegex URL pattern^/checkout/.+/success$
scriptCustom JS event — fires when your code calls the named eventEvent name string

Secondary goals

Pass secondary_goals as an array to track additional metrics alongside the primary goal:

{
"secondary_goals": [
{ "goal_name": "Newsletter Signup", "goal_type": "formSubmit", "goal_value": "#signup-form" },
{ "goal_name": "Pricing Page View", "goal_type": "pageview", "goal_value": "/pricing" }
]
}

Or reference existing goals by key array:

{ "secondary_goal_keys": ["signup-goal-key", "pricing-view-key"] }

Optional fields

Status

ValueBehaviour
9Draft — saved but not running (default)
1Live — starts traffic split immediately on creation
0Inactive — created in a deactivated state

Configuration

{
"configuration": {
"traffic_allocation": 100,
"confidence_interval": 95,
"start_test_date": "2026-04-01T00:00:00Z",
"end_test_date": "2026-04-30T23:59:59Z",
"completion_visitor": 1000,
"completion_conversion": 0,
"completion_after_period": 30,
"completion_stats_significant_flag": 1,
"is_autopilot": 0,
"is_mab": 0,
"bayesian": 1
}
}
FieldDefaultDescription
traffic_allocation100% of visitors included in the test (0–100)
confidence_interval95Statistical confidence threshold
start_test_datenullAuto-start date (ISO 8601)
end_test_datenullAuto-end date (ISO 8601)
completion_visitor0Stop when this many unique visitors reached (0 = disabled)
completion_conversion0Stop when this many conversions reached (0 = disabled)
completion_after_period0Stop after N days (0 = disabled)
completion_stats_significant_flag01 = auto-stop when statistical significance is reached
is_autopilot01 = enable autopilot (Mida auto-allocates traffic to the winning variant)
is_mab01 = enable Multi-Armed Bandit mode
bayesian11 = use Bayesian statistics; 0 = use frequentist statistics

Targeting

Restrict which visitors are included in the experiment. All rules are optional — omit any field to include all visitors of that type.

{
"targeting": {
"url_rules": [
{ "type": "contains", "value": "/pricing" },
{ "type": "exact", "value": "https://example.com/pricing" }
],
"device_rules": [
{ "type": "is", "value": "desktop" }
],
"country_rules": [
{ "type": "is", "value": "US" },
{ "type": "is", "value": "CA" }
]
}
}

url_rules — Filter by page URL:

typeBehaviour
containsURL contains the value string
exactURL exactly matches the value
starts_withURL starts with the value
regexURL matches the regex pattern

device_rules — Filter by device type. Supported value: "desktop", "mobile", "tablet".

country_rules — Filter by visitor country. Use ISO 3166-1 alpha-2 codes (e.g. "US", "GB", "DE").

Targeting after creation

After the experiment is created, you can update device, browser, and country targeting via the Update Experiment endpoint. URL-based targeting changes require recreating the experiment or using the dashboard.

Idempotency

Pass idempotency_key (or the x-idempotency-key header) to safely retry requests without creating duplicates. The same key returns the original response for 24 hours.

{ "idempotency_key": "deploy-2026-04-01-homepage-cta" }

Plan limits (free & Agency Lite)

For accounts on Sandbox (paid_plan 300) or Agency Lite (paid_plan 305), the API applies the same caps as the Mida app (specific internal company IDs may be exempt).

LimitValueWhen it applies
Concurrent live experiments2 per projectExperiments with status: 1, is_completed: 0, and not deploy experiments (is_deploy not set). Counted when you create as live (status: 1) or when you activate an experiment. Draft (9) or inactive (0) experiments do not count until they are live.
Goals per project2 goal profilesCreating new goals via inline primary_goal / secondary_goals, or any insert that would add another row to the project’s goal library. Referencing existing goals by key does not consume additional slots.

Paid plans above these tiers are not limited by these checks in the Public API.

Example

curl --request POST \
--url https://api-{region}.mida.so/v2/project/YOUR_PROJECT_KEY/create-experiment \
--header 'Authorization: Bearer YOUR_GENERATED_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"test_name": "Homepage CTA Button Color Test",
"status": 9,
"url": "https://example.com/",
"variants": [
{
"name": "Variant 1 - Red Button",
"customCSS": ".cta-button { background-color: #FF5733 !important; color: #fff !important; }",
"customJS": "",
"data": []
}
],
"primary_goal": {
"goal_name": "CTA Button Click",
"goal_type": "clickOnElement",
"goal_value": ".cta-button"
},
"configuration": {
"traffic_allocation": 100,
"confidence_interval": 95
}
}'

Success response

{
"success": true,
"status": 9,
"test_id": 28222,
"company_id": 1001,
"goal_profile_id": 8936,
"secondary_goals_count": 0,
"warnings": []
}

Save the test_id — you will use it in every subsequent call for this experiment.

No goal provided?

If you omit primary_goal and primary_goal_key, the experiment is still created but warnings will include "No goal payload provided. Draft was created without a primary goal mapping." You can add a goal later via the Update Experiment endpoint.

Error responses

StatusMeaning
400Missing required field (test_name, url, or variants), invalid status value, or malformed request body
401Invalid or missing API key
403Plan limit — too many concurrent live experiments for the project, or too many goals when creating new goal profiles
404Project not found
500Server error
Next step

After creating your experiment, use Update Experiment Status to launch it (status: 1), or Get Experiment Details to verify the experiment was created correctly.