Self-hosted
Runs in your own cluster. The links your users share never pass through a third-party preview service.
Open source · MIT · written in Go
Before
Have a look: https://github.com/golang/go
After: the card messengers show
Messengers show a card like this under a link. If you build a chat, a feed or a CMS, embisto makes those cards for your app, on your own server, so the links your users share stay private: no outside service sees them.
Paste a link. This page asks a real embisto server and draws its one answer in the layouts an app would build from it.
The live demo runs in the browser. Without it, ask the API directly:
curl 'https://api.embisto.com/v1/preview?url=https://github.com'
Link previews are table stakes in a chat or a feed. Renting them from a cloud service should not be.
Runs in your own cluster. The links your users share never pass through a third-party preview service.
A static Go binary or a distroless image. The cache lives in memory: no database, no Node, no browser to babysit.
The server is a thin wrapper over the public API. Import the same extractor into your own service and skip the network hop.
/iframely and /oembed answer in Iframely's format, so clients move over by changing one address. How close it is.
Every image comes with its width and height. Your app reserves the space up front and the feed never jumps.
It fetches links strangers paste, so SSRF protection and size and time limits are built in, not bolted on. How.
embisto reads every source a page offers and merges them by a fixed priority, so a card is complete even when a site gets one format wrong.
title, descriptionimageicon, site_namevideo, embedauthor, published_atlinks, sourcesStart the image, ask for a card. Configuration is a handful of environment variables; nothing else needs to run beside it.
API referenceGET /v1/preview?url=the card, as JSON or plain textGET /iframely?url=Iframely's formatGET /oembed?url=oEmbed's formatGET /healthz, /readyzprobes for KubernetesGET :9090/metricsPrometheusdocker run -p 8080:8080 ghcr.io/pantafive/embisto:latest
curl 'localhost:8080/v1/preview?url=https://github.com'import (
"github.com/pantafive/embisto"
"github.com/pantafive/embisto/card"
)
previews := embisto.New(embisto.Defaults())
result, err := previews.Extract(ctx, card.Request{URL: "https://github.com"})
if err != nil {
return err // card.CodeOf(err): invalid_url, blocked_url, fetch_failed, …
}
preview := result.Preview
fmt.Println(preview.Title, preview.Image.Width, preview.Image.Height)# Already on Iframely? Change the address, keep the client.
curl 'https://previews.internal.example/iframely?url=https://github.com'
curl 'https://previews.internal.example/oembed?url=https://github.com'
The same API answers at api.embisto.com, free and without a key, so you can try it before you
deploy, with 60 requests a minute per IP address; it runs on a best-effort basis, with no uptime promise. For
production, run your own. Every route is in the API reference.
curl 'https://api.embisto.com/v1/preview?url=https%3A%2F%2Fgithub.com'response, err := http.Get("https://api.embisto.com/v1/preview?url=https%3A%2F%2Fgithub.com")
if err != nil {
return err
}
defer response.Body.Close()
var card map[string]any
err = json.NewDecoder(response.Body).Decode(&card)import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://api.embisto.com/v1/preview?url=https%3A%2F%2Fgithub.com")).build();
var card = client.send(request, HttpResponse.BodyHandlers.ofString()).body();
System.out.println(card);const response = await fetch("https://api.embisto.com/v1/preview?url=https%3A%2F%2Fgithub.com");
const card = await response.json();import json
from urllib.request import urlopen
with urlopen("https://api.embisto.com/v1/preview?url=https%3A%2F%2Fgithub.com") as response:
card = json.load(response)
print(card["title"])require "json"
require "net/http"
card = JSON.parse(Net::HTTP.get(URI("https://api.embisto.com/v1/preview?url=https%3A%2F%2Fgithub.com")))
puts card["title"]Iframely, Embedly, Microlink and OpenGraph.io do more out of the box in places. Each comparison says where.