Documentation

Introduction

Link preview is a feature that provides users with a glimpse of a web page’s content before actually clicking on the link. It typically includes a preview of the page’s title, a brief description, an image, and the URL. Link previews are commonly used in messaging apps, social media platforms, and email clients to give users an idea of what to expect when they click on a shared link.

With the LinkPreview API, you can programmatically obtain detailed website information, including the title, preview image, and brief description, for any given URL.

This API documentation provides a comprehensive overview of how to use the API and the resources required for seamless integration.

How to get access

Authorization for LinkPreview relies on API keys, which clients must include in the X-Linkpreview-Api-Key header for each request.

Sign up for your free API key here.

When developing a web application that runs in a browser, our suggestion is to construct a server-side application for managing API requests. This approach grants you the capability to oversee access, authentication, and rate-limiting within a secure server environment, safeguarding your API keys from public exposure.

Quick start

Simple GET Request

curl "https://api.linkpreview.net/?q=https://google.com" -H "X-Linkpreview-Api-Key: 123456"

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"
}

Secure POST Request

You also have the option to make requests using the POST method. In the example below, we utilize the curl command line utility to transmit query parameters within the request body.

curl --data "q=https://google.com&fields=image_x,image_y,locale" https://api.linkpreview.net -H "X-Linkpreview-Api-Key: 123456"

API Endpoints

EndpointGETPOST
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 (&).

NameDescriptionExample
qURL to inspect*https://www.google.com
fieldsComma-separated list of fields to returnimage_x, icon_type, locale
keyYour API key** [deprecated]123456

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

** Deprecated, please use X-Linkpreview-Api-Key header instead.

Default and Additional Fields

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

https://api.linkpreview.net/?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 name that is used to represent the site. Defaults to top_level_domain+1.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

Unless otherwise noted, the default value for string type is an empty string "", and for a numeric type is zero 0. Default values are used when the parser is unable to find or extract the correct value from the requested URL.

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.

The LinkPreview API incorporates several additional measures to handle sudden spikes in incoming traffic and enhance its overall stability. Users who send many requests in quick succession may receive error responses, indicated by status code 503, or could be temporarily banned by our upstream provider.

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. The crawler identifies itself as “linkpreview” in the HTTP “User-agent” header field. 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)
  • Rendering page or adding meta tags with Javascript after document is loaded
  • Restrictions based on IP address or range of addresses (known cloud providers block)
  • Deep linking or platform specific links
  • Crawling exclusion by robots.txt rules (error 423)

You can use our Preview Tool to try and report incorrect 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. See example.

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.

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 = {q: 'https://www.google.com'}

fetch('https://api.linkpreview.net', {
  method: 'POST',
  headers: {
    'X-Linkpreview-Api-Key': '123456',
  },
  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',
  },
  {
    headers: {
      'X-Linkpreview-Api-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 "q=https://www.google.com" https://api.linkpreview.net -H "X-Linkpreview-Api-Key: 123456"

PHP using curl

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

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.linkpreview.net?&q={$target}");
$headers = [
    "X-Linkpreview-Api-Key: {$key}"
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
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 Python3

import requests

api_url = 'https://api.linkpreview.net'
api_key = '123456'
target = 'https://www.google.com'

response = requests.get(
    api_url,
    headers={'X-Linkpreview-Api-Key': api_key},
    params={'q': target},
)

print(response.json())

POST request using Ruby

require('httparty')

query = {
  "q"     => "https://www.google.com",
}

headers = {
  "X-Linkpreview-Api-Key"  => "123456",
}

response = HTTParty.post(
  "https://api.linkpreview.net",
  :query => query,
  :headers => headers
)

puts response.body

JQuery

jQuery simple CORS request

$.ajax({
    url: "https://api.linkpreview.net?q=https://www.google.com",
    headers: {
        'X-Linkpreview-Api-Key':'123456',
    },
    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?q=https://www.google.com",
    headers: {
        'X-Linkpreview-Api-Key':'123456',
    },
    type: "GET",
    contentType: "application/json",
    success: function(result){
        console.log(result);
    },
    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 = {q: 'https://www.google.com'}
    var key = "123456"

    fetch('https://api.linkpreview.net', {
      method: 'POST',
      headers: {
        'X-Linkpreview-Api-Key': key,
      },
      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>