Structured Content 2022: Join our conference to explore fresh perspectives on content and digital experiences →

Getting user information with webhooks

By Daniel Favand

Using webhooks and the Sanity API, you can merge content changes and user information

Webhook projection

{
  "projectId": sanity::projectId(), 
  "dataset": sanity::dataset(),
  "documentId": _id,
  "revisionId": _rev,
  "operation": delta::operation(),
  "before": before(),
  "after": after(),
  // user id of the person who made the change
  "author": identity(),
  // time the projection was calculated
  // not necessarily the time the transaction was posted!
  // The exact transaction time for a revision can be found in the history API
  "logTime": now(),
}

Webhook handler

// Built on Next.js API routes: https://nextjs.org/docs/api-routes/introduction

// provide your Sanity token from an environment variable
import {sanityToken} from 'lib/config'
import type {NextApiHandler, NextApiRequest, NextApiResponse} from 'next'

const handler: NextApiHandler = async (
  req: NextApiRequest,
  res: NextApiResponse
) => {

  const body = req.body

  const {
    projectId,
    dataset,
    documentId,
    revisionId,
    // we're not using `before` in this example, but we could use it to generate a diff
    // before,
    after,
    operation,
    author,
    // note this time will not be exactly the same as the actual transaction time
    // as this is the time when the webhook projection was run.
    // You can get the exact mutation time with an additional lookup to the transaction API if needed
    logTime,
  } = body

  const userResponse = await fetch(
    `https://${projectId}.api.sanity.io/v2022-04-29/users/${author}`,
    {
      headers: {
        Authorization: `Bearer ${sanityToken}`
      }
    }
  )

  const authorResult = await userResponse.json()

  const {
    displayName,
    email,
    sanityUserId,
    provider
  } = authorResult

  const logEntry = {
    user: {
      displayName,
      email,
      sanityUserId,
      provider
    },
    operation,
    projectId,
    dataset,
    documentId,
    revisionId,
    logTime,
    // here we're passing along the document
    // as it appears after the mutation.
    // We could also build a diff or send the "before" version
    updatedDocumentValue: after,
  }

  console.log('Send this to our logs =>', logEntry)

  return res.status(200).send('Log processed OK')
}

export default handler

While GROQ webhooks don't include detailed information about the user who triggered the webhook, the identity() function is available in the webhook projection. You can use this identifier to look up the user with Sanity's APIs.

This snippet shows an example GROQ webhook projection and corresponding webhook handler (using Next.js API routes).

Here is a webhook template that you can apply to your own project.

Note that error handling is omitted to highlight the basic workflow, you'll want to handle API errors appropriately.

Also note that you can probably cache user information responses to reduce the number of API calls you make.

Contributor

Other schemas by author