This guide gets you started with the GoodMetrics REST API. For custom or generic MCP client connections, see the MCP Server reference.
REST API requests use https://data.goodmetrics.io/{gmID}/events.
Replace {gmID} with the public GoodMetrics site identifier from the site you want to query.
Create an API key
Section titled “Create an API key”Create API keys in the GoodMetrics dashboard. Keys are shown once when created, so store the value securely before leaving the page.
API keys must be active and unexpired. Bearer-token access is read-only.
Send the key in the Authorization: Bearer YOUR_API_KEY header.
Make a realtime request
Section titled “Make a realtime request”Realtime endpoints use the current live window automatically.
curl "https://data.goodmetrics.io/{gmID}/events/realtime/visitors" \ -H "Authorization: Bearer YOUR_API_KEY"const gmID = '{gmID}';const apiKey = 'YOUR_API_KEY';const response = await fetch(`https://data.goodmetrics.io/${gmID}/events/realtime/visitors`, { headers: { Authorization: `Bearer ${apiKey}` }});
console.log(await response.json());import jsonimport urllib.request
gm_id = "{gmID}"api_key = "YOUR_API_KEY"request = urllib.request.Request( f"https://data.goodmetrics.io/{gm_id}/events/realtime/visitors", headers={"Authorization": f"Bearer {api_key}"},)
with urllib.request.urlopen(request) as response: print(json.load(response))import java.net.URI;import java.net.http.HttpClient;import java.net.http.HttpRequest;import java.net.http.HttpResponse;
class GoodMetricsExample { public static void main(String[] args) throws Exception { var gmID = "{gmID}"; var apiKey = "YOUR_API_KEY"; var url = "https://data.goodmetrics.io/" + gmID + "/events/realtime/visitors";
var request = HttpRequest.newBuilder() .uri(URI.create(url)) .header("Authorization", "Bearer " + apiKey) .GET() .build();
var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); }}using System;using System.Net.Http;using System.Net.Http.Headers;
var gmID = "{gmID}";var apiKey = "YOUR_API_KEY";var url = $"https://data.goodmetrics.io/{gmID}/events/realtime/visitors";
using var client = new HttpClient();using var request = new HttpRequestMessage(HttpMethod.Get, url);request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
using var response = await client.SendAsync(request);Console.WriteLine(await response.Content.ReadAsStringAsync());<?php$gmID = "{gmID}";$apiKey = "YOUR_API_KEY";$url = "https://data.goodmetrics.io/{$gmID}/events/realtime/visitors";
$context = stream_context_create([ "http" => [ "method" => "GET", "header" => "Authorization: Bearer {$apiKey}\r\n", ],]);
$response = file_get_contents($url, false, $context);echo $response;package main
import ( "fmt" "io" "net/http")
func main() { gmID := "{gmID}" apiKey := "YOUR_API_KEY"
request, _ := http.NewRequest( "GET", "https://data.goodmetrics.io/"+gmID+"/events/realtime/visitors", nil, ) request.Header.Set("Authorization", "Bearer "+apiKey)
response, _ := http.DefaultClient.Do(request) defer response.Body.Close()
body, _ := io.ReadAll(response.Body) fmt.Println(string(body))}A successful realtime response includes meta and data:
{ "meta": { "start": 1772476740000, "end": 1772476800000 }, "data": [ { "activeSessions": 14 } ]}Make a reporting request
Section titled “Make a reporting request”Reporting endpoints use flat query parameters for the date range, sorting, pagination, and filters.
curl "https://data.goodmetrics.io/{gmID}/events/audience/countries?start=1771872000&end=1772476799&page=1&limit=10&sort_by=uniqueVisitors&dir=desc&country_is=Canada" \ -H "Authorization: Bearer YOUR_API_KEY"const gmID = '{gmID}';const apiKey = 'YOUR_API_KEY';const params = new URLSearchParams({ "start": "1771872000", "end": "1772476799", "page": "1", "limit": "10", "sort_by": "uniqueVisitors", "dir": "desc", "country_is": "Canada"});
const response = await fetch(`https://data.goodmetrics.io/${gmID}/events/audience/countries?${params}`, { headers: { Authorization: `Bearer ${apiKey}` }});
console.log(await response.json());import jsonimport urllib.parseimport urllib.request
gm_id = "{gmID}"api_key = "YOUR_API_KEY"params = urllib.parse.urlencode({ "start": "1771872000", "end": "1772476799", "page": "1", "limit": "10", "sort_by": "uniqueVisitors", "dir": "desc", "country_is": "Canada"})
request = urllib.request.Request( f"https://data.goodmetrics.io/{gm_id}/events/audience/countries?{params}", headers={"Authorization": f"Bearer {api_key}"},)
with urllib.request.urlopen(request) as response: print(json.load(response))import java.net.URI;import java.net.http.HttpClient;import java.net.http.HttpRequest;import java.net.http.HttpResponse;
class GoodMetricsExample { public static void main(String[] args) throws Exception { var gmID = "{gmID}"; var apiKey = "YOUR_API_KEY"; var url = "https://data.goodmetrics.io/" + gmID + "/events/audience/countries?start=1771872000&end=1772476799&page=1&limit=10&sort_by=uniqueVisitors&dir=desc&country_is=Canada";
var request = HttpRequest.newBuilder() .uri(URI.create(url)) .header("Authorization", "Bearer " + apiKey) .GET() .build();
var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); }}using System;using System.Collections.Generic;using System.Linq;using System.Net.Http;using System.Net.Http.Headers;
var gmID = "{gmID}";var apiKey = "YOUR_API_KEY";var query = new Dictionary<string, string>{ ["start"] = "1771872000", ["end"] = "1772476799", ["page"] = "1", ["limit"] = "10", ["sort_by"] = "uniqueVisitors", ["dir"] = "desc", ["country_is"] = "Canada"};var queryString = string.Join("&", query.Select(parameter => $"{Uri.EscapeDataString(parameter.Key)}={Uri.EscapeDataString(parameter.Value)}"));
var url = $"https://data.goodmetrics.io/{gmID}/events/audience/countries?{queryString}";
using var client = new HttpClient();using var request = new HttpRequestMessage(HttpMethod.Get, url);request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
using var response = await client.SendAsync(request);Console.WriteLine(await response.Content.ReadAsStringAsync());<?php$gmID = "{gmID}";$apiKey = "YOUR_API_KEY";$params = http_build_query([ "start" => "1771872000", "end" => "1772476799", "page" => "1", "limit" => "10", "sort_by" => "uniqueVisitors", "dir" => "desc", "country_is" => "Canada"]);
$url = "https://data.goodmetrics.io/{$gmID}/events/audience/countries?{$params}";
$context = stream_context_create([ "http" => [ "method" => "GET", "header" => "Authorization: Bearer {$apiKey}\r\n", ],]);
$response = file_get_contents($url, false, $context);echo $response;package main
import ( "fmt" "io" "net/http" "net/url")
func main() { gmID := "{gmID}" apiKey := "YOUR_API_KEY"
params := url.Values{} params.Set("start", "1771872000") params.Set("end", "1772476799") params.Set("page", "1") params.Set("limit", "10") params.Set("sort_by", "uniqueVisitors") params.Set("dir", "desc") params.Set("country_is", "Canada")
request, _ := http.NewRequest( "GET", "https://data.goodmetrics.io/"+gmID+"/events/audience/countries?"+params.Encode(), nil, ) request.Header.Set("Authorization", "Bearer "+apiKey)
response, _ := http.DefaultClient.Do(request) defer response.Body.Close()
body, _ := io.ReadAll(response.Body) fmt.Println(string(body))}Next steps
Section titled “Next steps”- Read Authentication for REST API key behavior.
- Read Request Parameters for filters, date ranges, comparison ranges, sorting, and pagination.
- Read Responses for realtime, chart, table, and error response shapes.
- Browse the Realtime reference or Audience reference to start querying data.