Generate social preview images in your Next.js API from Sanity webhooks

Overview

sanity-next-social-image-generator

Automatically generate social share images using Sanity webhooks, and your Next.js API!
Functionality Example

A sample of what can be generated

Requirements

  • A Next.js application
  • A Sanity account and studio set up
  • A Redis database (we recommend Upstash - it's free!).

Note: Redis is necessary because we need a caching layer to prevent an infinite update loop in Sanity's webhooks when the library updates your social image. Also, we need to use a Redis service to solve this because Vercel's serverless functions are stateless, so we can not manage caching locally.

Table of Contents

Setup

1) Create a webhook in Sanity

Whenever an article is updated in your Sanity studio, we want Sanity to notify our Next.js app, and send along the data we need to generate the social share image.

  • Log in to the Sanity Dashboard
  • Select your project, and click on the "API" tab
  • Click the "Create Webhook" button
  • Set up a webhook with the following options:

Name: Can be anything you want
URL: The URL your webhook will hit to trigger the image generation (if you're deployed to vercel, it might look something like: https://your-app.vercel.app/api/generate-preview-image).
Note: If you want to test this functionality in your local dev environment, you will need to use an Ngrok URL to point to your localhost. More information on this can be found here.
Dataset: "Production"
Trigger on: Create, Update
Filter: Depending on your Sanity schemas, you can define different types of documents you'd like to generate social share images for. For example, if you wanted to add a social share image to your articles or topic pages, you would use:

  • _type == 'article' || _type == 'topic' Projection: Please follow the same data structure as below. These are the pieces of data that the social image generator needs to properly generate your image:
{
  "text": title,
  _id,
  "imageUrl": image.asset->url
}

Text: The text field you want to display on your social image. In the above example, it's our "title" field in our Sanity schema
imageUrl: The background image that you want to display on your social image. In the above example, it's our "image" field in our Sanity schema

Example webhook configuration

  • Click the "Save" button at the bottom of the page.

2) Create a Sanity Editor Token

If your Next.js application does not currently have a Read / Write token in Sanity

  • In the API tab, scroll down to the bottom of the page and click on "Add API Token"
  • Add a name, like "Social Share Image Generation"
  • Select "Editor" under permissions
  • Click "Save"
  • Copy your token and save it in your Next.js environment variables. You will need this later!

3) Update your Sanity Schema

In your Sanity project, add a new field to the document schema that you will be generating social share images for.

  • Add the field
{
  name       : 'shareImage',
  title      : 'Social Media Image',
  description: 'This is automatically generated by Next.js and can not be modified.',
  type       : 'image',
  readOnly   : true
},
  • Publish your schema update (e.g. sanity deploy)

4) Install the package in your Next App

In your Next.js application, run the following command to install this package:

yarn add sanity-next-social-image-generator
or
npm install sanity-next-social-image-generator --save

5) Create a Next.js API Route

This is used to receive Sanity's webhook requests.

  • Create a new file in your API folder called: pages/api/generate-preview-image.js
  • Paste the following code into this file:
import { createImageClient } from 'sanity-next-social-image-generator';

// Create the client
const client = createImageClient({
  dataset: 'production',
  projectId: process.env.SANITY_PROJECT_ID,
  redisUrl: process.env.REDIS_URL,
  token: process.env.SANITY_READ_WRITE_TOKEN,
});

const logo = require('./my-logo.jpg');

export default async function generatePreviewImage(req, res) {
  // Generate the image when Sanity's webhook hits your API
  const { imageUrl, text, _id, _type } = req.body;

  try {
    await client.generateImage({
      id: _id,
      backgroundImageUrl: imageUrl,
      text,
      blur: 10,
      darken: 50,
      logo,
      logoPosition: 'bottomRight',
    });
    res.status(200).send('Ok');
  } catch(e) {
    res.status(500).send(e);
  }
};

6) Update your Next.js page(s)' meta tags

In your Next.js page where you are using your article data, make sure you add your new image to your meta tags so that is shows up when your share your article!

Example page:

import Head from 'next/head';
import createImageUrlBuilder from '@sanity/image-url';

const urlFor = (source) => createImageUrlBuilder(config).image(source);

export default function MyArticlePage({ data }) {
  return (
    <div>
      <Head>
        {/* Add your meta tags */}
        <meta property="og:image" content={urlFor(data?.page?.shareImage?.asset).url()} />
        <meta name="twitter:image" content={urlFor(data?.page?.shareImage?.asset).url()} />
      </Head>
      {/* Page Content */}
    </div>
  );
}

export async function getStaticProps() {
  // Fetch your article data from Sanity
  const page = fetch('...');

  return {
    props: {
      data: {
        page
      },
    },
  }
}

Your app is now set up to receive Sanity webhooks and automatically generate your social share images!

API

Client

The client is used to authenticate with Sanity and upload your social share images. It takes the following arguments:

const client = createImageClient({
  dataset: 'production',
  projectId: 'zza4oo0z',
  redisUrl: 'rediss://username:[email protected]:37535',
  token: '1z2n78hds83o8xnfgm0921ufh25ltri32z90-lsz2jn2b4k7db82',
});

dataset: The Sanity dataset you want to update (e.g. production)
projectId: Your Sanity project ID
redisUrl: The full URL of your Redis instance. We recommend using Upstash since it's free!
token: Your Sanity Editor token (used for updating your article data with the social share image)\

Image Options

There are many options available to you that you can use to control how your social share image will look.

All available options

const image = await client.generateImage({
  id: '4e40b6bf-9ad3-4c8d-a6b3-a240074c3ed0', 
  backgroundImageUrl: 'https://i.picsum.photos/id/640/1200/600.jpg?hmac=jjcV1z6Vi_dLyTdWLTS8YNiQ6MNzPoggXvEF0Lji7dE',
  text: 'Generating Social Share Images Automatically with Sanity and Next',
  width: 1200,
  height: 600,
  backgroundFit: 'cover',
  fontSize: 50,
  fontName: 'Arial Black',
  fontColor: 'white',
  blur: 5,
  logo: 'https://www.stackfive.io/images/stackfive-logo-large.png',
  logoPosition: 'bottomRight',
  filterColor: '#07ae9d',
  darken: 25,
  lighten: 1.25,
});

id: Required The ID of the document you are adding a social share image to
backgroundImageUrl: Required The URL for the main image on your social share image. This can be any image, but typically you will use an image you define in Sanity (see Creating a Webhook in Sanity for more details)
text: Optional The text that will be displayed on your card
width: Optional The width of your social share image
height: Optional The height of your social share image
backgroundFit: Optional How the image should be resized to fit the dimensions. Can be one of cover, contain, fill, inside or outside.
fontColor: Optional The color of your text
fontSize: The size of your font. Note: You might need to modify this if you change the default width and height of the social share image
fontName: Optional The name of the font you want to use (font family)
blur: Optional Add blur to your background image
darken: Optional Darken your background image (# from 1-100)
lighten: Optional Brighten up your background image (each number is a multiplier)
logo: Optional The URL or Buffer of your logo
logoPosition: Optional Where you would like to place your logo on the image. Can be one of topLeft, topRight, bottomRight, or bottomLeft.
logoWidth: Optional Adjust the width of your logo
logoHeight: Optional Adjust the height of your logo
logoFit: Optional How the image should be resized to fit the dimensions. Can be one of cover, contain, fill, inside or outside.
filterColor: Optional Add a filter color overlay over the background image. Must be a hex code, or a valid css color type.

Creating an NGROK URL for Local Testing

If you want to test this functionality locally, your Sanity webhook will have to point to an NGROK URL. Ngrok tunnels your local environment, and creates a public URL.

Setup:

  1. Follow the NGROK setup guide here
  2. Run the following command in your terminal to expose your Next.js application: ngrok http 3000
  3. Copy the https URL that NGROK provides, and update your Sanity webhook URL to use this instead

If you followed the above steps, the Sanity webhook should now start hitting your localhost API. You can also configure a production and a dev webhook to use two different URLs if you wish.

Known Issues

M1 Macbooks

Node 16.x may cause issues on M1 Macbooks due to the Sharp library being used to process images.
If you run into an error in your Next.js application when using this library that says Module parse failed: Unexpected character '?', try updating your local Node version to 17.x.

Contributing

Pull requests are welcomed! Husky is set up to lint and format your code. Please also update the README.md file with any modifications you make.
There is a sample tool set up in sample/index.js to generate and save image files locally. You can run yarn sample to run this code while you are testing. The output file will be saved in /sample/output/sample.jpg.

Issues and Feature Requests

Please open an issue if you face any bugs, or would like to request new features.

You might also like...

Integrate Railway Project events with Telegram Chat/Channel using Railway Webhooks

Railway to Telegram Integrate Railway Project events with Telegram Chat/Channel using Railway Webhooks! One Click Self Deploy Manual Self Deploy Fork

Jul 5, 2022

An application for sending webhooks on Discord.

An application for sending webhooks on Discord.

Cordhook 🪝 Cordhook is an application for sending webhooks on Discord with ease. 🛠 Built with Tauri for desktop and Next.js for web. 🎨 Styled with

Jan 4, 2023

Slack Integration to receive incoming webhooks from openpix.com.br

Slack Integration to receive incoming webhooks from openpix.com.br

Slack Integration This is a aws lambda function to receive new transaction informations from OpenPix @ your company's slack workspace. Getting Started

Sep 19, 2022

medusa-plugin-webhooks

medusa-plugin-webhooks

Medusa Plugin Webhooks About Participants Anish De GitHub: @AnishDe12020 Twitter: @AnishDe12020 Discord: AnishDe12020#8442 (ID: 727047127271735387) De

Dec 18, 2022

Utility for generating preview images of StarCraft: Brood War and Remastered maps

bwpreview Utility for generating preview images of StarCraft: Brood War and Remastered maps (.scm and .scx files). All of the actual work of parsing m

Oct 14, 2022

A vanilla js library to show preview images on hover

Hover Preview A vanilla js library to show preview images on hover, check a Demo here Please watch 👀 or star 🌟 this repo if you like it. Getting sta

Dec 13, 2021

A social media platform aimed to capture the essence of all popular, existing social media platforms

A social media platform aimed to capture the essence of all popular, existing social media platforms

Social Fuel Reimagining Social Media, step by step 📌 About A social media platform aimed to capture the essence of all popular, existing social media

Feb 12, 2022

Generate static open graph images for Next.js at build time

next-static-og-images Generate static Open Graph images for Next.js at build time Getting started Installation npm i -D next-static-og-images or yarn

Jan 26, 2022
Releases(v1.0.1)
Owner
Jordan McRae
Build meaningful things.
Jordan McRae
Codebraid Preview provides a Markdown preview for Pandoc documents within VS Code.

Codebraid Preview provides a Markdown preview for Pandoc documents within VS Code. Most Markdown previews don't support all of Pandoc's extensions to Markdown syntax. Codebraid Preview supports 100% of Pandoc features—because the preview is generated by Pandoc itself! There is also full bidirectional scroll sync and document export.

Geoffrey Poore 12 Dec 28, 2022
Get an isolated preview database for every Netlify Preview Deployment

Netlify Preview Database Plugin Create an isolated preview database for each preview deployment in Netlify Quickstart • Website • Docs • Discord • Twi

Snaplet 10 Nov 16, 2022
Type safe library for interacting with Mindbody's Public API (v6) and Webhooks

Mindbody API Type safe library for interacting with Mindbody's Public API (v6) and Webhooks ⚠️ Read before installing This library is typed according

SplitPass 4 Dec 9, 2022
Generate link preview using our app, API or our NPM package.

get-link-preview ?? View the link preview using our App. Use the API to generate link preview in your app or use the NPM package to use the custom hoo

Siddhi Gate 25 Dec 21, 2022
Embed your NFT art anywhere, generate preview for oldschool platforms

Embed.Art Introduction Platform like twitter and facebook use meta tags to display preview when sharing url. The format these meta tags support are li

Ronan Sandford 12 Sep 26, 2022
Hackathon for Social Good 2022 and use your superpowers to create a solution for the social good.

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

Laura Diaz 3 Jun 27, 2022
This is the repo for the Medium2 project with Next.js, Sanity CMS, React and Tailwind CSS

Next.js + Tailwind CSS Example This example shows how to use Tailwind CSS (v3.0) with Next.js. It follows the steps outlined in the official Tailwind

null 1 Jan 22, 2022
Medium-Clone with Next.JS, Typescript, Tailwindcss, and Sanity!!

Medium Clone ?? Overview /pages ✔️ pages/index.tsx = Homepage and list all Blogs ✔️ pages/post/[slug].tsx = Details Blog /pages/api ✔️ pages/api/creat

argikurnia 23 Nov 16, 2022
Stablo is a minimal blog website template built with Next.js, TailwindCSS & Sanity CMS

Stablo Blog Template - Next.js & Sanity CMS Stablo is a JAMStack Starter template built with Next.js, Tailwind CSS & Sanity CMS by Web3Templates. Clic

Web3Templates 159 Dec 30, 2022
My personal website – Built using Next.js, TypeScript, MDX, Sanity.io and Tailwind

kenaqshal.com Framework: Next.js Database: PlanetScale ORM: Prisma Authentication: NextAuth.js Deployment: Vercel CMS: Sanity Styling: Tailwind CSS Ov

Ken Aqshal Bramasta 6 Nov 24, 2022