Browse Post Analytics
Search, filter, sort, and page through analytics for all posts in a Mallary profile.
curl --request GET \
--url https://mallary.ai/api/v1/analytics/posts \
--header 'Authorization: Bearer <token>'import requests
url = "https://mallary.ai/api/v1/analytics/posts"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://mallary.ai/api/v1/analytics/posts', 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://mallary.ai/api/v1/analytics/posts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://mallary.ai/api/v1/analytics/posts"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://mallary.ai/api/v1/analytics/posts")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://mallary.ai/api/v1/analytics/posts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"status": "ok",
"data": {
"profile_id": "AbC123xYz90",
"items": [
{
"id": "<string>",
"batch_id": "<string>",
"post_id": 123,
"job_ids": [
123
],
"title": "<string>",
"message": "<string>",
"thumbnail_url": "<string>",
"media_type": "<string>",
"status": "successful",
"created_at": "<string>",
"posted_at": "<string>",
"platforms": [
"<string>"
],
"platform_count": 123,
"platform_metrics": [
{
"job_id": 123,
"platform": "twitter",
"label": "<string>",
"platform_post_url": "<string>",
"status": "<string>",
"analytics_status": "available",
"captured_at": "2023-11-07T05:31:56Z",
"metric_window": "<string>",
"metric_semantics_version": 123,
"display_views": 123,
"display_views_available": true,
"engagement_rate": 123,
"engagement_rate_denominator": "views",
"outbound_click_rate": 123,
"outbound_click_rate_denominator": "impressions",
"url_click_rate": 123,
"url_click_rate_denominator": "impressions"
}
],
"views": 123,
"display_views": 123,
"display_views_available": true,
"display_views_partial": true,
"display_view_sample_count": 123,
"average_display_views": 123,
"impressions": 123,
"reach": 123,
"likes": 123,
"comments": 123,
"shares": 123,
"clicks": 123,
"saves": 123,
"bookmarks": 123,
"outbound_clicks": 123,
"pin_clicks": 123,
"url_clicks": 123,
"profile_clicks": 123,
"engaged_users": 123,
"engagement": 123,
"engagement_rate": 123,
"engagement_rate_denominator": "views",
"engagement_rate_partial": true,
"engagement_rate_sample_count": 123,
"outbound_click_rate": 123,
"outbound_click_rate_denominator": "impressions",
"url_click_rate": 123,
"url_click_rate_denominator": "impressions",
"metric_window": "lifetime",
"captured_at": "2023-11-07T05:31:56Z",
"analytics_available": true,
"analytics_partial": true,
"analytics_collecting": true,
"analytics_reconnect_required": true
}
],
"next_cursor": "<string>",
"page": 2,
"total_pages": 1,
"limit": 50,
"snapshot_at": "2023-11-07T05:31:56Z",
"total": 123,
"generated_at": "2023-11-07T05:31:56Z"
}
}profile_id to use the default profile. It requires Starter, Pro, or Business.
Use start_date and end_date to select posts created on those UTC dates. Each metric is the latest saved total for that post. The date filter does not turn lifetime totals into activity earned during the selected dates. metric_window tells you when a provider supplied a rolling 30-day or 90-day total instead.
The response returns up to 25 groups by default. Set limit to 1–100. For numbered pages, set page to 1–10000. The response includes data.page, data.total_pages, data.limit, and data.total, the count of matching groups across all pages. If no groups match, data.total_pages is 0. Pass the returned data.snapshot_at with later page requests, keeping the same filters, sort, and limit. The timestamp is in UTC YYYY-MM-DDTHH:mm:ssZ form and can be used only with page. It keeps metric ranking at the same saved point in time. A post’s status can still change while you browse.
You can also page forward with a cursor: pass data.next_cursor back as cursor, keeping the same filters and sort. A null cursor means the last page. Do not send page and cursor together. In numbered page mode, data.next_cursor is null.
Use platform, status, media_type, search, and sort to narrow the list. Sort by display_views, likes, comments, or engagement_rate for the highest values first. Add _asc to any of those values for the lowest first. display_views uses views when a platform supplies them, otherwise impressions. Posts without the selected metric appear last in either direction. Other existing sort values remain available. A cross-platform group matches a platform filter when any of its posts use that platform. Its platform_metrics still show each platform separately.
Metrics that the provider did not supply are null. A reported zero is 0. For each group total, check *_available and *_partial before comparing posts: a partial value covers only some platforms in that group. captured_at tells you when the latest snapshot was saved.
The group engagement_rate combines the available platform-post rates into one percentage. Mallary weights each rate by its positive base count, such as views, impressions, or reach. A platform post without a usable rate or base is left out, not counted as zero. engagement_rate_sample_count tells you how many platform posts contributed; engagement_rate_partial is true when a rate is available but some platform posts did not contribute. engagement_rate_denominator is mixed when the contributing rates use different bases. Check each platform_metrics row for its own rate and base. If the platform posts cover different reporting periods, metric_window is mixed.
For a compact recent snapshot or a single post by Mallary job ID, use Get Analytics. For follower and subscriber history, use Get Audience Counts.Authorizations
Use Authorization: Bearer {api_key}
Query Parameters
Connection profile to inspect. Omit to use the default profile.
Random public connection profile ID returned by GET /api/v1/profiles.
^[A-Za-z0-9]{6,32}$"AbC123xYz90"
Include post groups created on or after this UTC date.
Include post groups created on or before this UTC date.
Include groups with a post on this platform. Supported publishing platform identifier.
twitter, x, facebook, instagram, linkedin, youtube, tiktok, pinterest, reddit, threads, bluesky Filter by the post group's status.
successful, scheduled, failed, processing, partial Include groups with this media type.
video, photo, mixed_media, text_or_link Search post text and batch IDs.
200Sort post groups. Metric sorts are highest first unless the value ends in _asc. display_views uses a platform's views when available, otherwise its impressions. Posts without the selected metric appear last in either direction.
newest, oldest, views, display_views, display_views_asc, likes, likes_asc, comments, comments_asc, engagement, engagement_rate, engagement_rate_asc, clicks, impressions Maximum number of post groups in one page.
1 <= x <= 100Opaque next_cursor from the previous page. Keep filters and sort the same. Cannot be combined with page.
One-based page number for numbered navigation. Cannot be combined with cursor. Omit for cursor navigation.
1 <= x <= 10000UTC server timestamp in YYYY-MM-DDTHH:mm:ssZ form returned with the first numbered page. Use it only with page; pass it with later page numbers and the same filters, sort, and limit so metric ranking stays fixed while browsing.
Was this page helpful?
curl --request GET \
--url https://mallary.ai/api/v1/analytics/posts \
--header 'Authorization: Bearer <token>'import requests
url = "https://mallary.ai/api/v1/analytics/posts"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://mallary.ai/api/v1/analytics/posts', 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://mallary.ai/api/v1/analytics/posts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://mallary.ai/api/v1/analytics/posts"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://mallary.ai/api/v1/analytics/posts")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://mallary.ai/api/v1/analytics/posts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"status": "ok",
"data": {
"profile_id": "AbC123xYz90",
"items": [
{
"id": "<string>",
"batch_id": "<string>",
"post_id": 123,
"job_ids": [
123
],
"title": "<string>",
"message": "<string>",
"thumbnail_url": "<string>",
"media_type": "<string>",
"status": "successful",
"created_at": "<string>",
"posted_at": "<string>",
"platforms": [
"<string>"
],
"platform_count": 123,
"platform_metrics": [
{
"job_id": 123,
"platform": "twitter",
"label": "<string>",
"platform_post_url": "<string>",
"status": "<string>",
"analytics_status": "available",
"captured_at": "2023-11-07T05:31:56Z",
"metric_window": "<string>",
"metric_semantics_version": 123,
"display_views": 123,
"display_views_available": true,
"engagement_rate": 123,
"engagement_rate_denominator": "views",
"outbound_click_rate": 123,
"outbound_click_rate_denominator": "impressions",
"url_click_rate": 123,
"url_click_rate_denominator": "impressions"
}
],
"views": 123,
"display_views": 123,
"display_views_available": true,
"display_views_partial": true,
"display_view_sample_count": 123,
"average_display_views": 123,
"impressions": 123,
"reach": 123,
"likes": 123,
"comments": 123,
"shares": 123,
"clicks": 123,
"saves": 123,
"bookmarks": 123,
"outbound_clicks": 123,
"pin_clicks": 123,
"url_clicks": 123,
"profile_clicks": 123,
"engaged_users": 123,
"engagement": 123,
"engagement_rate": 123,
"engagement_rate_denominator": "views",
"engagement_rate_partial": true,
"engagement_rate_sample_count": 123,
"outbound_click_rate": 123,
"outbound_click_rate_denominator": "impressions",
"url_click_rate": 123,
"url_click_rate_denominator": "impressions",
"metric_window": "lifetime",
"captured_at": "2023-11-07T05:31:56Z",
"analytics_available": true,
"analytics_partial": true,
"analytics_collecting": true,
"analytics_reconnect_required": true
}
],
"next_cursor": "<string>",
"page": 2,
"total_pages": 1,
"limit": 50,
"snapshot_at": "2023-11-07T05:31:56Z",
"total": 123,
"generated_at": "2023-11-07T05:31:56Z"
}
}
