Get a video URL from Twitter API v2
Published: 2022-08-15 14:09:00

Twitter API v2 has been available for quite a while now, but it's an [evolving process](https://dev.to/twitterdev/evolving-the-twitter-api-266o) as we bring more endpoints and features to the new environment.

One data field that was not initially available at launch was the URL for videos attached to Tweets. This information was added to the data expansions [earlier this year](https://developer.twitter.com/en/updates/changelog), so if you are making a request to the API today, you can now add query parameters to have multiple video variant URLs returned as part of an attached expansion.  

> If you're into the details, you can always check what functionality is available in the API by grabbing the latest OpenAPI specification document, which lives at [`https://api.twitter.com/2/openapi.json`](https://api.twitter.com/2/openapi.json) - you can look at the [Changelog](https://developer.twitter.com/en/updates/changelog) for a more high-level list of updates

Twitter API v2 has many improvements over the legacy version, one of them being the concepts of _[fields and expansions](https://developer.twitter.com/en/docs/twitter-api/data-dictionary/using-fields-and-expansions)_. These are query parameters that control which elements of data are returned on an API call. To get the video information, the data we want to return is part of [the `media` object](https://developer.twitter.com/en/docs/twitter-api/data-dictionary/object-model/media), contained in `variants`, which is an array of available display formats. 

## Building a query

I'll pick a recent Tweet with an attached video from my own timeline at random:

{% embed https://twitter.com/andypiper/status/1557438090897137665 %}

The Tweet ID here is `1557438090897137665` (I got this by taking it from the URL of the Tweet on Twitter, but I could have picked it out from an API query). If we request that Tweet via the API, by default only the the basic fields will be returned (for a Tweet, these are `text` and `id`). In this case, we want to get the video URLs that are attached. In oder to do this, we need the following combination of fields and expansions:

 - `tweet.fields` - I need to ask for any `attachments` (the concept here is that videos are _attached to_ Tweets, and so are images, polls, etc)
- `expansions` - the name of the expansion is `attachments.media_keys`

These two parameters will now tell the API to return any `media` object associated with the Tweet inside the `includes` section of the response, but by default, the default fields for the `media` object are `media_key` (the value that links the data to the Tweet itself), and `type` (video, image, etc). So we need to add third parameter:

- `media.fields` - the video data is in the `variants` array. It may also be useful to request `alt_text` (if the user has set alternative text for accessibility), `preview_image_url`, `duration_ms`, and possibly also `public_metrics` so that we can see how many times the video has been viewed.

The final request we've built includes the URL parameters `?tweet.fields=attachments&expansions=attachments.media_keys&media.fields=variants,alt_text,preview_image_url,duration_ms,public_metrics`. These parameters can be used on any API calls that are expected to return Tweet objects, and will expand the media to include appropriate video information when available.

## Show us some code!

The Twitter team released some beta SDKs for the new API, starting with packages for JavaScript and TypeScript in Node, and also Java. 

{% embed https://twitter.com/TwitterDev/status/1503863301276827651 %}

> If you don't code in these languages (or even if you do, but you're familiar with a different SDK), the community has created a [range of great libraries](https://developer.twitter.com/en/docs/twitter-api/tools-and-libraries/v2) to help you code against the Twitter API!

Let's go ahead and use the TypeScript SDK to run our query. You'll need a Twitter Developer Account (if you don't have one yet, [sign up here](https://t.co/signup), it's free!), and to create a project containing an app to get a _Bearer Token_. You'll also need to install the Twitter SDK (add `"twitter-api-sdk": "^1.1.0"` to your `package.json` file)

Here's the code to get the same Tweet we looked at before, using the same set of parameters to the API.

```typescript
import { Client } from "twitter-api-sdk";

if (!process.env.BEARER_TOKEN) throw new Error("Please add your BEARER_TOKEN as an environment variable in the Secrets section");

const client = new Client(process.env.BEARER_TOKEN as string);

async function main() {
  const { data, includes } = await client.tweets.findTweetsById({
    "ids": [
      "1557438090897137665"
    ],
    "tweet.fields": [
      "attachments"
    ],
    "expansions": [
      "attachments.media_keys"
    ],
    "media.fields": [
      "alt_text",
      "duration_ms",
      "preview_image_url",
      "public_metrics",
      "variants"
    ]
  });

  if (!data) throw new Error("Couldn't retrieve Tweet");

  console.log("\nTweet text:\t" + data[0].text);
  console.log("Media:\t\t" + includes.media[0].type);
  console.log("Alt text:\t" + includes.media[0].alt_text);
  console.log("Views:\t\t" + includes.media[0].public_metrics.view_count);

  console.table(includes.media[0].variants, ['bit_rate', 'url']);

  // dump whole JSON data objects
  // console.log("data", JSON.stringify(data, null, 1));
  // console.log("includes", JSON.stringify(includes, null, 1));

}

main();
```

Let's go through this code. We start out by bringing in the Twitter SDK, and then we read the value of the bearer token in from the environment variables (you can do this via setting up secrets in a cloud runtime, or create a local shell environment variable e.g. `export BEARER_TOKEN=your-bearer-token-value` at the command line).

Inside our main function, we know the ID of the Tweet we want, so we use `client.tweets.findTweetsById` to call the [`GET /2/tweets/:id`](https://developer.twitter.com/en/docs/twitter-api/tweets/lookup/api-reference/get-tweets-id) API, passing in our Tweet ID. We could easily choose to use a search API, or we could request multiple Tweets at once, if we wanted to do so. Note that when we make the call, we request both the `data` *and* the `includes` (since the video information is included under `includes`, where attachments are added in the response)

We know the parameters we need to get the values, so we add those to the request.

Once the data is returned, we can grab just the values we want to show. In this example we're using `console.table` to quickly throw the URLs and additional fields into a table, but we could choose the handle it differently. To debug, we can simply dump out the whole JSON format `data` and `includes`, but that can stay commented out if we are confident with the data format.

```text
Tweet text: @biglesp @Jolly_Device It blinks! The module that is… not coded yet. https://t.co/ErJABKMFYL
Media:      video
Alt text:   undefined
Views:      13
┌─────────┬──────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ (index) │ bit_rate │                                                     url                                                      │
├─────────┼──────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│    0    │  256000  │    'https://video.twimg.com/ext_tw_video/1557437992389722112/pu/vid/480x270/XRx8UwJoOLZS1AE4.mp4?tag=14'     │
│    1    │  832000  │    'https://video.twimg.com/ext_tw_video/1557437992389722112/pu/vid/640x360/kbjqEmwvIA1_3zFq.mp4?tag=14'     │
│    2    │ 2176000  │    'https://video.twimg.com/ext_tw_video/1557437992389722112/pu/vid/1280x720/1nqh8h8iFoHno66E.mp4?tag=14'    │
│    3    │          │ 'https://video.twimg.com/ext_tw_video/1557437992389722112/pu/pl/e2nunEhaXNarlcHp.m3u8?tag=14&container=fmp4' │
│    4    │ 10368000 │   'https://video.twimg.com/ext_tw_video/1557437992389722112/pu/vid/1920x1080/QXFoJWg4begKhDss.mp4?tag=14'    │
└─────────┴──────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
```
<sub><em>I didn't add alt text for this video, which was not very user-friendly of me - I'll do better!</em></sub>

That's it - that's the sample. We looked at:

- where video information exists in the v2 API response
- which API parameters are needed (the _expansions_ and _fields_ added to the request - there are others to experiment with)
- quickly getting started with the beta Twitter SDK for TypeScript

I've created [a template on Replit](https://replit.com/@twitter/Get-Twitter-video-URL-from-Tweet) that can be forked and modified - add a valid BEARER_TOKEN value to the project secrets. You can also [find more examples of using the Twitter SDKs on Replit](https://replit.com/@twitter/).

{% embed https://replit.com/@twitter/Get-Twitter-video-URL-from-Tweet?v=1 %}

Hope you found this helpful - let us know in the comments!