Asynchronous Analytics
Introduction
The asynchronous analytics endpoints allow partners and advertisers to request metrics by submitting create requests that the server processes asynchronously. (We refer to these as asynchronous analytics "jobs.") With this approach, the client's connection does not need to remain open until the request has been fulfilled.
These endpoints, like their synchronous counterpart, allow partners and advertisers to request detailed statistics on campaign performance. They support requesting data for accounts, funding instruments, campaigns, line items, promoted Tweets, and media creatives. The difference between these and the synchronous endpoint is that the asynchronous analytics endpoints support longer date ranges, up to 90 days, as well as segmentation. Additional details on the differences between the two can be found on our Analytics Overview page.
Unlike our synchronous endpoints, rate limiting is based on the number of concurrent jobs for a given account. In other words, it's based on the number of jobs that can be in a processing state at a given time. We count this at the ads account level.
Usage
Retrieving campaign metrics using the asynchronous analytics endpoints is a multi-step process. It involves creating a job, checking whether the job has finished processing, and, finally, downloading the data. The data file must be decompressed. The four specific steps are outlined below.
- Create the job using the POST stats/jobs/accounts/:account_id endpoint.
- Make requests at regular intervals to the GET stats/jobs/accounts/:account_id endpoint to determine whether the job has finished processing.
- Once the job has finished processing, download the data file.
- Unzip the data file.
The response object returned in the data file has the same JSON schema as the synchronous analytics endpoint's response.
Segmented campaign metrics are only available via the asynchronous analytics endpoints. Campaign metrics can be broken out by location, gender, interest, keyword, and more. For a full list of options, see the Metrics and Segmentation page. In order to request segmented metrics, use the segmentation_type
request parameter when creating the job.
Example
This section demonstrates how to use the asynchronous analytics endpoints.
Start by creating a job using the POST stats/jobs/accounts/:account_id endpoint. The example below requests engagement metrics—such as impressions, likes, clicks, etc.—for a specific line item over a week's time. (Note that the requested time range goes up to, but does not include March 20th since the timestamp is set to midnight.)
$ twurl -X POST -H ads-api.x.com "/9/stats/jobs/accounts/18ce54d4x5t?entity=LINE_ITEM&entity_ids=el32n&start_time=2019-03-12T00:00:00Z&end_time=2019-03-20T00:00:00Z&granularity=TOTAL&placement=ALL_ON_TWITTER&metric_groups=ENGAGEMENT"
{
"request": {
"params": {
"start_time": "2019-03-12T00:00:00Z",
"entity_ids": [
"el32n"
],
"end_time": "2019-03-20T00:00:00Z",
"placement": "ALL_ON_TWITTER",
"granularity": "TOTAL",
"entity": "LINE_ITEM",
"metric_groups": [
"ENGAGEMENT"
]
}
},
"data": {
"start_time": "2019-03-12T00:00:00Z",
"segmentation_type": null,
"url": null,
"id_str": "1120829647711653888",
"entity_ids": [
"el32n"
],
"end_time": "2019-03-20T00:00:00Z",
"country": null,
"placement": "ALL_ON_TWITTER",
"id": 1120829647711653888,
"expires_at": null,
"account_id": "18ce54d4x5t",
"status": "PROCESSING",
"granularity": "TOTAL",
"entity": "LINE_ITEM",
"created_at": "2019-04-23T23:19:46Z",
"platform": null,
"updated_at": "2019-04-23T23:19:46Z",
"metric_groups": [
"ENGAGEMENT"
]
}
}
This response does not return the line item metrics. It simply provides information about the job you just created. The job ID is needed to check on the status of the job. This is shown in both the id
and id_str
response attributes.
Next, you'll want to check whether the job you've created using the id_str
from the previous response, has finished processing as indicated by "status": "SUCCESS"
in the response. This means the data is ready to download. The url
field contains the download link.
$ twurl -H ads-api.x.com "/9/stats/jobs/accounts/18ce54d4x5t?job_ids=1120829647711653888"
{
"request": {
"params": {
"job_ids": [
1120829647711653888
]
}
},
"next_cursor": "1120828505715920896",
"data": [
{
"start_time": "2019-03-12T00:00:00Z",
"segmentation_type": null,
"url": "https://ton.twimg.com/advertiser-api-async-analytics/zBkuuPeEVx-5OygDVcZpqNtwt51Z5X9d-_AXNRcyhBlhBOgOfi6UDmGBvUFJAKnHY9ABN8z9f9V3Wn4l3OmF4KzJDmTUjNCikq9JwBUYm2AP8pRRoV-kPUgR0PaIqAb4.json.gz",
"id_str": "1120829647711653888",
"entity_ids": [
"el32n"
],
"end_time": "2019-03-20T00:00:00Z",
"country": null,
"placement": "ALL_ON_TWITTER",
"id": 1120829647711653900,
"expires_at": "2019-04-25T23:19:48Z",
"account_id": "18ce54d4x5t",
"status": "SUCCESS",
"granularity": "TOTAL",
"entity": "LINE_ITEM",
"created_at": "2019-04-23T23:19:46Z",
"platform": null,
"updated_at": "2019-04-23T23:19:48Z",
"metric_groups": [
"ENGAGEMENT"
]
}
]
}
While we're passing in a single job ID in the above example, in practice, you'll want to use the job_ids
parameter to check on the status of multiple jobs at a time by specifying up to 200 job IDs.
Next, download the data file using the listed url
value.
$ wget https://ton.twimg.com/advertiser-api-async-analytics/zBkuuPeEVx-5OygDVcZpqNtwt51Z5X9d-_AXNRcyhBlhBOgOfi6UDmGBvUFJAKnHY9ABN8z9f9V3Wn4l3OmF4KzJDmTUjNCikq9JwBUYm2AP8pRRoV-kPUgR0PaIqAb4.json.gz
--2019-04-23 17:52:12-- https://ton.twimg.com/advertiser-api-async-analytics/zBkuuPeEVx-5OygDVcZpqNtwt51Z5X9d-_AXNRcyhBlhBOgOfi6UDmGBvUFJAKnHY9ABN8z9f9V3Wn4l3OmF4KzJDmTUjNCikq9JwBUYm2AP8pRRoV-kPUgR0PaIqAb4.json.gz
Resolving ton.twimg.com (ton.twimg.com)... 72.21.91.70
Connecting to ton.twimg.com (ton.twimg.com)|72.21.91.70|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 381 [application/gzip]
Saving to: 'zBkuuPeEVx-5OygDVcZpqNtwt51Z5X9d-_AXNRcyhBlhBOgOfi6UDmGBvUFJAKnHY9ABN8z9f9V3Wn4l3OmF4KzJDmTUjNCikq9JwBUYm2AP8pRRoV-kPUgR0PaIqAb4.json.gz'
zBkuuPeEVx-5OygDVcZpqNtwt51Z5 100%[=================================================>] 381 --.-KB/s in 0s
2019-04-23 17:52:12 (5.27 MB/s) - 'zBkuuPeEVx-5OygDVcZpqNtwt51Z5X9d-_AXNRcyhBlhBOgOfi6UDmGBvUFJAKnHY9ABN8z9f9V3Wn4l3OmF4KzJDmTUjNCikq9JwBUYm2AP8pRRoV-kPUgR0PaIqAb4.json.gz' saved [381/381]
Finally, unzip the file.
$ gunzip zBkuuPeEVx-5OygDVcZpqNtwt51Z5X9d-_AXNRcyhBlhBOgOfi6UDmGBvUFJAKnHY9ABN8z9f9V3Wn4l3OmF4KzJDmTUjNCikq9JwBUYm2AP8pRRoV-kPUgR0PaIqAb4.json.gz
The contents of the file are shown below.
$ cat zBkuuPeEVx-5OygDVcZpqNtwt51Z5X9d-_AXNRcyhBlhBOgOfi6UDmGBvUFJAKnHY9ABN8z9f9V3Wn4l3OmF4KzJDmTUjNCikq9JwBUYm2AP8pRRoV-kPUgR0PaIqAb4.json
{
"data_type": "stats",
"time_series_length": 1,
"data": [
{
"id": "el32n",
"id_data": [
{
"segment": null,
"metrics": {
"impressions": [
3482
],
"tweets_send": null,
"qualified_impressions": null,
"follows": null,
"app_clicks": null,
"retweets": [
102
],
"unfollows": null,
"likes": [
15
],
"engagements": [
171
],
"clicks": [
30
],
"card_engagements": null,
"poll_card_vote": null,
"replies": null,
"carousel_swipes": null
}
}
]
}
],
"request": {
"params": {
"start_time": "2019-03-12T00:00:00Z",
"segmentation_type": null,
"entity_ids": [
"el32n"
],
"end_time": "2019-03-20T00:00:00Z",
"country": null,
"placement": "ALL_ON_TWITTER",
"granularity": "TOTAL",
"entity": "LINE_ITEM",
"platform": null,
"metric_groups": [
"ENGAGEMENT"
]
}
}
}