> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.getunleash.io/api/client-bulk-metrics/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.getunleash.io/_mcp/server. # Send metrics in bulk POST https://app.unleash-instance.example.com/api/client/metrics/bulk Content-Type: application/json This operation accepts batched metrics from any client. Metrics will be inserted into Unleash's metrics storage Reference: https://docs.getunleash.io/api/client-bulk-metrics ## Authentication - `Authorization` header (required) — API key needed to access this API - `Authorization` header (bearer token, required) — API key needed to access this API, in Bearer token format ## Request ### Body (application/json) This endpoint expects a bulkMetricsSchema. - `applications` (list of bulkRegistrationSchema, required) — A list of applications registered by an Unleash SDK - `metrics` (list of clientMetricsEnvSchema, required) — a list of client usage metrics registered by downstream providers. (Typically Unleash Edge) - `impactMetrics` (list of impactMetricsSchema, optional) — a list of custom impact metrics registered by downstream providers. (Typically Unleash Edge) - `seenTokens` (list of string, optional) — A list of API tokens observed by downstream providers. (Typically Unleash Edge) ## Response ### 202 This response has no body. ## Errors ### 400 Bad Request Error The request data does not match what we expect. - `id` (string, optional) — The ID of the error instance - `name` (string, optional) — The name of the error kind - `message` (string, optional) — A description of what went wrong. ### 413 Content Too Large Error The request body is larger than what we accept. By default we only accept bodies of 100kB or less - `id` (string, optional) — The ID of the error instance - `name` (string, optional) — The name of the error kind - `message` (string, optional) — A description of what went wrong. ### 415 Unsupported Media Type Error The operation does not support request payloads of the provided type. Please ensure that you're using one of the listed payload types and that you have specified the right content type in the "content-type" header. - `id` (string, optional) — The ID of the error instance - `name` (string, optional) — The name of the error kind - `message` (string, optional) — A description of what went wrong. ## Types ### bulkRegistrationSchema An application registration. Defines the format POSTed by our backend SDKs when they're starting up - `appName` (string, required) — The name of the application that is evaluating toggles - `environment` (string, required) — Which environment the application is running in - `instanceId` (string, required) — A [(somewhat) unique identifier](https://docs.getunleash.io/sdks/node#advanced-usage) for the application - `connectVia` (list of BulkRegistrationSchemaConnectViaItems, optional) — A list of applications this app registration has been registered through. If connected directly to Unleash, this is an empty list. This can be used in later visualizations to tell how many levels of proxy or Edge instances our SDKs have connected through - `interval` (double, optional) — How often (in seconds) the application refreshes its features - `started` (dateSchema, optional) — The application started at - `strategies` (list of string, optional) — Enabled [strategies](https://docs.getunleash.io/concepts/activation-strategies) in the application - `projects` (list of string, optional) — The list of projects used in the application - `sdkVersion` (string, optional) — The version the sdk is running. Typically \:\ - `sdkType` (enum, optional, nullable) — The sdk type - Allowed values: `frontend`, `backend` - `sdkFlavor` (string, optional) — The identifier of an integration built on top of an Unleash SDK (e.g. an OpenFeature provider), forwarded by Edge so adoption of the integration can be tracked alongside sdkVersion. - `sdkFlavorVersion` (string, optional) — The version of the integration identified by sdkFlavor. ### clientMetricsEnvSchema Used for reporting feature evaluation results from SDKs - `featureName` (string, required) — Name of the feature checked by the SDK - `appName` (string, required) — The name of the application the SDK is being used in - `environment` (string, required) — Which environment the SDK is being used in - `timestamp` (dateSchema, optional) — The start of the time window these metrics are valid for. The window is 1 hour wide - `yes` (integer, optional) — How many times the toggle evaluated to true - `no` (integer, optional) — How many times the toggle evaluated to false - `variants` (map from string to integer, optional) — How many times each variant was returned ### impactMetricsSchema Used for reporting impact metrics from SDKs ### BulkRegistrationSchemaConnectViaItems - `appName` (string, required) - `instanceId` (string, required) ### dateSchema A representation of a date. Either as a date-time string or as a UNIX timestamp. ### ImpactMetricsSchema0 - `name` (string, required) — Name of the impact metric - `help` (string, required) — Human-readable description of what the metric measures - `type` (enum, required) — Type of the metric - Allowed values: `counter`, `gauge` - `samples` (list of ImpactMetricsSchemaOneOf0SamplesItems, required) — Samples of the numeric metric ### ImpactMetricsSchema1 - `name` (string, required) — Name of the impact metric - `help` (string, required) — Human-readable description of what the metric measures - `type` (enum, required) — Type of the metric - Allowed values: `histogram` - `samples` (list of ImpactMetricsSchemaOneOf1SamplesItems, required) — Samples of the histogram metric ### ImpactMetricsSchemaOneOf0SamplesItems A sample of a numeric metric with a value and optional labels - `value` (double, required) — The value of the metric sample - `labels` (map from string to ImpactMetricsSchemaOneOf0SamplesItemsLabels, optional) — Optional labels for the metric sample ### ImpactMetricsSchemaOneOf1SamplesItems A sample of a histogram metric with count, sum, buckets and optional labels - `count` (double, required) — Total count of observations - `sum` (double, required) — Sum of all observed values - `buckets` (list of ImpactMetricsSchemaOneOf1SamplesItemsBucketsItems, required) — Histogram buckets - `labels` (map from string to ImpactMetricsSchemaOneOf1SamplesItemsLabels, optional) — Optional labels for the metric sample ### ImpactMetricsSchemaOneOf0SamplesItemsLabels ### ImpactMetricsSchemaOneOf1SamplesItemsBucketsItems - `le` (ImpactMetricsSchemaOneOf1SamplesItemsBucketsItemsLe, required) — Upper bound of the bucket - `count` (double, required) — Count of observations in this bucket ### ImpactMetricsSchemaOneOf1SamplesItemsLabels ### ImpactMetricsSchemaOneOf1SamplesItemsBucketsItemsLe Upper bound of the bucket ## Examples **Request** ```json { "applications": [ { "appName": "Ingress load balancer", "environment": "development", "instanceId": "application-name-dacb1234" } ], "metrics": [ { "featureName": "my.special.feature", "appName": "accounting", "environment": "development" } ] } ``` **Response** ```json {} ``` **SDK Code** ```python import requests url = "https://app.unleash-instance.example.com/api/client/metrics/bulk" payload = { "applications": [ { "appName": "Ingress load balancer", "environment": "development", "instanceId": "application-name-dacb1234" } ], "metrics": [ { "featureName": "my.special.feature", "appName": "accounting", "environment": "development" } ] } headers = { "Authorization": "", "Content-Type": "application/json" } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript const url = 'https://app.unleash-instance.example.com/api/client/metrics/bulk'; const options = { method: 'POST', headers: {Authorization: '', 'Content-Type': 'application/json'}, body: '{"applications":[{"appName":"Ingress load balancer","environment":"development","instanceId":"application-name-dacb1234"}],"metrics":[{"featureName":"my.special.feature","appName":"accounting","environment":"development"}]}' }; try { const response = await fetch(url, options); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } ``` ```go package main import ( "fmt" "strings" "net/http" "io" ) func main() { url := "https://app.unleash-instance.example.com/api/client/metrics/bulk" payload := strings.NewReader("{\n \"applications\": [\n {\n \"appName\": \"Ingress load balancer\",\n \"environment\": \"development\",\n \"instanceId\": \"application-name-dacb1234\"\n }\n ],\n \"metrics\": [\n {\n \"featureName\": \"my.special.feature\",\n \"appName\": \"accounting\",\n \"environment\": \"development\"\n }\n ]\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("Authorization", "") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```ruby require 'uri' require 'net/http' url = URI("https://app.unleash-instance.example.com/api/client/metrics/bulk") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Post.new(url) request["Authorization"] = '' request["Content-Type"] = 'application/json' request.body = "{\n \"applications\": [\n {\n \"appName\": \"Ingress load balancer\",\n \"environment\": \"development\",\n \"instanceId\": \"application-name-dacb1234\"\n }\n ],\n \"metrics\": [\n {\n \"featureName\": \"my.special.feature\",\n \"appName\": \"accounting\",\n \"environment\": \"development\"\n }\n ]\n}" response = http.request(request) puts response.read_body ``` ```java import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.post("https://app.unleash-instance.example.com/api/client/metrics/bulk") .header("Authorization", "") .header("Content-Type", "application/json") .body("{\n \"applications\": [\n {\n \"appName\": \"Ingress load balancer\",\n \"environment\": \"development\",\n \"instanceId\": \"application-name-dacb1234\"\n }\n ],\n \"metrics\": [\n {\n \"featureName\": \"my.special.feature\",\n \"appName\": \"accounting\",\n \"environment\": \"development\"\n }\n ]\n}") .asString(); ``` ```php request('POST', 'https://app.unleash-instance.example.com/api/client/metrics/bulk', [ 'body' => '{ "applications": [ { "appName": "Ingress load balancer", "environment": "development", "instanceId": "application-name-dacb1234" } ], "metrics": [ { "featureName": "my.special.feature", "appName": "accounting", "environment": "development" } ] }', 'headers' => [ 'Authorization' => '', 'Content-Type' => 'application/json', ], ]); echo $response->getBody(); ``` ```csharp using RestSharp; var client = new RestClient("https://app.unleash-instance.example.com/api/client/metrics/bulk"); var request = new RestRequest(Method.POST); request.AddHeader("Authorization", ""); request.AddHeader("Content-Type", "application/json"); request.AddParameter("application/json", "{\n \"applications\": [\n {\n \"appName\": \"Ingress load balancer\",\n \"environment\": \"development\",\n \"instanceId\": \"application-name-dacb1234\"\n }\n ],\n \"metrics\": [\n {\n \"featureName\": \"my.special.feature\",\n \"appName\": \"accounting\",\n \"environment\": \"development\"\n }\n ]\n}", ParameterType.RequestBody); IRestResponse response = client.Execute(request); ``` ```swift import Foundation let headers = [ "Authorization": "", "Content-Type": "application/json" ] let parameters = [ "applications": [ [ "appName": "Ingress load balancer", "environment": "development", "instanceId": "application-name-dacb1234" ] ], "metrics": [ [ "featureName": "my.special.feature", "appName": "accounting", "environment": "development" ] ] ] as [String : Any] let postData = JSONSerialization.data(withJSONObject: parameters, options: []) let request = NSMutableURLRequest(url: NSURL(string: "https://app.unleash-instance.example.com/api/client/metrics/bulk")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "POST" request.allHTTPHeaderFields = headers request.httpBody = postData as Data let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error as Any) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) } }) dataTask.resume() ```