1. General

Note: the docs contain some opinions. You can treat them as "best practices" for working with embeds if you'd like. Of course, they are still just our opinions.

Different types of embeds

On the highest level there are two types of embeds: oEmbed and "regular embed". What they are and how they differ is this: oEmbed is (or should be) specifically crafted by the website owners to look optimal for that website; good examples are Twitter and Facebook. In reality, oEmbeds come in all sizes and shapes and often may be far from optimal.

Regular embeds, however, will look uniform across the field. Note, that "regular embed" is not an official term. Instead, they cover everything else which is not an oEmbed. These comprise of The Open Graph protocol and web scraping techniques. Regular embeds are divided further into different content types; more on that in a bit.

Because of the issues with oEmbeds and the uniform characteristics of other regular embeds we recommend to avoid using oEmbeds. Our example code on the bottom of this page will have an implementation which reflects this. Note also that our API will return both oEmbed and regular embed in the response, whenever available. The regular embed should be available for most of the time, while oEmbed may or may not be.

Security

oEmbeds have other problems as well — namely, the security isn't great. As it stands, oEmbed can contain any markup and thus injecting that into your site isn't safe, unless you really can trust the site. The safest way to present an oEmbed is to serve it in an iframe. Some sites (Twitter, Facebook) can probably be trusted, and serving them directly without an iframe should be OK.

There are other security consideration as well and this one applies to regular embeds: Linking to 3rd party images directly opens up Cross-Site Request Forgery (CSRF) and other vulnerabilities, and it's advisable to host all the images (including favicons) through a your own domain. That domain can be called, for example, safe.yourdomain.com, and it should be setup as a reverse proxy with NGINX to host the images. We will provide a sample NGINX configuration for that.

2. API

Request

The API is simple; you will issue a GET request to our url, and will get a JSON document as a response. The API endpoint is as follows:

https://api.embed.rocks/api/?url=<url>&key=<key>

The supplied url should be urlencoded. <key> is your API key (you'll find it in Dashboard).

Response

As a response, you will get a JSON document with relevant data fields. Depending on the type of webpage you will get a different types of responses, as explained below:

Common fields

There are a few fields that are common to all responses. These are:

NameValue
typerich | video | audio | photo
urlThe url you provided
oembedThe oembed data as such

Different types (rich, video, audio, photo) of responses have different fields, as show below:

type: rich

These are probably the most common types of responses. This indicates, that the page contains text + images (although it may contain only text too).

Note, the value can contain {...} which represents a JSON document. The value can also contain [...] which represents an array. An array can contain {...} (JSON documents).

Also note that the argument safe is for displaying the image safely and securely – we will provide sample NGINX configuration for this.

NameValue
typerich
urlThe url you provided
sitehostname of the site (www.example.com)
titleTitle of the page
descriptionA short (250 characters) snippet of text; best describing the page
authorAuthor's name (not always available)
published_dateNot always available, but if it is, it will be:

{
  • parsed: date in ISO 8601 format
  • orig: date in original format
}

Note that sometimes the site provides only date, not time, and the published_date.parsed date will show 00:00:00 for the time. in those cases you should be suspicious and check the original time as well (which is provided as published_date.orig).
articleThe whole article
favicon{
  • url: url of the favicon
  • safe: the same url as urlencoded component
}
images[ {
  • url: url of the image
  • safe: the same url as urlencoded component
} ]

type: video

NameValue
typevideo
urlThe url you provided
sitehostname of the site (www.example.com)
titleTitle of the page
descriptionA short (250 characters) snippet of text; best describing the page
favicon{
  • url: url of the favicon
  • safe: the same url as urlencoded component
}
videos[ {
  • url: url of the video
  • safe: the same url as urlencoded component
  • type: content-type of the video
} ]

Note that we return videos of content type text/html and application/flash if the site has told us that they are videos. Thus, we treat them as videos.

type: audio

NameValue
typeaudio
urlThe url you provided
sitehostname of the site (www.example.com)
titleTitle of the page
descriptionA short (250 characters) snippet of text; best describing the page
favicon{
  • url: url of the favicon
  • safe: the same url as urlencoded component
}
audios[ {
  • url: url of the audio
  • safe: the same url as urlencoded component
} ]

type: photo

NameValue
typephoto
urlThe url you provided
images[ {
  • url: url of the audio
  • safe: the same url as urlencoded component
} ]

3. Examples

3.1 A rich type

The rich type is probably the most common type; it contains usually an image and some text. The URL http://edition.cnn.com/2017/01/05/aviation/safest-airlines-for-2017/index.html will get us the following JSON document:

{
	"article": "<div>(article omitted in the example)</div>",
	"description": "AirlineRatings.com declares 2016 one of the safest years in aviation history as it names what it says are the world's safest airlines.",
	"favicon": {
		"safe": "http%3A%2F%2Fedition.cnn.com%2Ffavicon.ie9.ico",
		"url": "http://edition.cnn.com/favicon.ie9.ico"
	},
	"images": [
		{
			"safe": "http%3A%2F%2Fi2.cdn.cnn.com%2Fcnnnext%2Fdam%2Fassets%2F160412104516-airplane-generic-ii-super-tease.jpg",
			"url": "http://i2.cdn.cnn.com/cnnnext/dam/assets/160412104516-airplane-generic-ii-super-tease.jpg"
		}
	],
	"site": "CNN",
	"title": "The world's safest airlines for 2017?",
	"type": "rich",
	"url": "http://edition.cnn.com/2017/01/05/aviation/safest-airlines-for-2017/index.html",
	"videos": []
}

It will look like this when rendered (you render this yourself, so this is just an example):

3.2 An URL from YouTube.com

Here we will see a type of video — the videos array will contain items. The videos array will be sorted roughly in the order of preference — the most preferrable type are first. These would be "HTML5" videos. Flash videos would be less preferrable and they would be placed in the end of the array. Our example code will handle these correctly.

{
	"article": "<div><p>\n    <strong>Pour évaluer une vidéo, vous devez la louer.</strong>\n  </p></div>",
	"description": "A few pointers from my experience on things one should either do or avoid while in Finland. So some Finnish do's and don'ts! :) *On a side note, I know I hav...",
	"favicon": {
		"safe": "https%3A%2F%2Fs.ytimg.com%2Fyts%2Fimg%2Ffavicon-vflz7uhzw.ico",
		"url": "https://s.ytimg.com/yts/img/favicon-vflz7uhzw.ico"
	},
	"html": "<div class=\"card\">\n    <iframe style=\"width: 720px; height: 405px\" src=\"https://www.youtube.com/embed/9N0HB8vMJrI\"></iframe>\n    \n    <div class=\"card-text\">\n      <h3>Do's and Don'ts in Finland | KatChats</h3>\n      <p>A few pointers from my experience on things one should either do or avoid while in Finland. So some Finnish do's and don'ts! :) *On a side note, I know I hav...</p>\n      \n        <p class=\"fav\">\n          <img onerror=\"this.style.display='none'\" class=\"favicon\" src=\"https://s.ytimg.com/yts/img/favicon-vflz7uhzw.ico\">\n          YouTube\n        </p>\n    </div>\n  \n  </div>",
	"images": [
		{
			"safe": "https%3A%2F%2Fi.ytimg.com%2Fvi%2F9N0HB8vMJrI%2Fmaxresdefault.jpg",
			"url": "https://i.ytimg.com/vi/9N0HB8vMJrI/maxresdefault.jpg"
		}
	],
	"oembed": {
		"author_name": "KatChats",
		"author_url": "https://www.youtube.com/user/adamLsidney",
		"height": 270,
		"html": "<iframe width=\"480\" height=\"270\" src=\"https://www.youtube.com/embed/9N0HB8vMJrI?feature=oembed\" frameborder=\"0\" allowfullscreen></iframe>",
		"provider_name": "YouTube",
		"provider_url": "https://www.youtube.com/",
		"thumbnail_height": 360,
		"thumbnail_url": "https://i.ytimg.com/vi/9N0HB8vMJrI/hqdefault.jpg",
		"thumbnail_width": 480,
		"title": "Do's and Don'ts in Finland | KatChats",
		"type": "video",
		"version": "1.0",
		"width": 480
	},
	"site": "YouTube",
	"title": "Do's and Don'ts in Finland | KatChats",
	"type": "video",
	"url": "https://www.youtube.com/watch?v=9N0HB8vMJrI",
	"videos": [
		{
			"height": "720",
			"secureUrl": "https://www.youtube.com/embed/9N0HB8vMJrI",
			"type": "text/html",
			"url": "https://www.youtube.com/embed/9N0HB8vMJrI",
			"width": "1280"
		},
		{
			"height": "720",
			"secureUrl": "https://www.youtube.com/v/9N0HB8vMJrI?version=3&autohide=1",
			"type": "application/x-shockwave-flash",
			"url": "http://www.youtube.com/v/9N0HB8vMJrI?version=3&autohide=1",
			"width": "1280"
		},
		{
			"height": "720",
			"type": "text/html",
			"url": "https://www.youtube.com/embed/9N0HB8vMJrI",
			"width": "1280"
		}
	]
}

3.3 An URL from Twitter.com

Here we can decide if we want to render this as an oEmbed or a regular embed, because the JSON contains both. Below you can see how it looks like when rendered in both ways.

{
	"article": "<div><p>\n      Twitter may be over capacity or experiencing a momentary hiccup. <a href=\"#\">Try again</a> or visit <a href=\"http://status.twitter.com\">Twitter Status</a> for more information.\n    </p></div>",
	"description": "“to understand the pillow, one must become the pillow”",
	"favicon": {
		"safe": "https%3A%2F%2Fabs.twimg.com%2Ffavicons%2Ffavicon.ico",
		"url": "https://abs.twimg.com/favicons/favicon.ico"
	},
	"html": "<div class=\"card\">\n    <a target=\"_blank\" href=\"https://twitter.com/EmrgencyKittens/status/817189457476648960\">\n      \n    <img onerror=\"this.style.display='none'\" class=\"card-image\" src=\"https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FC1c9erlWgAAUhEO.jpg%3Alarge\">\n  \n      \n    <div class=\"card-text\">\n      <h3>Emergency Kittens on Twitter</h3>\n      <p>“to understand the pillow, one must become the pillow”</p>\n      \n        <p class=\"fav\">\n          <img onerror=\"this.style.display='none'\" class=\"favicon\" src=\"https://abs.twimg.com/favicons/favicon.ico\">\n          Twitter\n        </p>\n    </div>\n  \n    </a>\n    </div>",
	"images": [
		{
			"safe": "https%3A%2F%2Fpbs.twimg.com%2Fmedia%2FC1c9erlWgAAUhEO.jpg%3Alarge",
			"url": "https://pbs.twimg.com/media/C1c9erlWgAAUhEO.jpg:large"
		}
	],
	"oembed": {
		"author_name": "Emergency Kittens",
		"author_url": "https://twitter.com/EmrgencyKittens",
		"cache_age": "3153600000",
		"height": null,
		"html": "<blockquote class=\"twitter-tweet\"><p lang=\"en\" dir=\"ltr\">to understand the pillow, one must become the pillow <a href=\"https://t.co/UUqd0uJQht\">pic.twitter.com/UUqd0uJQht</a></p>&mdash; Emergency Kittens (@EmrgencyKittens) <a href=\"https://twitter.com/EmrgencyKittens/status/817189457476648960\">January 6, 2017</a></blockquote>\n<script async src=\"//platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>",
		"provider_name": "Twitter",
		"provider_url": "https://twitter.com",
		"type": "rich",
		"url": "https://twitter.com/EmrgencyKittens/status/817189457476648960",
		"version": "1.0",
		"width": 550
	},
	"site": "Twitter",
	"title": "Emergency Kittens on Twitter",
	"type": "rich",
	"url": "https://twitter.com/EmrgencyKittens/status/817189457476648960",
	"videos": []
}

Here is the oEmbed rendering:

And here the regular:

4. Notes on image sizes

You can control he image sizes with CSS. On the home page you saw the airplace card in two different sizes. The smaller had this CSS for the image:

.card img.card-image {float: left;max-width: 250px;min-width: 100px;max-height: 125px;}

The bigger had this CSS:

.card.card-big img.card-image {max-width: 100%;max-height: 450px;margin-bottom: 10px;}

The bigger had this CSS:

Note that if you combine these two methods, you can do as we have done here, that small images are floated to the left and big images are shown on the top as big ones.

You may also want to create square images, while maintaining the original aspect ratio, which you can do like this:

.card.square img.card-image {width: 150px;height: 150px;object-fit: cover;}

Word of caution; if the image is very tall and narrow or wide and shallow, the cropped area may not reflect what's in the image. Here's the example of the same aeroplane in a cropped square form:

5. Example code

We have two example apps for integration: one with plain JavaScript and one with a templating engine. Use whichever suits you best, or even both. You can use these as a starting point for your own implementation.

In case you want to use Nginx to serve images safely, here is our config file for that: NGINX.conf. You can find examples how to use that in the eintegration examples above.