Tweets with multiple photos

In last night’s post, I embedded a John Gruber tweet that included two photos.

Original iPhone, snapped with 5S, and vice versa. The difference 7 years makes




John Gruber (@gruber) Jun 29 2014 5:18 PM

To do so, I had to modify my blackbirdpy script for embedding tweets. It now takes advantage of Twitter’s new system for including multiple images in a tweet.

The Twitter API call for getting a particular tweet is statuses/show, which is accessed through an HTTP GET on a URL that looks like this:1

https://api.twitter.com/1.1/statuses/show/483374067588685824.json

The API then returns a big chunk of JSON. Special items within a tweet, like URLs, user mentions, and hashtags, are included in the entities entry, which looks like this for the Gruber tweet:

"entities": {
  "hashtags": [],
  "symbols": [],
  "urls": [],
  "user_mentions": [],
  "media": [
    {
      "id": 483374059053277200,
      "id_str": "483374059053277184",
      "indices": [
        79,
        101
      ],
      "media_url": "http://pbs.twimg.com/media/BrVKJUuCYAA-GaK.jpg",
      "media_url_https": "https://pbs.twimg.com/media/BrVKJUuCYAA-GaK.jpg",
      "url": "http://t.co/qDwHEFl6rR",
      "display_url": "pic.twitter.com/qDwHEFl6rR",
      "expanded_url": "http://twitter.com/gruber/status/483374067588685824/photo/1",
      "type": "photo",
      "sizes": {
        "large": {
          "w": 800,
          "h": 600,
          "resize": "fit"
        },
        "medium": {
          "w": 600,
          "h": 450,
          "resize": "fit"
        },
        "thumb": {
          "w": 150,
          "h": 150,
          "resize": "crop"
        },
        "small": {
          "w": 340,
          "h": 255,
          "resize": "fit"
        }
      }
    }
  ]
}

As you can see, there’s also a media entity that’s used for images. Until the new system for images was implemented last month, this was the only place for images to be specified and despite the media item being a list (note that its value is in square brackets), I don’t remember ever seeing more than one image included in the media entry. As you can see above, although Gruber included two images in the tweet, only one is in the entities media.

When Twitter decided to allow multiple images they created an entirely new JSON entry: extended_entities.2 The extended_entities entry for Gruber’s tweet looks like this:

"extended_entities": {
  "media": [
    {
      "id": 483374059053277200,
      "id_str": "483374059053277184",
      "indices": [
        79,
        101
      ],
      "media_url": "http://pbs.twimg.com/media/BrVKJUuCYAA-GaK.jpg",
      "media_url_https": "https://pbs.twimg.com/media/BrVKJUuCYAA-GaK.jpg",
      "url": "http://t.co/qDwHEFl6rR",
      "display_url": "pic.twitter.com/qDwHEFl6rR",
      "expanded_url": "http://twitter.com/gruber/status/483374067588685824/photo/1",
      "type": "photo",
      "sizes": {
        "large": {
          "w": 800,
          "h": 600,
          "resize": "fit"
        },
        "medium": {
          "w": 600,
          "h": 450,
          "resize": "fit"
        },
        "thumb": {
          "w": 150,
          "h": 150,
          "resize": "crop"
        },
        "small": {
          "w": 340,
          "h": 255,
          "resize": "fit"
        }
      }
    },
    {
      "id": 483374064434569200,
      "id_str": "483374064434569216",
      "indices": [
        79,
        101
      ],
      "media_url": "http://pbs.twimg.com/media/BrVKJoxCYAAV4QN.jpg",
      "media_url_https": "https://pbs.twimg.com/media/BrVKJoxCYAAV4QN.jpg",
      "url": "http://t.co/qDwHEFl6rR",
      "display_url": "pic.twitter.com/qDwHEFl6rR",
      "expanded_url": "http://twitter.com/gruber/status/483374067588685824/photo/1",
      "type": "photo",
      "sizes": {
        "medium": {
          "w": 600,
          "h": 450,
          "resize": "fit"
        },
        "large": {
          "w": 1024,
          "h": 768,
          "resize": "fit"
        },
        "thumb": {
          "w": 150,
          "h": 150,
          "resize": "crop"
        },
        "small": {
          "w": 340,
          "h": 255,
          "resize": "fit"
        }
      }
    }
  ]
}

As you can see, the structure of the media entry within extended_entries is the same as that of the media entry within entities. The only difference is that here they actually put more than one item in the list. Why couldn’t they have just used the entities version of media? I have no idea, but I assume there’s some monetization plan behind it.

To handle this brave new world of multiple images, I had to modify my blackbirdpy script to access the new extended_entities structure. It wasn’t especially hard, but I was a bit surprised to find that all the images share a common url entry. I guess this was done so that multiple images would only “cost” the 22 characters of a single shortened URL. If you’re interested in the new blackbirdpy, you can see it in its GitHub repository.

I assume that if you use the official Twitter embedding code, multiple images will be handled for you automatically. I don’t do that because:

  1. It’s no fun.
  2. I have no idea what kind of tracking/cookie code Twitter includes in its embedding script. I don’t think it’s right for you get tracked by Twitter just because you visited my site. I stopped using Google Analytics about a year ago for the same reason.

With blackbirdpy under my belt, I’ll move on to modifying Dr. Twoot to handle multiple images, too.


  1. You can play around with calls to the Twitter API on the console page, but I think you have to sign up as a developer first. It’s easy to sign up and it’s free. 

  2. If you click that link and get an “Access denied” error, try again after signing out of your Twitter account. For some reason, access to that page is screwed up and you can only see it if you’re not signed in. This is one of the many things that makes you question Twitter’s competence.