Skip to main content

Campaign Reporting

Pull delivery data for campaigns registered with use case campaign_optimization or campaign_reporting. See exactly where your ads served, with optional breakdowns by date, domain, device, and geography.

Reporting is asynchronous. Submit a report request, receive an ID, and poll for results.

Contextual analysis

Set include_classification: true to have Classify analyze the URLs where your ads served. The report will include IAB categories, keywords, entities, and sentiment for each URL — even if you didn't use Classify segments to target.


The campaign report object

{
"id": 402,
"status": "complete",
"campaign_id": 609,
"start_date": "2026-01-15",
"end_date": "2026-02-14",
"dimensions": ["date", "domain"],
"include_classification": false,
"created_date": "2026-02-16T10:00:00Z",
"processed_date": "2026-02-16T10:03:12Z",
"summary": {
"impressions": 48231,
"unique_urls": 1847,
"unique_domains": 312
},
"data": [...]
}
FieldTypeDescription
idintegerUnique report ID
statusstringpendingprocessingcomplete or failed
campaign_idintegerThe pixel campaign this report is for
start_datestring (ISO 8601)Report start date (inclusive)
end_datestring (ISO 8601)Report end date (inclusive)
dimensionsarray[string] | nullBreakdown dimensions requested
include_classificationbooleanWhether contextual classification data is included
created_datestring (ISO 8601)When the report was requested
processed_datestring (ISO 8601) | nullWhen results were ready. null until complete.
summaryobject | nullAggregate totals. Present when status is complete.
dataarray[object] | nullRow-level data. Present when status is complete.

Create a campaign report

POST https://api.clsfy.me/v1/pixel/reports/campaign

Parameters

ParameterTypeRequiredDescription
campaign_idintegerRequiredThe pixel campaign ID
start_datestring (ISO 8601)RequiredStart of the reporting period
end_datestring (ISO 8601)RequiredEnd of the reporting period (inclusive)
dimensionsarray[string]OptionalBreakdown dimensions. Values: date, domain, url, device, geo. Omit for summary only.
include_classificationbooleanOptionalInclude contextual classification data (IAB categories, keywords, entities, sentiment) for served URLs. Default false.
filtersobjectOptionalNarrow results. Supported keys: domains, devices, geo.

Filter values:

  • domains: array of domain strings (e.g. ["nytimes.com", "bbc.com"])
  • devices: desktop, mobile, tablet, ctv
  • geo: ISO 3166-1 alpha-2 country codes

Request

curl -X POST "https://api.clsfy.me/v1/pixel/reports/campaign" \
-H "X-API-Key: <your_api_key>" \
-H "Content-Type: application/json" \
-d '{
"campaign_id": 609,
"start_date": "2026-01-15",
"end_date": "2026-02-14",
"dimensions": ["date", "domain"],
"include_classification": true
}'

Response

{
"id": 402,
"status": "pending",
"campaign_id": 609,
"start_date": "2026-01-15",
"end_date": "2026-02-14",
"dimensions": ["date", "domain"],
"include_classification": true,
"created_date": "2026-02-16T10:00:00Z",
"processed_date": null,
"summary": null,
"data": null
}

Get a campaign report

GET https://api.clsfy.me/v1/pixel/reports/campaign/{id}
ParameterTypeDescription
idintegerThe report ID
limitinteger (query)Results per page. Default 1000, max 10000.
offsetinteger (query)Results to skip. Default 0.
curl "https://api.clsfy.me/v1/pixel/reports/campaign/402" \
-H "X-API-Key: <your_api_key>"

Completed response

{
"id": 402,
"status": "complete",
"campaign_id": 609,
"start_date": "2026-01-15",
"end_date": "2026-02-14",
"dimensions": ["date", "domain"],
"include_classification": true,
"created_date": "2026-02-16T10:00:00Z",
"processed_date": "2026-02-16T10:03:12Z",
"summary": {
"impressions": 48231,
"unique_urls": 1847,
"unique_domains": 312
},
"data": [
{
"date": "2026-01-15",
"domain": "nytimes.com",
"impressions": 142,
"classification": {
"iab_categories": [
{"id": "IAB19-6", "name": "Technology & Computing", "confidence": 0.93}
],
"keywords": ["AI chips", "semiconductor", "GPU"],
"entities": [
{"name": "NVIDIA", "type": "brand", "confidence": 0.91}
],
"sentiment": {"label": "positive", "score": 0.72}
}
},
{
"date": "2026-01-15",
"domain": "bbc.com",
"impressions": 89,
"classification": {
"iab_categories": [
{"id": "IAB17-44", "name": "Sports", "confidence": 0.96}
],
"keywords": ["football", "Premier League"],
"entities": [
{"name": "Premier League", "type": "thing", "confidence": 0.94}
],
"sentiment": {"label": "neutral", "score": 0.51}
}
}
]
}
note

When include_classification is false, the classification field is omitted from each data row.

Macro data

If your pixel code includes macros, their expanded values appear as additional fields in each data row. For example, if your pixel passes google-site=%%SITE%%:

{
"date": "2026-01-15",
"domain": "nytimes.com",
"impressions": 142,
"macros": {
"google-site": "nytimes.com"
}
}

Compare the macros.google-site value against the domain to detect inventory misrepresentation.


Polling for results

import requests
import time

def wait_for_campaign_report(report_id: int, api_key: str, poll_interval: int = 30):
"""Poll until a campaign report is ready."""
url = f"https://api.clsfy.me/v1/pixel/reports/campaign/{report_id}"
headers = {"X-API-Key": api_key}

while True:
report = requests.get(url, headers=headers).json()

if report["status"] == "complete":
print(f"Done — {report['summary']['impressions']} impressions")
return report
elif report["status"] == "failed":
raise RuntimeError(f"Report {report_id} failed.")

print(f"Status: {report['status']} — retrying in {poll_interval}s")
time.sleep(poll_interval)

Dimensions reference

DimensionValueGranularity
DatedateDaily
DomaindomainPublisher domain
URLurlIndividual page URL
Devicedevicedesktop, mobile, tablet, ctv
GeographygeoCountry (ISO 3166-1 alpha-2)

Error responses

When a request fails, the API returns a JSON object with an error code and a human-readable message:

{
"error": "not_found",
"message": "Campaign report with ID 999 not found"
}

HTTP status codes

StatusMeaning
200 OKSuccess
201 CreatedResource created (POST endpoints)
400 Bad RequestInvalid or missing parameters
401 UnauthorizedMissing or invalid API key
404 Not FoundResource not found
422 Unprocessable ContentValidation error (e.g. invalid field values)
429 Too Many RequestsRate limit exceeded