Engagement API
Overview
This is an enterprise API available within our managed access levels only. To use this API, you must first set up an account with our enterprise sales team. Learn more
The Engagement API provides access to Post impression and engagement metrics. While most metrics and endpoints require you to authenticate using OAuth 1.0a User Context, you can access public Favorite, Retweet, Reply, and Video Views metrics using OAuth 2.0 Bearer Token and the /totals endpoint.
Note: You may observe differences between reported data on some of the X web dashboards, and the data reported in the Engagement API. These differences occur because the web dashboards typically only show engagements and/or impressions that occurred within the selected time range. For example, a web dashboard may show engagement on Posts within the span of a calendar month, while the Engagement API may show engagements that fall beyond the span of that month, but within the time range requested. The Engagement API should be seen as the valid source, in these cases.
Request endpoints
The Engagement API has three endpoints:
Current Totals: [/totals]
- Requests return a total metric for impressions and a total metric for engagements for the desired Posts
- Limited to the following metrics: Impressions, Engagements, Favorites, Replies, Retweets, Quote Tweets, and Video Views
- Supports the ability to retrieve Impressions and Engagements metrics for Posts created within the last 90 days using OAuth 1.0a User Context
- Supports the ability to retrieve Favorites, Retweets, Quote Tweets, Replies, and Video Views metrics for any Post using OAuth 2.0 Bearer token
- The results are based on the current total of impressions and engagements at the time the request is made
- Ideal for powering a dashboard report and for calculating engagement rates across a variety of @handles
- Supports requesting metrics for up to 250 Posts per request
Last 28 hours: [/28hr]
- Requests can return a total metric for impressions, a total metric for engagements, and breakdown of individual engagement metrics that have occurred in the last 28 hours
- Data can be grouped by Post ID, and in time-series in aggregate, by day, or by hour
- Ideal for tracking the performance of recently created content
- Supports all available metrics
- Supports requesting metrics for up to 25 Posts per request
Historical: [/historical]
- Requests can return impressions, engagements, and a breakdown of individual engagement metrics for the most recent one year, based on the engagement time (not the Post creation time).
- Requests support a start date and end date parameter, providing flexibility to narrow into a specific time frame up to 4 weeks in duration.
- Post engagement data is limited to only 365 days in the past.
- Data can be grouped by Post ID, and in time-series in aggregate, by day, or by hour.
- Ideal for evaluating recent performance against a historical benchmark or developing a historical picture of an @handle’s performance.
- Supports all available metrics.
- Supports requesting metrics for up to 25 Posts per request.
Available metrics
The table below describes the types of metrics that can be accessed through the Engagement API.
Please check out our Interpreting the metrics page to learn more about the below metrics.
Metric | Endpoint Availability | User Context Required | Description |
---|---|---|---|
impressions | All | Yes | A count of how many times the Post has been viewed. This metric is only available for Posts that have been posted within the past 90 days. |
engagements | All | Yes | A count of the number of times a user has interacted with the Post. This metric is only available for Posts that have been posted within the past 90 days. |
favorites | All | Yes - /28hrs & /Historical No - /totals | A count of how many times the Post has been favorited. |
retweets | All | Yes - /28hrs & /Historical No - /totals | A count of how many times the Post has been Retweeted. |
quote_tweets | /totals | No - /totals | A count of times a Post has been Retweeted with a comment (also known as Quote). |
replies | All | Yes - /28hrs & /Historical No - /totals | A count of how many times the Post has been replied to. |
video_views | All | Yes - /28hrs & /Historical No - /totals | A count of how many times a video in the given Post has been 50% visible for at least two seconds. Video views are only available for Posts that are 1800 days old or less. If you try to request video views for any Posts older than 1800 days, you will receive the following object within your response, along with a separate object that contains any other metrics that you requested: “unsupported_for_video_views_tweet_ids”: [“TWEET_ID”] Please note: You may see a discrepancy between the video views metric displayed in the X owned and operated platforms (mobile app and website) and the number that you receive via the /28hr and /historical endpoints. * The video views displayed in the X user interface and with the /totals endpoint will display the video view aggregated across all Posts in which the given video has been posted. That means that the metric displayed in the UI includes the combined views from any instance where the video has been Retweeted or reposted in separate Posts. This metric does not include video views on gifs. * The video views provided by the /28hr and /historical endpoints will just include those views generated by the specific Post for which you are pulling metrics. This metric does not include video views on gifs. |
media_views | /28hr /historical | Yes | A count of all views (autoplay and click) of your media counted across videos, gifs, and images. |
media_engagements (formerly Media Clicks) | /28hr /historical | Yes | A count of how many times media such as an image or video in the Post has been clicked. |
url_clicks | /28hr /historical | Yes | A count of how many times a URL in the Post has been clicked. |
hashtag_clicks | /28hr /historical | Yes | A count of how many times a hashtag in the Post has been clicked. |
detail_expands | /28hr /historical | Yes | A count of how many times the Post has been clicked to see more details. |
permalink_clicks | /28hr /historical | Yes | A count of how many times the permalink to the Post (the individual web page dedicated to this Post) has been clicked. |
app_install_attempts | /28hr /historical | Yes | A count of how many times an App Install event has occurred from the Post |
app_opens | /28hr /historical | Yes | A count of how many times an App Open event has occurred from the Post. |
email_tweet | /28hr /historical | Yes | A count of how many times the Post has been shared via email. |
user_follows | /28hr /historical | Yes | A count of how many times the User (Post author) has been followed from this Post. |
user_profile_clicks | /28hr /historical | Yes | A count of how many times the User (Post author) has had their profile clicked from this Post. |
Engagement groupings
Groupings enable custom organization of the returned engagement metrics. You can include a maximum of 3 groupings per request. You can choose to group the metrics by one or more of the following values:
All three endpoints support:
- tweet.id
- engagement.type
The /28hr
and /historical
can provide time-series metrics, and thus support:
- engagement.day
- engagement.hour
To learn more about grouping, please visit the Engagement API Grouping page within the Guides section.
Guides
Developer getting started guide
Introduction
The purpose of this documentation is to provide developers an introduction to integrating with the Engagement API. We’ll start off by discussing the ‘whys’ of integrating, then start digging into the technical ‘how’ details.
What does the Engagement API provide?
- The Engagement API provides impression and engagement data for any X account’s owned Posts from the last 90 days, assuming that account has authorized your App to request metrics on their behalf using 3-legged OAuth. This powerful, yet easy-to-implement solution gives immediate access to impressions and deep engagements such as URL clicks, #hashtag clicks, and many more.
- The Engagement API provides total aggregate metrics for favorites, Retweets, Quote Tweets, replies, and video views views for any Post. This can be used as a powerful way to get basic engagement data about any Post or collection of Posts.
- The Engagement API delivers new value to social listening, marketing, and publishing platforms by allowing customers to measure ROI on X by effectively measuring the performance of content using 15+ performance metrics.
- The Engagement API is a request/response API that allows app developers to send requests with Post IDs, desired metrics, and a time frame, for which the API instantly returns data.
Why integrate? Example use-cases
- Understand the total reach of your content to see how many people view it. See how many people view videos, click on links, click on hashtags, or install my apps.
- Generate both total and time-series engagement metrics.
- Understand basic engagement metrics (favorites, Retweets, Quote Tweets, replies) about any public Post.
- Use these metrics to determine what types of Posts work so I can post them more often and get more impressions and more engagements for my content.
- Automate marketing behavior (such as Retweeting content from a different owned account) every time one of my Posts reaches 100 Likes, or another threshold.
- Benchmark and compare my campaigns against each other as a tool for A/B testing.
- Analyze what type of content resonates for my customer service department to determine how and when to respond.
- Show analytics for content that is published from my platform.
The Engagement API was launched in 2016 and was the first X API to provide these in-depth engagement metrics at scale. The Engagement API is easy to use and enables customers to automate the process. Here is a case study describing an example integration:
Now that we’ve explored the ‘whys’ of the Engagement API, let’s start digging into the technical details.
Integrating the Engagement API
Introduction to API
The Engagement API is a simple RESTful API that receives requests encoded in JSON and responds with engagement metrics encoded in JSON. Requests consist three main parts (follow links for more documentation):
- Array of Post IDs.
- Array specifying the metric types of interest. Types include things such as ‘impressions’, ‘retweets’, ‘hashtag_clicks’, and ‘user_follows’.
- Engagement groupings, which is a JSON structure indicating how you want the engagement data arranged in the API response.
In many situations, the Engagement Types and Groupings will remains relatively constant from request to request, with only the Post IDs being updated.
The Engagement API provides three endpoints:
- Totals - Provides grand totals of engagements for Posts. Some metrics are available for all Posts, while others are only available for the past 90 days.
- 28 hour - Provides time-series engagement metrics from the last 28 hours.
- Historical - Provides time-series engagement metrics for up to four consecutive weeks for Posts posted since September 1, 2014.
The /totals endpoint supports requesting metrics for up to 250 Posts per request. The /28hour and /historical endpoints support 25 per request.
After discussing getting access to the Engagement API, we’ll walk through making an API request, provide an OAuth overview, and provide links to other technical resources.
Getting API access
If you are reading this document, you have most likely already obtained access to the Engagement API. If not, please reach out to your Enterprise account manager, or apply for Enterprise access here.
The first step is creating a X app using an approved developer account via the developer portal. Your account manager will need the numeric App ID associated with this application to provide access. If you need to apply for a developer account, you can do so here.
Making a request
The good news is that making requests to the Engagement API is simple. For our request, we’ll ask it for total Retweets, Quote Tweets, Favorites, and replies, for the following two @XDevelopers Posts:
1/ Today we’re sharing our vision for the future of the Twitter API platform
— Twitter Dev (@TwitterDev) April 6, 2017
Don’t miss the Posts about your Post.
Now on iOS, you can see Retweets with comments all in one place. pic.x.com/oanjZfzC6y
— X (@X) May 12, 2020
The first step is constructing the API request in JSON, consisting of these two Post IDs placed in an array, an array of engagement types of interest, and a custom-named “groupings” JSON object that indicates how we want the metrics arranged in the response. Here is what our request looks like:
To retrieve these total metrics, we POST this JSON request to the https://data-api.x.com/insights/engagement/totals endpoint.
We’ll include the following headers to indicate that our request is encoded in JSON, and that it is Gzipped (request bodies can get big):
- Content-Type: application/json
- Accept-Encoding: gzip
When making requests we authenticate using OAuth, which we’ll discuss more in the next section.
The API returns the following payload:
Note that the response has our requested metrics in the structure described by the “groupings” definitions, with metrics listed by Post ID first, then by engagement type on the next level.
That was pretty simple. If you are new to authenticating with OAuth, check out the next section.
Authenticating with OAuth
OAuth is an authentication standard that is very common in the technology industry. If you are already using OAuth (perhaps with other X APIs) then you are likely using a language-specific OAuth package that abstracts away all the gnarly details. If you are new to OAuth, please visit our Oauth with the X API page or head directly to the https://oauth.net to learn more. Then we recommend that you find an OAuth package for your integration language of choice and start there. With these packages, the path to authenticating typically means configuring your keys and tokens, creating some sort of HTTP object, then making requests with that object.
For example, in the Ruby world, the following pseudo-code represents a recipe to build an OAuth-enabled app using the Ruby gem ‘oauth’ and making a POST request:
The Engagement API supports both application-only and user-context authentication. If you are collecting engagement metrics for unowned public Posts with the /totals endpoint then no user permission is required and you can use application-only authentication. In this case, you’ll use only your app key and secret to authenticate.
OAuth also allows an app to make an API request “on behalf of another user”, using tokens that relate to the user. If you are generating Engagement metrics for owned Posts, ie Posts that were published by a user whom you have user tokens for, you will be making requests with a user context, meaning authenticating with both your app keys and user-specific access tokens. These user access tokens are typically supplied with the ‘Sign-in with X’ process or acquired directly from the user (please note that you must use twurl if you acquire the tokens directly from the user). Once the user provides their tokens, they do not expire and can be used with the Engagement API to make requests on their behalf, as long as the user doesn’t reset their tokens or change their password, in which case they will have to provide you the new tokens.
You can review which metrics require which authentication via this table.
Selecting an Engagement API Endpoint
The Engagement API provides three distinct endpoints:
- Totals - provides grand totals of select metrics from owned ‘owned’ or ‘unowned’ Posts. Some metrics are available for all Posts, while others are only available for Posts published in the last 90 days. Supports 250 Posts per request.
- 28 hour - provides time-series Engagement metrics for ‘owned’ Posts from the last 28 hours. Supports 25 Posts per request.
- Historical - provides time-series Engagement metrics for up to four consecutive weeks for ‘owned’ Posts posted since September 1, 2014. Supports 25 Posts per request.
Each endpoint has its own unique characteristics. Whether you are planning to use all three, or are trying to decide which one best matches your use case, it’s important to understand the differences between them.
Below we introduce some key concepts, further explore the three endpoints, and then present example use cases that map generally to a specific endpoint. Our hope is that this information will help you more efficiently integrate all three, or help you decide which single endpoint best fits your mission.
Key concepts
There are several key concepts that help illustrate the different features of, and data provided by, the three Engagement API endpoints.
Impressions and engagement metrics
Impressions represent the number of times that a given Post has been viewed on the X platform in an organic context. Impressions generated from Posts that are seen in a Promoted or Paid context are not included. Before the Engagement API, Post impressions represented only a measure of potential views. It was based on counting followers of the author’s account and those of any account Retweeting the content. It did not take into account the common situation when a given user does not actually see the Post.
The impression metrics generated by the Engagement API is an actual measure of the number of times a Post has been rendered for display. If a follower of your account misses your Post, it does not count as an impression.
The Engagement API provides metrics on 14 unique engagement metric types, each representing a distinct action a user can take when presented a Post. These include Retweeting, Liking, Replying, clicking on entities like #hashtags, links and media, following the author, and viewing the author’s profile. All of these individual actions are rolled up into a single Engagements metric.
Owned and unowned X content
The Engagement makes a clear distinction between owned and unowned Posts. Owned Posts are Posts that are posted from your account, or Posts that you have obtained permission to request Engagement data for. As with other X APIs, you obtain permission by having other X users/accounts share access tokens that enable you to make API requests on their behalf. A common way to obtain these tokens is with the ‘Sign in with X’ process.
The /totals endpoint provides engagement data for both owned and unowned Posts. For unowned Posts, you can request engagement metrics that are publicly available in a Post display: Favorite, Retweet, and Reply. For these metrics, what the Engagement API brings to the table is the ability to retrieve these metrics at scale in an automated way. For owned Posts, the /totals endpoint also provides Impression and (total) Engagement metrics.
The /28hr and /historical endpoints provide metrics for owned Posts only, meaning that you have to pass along user context when making the request to these endpoints.
Total and time-series engagement Data
The /totals endpoint provides, as its name implies, only grand totals for its engagement types. Its numbers represent the up-to-date totals since the Post was posted. If a Post was just posted and you repeatedly request its metrics, these totals will commonly change with each request.
The /28hr and /historical endpoints can provide both grand totals and time-series data. When requesting time-series data, the engagement metrics can be rolled up into daily or hourly data.
See our documentation on engagement groupings for how to request time-series data with the /28hr and /historical endpoints.
Endpoints and example use cases
Given the characteristics and differences discussed above, each individual endpoint generally maps to different types of use cases. To help you decide which endpoint best serves your particular use case, below are some example user statements and the endpoint that best satisfies it.
/totals
- I only need access to some metric types (Impressions, Engagements, Favorites, Retweets, Quote Tweets, Replies, and Video Views).
- I need access to basic engagement data for any Post, not just owned Posts.
- I want to compare performance against a competitor.
- I want to track basic engagement stats for a hashtag or campaign that includes Posts that I don’t own.
- I don’t need data broken out by day or hour, I just need the current total when I make a request.
- I need a single metric to show in a report or dashboard and don’t want to store any data.
- I want to show data at page load time, and just need to make a request and get a response.
- I need access to get data for hundreds of thousands or millions of Posts per day.
/28hr
- I need access to all 17 metric types.
- I want to show data for very recent Posts posted in last 28 hours.
- I have a job that runs once a day to get data that I care about and only need to get data for the last day.
- I need to have metrics broken out by day or hour.
- I want to show time-series breakouts of activity by hour in a dashboard.
- I need high access for hundreds of thousands to Posts per day
- I have storage capabilities and can refresh data once per day and keep a running tally.
/historical
- I need access to all 17 metric types.
- I need to get historical data for Posts created all the way back to September 2014.
- I want to show detailed historical analysis that compares campaigns.
- I need to have metrics broken out by day or hour.
- I don’t need high access to the Engagement API and only need to get data for a few hundred or thousand Posts per day.
Engagement API key characteristics
- RESTful API serving JSON data, supporting POST requests with JSON data bodies.
- Types of Requests: Client apps may make the following types of requests:
- Total engagements — HTTP POST request to /totals endpoint
- Last 28-hour engagements — HTTP POST request to /28hr endpoint
- Historical engagements — HTTP POST request to /historical endpoint
- OAuth authentication:
- OAuth 1.0 User Context: All available metrics are available for Posts that are owned by a user that has authorized your App using 3-legged OAuth. You must use that user’s Access Tokens when making your request.
- OAuth 2.0 Bearer Token: Select metrics (Retweets, Quote Tweets, Replies, Favorites, and Video Views) are available for any public Post.
- Request metadata and structure: Request data is a JSON object consisting of a Post ID array, an array of engagement types, and an engagement grouping structure.
- Posts per request:
- /totals endpoint: 250 Post IDs
- /28hr endpoint: 25 Post IDs
- /historical endpoint: 25 Post IDs
- Engagement metrics availability:
- /totals — Metric totals since when Post was posted. Impressions and Engagements are available for Posts published in the last 90 days, while Retweets, Quote Tweets, Replies, Favorites, and Video Views are available for all Posts.
- /28hr — Last 28 hours from time of request.
- /historical — Any 28-day period starting September 1, 2014.
- Metric types: Each request includes an array of Metric Types. The availability of these depends on the endpoint and, if requesting from the /totals endpoint, on whether Posts are user-permissioned.
- /totals endpoint:
- All Posts: Favorites, Retweets, Quote Tweets, Replies, and Video Views
- Requires OAuth 1.0a User Context: Impressions, Engagements, Favorites, Replies, and Retweets
- /28hr and /historical endpoints (Requires OAuth 1.0a User Context with Post owner’s Access Token): Impressions, Engagements, Favorites, Replies, Retweets, URL Clicks, Hashtag Clicks, Detail Click, Permalink Clicks, Media Clicks, App Install Attempts, App Opens, Post Emails, Video Views, and Media Views
- /totals endpoint:
- Engagement groupings: Each request includes an array of Engagement Groupings. With these groupings you can customize how the returned metrics are organized. Up to three groupings can be included with each request. Metrics can be organized by the following values:
- All endpoints: Post ID, Engagement Type
- /28hr and /historical endpoints: These endpoints provide time-series if these additional groupings are specified: Engagement Day, Engagement Hour
- Integration Expectations: Your team will be responsible for the following.
- Creating and maintaining a client app that can send HTTP requests to the Engagement API that returns engagement metrics for Post ID included in request.
- Limitations
- Video views are only available for Posts that are 1800 days old or less.
Authenticating with the Engagement API
Please note:
X needs to enable access to the Engagement API for your developer App before you can start using the API. To this end, make sure to share the App ID that you intend to use for authentication purposes with your account manager or technical support team.
There are two authentication methods available with the Engagement API: OAuth 1.0a and OAuth 2.0 Bearer Token.
OAuth 2.0 Bearer Token (also referred to as “application-only”) allows you to access publicly available engagement metrics. This authentication method can be used to get total counts for Favorites (aka Likes), Retweets, Quote Tweets, Replies, and video views for any publicly available Posts when making requests to the /totals endpoint.
OAuth 1.0a (also referred to as “user context”) allows you to make requests on behalf of a user and access private engagement metrics that belong to the user in question.
This authentication method is required for:
- All requests sent to the /28hr endpoint and /historical endpoint
- Accessing any of the following private metrics: Impressions, Engagements, Media Views, Media Engagements, URL Clicks, Hashtag Clicks, Detail Expands, Permalink Clicks, App Install Attempts, App Opens, Email Post, User Follows, and User Profile Clicks
When sending a request with OAuth 1.0a, you need to include the Access Tokens (Access Token and Secret) of the user who owns the Post or protected resource of interest. If you do not provide the correct user Access Tokens when requesting protected user data, the Engagement API will return a 403 Forbidden
error.
The Engagement API will not allow you to fetch engagement data for protected Posts, even if you are authenticating on behalf of the user who owns these Posts. Attempting to do so will return a 400 Bad Request
error, with the message "Tweet ID(s) are unavailable"
.
If you are sending a request on behalf of your own X account (in other words, the account that owns the developer App), you can generate the required Access Tokens directly from within the developer portal, under the “Keys and tokens” tab for the developer App.
If you are making a request on behalf of any other user, you will need to use the 3-legged OAuth flow to obtain the required Access Tokens. The following documentation contains more information on how to do this: OAuth 1.0a: how to obtain a user’s access tokens.
For additional examples, including how to authenticate using OAuth 1.0a, check outXDevelopers sample Python code for the Engagement API.
Recent changes to the Engagement API
The Engagement API delivers invaluable impression and engagement metrics that enable you to monitor the performance of your activity on X. In our continual effort to enable marketing decisions based on our data, we are excited to share recent changes to the Engagement API that provide greater consistency with metrics across all of X.
We recently deployed changes to modernize the Engagement API to use the same metrics aggregation methodology in use by the X analytics dashboard (analytics.x.com). We took a thoughtful approach to try and minimize breaking API changes when rolling out these new metrics and deployed the first set of changes on October 9, 2017. These changes improve consistency from all of the places you or your customers might monitor your performance on X. Please see the detailed outline of the changes below:
Metric | Change |
engagements | We’ve updated the metrics that roll into overall engagements to match consistency with the Post analytics dashboard. Engagements measures “times people interacted with this Post”. For Posts that include media like a video or a GIF, the engagements metric will no longer include media views. Media views can now be accessed in a new metric, media_views. |
media_clicks* | This metric has been replaced by a new metric called “media_engagements”. |
video_views | As of July 6th, 2018, this metric is now available for ‘unowned’ Posts via the /totals endpoint. This means that you can access the video views for all Posts by using app-only authentication. You can only request video views that are younger than 1800 days old. If you try to request video views for a Post older than 1800 days, you will receive the following: “unsupported_for_video_views_tweet_ids”: [“TWEET_ID”] Please note that it will differ from media_views in that video_views relies on the MRC standard of 50% of the video in view for at least two seconds. Also, note that you may see a discrepancy between the video views metric displayed in the X owned and operated platforms (mobile app and website) and the number that you receive via the /28hr and /historical endpoints. * The video views displayed in the X user interface and that delivers using the /totals endpoint will display the video view aggregated across all Posts in which the given video has been posted. That means that the metric displayed in the UI includes the combined views from any instance where the video has been Retweeted or reposted in separate Posts. * The video views provided by the /28hr and /historical endpoints will just include those views generated by the specific Post for which you are pulling metrics. |
media_views | This includes all views (autoplay and click) of your media counted across videos, vines, gifs, and images. Please note that Posts with images do not show a media_views metric in the analytics dashboard but will be returned in the Engagement API. |
media_engagements* | This includes the number of clicks on your media across videos, vines, gifs, and images. This metric is replacing media_clicks. |
quote_tweets | As of July 7th, 2020, this metric is now available for ‘unowned’ Posts via the /totals endpoint. This means that you can access the Quote Post count for all Posts by using app-only authentication. |
Interpreting the metrics
Note: You may observe differences between reported data on some of the X web dashboards, and the data reported in the Engagement API. These differences occur because the web dashboards typically only show engagements and/or impressions that occurred within the selected time range. For example, a web dashboard may show engagement on Posts within the span of a calendar month, while the Engagement API may show engagements that fall beyond the span of that month, but within the time range requested. The Engagement API should be seen as the valid source, in these cases.
Impressions and engagement data
The Engagement API delivers organic impressions and engagement data.
Impressions represent the number of times that a given Post has been viewed on the X platform in an organic context. Impressions generated from Posts that are seen in a Promoted or Paid context are not included.
Engagements represent the number of times that a given Post was engaged upon by a viewer in both an organic and promoted context. Engagements include, but are not limited to, Retweets, Favorites, Replies, URL Clicks, Hashtag Clicks, Mention Clicks, and Media Views. For the full list of included engagement actions, please see the Engagement Data section.
In order to calculate a baseline engagement rate, please use the total number of engagements divided by the total number of impressions for a given Post for the time period you are analyzing.
Impression and engagement data can only be retrieved for Posts from owned @handles, or @handles that have authorized your application to view details about their Posts. Internally, the Engagement API will track the number of unique @handles that have been requested against the contracted @handle limit. It’s recommended to also track the @handle request usage on the client side throughout the month.
Video metrics
There are a couple of different metrics that represent impressions of media within X. The first of which is our video views metric, which relies on the MRC standard of 50% of the video in view for at least two seconds. The second is Media Views, that includes all views (autoplay and click) of your media counted across videos, vines, gifs, and images.
The video views metric is available for owned Posts via the /28hour and /historical endpoints, as well as for all unowned Posts via the /totals endpoint.
While the video views metric within the X user interface is using the same MRC standard, please note that you may see a discrepancy between the video views metric displayed in the X owned and operated platforms (mobile app and website) and the number that you receive via the different Engagement API endpoints.
- The video views provided by the /totals endpoint and the X user interface will display the video view aggregated across all Posts in which the given video has been posted. That means that the metric delivered via /totals and displayed in the X UI includes the combined views from any instance where the video has been Retweeted or reposted in separate Posts.
- The video views provided by the /28hour and /historical Engagement API endpoints will just include those views generated by the specific Post for which you are pulling metrics.
Please note that we do not deliver video views for Posts that are older than 1800 days. Instead, we deliver an object that lists the Posts that are older than 1800 days. You will still receive all other metrics for your requested Posts in a separate object. Here is an example response:
The Media Views metric is only available for owned Posts with the /28hour and /historical endpoints.
Engagement API groupings
Groupings enable custom organization of the returned engagement metrics. You can include a maximum of 3 groupings per request. You can choose to group the metrics by one or more of the following values:
All three endpoints support:
- tweet.id
- engagement.type
The /28hr
and /historical
can provide time-series metrics, and thus support:
- engagement.day
- engagement.hour
Groupings are honored serially, so that you can change the desired result format by changing the order of your group_by
values. Groupings that contain four group_by
values will only be supported in one of the following two formats:
OR
For example, if you want to generate grand totals of metric types, include the following “groupings” specification as part of your request (and see the API Reference page for more information on assembling requests):
With this grouping, the Engagement API’s JSON response will include a root-level "Grand Totals"
attribute which contains grand totals by metrics type:
To generate a 4-hour time-series of metrics for a single Post grouped by Post IDs, the following Grouping specification would be part of the request:
With this grouping, the Engagement API’s JSON response will include a root-level "Tweets_MetricType_TimeSeries"
attribute which contains the metrics broken down by Post ID, then metric type, and the corresponding hourly time-series:
Frequently asked questions
Enterprise
Engagement API
Error troubleshooting guide
Still can’t find what you’re looking for?
API reference
POST insights/engagement
Methods
Method | Description |
---|---|
POST /insights/engagement/totals | Retrieve total impressions and engagements for a collection of Tweets. |
POST /insights/engagement/historical | Retrieve impressions and engagements for a collection of Tweets for a period up to 4 weeks in duration, back to September 1, 2014. |
POST /insights/engagement/28hr | Retrieve impressions and engagements for a collection of Tweets for the past 28 hours. |
Authentication
The Engagement API requires the use of HTTPS and supports the use of both User Context and Application-Only OAuth. Most requests to the Engagement API require the use of 3-Legged OAuth (A specific version of User Context), meaning that you use the consumer key and secret of the app that has been registered and approved for Engagement API access by your Twitter account manager, as well as the Tweet owners’ access token and access token secret to call the endpoint. The following requests require this type of OAuth:
- Any request to /totals to obtain Impressions and Engagements metric types, which are limited to owned Tweets
- Any request to /28hr
- Any request to /historical
Some requests to the Engagement API can be performed using Application-Only OAuth, meaning that you just need to provide your consumer key and secret, or a bearer token. The following request can be performed with this type of OAuth:
- Any request to /totals to obtain Favorites, Replies, Retweets, or Video Views metric types, which can be retrieved for any Tweet
For any request, you will need to set up a Twitter app and corresponding API key using the app management console available at developer.twitter.com.
Please note - You can view and edit your existing Twitter apps via the Twitter app dashboard if you are logged into your Twitter account on developer.twitter.com.
Once you have set up your app, the app ID will need to be approved by your account representative in order for your app to make requests to the Engagement API. Access tokens must be used to represent the “current user”, and requests made on behalf of a separate user must be signed with a valid token. Ensure that you’re encoding reserved characters appropriately within URLs and POST bodies before preparing OAuth signature base strings.
For more information on how to get started with OAuth, please visit the following links:
POST /insights/engagement/totals
The totals endpoint provides the ability to retrieve current total impressions and engagements for a collection of up to 250 Tweets at a time.
Request Method | HTTP POST |
URL | https://data-api.x.com/insights/engagement/totals |
Content Type | application/json |
Compression | Gzip. To make a request using Gzip compression, send an Accept-Encoding header in the connection request. The header should look like the following: Accept-Encoding: gzip |
POST Format | Requests can be sent as a POST request where the body is a JSON object containing a collection of Tweet IDs and a desired grouping. The POST is formatted as an array with a tweets , engagements , and groupings object. Each request can have a maximum of 250 Tweet IDs. An example POST body looks like: { “tweet_ids”: [ “Tweet ID 1”, “Tweet ID 2”, “Tweet ID 3” ], “engagement_types”: [ “impressions”, “engagements”, “favorites”, “quote_tweets” ], “groupings”: { “grouping name”: { “group_by”: [ “tweet.id”, “engagement.type” ] } } } |
Tweet IDs | An array that includes the Tweet IDs for the Tweets to be queried for engagement data. Please note that you are only able to request data for Tweets that were created by the authenticating @handle. Up to 250 Tweets may be included per request, and Tweet IDs must be represented as strings. |
Engagement Types | An array that includes the types of engagement metrics to be queried. The Totals endpoint supports only the following engagement types: impressions , engagements , favorites , retweets , quote_tweets , replies , video_views . The /totals endpoint supports the ability to retrieve impressions and engagements for Tweets created within the last 90 days, and favorites , retweets , quote_tweets , replies , and video_views for any Tweet. |
Groupings | Results from the Engagement API can be returned in different groups to best fit your needs. You can include a maximum of 3 groupings per request. For each grouping, you may define a custom grouping name to make it easier to refer to this grouping type in your application. Once you have defined a grouping name, you can choose to group tweet.id and/or engagement.type . Groupings are honored serially, so that you can change the desired result format by changing the order of your group_by values. An example grouping that will show metrics separated by Tweet ID and metric type looks like: “groupings”: { “my grouping name”: { “group_by”: [ “tweet.id”, “engagement.type” ] } } |
POST Size Limit | Requests can be made for a maximum of 250 Tweet IDs at a time. |
Response Format | JSON. The header of your request should specify JSON format for the response. |
Rate Limit | You will be rate limited by minute, as specified in your contract according to your level of access. |
Example Request (public metrics) | curl —request POST —url https://data-api.x.com/insights/engagement/totals —header ‘accept-encoding: gzip’ —header ‘authorization: Bearer ’ —header ‘content-type: application/json’ —data ’{ “tweet_ids”: [ “1070059276213702656”,“1021817816134156288”,“1067094924124872705” ], “engagement_types”: [ “favorites”,“retweets”,“replies”,“quote_tweets”,“video_views” ], “groupings”: { “perTweetMetricsUnowned”: { “group_by”: [ “tweet.id”, “engagement.type” ] } } } —verbose —compressed |
Example Request | curl —request POST —url https://data-api.x.com/insights/engagement/totals —header ‘accept-encoding: gzip’ —header ‘authorization: OAuth oauth_consumer_key=“consumer-key-for-app”,oauth_nonce=“generated-nonce”,oauth_signature=“generated-signature”,oauth_signature_method=“HMAC-SHA1”, oauth_timestamp=“generated-timestamp”,oauth_token=“access-token-for-authed-user”, oauth_version=“1.0”’ —header ‘content-type: application/json’ —data ’{ “tweet_ids”: [ “1060976163948904448”,“1045709644067471360” ], “engagement_types”: [ “favorites”,“replies”,“retweets”,“video_views”,“impressions”,“engagements” ], “groupings”: { “perTweetMetricsOwned”: { “group_by”: [ “tweet.id”, “engagement.type” ] } } }’ —verbose —compressed |
Example Response (public metrics) | { “perTweetMetricsUnowned”: { “1021817816134156288”: { “favorites”: “530”, “quote_tweets”: “79”, “replies”: “147”, “retweets”: “323”, “video_views”: “0” }, “1067094924124872705”: { “favorites”: “1360”, “quote_tweets”: “29”, “replies”: “56”, “retweets”: “178”, “video_views”: “5754512” }, “1070059276213702656”: { “favorites”: “69”, “quote_tweets”: “5”, “replies”: “7”, “retweets”: “26”, “video_views”: “0” } } } |
Example Response | { “perTweetMetricsOwned”: { “1045709644067471360”: { “engagements”: “2”, “favorites”: “0”, “impressions”: “47”, “replies”: “0”, “retweets”: “8”, “quote_tweets”: “5”, “video_views”: “0” }, “1060976163948904448”: { “engagements”: “4”, “favorites”: “0”, “impressions”: “148”, “replies”: “1”, “retweets”: “9”, “quote_tweets”: “2”, “video_views”: “0” } } } |
Unavailable Tweet IDs | For queries that include Tweet IDs that have been made unavailable (e.g., have been deleted), appropriate data will be returned for all available Tweet IDs, and unavailable Tweet IDs will be referenced in an array called unavailable_tweet_ids . For example: { “start”: “2015-11-17T22:00:00Z”, “end”: “2015-11-19T02:00:00Z”, “unavailable_tweet_ids”: [ “323456789” ], “group1”: { “423456789”: { “favorites”: “67”, “replies”: “8”, “retweets”: “26”, “quote_tweets”: “2” } } } |
POST /insights/engagement/28hr
The 28 hour endpoint provides the ability to retrieve impressions and engagements for a collection of up to 25 Tweets for the past 28 hours. The 28 hour endpoint also provides the ability to request metrics for all supported individual metrics. For the full list of supported metrics see Metric Availability.
Request Method | HTTP POST |
URL | https://data-api.x.com/insights/engagement/28hr |
Content Type | application/json |
Compression | Gzip. To make a request using Gzip compression, send an Accept-Encoding header in the connection request. The header should look like the following: Accept-Encoding: gzip |
POST Format | Requests can be sent as a POST request where the body is a JSON object containing a collection of Tweet IDs and a desired grouping. The POST is formatted as an array with a tweets , engagements , and groupings object. Each request can have a maximum of 25 Tweet IDs. An example POST body looks like: { “tweet_ids”: [ “Tweet ID 1”, “Tweet ID 2”, “Tweet ID 3” ], “engagement_types”: [ “impressions”, “engagements”, “url_clicks”, “detail_expands” ], “groupings”: { “grouping name”: { “group_by”: [ “tweet.id”, “engagement.type”, “engagement.hour” ] } } } |
Tweet IDs | An array that includes the Tweet IDs for the Tweets to be queried for engagement data. Please note that you are only able to requests data for Tweets that were created by the authenticating @handle. The 28 hour endpoint supports up to a maximum of 25 Tweets per request, and Tweet IDs must be represented as strings. |
Engagement Types | An array the types of engagement metrics to be queried. For the 28 hour endpoint, impressions , engagements , and all individual engagement types are supported metrics. For the full list of supported engagement metrics see Engagement Data. |
Groupings | Results from the Engagement API can be returned in different groups to best fit your needs. You can include a maximum of 3 groupings per request. For each grouping, you may define a custom grouping name to make it easier to refer to this grouping type in your application. Once you have defined a grouping name, you can choose to group by one or more of the following values: tweet.id engagement.type engagement.day engagement.hour Groupings are honored serially, so that you can change the desired result format by changing the order of your group_by values. An example grouping that will show metrics separated by Tweet ID, metric type, and looks like: “groupings”: { “my grouping name”: { “group_by”: [ “tweet.id”, “engagement.type”, “engagement.day” ] } } Groupings that have 4 group_by items are only valid if they use one of the following two orders. Requests that have 4 group_by items in a single grouping that are not one of the following will return an error. Additionally, only one grouping with 4 group_by items will be allowed per request. “group_by”: [ “tweet.id”, “engagement.type”, “engagement.day”, “engagement.hour” ] “group_by”: [ “engagement.type”, “tweet.id”, “engagement.day”, “engagement.hour” ] |
POST Size Limit | Requests can be made for a maximum of 25 Tweet IDs at a time. |
Response Format | JSON. The header of your request should specify JSON format for the response. |
Rate Limit | You will be rate limited by minute, as specified in your contract according to your level of access. |
Example Request | curl -X POST “https://data-api.x.com/insights/engagement/28hr” -H ‘Accept-Encoding: gzip’ -H ‘Authorization OAuth oauth_consumer_key=“consumer-key-for-app”,oauth_nonce=“generated-nonce”,oauth_signature=“generated-signature”,oauth_signature_method=“HMAC-SHA1”, oauth_timestamp=“generated-timestamp”,oauth_token=“access-token-for-authed-user”, oauth_version=“1.0”’ -d ’{ “tweet_ids”: [ “123456789” ], “engagement_types”: [ “impressions”, “engagements” ], “groupings”: { “hourly-time-series”: { “group_by”: [ “tweet.id”, “engagement.type”, “engagement.day”, “engagement.hour” ] } } }‘ |
Example Response | { “start”: “2015-09-14T17:00:00Z”, “end”: “2015-09-15T22:00:00Z”, “hourly-time-series”: { “123456789”: { “impressions”: { “2015-09-14”: { “17”: “551”, “18”: “412”, “19”: “371”, “20”: “280”, “21”: “100”, “22”: “19”, “23”: “6” }, “2015-09-15”: { “00”: “5”, “01”: “2”, “02”: “7”, “03”: “3”, “04”: “1”, “05”: “0”, “06”: “0”, “07”: “0”, “08”: “0”, “09”: “0”, “10”: “0”, “11”: “0”, “12”: “0”, “13”: “0”, “14”: “0”, “15”: “0”, “16”: “0”, “17”: “0”, “18”: “0”, “19”: “0”, “20”: “0”, “21”: “0” } }, “engagements”: { “2015-09-14”: { “17”: “0”, “18”: “0”, “19”: “0”, “20”: “0”, “21”: “0”, “22”: “0”, “23”: “0” }, “2015-09-15”: { “00”: “0”, “01”: “0”, “02”: “0”, “03”: “0”, “04”: “0”, “05”: “0”, “06”: “0”, “07”: “0”, “08”: “0”, “09”: “0”, “10”: “0”, “11”: “0”, “12”: “0”, “13”: “0”, “14”: “0”, “15”: “0”, “16”: “0”, “17”: “0”, “18”: “0”, “19”: “0”, “20”: “0”, “21”: “0” } } } } } |
Unavailable Tweet IDs | For queries that include Tweet IDs that have been made unavailable (e.g., have been deleted), appropriate data will be returned for all available Tweet IDs, and unavailable Tweet IDs will be referenced in an array called unavailable_tweet_ids . For example: { “start”: “2015-11-17T22:00:00Z”, “end”: “2015-11-19T02:00:00Z”, “unavailable_tweet_ids”: [ “323456789” ], “group1”: { “423456789”: { “favorites”: “67”, “replies”: “8”, “retweets”: 26 } } } |
POST /insights/engagement/historical
The historical endpoint provides the ability to retrieve impressions and engagements for a collection of up to 25 Tweets for any period up to 4 weeks in duration. Currently, data older than September 1, 2014 cannot be requested from the API. The historical endpoint also provides the ability to request metrics for all supported individual metrics. For the full list of supported metrics see Metric Availability.
Request Method | HTTP POST |
URL | https://data-api.x.com/insights/engagement/historical |
Content Type | application/json |
Compression | Gzip. To make a request using Gzip compression, send an Accept-Encoding header in the connection request. The header should look like the following: Accept-Encoding: gzip |
POST Format | Requests can be sent as a POST request where the body is a JSON object containing a collection of Tweet IDs and a desired grouping. The POST is formatted as an array with a tweets , engagements , and groupings object. Each request can have a maximum of 25 Tweet IDs. Each request can be specified with a custom Start and End date up to four weeks in duration. { “tweet_ids”: [ “Tweet ID 1”, “Tweet ID 2”, “Tweet ID 3” ], “engagement_types”: [ “impressions”, “engagements”, “url_clicks”, “detail_expands” ], “groupings”: { “grouping name”: { “group_by”: [ “tweet.id”, “engagement.type”, “engagement.hour” ] } } } |
Start and End Date | A custom start and end date can be specified with the start and end values as part of the request. You must specify a start and end date that are not longer than 4 weeks in duration. The oldest possible start date at this time is September 1, 2014. End dates in the future are not supported. If no Start and End date are supplied, the API will default to the immediately previous 4 weeks. The lowest granularity that data can be returned from the Engagement API is by hour. For any requests made with Start or End values that do not fall directly on an hourly boundary, requests will default to the nearest inclusive hour. For instance, a request with “start”:“2015-07-01T12:24:00Z” and “end”:“2015-07-10T08:37:00Z” will default to “start”:“2015-07-01T12:00:00Z”,“end”:“2015-07-10T09:00:00Z”. |
Tweet IDs | An array that includes the Tweet IDs for the Tweets to be queried for engagement data. Please note that you are only able to requests data for Tweets that were created by the authenticating @handle. The 4 week historical endpoint supports up to a maximum of 25 Tweets per request, and Tweet IDs must be represented as strings. |
Engagement Types | n array that includes the types of engagement metrics to be queried. For the 4 week historical endpoint, impressions , engagements , and all individual engagement types are supported metrics. For the full list of supported engagement metrics see Engagement Data. **Note:**Currently there are three metrics that will display as zero for queries made before September 15, 2015: favorites , replies , and retweets . |
Groupings | Results from the Engagement API can be returned in different groups to best fit your needs. You can include a maximum of 3 groupings per request. For each grouping, you may define a custom grouping name to make it easier to refer to this grouping type in your application. Once you have defined a grouping name, you can choose to group by one or more of the following values: tweet.id engagement.type engagement.day engagement.hour Groupings are honored serially, so that you can change the desired result format by changing the order of your group_by values. An example grouping that will show metrics separated by Tweet ID, metric type, and looks like: “groupings”: { “my grouping name”: { “group_by”: [ “tweet.id”, “engagement.type”, “engagement.day” ] } } Groupings that have 4 group_by items are only valid if they use one of the following two orders. Requests that have 4 group_by items in a single grouping that are not one of the following will return an error. Additionally, only one grouping with 4 group_by items will be allowed per request. “group_by”: [ “tweet.id”, “engagement.type”, “engagement.day”, “engagement.hour” ] “group_by”: [ “engagement.type”, “tweet.id”, “engagement.day”, “engagement.hour” ] |
POST Size Limit | Requests can be made for a maximum of 25 Tweet IDs at a time. |
Response Format | JSON. The header of your request should specify JSON format for the response. |
Rate Limit | You will be rate limited by minute, as specified in your contract according to your level of access. |
Example Request | curl -XPOST “https://data-api.x.com/insights/engagement/historical” -H ‘Accept-Encoding: gzip’ -H ‘Authorization OAuth oauth_consumer_key=“consumer-key-for-app”,oauth_nonce=“generated-nonce”,oauth_signature=“generated-signature”,oauth_signature_method=“HMAC-SHA1”, oauth_timestamp=“generated-timestamp”,oauth_token=“access-token-for-authed-user”, oauth_version=“1.0”’ -d ’{ “start”: “2015-08-01”, “end”: “2015-08-15”, “tweet_ids”: [ “123456789”, “223456789”, “323456789” ], “engagement_types”: [ “impressions”, “engagements”, “url_clicks”, “detail_expands” ], “groupings”: { “types-by-tweet-id”: { “group_by”: [ “tweet.id”, “engagement.type” ] } } }‘ |
Example Response | { “start”: “2015-08-01T00:00:00Z”, “end”: “2015-08-15T00:00:00Z”, “types-by-tweet-id”: { “123456789”: { “impressions”: “0”, “engagements”: “0”, “url_clicks”: “0”, “detail_expands”: “0” }, “223456789”: { “impressions”: “788”, “engagements”: “134”, “url_clicks”: “30”, “detail_expands”: “1323” }, “323456789”: { “impressions”: “4”, “engagements”: “0”, “url_clicks”: “2”, “detail_expands”: “0” } } } |
Unavailable Tweet IDs | For queries that include Tweet IDs that have been made unavailable (e.g., have been deleted), appropriate data will be returned for all available Tweet IDs, and unavailable Tweet IDs will be referenced in an array called unavailable_tweet_ids . For example:{ “start”: “2015-11-17T22:00:00Z”, “end”: “2015-11-19T02:27:50Z”, “unavailable_tweet_ids”: [ “323456789” ], “group1”: { “423456789”: { “favorites”: “67”, “replies”: “8”, “retweets”: 26 } } } |
Response codes
Status | Text | Description |
---|---|---|
200 | OK | The request was successful. |
400 | Bad Request | Generally, this response occurs due to the presence of invalid JSON in the request, or where the request failed to send any JSON payload. |
401 | Unauthorized | HTTP authentication failed due to invalid credentials. Check your OAuth keys and tokens. |
404 | Not Found | The resource was not found at the URL to which the request was sent, likely because an incorrect URL was used. |
429 | Too Many Requests | Your app has exceeded the limit on API requests. |
500 | Internal Server Error | There was an error on Gnip’s side. Retry your request using an exponential backoff pattern. |
502 | Proxy Error | There was an error on Gnip’s side. Retry your request using an exponential backoff pattern. |
503 | Service Unavailable | There was an error on Gnip’s side. Retry your request using an exponential backoff pattern. |
Error Messages
In various scenarios, the Engagement API will occur situation-specific error messages that your application should be equipped to deal with. The table below includes common examples of these error messages and how you should interpret them. Please note that in many cases the Engagement API will return partial results for available data with specific error messages as part of a 200 OK response with more information.
Error Message | Description |
---|---|
"errors":["Your account could not be authenticated. Reason: Access token not found"] | An error in the authentication component of the request. The “Reason” should provide information that is helpful to troubleshoot the error. In cases where you are not able to resolve, please send the full error, including the “Reason”, to our support team. |
"errors":["1 Tweet ID(s) are unavailable"],"unavailable_tweet_ids": ["TWEET_IDS"] | The Tweet ID or IDs you have requested are no longer available, usually indicating that they have been deleted or are no longer publicly available for another reason. |
"errors":["Impressions & engagements for tweets older than 90 days (*TIME_PERIOD*) are not supported"],"unsupported_for_impressions_engagements_tweet_ids":[*TWEET_IDS*] | The Tweet ID or IDs you have requested specific to the /totals endpoint are not 90 days or newer and are thus not available for returning the impressions or engagements metrics. |
"errors":["Forbidden to access tweets: *TWEET_IDS*"] | The Tweet ID or IDs you have requested are not available based on the authentication token you are using to retrieve data on behalf of a third party. |