LinkedIn Statistics
Retrieve analytics for your LinkedIn posts: impressions, reach, reactions, comments, and reshares.
Endpoint
POST https://api.postpost.dev/api/v1/linkedin-post-statisticsHeaders
| Header | Required | Description |
|---|---|---|
x-api-key | Yes | Your API key |
Content-Type | Yes | application/json |
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
postedId | string | Yes | LinkedIn post URN (e.g., urn:li:share:123456789) or share ID |
platformId | string | Yes | LinkedIn connection ID (format: linkedin-ABC123) |
queryType | string | No | Single metric: IMPRESSION, MEMBERS_REACHED, RESHARE, REACTION, COMMENT |
queryTypes | string[] or "ALL" | No | Multiple metrics at once. Use "ALL" for all 5 metrics. |
Use either queryType (single) or queryTypes (multiple), not both.
Note: The
queryTypes(plural) andaggregationparameters are case-insensitive — e.g.,"impression","Impression", and"IMPRESSION"are all accepted. However,queryType(single metric) must be UPPERCASE — only"IMPRESSION"is valid, not"impression"or"Impression".
Available Metrics
| Metric | Description |
|---|---|
IMPRESSION | Total number of times the post was displayed |
MEMBERS_REACHED | Unique LinkedIn members who saw the post |
RESHARE | Number of times the post was reposted |
REACTION | Total reactions (LIKE, PRAISE, EMPATHY, INTEREST, APPRECIATION, ENTERTAINMENT) |
COMMENT | Total number of comments |
Response (Single Metric)
{
"success": true,
"count": 1542,
"cached": false
}Response (Multiple Metrics)
{
"success": true,
"metrics": {
"IMPRESSION": 15420,
"MEMBERS_REACHED": 8234,
"RESHARE": 23,
"REACTION": 456,
"COMMENT": 89
},
"cachedMetrics": ["IMPRESSION", "REACTION"],
"cached": true
}The cachedMetrics field lists which individual metrics were served from cache. It is only present when at least one metric was served from cache (i.e., the array is non-empty). Results are cached for 30 minutes. cached: true means at least one metric was served from cache.
Partial Failure (Multiple Metrics)
When requesting multiple metrics, some may succeed while others fail. The response includes an errors array:
{
"success": false,
"metrics": {
"IMPRESSION": 15420,
"MEMBERS_REACHED": null,
"REACTION": 456,
"COMMENT": 89,
"RESHARE": null
},
"errors": [
{ "metric": "MEMBERS_REACHED", "error": "Failed to fetch metric from LinkedIn" },
{ "metric": "RESHARE", "error": "Failed to fetch metric from LinkedIn" }
],
"cached": false
}Failed metrics are included in the metrics object with null values (they are not omitted). The error message is always "Failed to fetch metric from LinkedIn" regardless of the underlying cause. Check the errors array to identify which metrics failed.
Note: A metric value may be
nullin themetricsobject without a corresponding entry in theerrorsarray. This occurs when LinkedIn returns a-1count (interpreted as unavailable data), as opposed to a fetch failure which produces both anullmetric and anerrorsentry.
Examples
Get all metrics for a post
JavaScript (fetch)
const response = await fetch('https://api.postpost.dev/api/v1/linkedin-post-statistics', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
},
body: JSON.stringify({
postedId: 'urn:li:share:7123456789012345678',
platformId: 'linkedin-Tz9W5i6ZYG',
queryTypes: 'ALL'
})
});
const data = await response.json();
console.log(`Impressions: ${data.metrics.IMPRESSION}`);
console.log(`Reactions: ${data.metrics.REACTION}`);
console.log(`Comments: ${data.metrics.COMMENT}`);Python (requests)
import requests
response = requests.post(
'https://api.postpost.dev/api/v1/linkedin-post-statistics',
headers={
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
},
json={
'postedId': 'urn:li:share:7123456789012345678',
'platformId': 'linkedin-Tz9W5i6ZYG',
'queryTypes': 'ALL'
}
)
metrics = response.json()['metrics']
print(f"Impressions: {metrics['IMPRESSION']}")
print(f"Reach: {metrics['MEMBERS_REACHED']}")
print(f"Engagement: {metrics['REACTION'] + metrics['COMMENT'] + metrics['RESHARE']}")cURL
curl -X POST https://api.postpost.dev/api/v1/linkedin-post-statistics \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"postedId": "urn:li:share:7123456789012345678",
"platformId": "linkedin-Tz9W5i6ZYG",
"queryTypes": "ALL"
}'Get a single metric
const response = await fetch('https://api.postpost.dev/api/v1/linkedin-post-statistics', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
},
body: JSON.stringify({
postedId: 'urn:li:share:7123456789012345678',
platformId: 'linkedin-Tz9W5i6ZYG',
queryType: 'IMPRESSION'
})
});
const data = await response.json();
console.log(`Impressions: ${data.count}`); // 1542Get specific metrics
response = requests.post(
'https://api.postpost.dev/api/v1/linkedin-post-statistics',
headers={
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
},
json={
'postedId': 'urn:li:share:7123456789012345678',
'platformId': 'linkedin-Tz9W5i6ZYG',
'queryTypes': ['IMPRESSION', 'REACTION', 'COMMENT']
}
)LinkedIn Account Statistics
Get aggregated metrics across all published LinkedIn posts for an account.
Endpoint
POST https://api.postpost.dev/api/v1/linkedin-account-statisticsRequest Body
| Parameter | Type | Required | Description |
|---|---|---|---|
platformId | string | Yes | LinkedIn connection ID (format: linkedin-ABC123) |
queryType | string | No | Single metric (same options as post statistics) |
queryTypes | string[] or "ALL" | No | Multiple metrics at once |
aggregation | string | No | "TOTAL" (default) or "DAILY" |
dateRange | object | No | { start: { year, month, day }, end: { year, month, day } } |
Note: The
queryTypes(plural) andaggregationparameters are case-insensitive — e.g.,"total","Total", and"TOTAL"are all accepted. However,queryType(single metric) must be UPPERCASE — only"IMPRESSION"is valid, not"impression"or"Impression".
{
"platformId": "linkedin-Tz9W5i6ZYG",
"queryTypes": "ALL",
"aggregation": "TOTAL"
}Response (Single Metric)
When using queryType (single metric), the account statistics response includes the raw data and aggregation type. The data field type depends on the aggregation:
- TOTAL aggregation:
datais a number (the aggregated total), ornullwhen LinkedIn returns-1(indicating data is unavailable for that metric). - DAILY aggregation:
datais an array of objects, each withcountanddateRangefields.
TOTAL aggregation example
{
"success": true,
"data": 15420,
"aggregation": "TOTAL",
"cached": false
}DAILY aggregation example
{
"success": true,
"data": [
{ "count": 1200, "dateRange": { "start": { "year": 2024, "month": 1, "day": 15 }, "end": { "year": 2024, "month": 1, "day": 16 } } },
{ "count": 980, "dateRange": { "start": { "year": 2024, "month": 1, "day": 16 }, "end": { "year": 2024, "month": 1, "day": 17 } } }
],
"aggregation": "DAILY",
"cached": false
}Response (Multiple Metrics — Total Aggregation)
When using queryTypes (multiple metrics), the response uses the same format as post statistics but also includes the aggregation field:
{
"success": true,
"metrics": {
"IMPRESSION": 45230,
"MEMBERS_REACHED": 22150,
"RESHARE": 89,
"REACTION": 1234,
"COMMENT": 256
},
"aggregation": "TOTAL",
"cachedMetrics": ["IMPRESSION"],
"cached": true
}Response (Daily Aggregation)
When aggregation is "DAILY", each metric value is an array of daily data points instead of a single number:
{
"success": true,
"metrics": {
"IMPRESSION": [
{ "count": 1200, "dateRange": { "start": { "year": 2024, "month": 1, "day": 15 }, "end": { "year": 2024, "month": 1, "day": 16 } } },
{ "count": 980, "dateRange": { "start": { "year": 2024, "month": 1, "day": 16 }, "end": { "year": 2024, "month": 1, "day": 17 } } }
]
},
"aggregation": "DAILY",
"cached": false
}JavaScript
const response = await fetch('https://api.postpost.dev/api/v1/linkedin-account-statistics', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
},
body: JSON.stringify({
platformId: 'linkedin-Tz9W5i6ZYG',
queryTypes: 'ALL',
aggregation: 'TOTAL'
})
});
const data = await response.json();
console.log(`Total impressions: ${data.metrics.IMPRESSION}`);
console.log(`Total engagement: ${data.metrics.REACTION + data.metrics.COMMENT}`);Python
response = requests.post(
'https://api.postpost.dev/api/v1/linkedin-account-statistics',
headers={
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
},
json={
'platformId': 'linkedin-Tz9W5i6ZYG',
'queryTypes': 'ALL',
'aggregation': 'TOTAL'
}
)
stats = response.json()
print(f"Total impressions: {stats['metrics']['IMPRESSION']}")
print(f"Total engagement: {stats['metrics']['REACTION'] + stats['metrics']['COMMENT']}")Node.js (axios)
const axios = require('axios');
const client = axios.create({
baseURL: 'https://api.postpost.dev/api/v1',
headers: { 'x-api-key': process.env.PUBLORA_API_KEY }
});
// Get post statistics
async function getPostStats(postedId, platformId) {
const { data } = await client.post('/linkedin-post-statistics', {
postedId,
platformId,
queryTypes: 'ALL'
});
return data.metrics;
}
// Get account statistics
async function getAccountStats(platformId) {
const { data } = await client.post('/linkedin-account-statistics', {
platformId,
queryTypes: 'ALL',
aggregation: 'TOTAL'
});
return data.metrics;
}
// Usage
const postMetrics = await getPostStats('urn:li:share:123', 'linkedin-ABC');
const accountMetrics = await getAccountStats('linkedin-ABC');
console.log(`Post impressions: ${postMetrics.IMPRESSION}`);
console.log(`Account total impressions: ${accountMetrics.IMPRESSION}`);With Error Handling
async function getLinkedInStats(platformId, postedId = null) {
try {
const endpoint = postedId
? '/linkedin-post-statistics'
: '/linkedin-account-statistics';
const payload = {
platformId,
queryTypes: 'ALL',
...(postedId && { postedId }),
...(!postedId && { aggregation: 'TOTAL' })
};
const response = await fetch(`https://api.postpost.dev/api/v1${endpoint}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.PUBLORA_API_KEY
},
body: JSON.stringify(payload)
});
const data = await response.json();
if (!response.ok) {
switch (response.status) {
case 400:
throw new Error(`Invalid request: ${data.error}`);
case 404:
throw new Error('LinkedIn account not found. Check your platformId.');
default:
throw new Error(data.error || `HTTP ${response.status}`);
}
}
return {
metrics: data.metrics,
cached: data.cached,
engagementRate: calculateEngagementRate(data.metrics)
};
} catch (error) {
console.error('Failed to fetch LinkedIn stats:', error.message);
throw error;
}
}
function calculateEngagementRate(metrics) {
const engagement = metrics.REACTION + metrics.COMMENT + metrics.RESHARE;
const reach = metrics.MEMBERS_REACHED || metrics.IMPRESSION;
return reach > 0 ? ((engagement / reach) * 100).toFixed(2) + '%' : '0%';
}import os
import requests
def get_linkedin_stats(platform_id, posted_id=None):
"""Get LinkedIn statistics with error handling."""
endpoint = 'linkedin-post-statistics' if posted_id else 'linkedin-account-statistics'
url = f'https://api.postpost.dev/api/v1/{endpoint}'
payload = {
'platformId': platform_id,
'queryTypes': 'ALL'
}
if posted_id:
payload['postedId'] = posted_id
else:
payload['aggregation'] = 'TOTAL'
try:
response = requests.post(
url,
headers={
'Content-Type': 'application/json',
'x-api-key': os.environ['PUBLORA_API_KEY']
},
json=payload
)
data = response.json()
if response.status_code == 400:
raise ValueError(f"Invalid request: {data.get('error')}")
if response.status_code == 404:
raise ValueError('LinkedIn account not found. Check your platformId.')
response.raise_for_status()
metrics = data['metrics']
engagement = metrics['REACTION'] + metrics['COMMENT'] + metrics['RESHARE']
reach = metrics.get('MEMBERS_REACHED', metrics['IMPRESSION'])
engagement_rate = (engagement / reach * 100) if reach > 0 else 0
return {
'metrics': metrics,
'cached': data['cached'],
'engagement_rate': f"{engagement_rate:.2f}%"
}
except requests.RequestException as e:
print(f'Failed to fetch LinkedIn stats: {e}')
raise
# Usage
stats = get_linkedin_stats('linkedin-Tz9W5i6ZYG')
print(f"Total impressions: {stats['metrics']['IMPRESSION']}")
print(f"Engagement rate: {stats['engagement_rate']}")Errors
Post Statistics Errors
| Status | Error | Cause |
|---|---|---|
| 400 | "postedId and platformId are required" | Missing postedId or platformId |
| 400 | "postedId and platformId must be strings" | postedId or platformId is not a string type |
| 400 | "queryType or queryTypes is required" | Neither queryType nor queryTypes provided |
| 400 | "Invalid queryType. Must be one of: IMPRESSION, MEMBERS_REACHED, RESHARE, REACTION, COMMENT" | queryType not one of the 5 valid types |
| 400 | "Invalid queryTypes: ${invalidTypes}. Must be one of: IMPRESSION, MEMBERS_REACHED, RESHARE, REACTION, COMMENT, or \"ALL\"" | queryTypes contains invalid values |
| 401 | "API key is required" | No x-api-key header provided |
| 401 | "Invalid API key" | Bad or missing x-api-key |
| 401 | "Invalid API key owner" | API key owner user not found in database |
| 403 | "API access is not enabled for this account" | Account's plan does not include API access |
| 404 | "LinkedIn connection not found" | No LinkedIn account with that platformId |
| 500 | "Failed to fetch metric from LinkedIn" | Server error while fetching a single metric (queryType) — LinkedIn returned null data |
| 500 | "Failed to fetch LinkedIn post statistics" | Catch-all server error from outer try/catch |
Note: Error status codes from the LinkedIn API may be forwarded directly (e.g., 403, 429), so you may receive error codes other than those listed above.
Account Statistics Errors
| Status | Error | Cause |
|---|---|---|
| 400 | "platformId is required" | Missing platformId |
| 400 | "platformId must be a string" | platformId is not a string type |
| 400 | "queryType or queryTypes is required" | Neither queryType nor queryTypes provided |
| 400 | "Invalid queryType. Must be one of: IMPRESSION, MEMBERS_REACHED, RESHARE, REACTION, COMMENT" | queryType not one of the 5 valid types |
| 400 | "Invalid queryTypes: ${invalidTypes}. Must be one of: IMPRESSION, MEMBERS_REACHED, RESHARE, REACTION, COMMENT, or \"ALL\"" | queryTypes contains invalid values |
| 400 | "aggregation must be a string" | aggregation parameter was provided but is not a string type |
| 400 | "Invalid aggregation. Must be one of: DAILY, TOTAL" | aggregation not TOTAL or DAILY |
| 400 | "dateRange must be an object" | dateRange parameter was provided but is not an object type |
| 400 | "dateRange must have both 'start' and 'end' objects" | dateRange provided but missing start or end |
| 400 | "dateRange.start and dateRange.end must have: year, month, day" | dateRange start/end missing required fields |
| 400 | "MEMBERS_REACHED with DAILY aggregation is not supported by LinkedIn API" | Unsupported metric/aggregation combination |
| 401 | "API key is required" | No x-api-key header provided |
| 401 | "Invalid API key" | Bad or missing x-api-key |
| 401 | "Invalid API key owner" | API key owner user not found in database |
| 403 | "API access is not enabled for this account" | Account's plan does not include API access |
| 404 | "LinkedIn connection not found" | No LinkedIn account with that platformId |
| 500 | "Failed to fetch metric from LinkedIn" | Single-metric request (queryType) returned null data from LinkedIn |
| 500 | "Failed to fetch LinkedIn account statistics" | Catch-all server error from outer try/catch |
Note: Error status codes from the LinkedIn API may be forwarded directly (e.g., 403, 429), so you may receive error codes other than those listed above.