9-Dec

React

Implementing unfurling URLs in Sanity

Want to add those nice-looking link previews you get when you share a link on Medium or Twitter? Then this article is for you!

3 min read

·

By Kristofer Selbekk

·

December 9, 2021

The concept of unfurling links – that is, showing a link with a preview image, the title of the page and a short description – is becoming a pretty popular feature on lots of sites these days. But how can you add it to your Sanity blog?

In this article, we will show you a quick and easy way to add this neat little feature in no time at all!

Create a custom block type

First, we need to add a new custom type to our document schema. It's pretty straight forward - with a single URL prop:


export default {
  type: "object",
  name: "unfurledUrl",
  title: "Unfurled URL",
  fields: [
    {
      name: "url",
      type: "url",
      description: "The URL to unfurl",
      validation: (Rule) => Rule.required(),
    },
  ],
};

Next, you need to add this to your block type field (like the content field of your blog post type):

// Example
const portableTextSchema = {
  name: "portableText",
  type: "array",
  title: "Post body",
  of: [
    { type: 'block' },
    { type: "unfurledUrl", icon: FiLink2 },
  ]
}

You can now add links to your content - but they won't show up like they should just yet.

Adding OpenGraph Ninja

Unfurling URLs is pretty straight forward. You make a request to the page, parse the response, and select some of the metadata tags. Some pages add something called "open graph" metadata, which makes these previews even better!

We could implement this ourselves, but let's just use a small service that does this for us - OpenGraph Ninja. Hei

Full disclosure – I made and maintain OpenGraph Ninja – so I'm obviously super biased over how great this tool is. But give it a try before you discard it completely!

OpenGraph Ninja even comes with a handy ready-made React library, which makes using this service a breeze. Let's start using it right inside of Sanity!

Navigate to your studio, and install the OpenGraph Ninja dependency:

npm install @opengraphninja/react

Next, let's add a preview component to our unfurl schema definition!

import { PreviewLink } from "@opengraphninja/react";
import "@opengraphninja/react/styles.css?raw";

export default {
  type: "object",
  name: "unfurledUrl",
  title: "Unfurled URL",
  fields: [
    {
      name: "url",
      type: "url",
      description: "The URL to unfurl",
      validation: (Rule) => Rule.required(),
    },
  ],
  preview: {
    select: {
      href: "url",
    },
    component: (props) => (
      <PreviewLink href={props.value.href} />
    ),
  },
};

That's a few changes, so let's go through them one by one. First we import the PreviewLink component and its required CSS styles. You can of course write your own styles if you want, but let's leave that as an exercise to the reader.

Oh, and note that you have to add ?raw to the end of the style import - that's a Sanity-specific thing you can read more about here.

We've also added a preview section, where we pass in the preview component, and pass in the url as a prop. Now we get a real nice-looking preview in our editor, too!

A preview of the link in the Sanity Studio
This is how it would look in the Studio

Showing it to our users

Unfortunately, even with all this work, our users won't know a thing – so let's add some support for our new custom unfurler.

Now, this next part depends on what kind of technology you're using on your end. In this guide, we'll assume you're using the @sanity/block-content-to-react package. Let's visit your imaginary features/PortableText.jsx file:

import React from 'react';
import { BlockContent } from '@sanity/block-content-to-react';
import { PreviewLink } from '@opengraphninja/react';
import '@opengraphninja/react/styles.css';

const serializers = {
  // your other serializers
  unfurledUrl: (props) => (
    <PreviewLink href={props.node.url} />
  )
};

export const PortableText = (props) => {
  return (
    <BlockContent 
      blocks={props.blocks} 
      serializers={serializers} 
    />
  );
}

All we're really adding here, is the way we deserialize the unfurledUrl content type. We're using the same preview component here, but you might want to create your own implementation with the provided usePreviewData hook instead.

Either way, the result is sure to look amazing. Here's a link to bekk.christmas:

Improve your own links!

Now you've seen the quick and easy way to implement unfurling of links. We cheated a bit, by using a (free) service and its provided React SDK, but you can implement something pretty similar yourself if you have the time.

This article was actually written while implementing this functionality for this website, so rest assured it's built on real world experience!

I hope you enjoyed this article - and if you did, give opengraph.ninja a chance!