Documentation

Introduction

With LinkPreview API you can get detailed website information - title, preview image, and short description in JSON format for any given URL.

This API document describes the usage and resources needed for integrating with the API.

If you’re looking for a Screenshot API instead, you can check our SavePage service.

How to get access

The LinkPreview uses API keys for authorization. An API key is a special access token that the client needs to provide as a query parameter when making API calls.

You can sign up for a free API key here. Our Free Plan offers generous limits for getting started with LinkPreview.

Quick start

Simple GET Request

http://api.linkpreview.net/?key=123456&q=https://www.google.com

Secure POST Request

Requests can be made using POST method as well. In the following example we are using the curl command line utility to submit query parameters in the body of the request.

curl --data "key=123456&q=https://www.google.com" https://api.linkpreview.net

Default JSON Response

{
   "title":"Google",
   "description":"Search webpages, images, videos and more.",
   "image":"https://www.google.com/images/logo.png",
   "url":"https://www.google.com"
}

API Endpoints

We provide both HTTP and HTTPS endpoints for our service:

EndpointGETPOST
http://api.linkpreview.netYesYes
https://api.linkpreview.netYesYes

Query parameters

Basics

Our API uses query parameters since they are the simplest and the most common type of parameters. When using the GET request, they appear at the end of the request URL after the question mark (?), with name=value pairs separated by ampersands (&).

NameDescriptionExampleRequired
keyYour API key123456Yes
qURL to inspect*https://www.google.comYes
fieldsComma-separated list of fields to returnimage_x, icon_type, localeNo

* Since this parameter can contain reserved characters :/?#[]@!$&'()*+,;= it should be sent as percent-encoded (encodeURIComponent/urlencode).

Default and Additional Fields

LinkPreview can return additional fields based on your current subscription plan. Example request - asking for three additional fields:

http://api.linkpreview.net/?key=123456&fields=image_x,icon_type,locale&q=https://www.google.com
NameTypeDescriptionExample ResponseSubscription Plan
titlestringWebsite title. Returned by default.GoogleAvailable on all plans
descriptionstringDescription summary. Returned by default.Search webpages, images, videos and more.Available on all plans
imagestringPreview image URL. Returned by default.https://google.com/logo.pngAvailable on all plans
urlstringDestination URL. Returned by default.https://www.google.comAvailable on all plans
canonicalstringCanonical or “preferred” version of a web page. Defaults to blank "" if not found.https://www.google.com/enBasic, Pro, Enterprise
localestringWeb page’s locale formatted as language_TERRITORY. Defaults to “en_US” if not found. You can use this to detect RTL languages or to display other language-specific elements.en_GBBasic, Pro, Enterprise
site_namestringShort domain name formatted as top_level_domain+1. Use this to display short name instead of a full link.google.comBasic, Pro, Enterprise
image_xnumberImage width in pixels. See image processing.600Pro, Enterprise
image_ynumberImage height in pixels. See image processing.400Pro, Enterprise
image_sizenumberImage size in bytes. See image processing.643252Pro, Enterprise
image_typestringImage MIME content type.image/jpegPro, Enterprise
iconstringWebsite icon URL, also known as favicon.https://google.com/fav.icoPro, Enterprise
icon_xnumberWebsite icon width in pixels.50Pro, Enterprise
icon_ynumberWebsite icon height in pixels.50Pro, Enterprise
icon_sizenumberWebsite icon size in bytes.48322Pro, Enterprise
icon_typestringWebsite icon MIME content type.image/x-iconPro, Enterprise

Responses

Successful API response will be sent with HTTP status code 200 and it will contain application/json data. You should always validate/sanitize API response before using it.

Default Response

Successful HTTP response will be sent as 200 OK and it will contain JSON data:

{
   "title":"Google",
   "description":"Search webpages, images, videos and more.",
   "image":"https://www.google.com/images/logo.png",
   "url":"https://www.google.com"
}

Extended Response

Extended API response will contain all requested additional fields. Make sure your current plan supports this:

{
   "title":"Google",
   "description":"Search webpages, images, videos and more.",
   "image":"https://www.google.com/images/logo.png",
   "url":"https://www.google.com"
   "image_size": 896933,
   "image_type: "image/gif",
   "image_x: 1100,
   "image_y: 440,
   "icon": "https://www.google.com/favicon.ico",
   "icon_type": "image/x-icon",
   "icon_x": 32,
   "icon_y": 32,
   "locale: "en_US"
}

Errors

If a request cannot be completed successfully, the response from the API will contain HTTP status code 400 or higher. The response from the API may also contain one or more error elements in the response. This information can be used to determine what went wrong. Each of these elements may contain an error code, message, and (if applicable) other informative values to assist in debugging the problem.

Error CodeDescription
400Generic error
401Cannot verify API access key
403Invalid or blank API access key
423Forbidden by robots.txt - the requested website does not allow us to access this page
425Invalid response status code (with the actual response code we got from the remote server)
426Too many requests per second on a single domain
429Too many requests / rate limit exceeded

Example Error Response (HTTP Status code 401):

{
   "title":"",
   "description":"Linkpreview service denied",
   "image":"",
   "url":"",
   "error":401
}

Rate limits

The counters for your API key reset on a rolling basis using the sliding window algorithm. Every hit to the API counts as one request.

Example for PRO Plan: If you made 500 requests at 10:15AM and 500 requests at 10:25AM, your API key would become temporarily blocked. This temporary block of your API key would cease at 11:15AM, at which point you could make 500 requests. At 11:25AM, you could then make another 500 requests.

Parser

Our engine can only retrieve and parse publicly accessible pages and domains that use our custom integrations. Our crawler will respect robots.txt specification and some public pages may still be blocked due to this. Unfortunately, we cannot guarantee the correct response data for every single URL but we’re constantly working to resolve or minimize these edge-cases.

Some of the reasons for the failed, blank, or incomplete API response are beyond our control:

  • Private pages or pages that require authentication or login
  • Advanced bot-prevention installed at the targeted website
  • Captcha protection
  • Paywall protection
  • Temporary networking issues or downtimes
  • Webmasters not following best practices (no meta tags, open graph, or other content clues)
  • Restrictions based on IP address or range of addresses (known cloud providers block)
  • Crawling exclusion by robots.txt rules (error 423)

You can use our Preview Tool to try and report incorect URL, or use Similar Validator to double-check if the URL can be parsed correctly by a different engine.

Image Processing and Validation

Sometimes the website can provide og:image that is not accessible, served via the insecure HTTP protocol, invalid, or the URL is simply wrong. LinkPreview API can help and process images to validate them and extract additional data such as image width, image height, content-type, and size. Supported web image formats include jpeg, png, gif, ico, and webp images up to 5MB in size.

To validate the image, send your request with additional field image_size and check if the returned image size is greater than zero. You can also use image width and height parameters to calculate the image orientation (portrait/landscape) and use that to decide which of your layouts to render. You can use image size to discard images that are too small or too big for your specific layout.

It is highly recommended to set up a proxy and serve all the images through your own cached and secure environment without leaking users IP addresses.

Same-origin policy

Bypassing same-origin policy is handled automatically. You can use either CORS or JSONP requests to bypass same-origin policy in your front-end application. Since CORS allows you to use POST requests we recommend this method for all modern applications. JSONP is provided for compatibility reasons.

Caching

The LinkPreview API will cache requested pages and it will return the cached response for a while. Any page updates will get noted on its next crawl and not immediately. The exact TTL depends on various parameters and it can take up to a day for this cache to expire.

Per Domain Limits

Each request requires some resources to be allocated from the requested website. Too many connections to a single website imply a lot of burden for that server and can be flagged as a DoS attack. A Denial of Service(DoS) attack means that you are trying to make the server so busy that it’s incapable of dealing with other requests.

To avoid congestion and protect smaller websites, our service will rate-limit requests made to the same domain in short bursts.

You can make a maximum of 1 request each second to a single domain. If you go over this limit, the error 426 will be thrown.

However, this limit is not imposed on high-throughput domains such as Youtube, Amazon, Twitter, etc since they have a lot of resources to handle our requests.

If you for some reason need a higher limit, please contact us to request the increase.

Free Plan Limitations

Users of our Free Plan are limited to 60 requests per hour under a Creative Commons Attribution 4.0 International License. You’re welcome to use the LinkPreview API to build other services, but you must identify LinkPreview API as the source of the data.

Clear and visible attribution with a link to linkpreview.net should be present anywhere data from the service is used. The attribution requirement can be met by including the following:

This product uses LinkPreview API available from
<a href="https://www.linkpreview.net">https://www.linkpreview.net</a>.

In order to use the LinkPreview API without attribution, you can upgrade to one of our paid plans.

Examples

Using the LinkPreview API requires some technical knowledge and programming skills. Please note that we do not provide support for your applications, plugins, cms, or web frameworks that make use of our API.

Codepen

Simple working example - Frontend with Bulma CSS

LinkPreview HTML Generator - Email Template

Javascript

POST request using javascript / Fetch API

var data = {key: '123456', q: 'https://www.google.com'}

fetch('https://api.linkpreview.net', {
  method: 'POST',
  mode: 'cors',
  body: JSON.stringify(data),
}).then(res => {
  if (res.status != 200) {
    console.log(res.status)
    throw new Error('something went wrong');
  }
  return res.json()
}).then(response => {
  console.log(response)
}).catch(error => {
  console.log(error)
})

POST request using javascript / axios

import axios from 'axios'

axios.post(
  'https://api.linkpreview.net',
  {
    q: 'https://www.google.com',
    key: '123456'
  }).then(resp => {
    console.log(resp.data)
  }).catch(err => {
    // something went wrong
    console.log(err.response.status)
  })

PHP, Python, Ruby, cURL

Shell / cURL

curl --data "key=123456&q=https://www.google.com" https://api.linkpreview.net

PHP using curl

$target = urlencode("https://www.google.com");
$key = "123456";

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.linkpreview.net?key={$key}&q={$target}");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = json_decode(curl_exec($ch));
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($status != 200) {
    // something went wrong
    print_r($status);
    die;
}

print_r($output);

POST request using Python

import requests

api_url = 'https://api.linkpreview.net'
api_key = '123456'
target = 'https://www.google.com'
response = requests.get(api_url, params={'key': api_key, 'q': target})
print(response.json())

POST request using Ruby

require('httparty')

response = HTTParty.post('https://api.linkpreview.net?key=123456&q=https://www.google.com')
puts response.body

JQuery

jQuery simple CORS request

$.ajax({
    url: "https://api.linkpreview.net?key=123456&q=https://www.google.com",
    success: function(result) {
        console.log(result);
    },
    error: function(error) {
        // something went wrong
        console.log(error.status)
    }
});

jQuery preflight CORS request

$.ajax({
    url: "https://api.linkpreview.net?key=123456&q=https://www.google.com",
    type: "GET",
    contentType: "application/json",
    success: function(result){
        console.log(result);
    },
    error: function(error) {
        // something went wrong
        console.log(error.status)
    }
});

jQuery cross-origin request using JSONP

var target = "https://www.google.com";
var key    = "123456";

$.ajax({
    url: "https://api.linkpreview.net",
    dataType: "jsonp",
    data: {q: target, key: key},
    success: function (response) {
        if (response.error) {
            console.log(response.description);
            return;
        }
        console.log(response);
    },
    error: function(error) {
        // something went wrong
        console.log(error.status)
    }
});

Full Frontend Example

Frontend code using Bulma CSS and Javascript with Fetch API:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
  </head>
  <body>
  <section class="section">
    <div class="container">
      <div class="box" style="width:300px">
        <img id="myimage" src="">
        <div class="is-clipped">
          <div id="mytitle" class="has-text-weight-bold"></div>
          <div id="mydescription" class="mt-2"></div>
          <div id="myurl" class="mt-2 is-size-7"></div>
        </div>
      </div>
    </div>
  </section>

  <script>
    var data = {key: '123456', q: 'https://www.google.com'}

    fetch('https://api.linkpreview.net', {
      method: 'POST',
      mode: 'cors',
      body: JSON.stringify(data),
    })
      .then(res => res.json())
      .then(response => {
    document.getElementById("mytitle").innerHTML = response.title
    document.getElementById("mydescription").innerHTML = response.description
    document.getElementById("myimage").src = response.image
    document.getElementById("myurl").innerHTML = response.url
    })
  </script>
  </body>
</html>