Create a single fact metric
curl -X POST 'https://api.growthbook.io/api/v1/fact-metrics' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"name":"Purchased","metricType":"proportion","numerator":{"factTableId":"ftb_abc123","column":"$$distinctUsers","filters":[]},"priorSettings":{"override":false,"proper":false,"mean":0,"stddev":0.3}}'import requests
url = "https://api.growthbook.io/api/v1/fact-metrics"
payload = {
"name": "<string>",
"description": "<string>",
"owner": "<string>",
"projects": ["<string>"],
"tags": ["<string>"],
"numerator": {
"factTableId": "<string>",
"column": "<string>",
"filters": ["<string>"],
"inlineFilters": {},
"rowFilters": [
{
"values": ["<string>"],
"column": "<string>"
}
],
"aggregateFilterColumn": "<string>",
"aggregateFilter": "<string>"
},
"inverse": True,
"riskThresholdSuccess": 1,
"riskThresholdDanger": 1,
"displayAsPercentage": True,
"minPercentChange": 1,
"maxPercentChange": 1,
"minSampleSize": 1,
"targetMDE": 1,
"metricAutoSlices": ["<string>"],
"replaces": ["<string>"]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
description: '<string>',
owner: '<string>',
projects: ['<string>'],
tags: ['<string>'],
numerator: {
factTableId: '<string>',
column: '<string>',
filters: ['<string>'],
inlineFilters: {},
rowFilters: [{values: ['<string>'], column: '<string>'}],
aggregateFilterColumn: '<string>',
aggregateFilter: '<string>'
},
inverse: true,
riskThresholdSuccess: 1,
riskThresholdDanger: 1,
displayAsPercentage: true,
minPercentChange: 1,
maxPercentChange: 1,
minSampleSize: 1,
targetMDE: 1,
metricAutoSlices: ['<string>'],
replaces: ['<string>']
})
};
fetch('https://api.growthbook.io/api/v1/fact-metrics', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.growthbook.io/api/v1/fact-metrics",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'description' => '<string>',
'owner' => '<string>',
'projects' => [
'<string>'
],
'tags' => [
'<string>'
],
'numerator' => [
'factTableId' => '<string>',
'column' => '<string>',
'filters' => [
'<string>'
],
'inlineFilters' => [
],
'rowFilters' => [
[
'values' => [
'<string>'
],
'column' => '<string>'
]
],
'aggregateFilterColumn' => '<string>',
'aggregateFilter' => '<string>'
],
'inverse' => true,
'riskThresholdSuccess' => 1,
'riskThresholdDanger' => 1,
'displayAsPercentage' => true,
'minPercentChange' => 1,
'maxPercentChange' => 1,
'minSampleSize' => 1,
'targetMDE' => 1,
'metricAutoSlices' => [
'<string>'
],
'replaces' => [
'<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.growthbook.io/api/v1/fact-metrics"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"owner\": \"<string>\",\n \"projects\": [\n \"<string>\"\n ],\n \"tags\": [\n \"<string>\"\n ],\n \"numerator\": {\n \"factTableId\": \"<string>\",\n \"column\": \"<string>\",\n \"filters\": [\n \"<string>\"\n ],\n \"inlineFilters\": {},\n \"rowFilters\": [\n {\n \"values\": [\n \"<string>\"\n ],\n \"column\": \"<string>\"\n }\n ],\n \"aggregateFilterColumn\": \"<string>\",\n \"aggregateFilter\": \"<string>\"\n },\n \"inverse\": true,\n \"riskThresholdSuccess\": 1,\n \"riskThresholdDanger\": 1,\n \"displayAsPercentage\": true,\n \"minPercentChange\": 1,\n \"maxPercentChange\": 1,\n \"minSampleSize\": 1,\n \"targetMDE\": 1,\n \"metricAutoSlices\": [\n \"<string>\"\n ],\n \"replaces\": [\n \"<string>\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.growthbook.io/api/v1/fact-metrics")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"owner\": \"<string>\",\n \"projects\": [\n \"<string>\"\n ],\n \"tags\": [\n \"<string>\"\n ],\n \"numerator\": {\n \"factTableId\": \"<string>\",\n \"column\": \"<string>\",\n \"filters\": [\n \"<string>\"\n ],\n \"inlineFilters\": {},\n \"rowFilters\": [\n {\n \"values\": [\n \"<string>\"\n ],\n \"column\": \"<string>\"\n }\n ],\n \"aggregateFilterColumn\": \"<string>\",\n \"aggregateFilter\": \"<string>\"\n },\n \"inverse\": true,\n \"riskThresholdSuccess\": 1,\n \"riskThresholdDanger\": 1,\n \"displayAsPercentage\": true,\n \"minPercentChange\": 1,\n \"maxPercentChange\": 1,\n \"minSampleSize\": 1,\n \"targetMDE\": 1,\n \"metricAutoSlices\": [\n \"<string>\"\n ],\n \"replaces\": [\n \"<string>\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.growthbook.io/api/v1/fact-metrics")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"owner\": \"<string>\",\n \"projects\": [\n \"<string>\"\n ],\n \"tags\": [\n \"<string>\"\n ],\n \"numerator\": {\n \"factTableId\": \"<string>\",\n \"column\": \"<string>\",\n \"filters\": [\n \"<string>\"\n ],\n \"inlineFilters\": {},\n \"rowFilters\": [\n {\n \"values\": [\n \"<string>\"\n ],\n \"column\": \"<string>\"\n }\n ],\n \"aggregateFilterColumn\": \"<string>\",\n \"aggregateFilter\": \"<string>\"\n },\n \"inverse\": true,\n \"riskThresholdSuccess\": 1,\n \"riskThresholdDanger\": 1,\n \"displayAsPercentage\": true,\n \"minPercentChange\": 1,\n \"maxPercentChange\": 1,\n \"minSampleSize\": 1,\n \"targetMDE\": 1,\n \"metricAutoSlices\": [\n \"<string>\"\n ],\n \"replaces\": [\n \"<string>\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"factMetric": {
"id": "<string>",
"name": "<string>",
"description": "<string>",
"owner": "<string>",
"projects": [
"<string>"
],
"tags": [
"<string>"
],
"datasource": "<string>",
"metricType": "proportion",
"inverse": true,
"cappingSettings": {
"type": "none",
"value": 123,
"ignoreZeros": true
},
"windowSettings": {
"type": "none",
"delayValue": 123,
"delayUnit": "minutes",
"windowValue": 123,
"windowUnit": "minutes"
},
"priorSettings": {
"override": true,
"proper": true,
"mean": 123,
"stddev": 123
},
"regressionAdjustmentSettings": {
"override": true,
"enabled": true,
"days": 123
},
"riskThresholdSuccess": 123,
"riskThresholdDanger": 123,
"minPercentChange": 123,
"maxPercentChange": 123,
"minSampleSize": 123,
"targetMDE": 123,
"managedBy": "",
"dateCreated": "2023-11-07T05:31:56Z",
"dateUpdated": "2023-11-07T05:31:56Z",
"ownerEmail": "<string>",
"numerator": {
"factTableId": "<string>",
"column": "<string>",
"aggregation": "sum",
"filters": [
"<string>"
],
"inlineFilters": {},
"rowFilters": [
{
"operator": "=",
"values": [
"<string>"
],
"column": "<string>"
}
],
"aggregateFilterColumn": "<string>",
"aggregateFilter": "<string>"
},
"denominator": {
"factTableId": "<string>",
"column": "<string>",
"filters": [
"<string>"
],
"inlineFilters": {},
"rowFilters": [
{
"operator": "=",
"values": [
"<string>"
],
"column": "<string>"
}
]
},
"quantileSettings": {
"type": "event",
"ignoreZeros": true,
"quantile": 0.5,
"quantileEventCountColumn": "<string>"
},
"funnelSettings": {
"steps": [
{
"name": "<string>",
"factTableId": "<string>",
"rowFilters": [
{
"operator": "=",
"values": [
"<string>"
],
"column": "<string>"
}
],
"optional": true,
"conversionWindow": {
"unit": "weeks",
"value": 123
}
}
],
"ordering": "sequential",
"concurrencyWindowSeconds": 1
},
"displayAsPercentage": true,
"archived": true,
"metricAutoSlices": [
"<string>"
],
"replaces": [
"<string>"
]
}
}Authorizations
If using Bearer auth, pass the Secret Key as the token:
curl https://api.growthbook.io/api/v1/features -H "Authorization: Bearer secret_abc123DEF456"
Body
proportion, retention, mean, quantile, ratio, dailyParticipation, funnel 10000The userId or email address of the owner. If an email address is provided, it will be used to look up the userId of the matching organization member. If an ID is provided, it will be validated as existing in the organization.
Show child attributes
Show child attributes
Only when metricType is 'ratio'
Show child attributes
Show child attributes
Set to true for things like Bounce Rate, where you want the metric to decrease
Controls the settings for quantile metrics (mandatory if metricType is "quantile")
Show child attributes
Show child attributes
Funnel metric settings (required when metricType is "funnel")
Show child attributes
Show child attributes
Controls how outliers are handled
Show child attributes
Show child attributes
Controls the conversion window for the metric
Show child attributes
Show child attributes
Controls the bayesian prior for the metric. If omitted, organization defaults will be used.
Show child attributes
Show child attributes
Controls the regression adjustment (CUPED) settings for the metric
Show child attributes
Show child attributes
No longer used. Threshold for Risk to be considered low enough, as a proportion (e.g. put 0.0025 for 0.25%).
Must be a non-negative number and must not be higher than riskThresholdDanger.
x >= 0No longer used. Threshold for Risk to be considered too high, as a proportion (e.g. put 0.0125 for 1.25%).
Must be a non-negative number.
x >= 0If true and the metric is a ratio or dailyParticipation metric, variation means will be displayed as a percentage. Defaults to true for dailyParticipation metrics and false for ratio metrics.
Minimum percent change to consider uplift significant, as a proportion (e.g. put 0.005 for 0.5%)
x >= 0Maximum percent change to consider uplift significant, as a proportion (e.g. put 0.5 for 50%)
x >= 0x >= 0The percentage change that you want to reliably detect before ending an experiment, as a proportion (e.g. put 0.1 for 10%). This is used to estimate the "Days Left" for running experiments.
x >= 0Set this to "api" to disable editing in the GrowthBook UI
, api, admin Array of slice column names that will be automatically included in metric analysis. This is an enterprise feature.
Ids of older metrics (legacy or fact) that this metric supersedes, for example the legacy metric it was migrated from. Cannot include this metric's own id. Informational only - GrowthBook uses it to link the old and new definitions in the UI and to keep showing results from a snapshot that was created before an experiment switched to this metric. This field can only be set through the API.
Response
Resource created
Show child attributes
Show child attributes
Was this page helpful?
curl -X POST 'https://api.growthbook.io/api/v1/fact-metrics' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"name":"Purchased","metricType":"proportion","numerator":{"factTableId":"ftb_abc123","column":"$$distinctUsers","filters":[]},"priorSettings":{"override":false,"proper":false,"mean":0,"stddev":0.3}}'import requests
url = "https://api.growthbook.io/api/v1/fact-metrics"
payload = {
"name": "<string>",
"description": "<string>",
"owner": "<string>",
"projects": ["<string>"],
"tags": ["<string>"],
"numerator": {
"factTableId": "<string>",
"column": "<string>",
"filters": ["<string>"],
"inlineFilters": {},
"rowFilters": [
{
"values": ["<string>"],
"column": "<string>"
}
],
"aggregateFilterColumn": "<string>",
"aggregateFilter": "<string>"
},
"inverse": True,
"riskThresholdSuccess": 1,
"riskThresholdDanger": 1,
"displayAsPercentage": True,
"minPercentChange": 1,
"maxPercentChange": 1,
"minSampleSize": 1,
"targetMDE": 1,
"metricAutoSlices": ["<string>"],
"replaces": ["<string>"]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: '<string>',
description: '<string>',
owner: '<string>',
projects: ['<string>'],
tags: ['<string>'],
numerator: {
factTableId: '<string>',
column: '<string>',
filters: ['<string>'],
inlineFilters: {},
rowFilters: [{values: ['<string>'], column: '<string>'}],
aggregateFilterColumn: '<string>',
aggregateFilter: '<string>'
},
inverse: true,
riskThresholdSuccess: 1,
riskThresholdDanger: 1,
displayAsPercentage: true,
minPercentChange: 1,
maxPercentChange: 1,
minSampleSize: 1,
targetMDE: 1,
metricAutoSlices: ['<string>'],
replaces: ['<string>']
})
};
fetch('https://api.growthbook.io/api/v1/fact-metrics', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.growthbook.io/api/v1/fact-metrics",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'description' => '<string>',
'owner' => '<string>',
'projects' => [
'<string>'
],
'tags' => [
'<string>'
],
'numerator' => [
'factTableId' => '<string>',
'column' => '<string>',
'filters' => [
'<string>'
],
'inlineFilters' => [
],
'rowFilters' => [
[
'values' => [
'<string>'
],
'column' => '<string>'
]
],
'aggregateFilterColumn' => '<string>',
'aggregateFilter' => '<string>'
],
'inverse' => true,
'riskThresholdSuccess' => 1,
'riskThresholdDanger' => 1,
'displayAsPercentage' => true,
'minPercentChange' => 1,
'maxPercentChange' => 1,
'minSampleSize' => 1,
'targetMDE' => 1,
'metricAutoSlices' => [
'<string>'
],
'replaces' => [
'<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.growthbook.io/api/v1/fact-metrics"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"owner\": \"<string>\",\n \"projects\": [\n \"<string>\"\n ],\n \"tags\": [\n \"<string>\"\n ],\n \"numerator\": {\n \"factTableId\": \"<string>\",\n \"column\": \"<string>\",\n \"filters\": [\n \"<string>\"\n ],\n \"inlineFilters\": {},\n \"rowFilters\": [\n {\n \"values\": [\n \"<string>\"\n ],\n \"column\": \"<string>\"\n }\n ],\n \"aggregateFilterColumn\": \"<string>\",\n \"aggregateFilter\": \"<string>\"\n },\n \"inverse\": true,\n \"riskThresholdSuccess\": 1,\n \"riskThresholdDanger\": 1,\n \"displayAsPercentage\": true,\n \"minPercentChange\": 1,\n \"maxPercentChange\": 1,\n \"minSampleSize\": 1,\n \"targetMDE\": 1,\n \"metricAutoSlices\": [\n \"<string>\"\n ],\n \"replaces\": [\n \"<string>\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.growthbook.io/api/v1/fact-metrics")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"owner\": \"<string>\",\n \"projects\": [\n \"<string>\"\n ],\n \"tags\": [\n \"<string>\"\n ],\n \"numerator\": {\n \"factTableId\": \"<string>\",\n \"column\": \"<string>\",\n \"filters\": [\n \"<string>\"\n ],\n \"inlineFilters\": {},\n \"rowFilters\": [\n {\n \"values\": [\n \"<string>\"\n ],\n \"column\": \"<string>\"\n }\n ],\n \"aggregateFilterColumn\": \"<string>\",\n \"aggregateFilter\": \"<string>\"\n },\n \"inverse\": true,\n \"riskThresholdSuccess\": 1,\n \"riskThresholdDanger\": 1,\n \"displayAsPercentage\": true,\n \"minPercentChange\": 1,\n \"maxPercentChange\": 1,\n \"minSampleSize\": 1,\n \"targetMDE\": 1,\n \"metricAutoSlices\": [\n \"<string>\"\n ],\n \"replaces\": [\n \"<string>\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.growthbook.io/api/v1/fact-metrics")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"owner\": \"<string>\",\n \"projects\": [\n \"<string>\"\n ],\n \"tags\": [\n \"<string>\"\n ],\n \"numerator\": {\n \"factTableId\": \"<string>\",\n \"column\": \"<string>\",\n \"filters\": [\n \"<string>\"\n ],\n \"inlineFilters\": {},\n \"rowFilters\": [\n {\n \"values\": [\n \"<string>\"\n ],\n \"column\": \"<string>\"\n }\n ],\n \"aggregateFilterColumn\": \"<string>\",\n \"aggregateFilter\": \"<string>\"\n },\n \"inverse\": true,\n \"riskThresholdSuccess\": 1,\n \"riskThresholdDanger\": 1,\n \"displayAsPercentage\": true,\n \"minPercentChange\": 1,\n \"maxPercentChange\": 1,\n \"minSampleSize\": 1,\n \"targetMDE\": 1,\n \"metricAutoSlices\": [\n \"<string>\"\n ],\n \"replaces\": [\n \"<string>\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"factMetric": {
"id": "<string>",
"name": "<string>",
"description": "<string>",
"owner": "<string>",
"projects": [
"<string>"
],
"tags": [
"<string>"
],
"datasource": "<string>",
"metricType": "proportion",
"inverse": true,
"cappingSettings": {
"type": "none",
"value": 123,
"ignoreZeros": true
},
"windowSettings": {
"type": "none",
"delayValue": 123,
"delayUnit": "minutes",
"windowValue": 123,
"windowUnit": "minutes"
},
"priorSettings": {
"override": true,
"proper": true,
"mean": 123,
"stddev": 123
},
"regressionAdjustmentSettings": {
"override": true,
"enabled": true,
"days": 123
},
"riskThresholdSuccess": 123,
"riskThresholdDanger": 123,
"minPercentChange": 123,
"maxPercentChange": 123,
"minSampleSize": 123,
"targetMDE": 123,
"managedBy": "",
"dateCreated": "2023-11-07T05:31:56Z",
"dateUpdated": "2023-11-07T05:31:56Z",
"ownerEmail": "<string>",
"numerator": {
"factTableId": "<string>",
"column": "<string>",
"aggregation": "sum",
"filters": [
"<string>"
],
"inlineFilters": {},
"rowFilters": [
{
"operator": "=",
"values": [
"<string>"
],
"column": "<string>"
}
],
"aggregateFilterColumn": "<string>",
"aggregateFilter": "<string>"
},
"denominator": {
"factTableId": "<string>",
"column": "<string>",
"filters": [
"<string>"
],
"inlineFilters": {},
"rowFilters": [
{
"operator": "=",
"values": [
"<string>"
],
"column": "<string>"
}
]
},
"quantileSettings": {
"type": "event",
"ignoreZeros": true,
"quantile": 0.5,
"quantileEventCountColumn": "<string>"
},
"funnelSettings": {
"steps": [
{
"name": "<string>",
"factTableId": "<string>",
"rowFilters": [
{
"operator": "=",
"values": [
"<string>"
],
"column": "<string>"
}
],
"optional": true,
"conversionWindow": {
"unit": "weeks",
"value": 123
}
}
],
"ordering": "sequential",
"concurrencyWindowSeconds": 1
},
"displayAsPercentage": true,
"archived": true,
"metricAutoSlices": [
"<string>"
],
"replaces": [
"<string>"
]
}
}
