Displaying Status Entities

Twitter content

Special care must be taken when displaying status entities.

To access data from the API, a customer must have accepted the API usage agreement for a given stream within Experiences. This includes agreeing to comply with Twitter Display Requirements when displaying Twitter statuses. This document is meant to supplement Twitter's requirements and not replace or supersede it.

Twitter Display Requirements
https://dev.twitter.com/terms/display-requirements

Example Twitter statuses (including media): http://api.massrelevance.com/MassRelDemo/all-networks.json?network=twitter

Anatomy of a Tweet

Anatomy of a Tweet
Deriving URLs

The API will not provide you with relevant URLs for permalinks and profiles, etc. This is how you can build relevant URLs using Tweet data.

Assume that the Tweet's data is saved in a variable named tweet

More info: Twitter action URLs (aka "intents") https://dev.twitter.com/docs/intents

Auto-linking t.co URLs with correct display URLs

As part of their analytics initiative, Twitter replaces all URLs within a tweet with a t.co URL that you must preserve within a Tweet. However these t.co links look ugly and hide what URL a person is linking to. Luckily, the API includes the URL needed to replace the t.co link for display via the entities object within a Tweet object.

More info:

Entities object example

Below is an example of the entities hash. The relevant portion to use when auto-linking is the urls child object

More info: About Twitter entities https://dev.twitter.com/docs/tweet-entities

"entities": {
    "hashtags": [{
        "text": "2012Olympics",
        "indices": [
        89, 102]
    }, {
        "text": "Olympics",
        "indices": [
        103, 112]
    }],
    "urls": [{
        "url": "http://t.co/zgkQdeyG",
        "expanded_url": "http://www.nbcolympics.com/video/swimming/natalie-coughlin-profile-409643.html",
        "display_url": "nbcolympics.com/video/swimming…",
        "indices": [
        68, 88]
    }],
    "user_mentions": [{
        "screen_name": "NatalieCoughlin",
        "name": "Natalie Coughlin",
        "id": 26593416,
        "id_str": "26593416",
        "indices": [
        11, 27]
    }]
}
Pseudo code for auto-linking
tweet = get_newest_tweet()
tweet_text = tweet.text

url_entities = tweet.entities.urls
foreach entity in url_entities
  tco_url = entity.url
  display_url = entity.display_url

  # note: you must continue to link to the t.co link
  html_link = "<a href=\"#{tco_url}\">#{display_url}</a>"

  # replace tco with html link
  tweet_text = tweet_text.replace(tco_url, html_link)
end

print tweet_text

To make this easy, Twitter provides many open-source client libraries to correctly display and link statuses:

Rendering Retweets

Retweets are tricky because the person that retweeted is the top level data that comes with a Tweet. If you do not take any steps to handle retweets then nothing will break, but you won't display the original Tweet's avatar, etc.

Pesudocode on how to handle retweets
tweet = get_newest_tweet()

# it's a retweet if the tweet object contains
# the `retweeted_status` property
is_retweet = tweet.retweeted_status != nil

if is_retweet
  # user that pressed "retweet" button
  retweeter = tweet.user

  # make the original tweet that was retweeted the main tweet
  tweet = tweet.retweeted_status

  # now set the user info of the person that pressed
  # "retweet" on the retweeted tweet
  tweet.retweeter = retweeter
  tweet.is_retweet
end

render(tweet)

We have found that by augmenting the way the data of a retweet is stored, it allows us to reuse templates easier while displaying a retweet like you'd see one on twitter.com

Rendering Twitter avatars

When a user changes his or her avatar image after a post has been approved, eventually the previous avatar image is removed from the web. For this reason, we recommend you render a placeholder image in the event that the avatar is unavailable. Alternatively, you can reject or manually re-add problematic posts.

Suggested HTML:

<div class="twitter-avatar-container">
  <div class="avatar" style="background-image: url({{user.profile_image_url}})"></div>
</div>

CSS:

.twitter-avatar-container {
  background: transparent url("images/default-avatar-image.jpg") 0 0 no-repeat;
}

We recommend a div here so that the placeholder image can be displayed instead of a broken image icon.

Rendering Twitter media

Twitter users can include media with Tweets using a variety of methods. The user can upload an image natively within the Twitter application, or the user can include a link to the media in his or her Tweet. These two upload methods require different approaches for display.

Option 1: Uploaded media

When a user uploads an image directly, the image is stored on Twitter's servers and URLs to the image are included in the Tweet JSON in the entities.media section. This makes media display very simple.

Example JSON:

"media": [
  {
    "id": 385820297112191000,
    "id_str": "385820297112190976",
    "indices": [
      50,
      72
    ],
    "media_url": "http://pbs.twimg.com/media/BVq1hByCAAAS7Ll.jpg",
    "media_url_https": "https://pbs.twimg.com/media/BVq1hByCAAAS7Ll.jpg",
    "url": "http://t.co/onCnfAcozM",
    "display_url": "pic.twitter.com/onCnfAcozM",
    "expanded_url": "http://twitter.com/samdecker/status/385820297313533952/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"
      }
    }
  }
]

Using geolocation information

There are two flavors of geolocation data available on some Tweets:

The first is geo data. This is included in the Tweet response when a user explicitly shares his or her location using the Twitter app. These coordinates are very precise and great for placing content on a map. This will appear in the geo field of a stream object:

  {
    "geo": {
      "type": "Point",
      "coordinates": [
        30.222758, -97.767243]
      }
  }

The second is geo_hint data. If a user does not explicitly share his or her location when Tweeting, Geo Hinting can be used to guess the user's approximate location based on information in his or her Twitter profile text (e.g. "Austin, TX" or "NYC"). To include geo_hint data in the response, use the geo_hint=1 parameter.

{
    "geo_hint": {
        "country": "US",
        "state": "CA",
        "coordinates": [
          34.0522342, -118.2436849]
    }
}

Pseudocode for handling these:

    if (network === twitter) {
      if (geo != null) {
        // do something with geo[coordinates]
      }
      else if (geo_hint != null) {
        // do something with geo_hint[coordinates]
      }
      else {
        // ignore, because there is no geo data
      }
    }

Both these fields will return null if no geolocation information is available on the tweet. If you want your stream to contain only geo or geo-hintable Tweets, use a rule to reject content that does not contain geolocation information.

Option 2: Linked media

When a user includes a link to a page that contains media such as Vine, Twitpic, Yfrog, or Instagram, direct URLs to the media are not included in the JSON response. The destination page must be scraped to find the original media URL for display.

Experiences templates leverage a service called Embed.ly for this purpose, but there are other providers that provide similar functionality.

Facebook content

This section provides a basic overview of the fundamental components of Facebook posts/statuses. This section is meant to supplement the Facebook Graph API documentation available here. This information is current as of July 2014.

Example Facebook statuses of various types: http://api.massrelevance.com/MassRelDemo/all-networks.json?network=facebook

Posts/statuses

Content with kind equal to "status".

Anatomy of a Facebook Post

Assume that the post's data is saved in a variable named post

Posts with links

Content with kind equal to "link".

Anatomy of a Facebook Post

Assume that the post's data is saved in a variable named post

Posts with photos

Content with kind equal to "photo".

Anatomy of a Facebook Post

Assume that the post's data is saved in a variable named post

Low resolution images

Oftentimes, the included image URL (post.picture) URL links to a low resolution image. Instead, use the images data instead (if it exists); it provides various resolutions that may be more useful.

Comments

Content with kind equal to "comment".

Anatomy of a Facebook Post

Assume that the comment's data is saved in a variable named comment

Instagram content

For guidance on displaying Instagram entities, check out their API documentation at http://instagram.com/developer/endpoints/media/ (see RESPONSE under "/media/media-id" including video example).

Example Instagram statuses of various types: http://api.massrelevance.com/MassRelDemo/all-networks.json?network=instagram

Handling Instagram avatars

When a user changes his or her avatar image after a post has been approved, eventually the previous avatar image is removed from the web. For this reason, we recommend you render a placeholder image in the event that the avatar is unavailable. Alternatively, you can reject problematic posts.

Suggested HTML:

<div class="instagram-avatar-container">
  <div class="avatar" style="background-image: url({{user.avatar_image_url}})"></div>
</div>

CSS:

.instagram-avatar-container {
  background: transparent url("images/default-avatar-image.jpg") 0 0 no-repeat;
}

We recommend a div here so that the placeholder image can be displayed instead of a broken image icon.

Using geolocation information

Some users choose to share their location when posting to Instagram. This information is returned in the location field of an entity object:

{
  "location": {
    "latitude": 43.877514794,
    "name": "Grand Teton National Park, Wyoming",
    "longitude": -110.577783863,
    "id": 4755902
  }
}

This field will return null if no geolocation information is available on the Instagram post. If you want your stream to contain only geo Instagram posts, use a rule to reject content that does not contain geolocation information.

Pseudocode for handling this:

else if (network === instagram) {
  if (location != null) {
    // do something with location[latitude] and location[latitude]
  }
  else {
    // ignore, because there is no geo data
  }
}