The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 1,860 other subscribers

Twitter image size suffixes reloaded: pbs.twimg.com URL information

Posted by jpluimers on 2025/02/18

It’s almost

Goal of the current post amend the above posts with information so I can later write a bookmarklet or web-page with JavaScript that – from a x.com or twitter.com – tweet URL can get the JSON, then the images and/or videos in all sizes, then generate a web-page from it for Wayback Machine archival.

Note that htmlpreview needs a CORS server and currently (as the other CORS servers are no longer available, see [Wayback/Archive] Merge branch ‘master’ into notCorsFirst · htmlpreview/htmlpreview.github.com@dfb47f7 · GitHub) depends on the open source [Wayback/Archive] GitHub – jolav/codetabs: Free Online Services. Github/GitLab star history. Count Lines of Code. CORS proxy server. IP GeoLocation. HTTP Headers. Random Data. Api weather temp. Alexa ranking.

If that goes off-line, the CORS server will need changing, hopefully [WaybackSave/Archive] free cors server – Google Search returns enough results. The CORS server days remind me of the SOAP XML days, with by now have hardly any free example server left (see for instance [Wayback/Archive] Compiled list of free and working WSDL URLs. | by Nishanthi Grashia Suresh | Medium).

Media URLs

Media URLs can be obtained from links like https://cdn.syndication.twimg.com/tweet-result?id=1863177456087158995&token=! where 1863177456087158995 is the tweet ID (the token trick is from [Wayback/Archive] Twitter Updates · Issue #32392 · ytdl-org/youtube-dl · GitHub which I already mentioned in the Twitter videos blog post mentioned above but is much worth repeating).

These contain the full data of a Tweet in JSON format. Let’s call them Tweet JSON from now on.

The Tweet JSON can be queried using [Wayback/Archive] GitHub – dchester/jsonpath: Query and manipulate JavaScript objects with JSONPath expressions. Robust JSONPath engine for Node.js.

In the returned JSON, to find video URLs (in my experience: always 3, and always using the same resolution), either search for:

  • Search for nodes having content_type="video/mp4", then for the next sibling with key url key, pick the value. You will find 3 occurrences, each with a resolution and file identifier in their URL:
    • url="https://video.twimg.com/amplify_video/1863174334975504384/vid/avc1/320x568/ugEx1eBAdVkKtAAr.mp4?tag=16"
    • url="https://video.twimg.com/amplify_video/1863174334975504384/vid/avc1/480x852/9o9-VFVM8We6RKnJ.mp4?tag=16"
    • url="https://video.twimg.com/amplify_video/1863174334975504384/vid/avc1/576x1024/7VZu059ex7YV2gya.mp4?tag=16"

    Notes:

    • The JSONPath query for the values of this is $..[?(@.content_type=='video/mp4')].url
    • From these url values, you can remove the ?tag=16 suffix
  • Search for nodes having type="video/mp4", then for the next sibling with key url key, pick the value. You will find 3 occurrences, each with a resolution and file identifier in their URL:
    • src="https://video.twimg.com/amplify_video/1863174334975504384/vid/avc1/320x568/ugEx1eBAdVkKtAAr.mp4?tag=16"
    • src="https://video.twimg.com/amplify_video/1863174334975504384/vid/avc1/480x852/9o9-VFVM8We6RKnJ.mp4?tag=16"
    • src="https://video.twimg.com/amplify_video/1863174334975504384/vid/avc1/576x1024/7VZu059ex7YV2gya.mp4?tag=16"

    Notes:

    • The JSONPath query for the values of this is $..[?(@.type=='video/mp4')].src
    • From these url values, you can remove the ?tag=16 suffix as well

To find he video cover picture (some call this thumbnail or photo):

  • Search for the node with name media_url_https and take its value. There is just one occurrence:
    • media_url_https="https://pbs.twimg.com/amplify_video_thumb/1863174334975504384/img/b3KPFYiKRFz7vW-O.jpg",

    Notes the JSONPath query for this is $..media_url_https

  • Search for the node with name poster and take its value. There is just which has one occurrence:
    • poster="https://pbs.twimg.com/amplify_video_thumb/1863174334975504384/img/b3KPFYiKRFz7vW-O.jpg"

    Note the JSONPath query for this can be either $..poster or $.video.poster

JSONPath

The sibbling part (getting to url from content_type and to src from type) of the above queries is based on [Wayback/Archive] jsonpath – Json filter data on the sibling node – Stack Overflow (thanks [Wayback/Archive] Gico).

For the above JSONPath queries, I first pretty printed the Tweet JSON using [Wayback/Archive] JSON Parser Online to parse JSON, then tested all the JSONPath queries using [Wayback/Archive] JSONPath Online Evaluator which is open source at [Wayback/Archive] GitHub – ashphy/jsonpath-online-evaluator: JSONPath Online Evaluator.

Actually, I think the query syntax is OK (not great, as they aimed for a very concise syntax, but hey: it is based off XPath with a notoriously hard syntax and using JSONPath is way easier than writing out all the filtering code), so I want to use it in this aimed to be tiny project of tweet data displaying project.

This means I have to learn how to incorporate JSONPath in either a Bookmarklet or web-page, preferably without using nodejs in order not to blow up the solutions beyond being small.

Hopefully these links help me:

JSONPath history

Early February 2007 was the start of JSONPath with the post [Wayback/Archive] JSONPath – XPath for JSON followed by 4 updates in august that year covering expressions, examples, implementation and issues.

The first implementations included JavaScript and PHP, with soon a repository now at [Wayback/Archive] Google Code Archive – Long-term storage for Google Code Project Hosting. covering C# as well.

All current implementations are derived from that code base.

Getting the JSON

I wasn’t sure how to download a string from a URL in JavaScript, but luckily [Wayback/Archive] javascript – How would I parse json from an external url? – Stack Overflow showed this can be done with good old SOAP-era XMLHttpRequest.

The Stack Overflow code has some examples, and JavaScript documentation is at [Wayback/Archive] XMLHttpRequest – Web APIs | MDN

Image resolutions

The first linked blog post above was in part based on [WaybackSave/Archive] Entities in Objects — Twitter Developers. That link is now gone, but the documentation itself was extended and is now published on [Wayback/Archive] Entities object | Docs | Twitter Developer Platform. New information is now in the table below, including maximum resolutions and URL format names.

I have summarised the information in the table further below.

Tweet JSON after deletion

If a tweet gets deleted, the JSON changes to indicate id is removed, but the the media links from a tweet will stay on-line (so if you have old JSON, then you can still find the tweet content: this is one of the big reasons for writing this blog post: providing information to help archiving old content).

You can see this when looking at two archivals of https://cdn.syndication.twimg.com/tweet-result?id=1577533879283585025&token=!

  1. 20230920: [Wayback/Archive] tweet with content
  2. 20241203: [Wayback/Archive] deleted tweet

This makes it very important to archive the Tweet JSON in both Wayback Machine and Archive Today, as with that you can get back to the Tweet media.

Tables (some updated)

Image resolutions and suffixes

media entity observed resolution maximum resolution Legacy format: <base_url>.<format>:<name> Modern format: <base_url>?format=<format>&name=<name>
thumb 150×150 150×150 https://pbs.twimg.com/media/CiMNh9rWEAAdM6Q.png:thumb
[Wayback/Archive]
https://pbs.twimg.com/media/CiMNh9rWEAAdM6Q?format=png&name=thumb
[Wayback/Archive]
small 340×325 680×680 https://pbs.twimg.com/media/CiMNh9rWEAAdM6Q.png:small
[Wayback/Archive]
https://pbs.twimg.com/media/CiMNh9rWEAAdM6Q?format=png&name=small
[Wayback/Archive]
medium 600×573 1200×1200 https://pbs.twimg.com/media/CiMNh9rWEAAdM6Q.png:medium
[Wayback/Archive]
https://pbs.twimg.com/media/CiMNh9rWEAAdM6Q?format=png&name=medium
[Wayback/Archive]
(none) 600×573 1200×1200 https://pbs.twimg.com/media/CiMNh9rWEAAdM6Q.png
[Wayback/Archive]
https://pbs.twimg.com/media/CiMNh9rWEAAdM6Q?format=png
[Wayback/Archive]
large 1024×979 2048×2048 https://pbs.twimg.com/media/CiMNh9rWEAAdM6Q.png:large
[Wayback/Archive]
https://pbs.twimg.com/media/CiMNh9rWEAAdM6Q?format=png&name=large
[Wayback/Archive]
orig 1600×1529 4096×4096 https://pbs.twimg.com/media/CiMNh9rWEAAdM6Q.png:orig
[Wayback/Archive]
https://pbs.twimg.com/media/CiMNh9rWEAAdM6Q?format=png&name=orig
[Wayback/Archive]

Notes:

  • medium is still the default
  • orig is still undocumented

I got the maximum “orig” resolution from [Wayback/Archive] Retrieving full-size images — media.fields=url points to resized version? – X API / X API v2 – X Developers

Video resolutions

There seem to be tree video resolutions:

  • 320×568
  • 480×852
  • 576×1024

Since all video files have unique IDs, there is no “default”.

Not the first to find out about the CDN JSON

Above you saw the GitHub thread where I got the token from. So I wasn’t the first about finding out about the Tweet JSON. The underlying links are these:

  1. [WaybackSave/Archive] Twitter Updates · Issue #32392 · ytdl-org/youtube-dl · GitHub
  2. [WaybackSave/Archive] [Twitter] Account is now required to download (Failed to parse JSON) · Issue #7473 · yt-dlp/yt-dlp · GitHub
  3. [Wayback/Archive] cdn.syndication.twimg.com/tweet-result?id=1577533879283585025&token=!
  4. [WaybackSave/Archive] [extractor/twitter] Fix unauthenticated extraction by bashonly · Pull Request #7476 · yt-dlp/yt-dlp · GitHub
  5. [Wayback/Archive] [extractor/twitter] Fix unauthenticated extraction by bashonly · Pull Request #7476 · yt-dlp/yt-dlp · GitHub
  6. [Wayback/Archive] [extractor/twitter] Fix unauthenticated extraction by bashonly · Pull Request #7476 · yt-dlp/yt-dlp · GitHub

I wasn’t the second either, as when doing the final search it appeared Vercel people found out about that JSON too as part of their project [WaybackSave/Archive] GitHub – vercel/react-tweet: Embed tweets in your React application.:

  1. [Wayback/Archive] How to prerender Tweets without using the official Twitter APIs | Stefan Judis Web Development

    The Vercel release post points to the solution:

    Under the hood, react-tweet reverse-engineers the Twitter’s Embed API to fetch data for a given tweet and renders it in the same style as Twitter’s embedded iframe.

    The key is that Twitter’s original widget.js talks to an open API at cdn.syndication.twimg.com. This API includes most of the needed data to render a Tweet on your sites (unfortunately, retweet count is unavailable). Reverse engineering the response takes some time but is worth it because, as Vercel says, react-tweet uses 35x less client-side JavaScript than the Twitter’s Native embed”.

  2. [Wayback/Archive] Introducing React Tweet – Vercel with these demos:
  3. [Wayback/Archive] react-tweet/packages/react-tweet/src/api/get-tweet.ts at 03f4db52f393ddf84e62a42222d49c765bbd3420 · vercel/react-tweet · GitHub
  4. [Wayback/Archive] Add missing token to api calls to Twitter’s CDN (#128) · vercel/react-tweet@dc5cadf · GitHub
  5. [Wayback/Archive] Add missing token to api calls to Twitter’s CDN by lfades · Pull Request #128 · vercel/react-tweet · GitHub

TODO: profile pictures and banners.

It looks like the are stored at these sizes:

Links:

TODO: verify

I want to check the above information against the guidelines in [Wayback/Archive] Twitter Image Specs: An Updated Guide to Sizes for 2024 summarised as:

  • X (Twitter) supports various file types, including PNG, GIF, JPG, and even animated GIFs. Each file type has specific requirements for aspect ratio, file size, and dimensions.
  • X (Twitter) supports images with aspect ratios of 16:9 and 1:1, the latter being recommended. For animated GIFs, the aspect ratio must be between 1:1 and 3:1. The maximum file size for images is 5 MB, while for animated GIFs, it’s 15 MB.
  • The recommended image size for X (Twitter) is 1200 x 675 pixels for landscape images, 900 x 900 pixels for square images, and 506 x 253 pixels for 2:1 aspect ratio images. For profile pictures, the recommended size is 400 x 400 pixels, while the header image size is 1500 x 500 pixels.
  • X (Twitter) profile image

    • Under 2 MB
    • 400 x 400 pixels
  • X (Twitter) cover photo

    • Up to 2 MB
    • 1500 x 1500 pixels
  • X (Twitter) image post size

    • Landscape: 1600 x 900 pixels
    • Square: 1080  x 1080 pixels
    • Portrait: 1080 x 1350 pixels
    • Aspect ratio between a 2:1 and 1:1 for desktop, and either 2:1, 3:4, or 16:9 for mobile
  • X (Twitter) card images

    • 1200 x 628 pixels
    • 1.91:1 aspect ratio
    • X (Twitter) will display your image at a maximum of 4096 x 4096 pixels.
  • Image ads

    • Up to 5 MB
    • Sizes and aspect ratios vary
  • X (Twitter) also recommends the following:

    • Image ads with app buttons: 800 x 418 pixels recommended for 1.91:1 aspect ratio, and 800 x 800 pixels recommended for 1:1 aspect ratio
    • Image ads with conversation buttons: 800 x 418 pixels and 1.91:1 aspect ratio
    • Image ads with polls: 800 x 418 pixels recommended for 1.91:1 aspect ratio, and 800 x 800 pixels recommended for 1:1 aspect ratio; 1:1 will crop to 1.91:1 in mobile timeline
    • Image ads with website buttons: 800 x 418 pixels recommended for 1.91:1 aspect ratio, and 800 x 800 pixels recommended for 1:1 aspect ratio
    • Standalone image ads: 1200 x 1200 pixels recommended for 1:1 aspect ratio, and 1200 x 628 pixels recommended for 1.91:1 aspect ratio; larger images are better for when users click to expand images
    • Image carousel: 800 x 418 pixels recommended for 1.91:1 aspect ratio, and 800 x 800 pixels recommended for 1:1 aspect ratio
  • In-stream images

    • 440 x 220 pixels
    • X (Twitter) will display your image at a maximum of 1024 x 512 pixels, so it’s important to make sure that your image looks good at that size as well.
  • X (Twitter) image file types and sizes

    X (Twitter) accepts the following image file types:
    • JPG
    • PNG
    • GIF
    • WebP
    You can’t use other image file types like BMP, PDF, etc.

Hosting code in GitHub gists

See [Wayback/Archive] javascript – Embed Partial Gist File – Stack Overflow and [Wayback/Archive] GitHub – kashif-umair/gist-embed: Easily embed gists into any blog or webpage

Similarly you can host code on GitHub.

Queries

--jeroen

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.