Monitoring & Observability8 min read

How to Integrate LogRocket with Your Headless CMS

Connect LogRocket to structured content so every replay, error, network trace, and rage click can be tied back to the exact article, product, locale, or campaign a user saw.

Published April 29, 2026
01 โ€” Overview

What is LogRocket?

LogRocket is a session replay and frontend observability platform for web and mobile teams. It records user sessions, JavaScript errors, console logs, network requests, performance data, and product behavior so engineering, product, and support teams can reproduce issues with context. Teams use it when a stack trace alone isn't enough, especially for bugs that depend on user state, browser behavior, content, or timing.


02 โ€” The case for integration

Why integrate LogRocket with a headless CMS?

A replay that says a user clicked a broken CTA on `/summer-sale` helps. A replay that says they clicked `cta.primary` on landing page `summer-sale-2026`, locale `en-US`, content release `spring-launch`, and variant `B` helps a lot more. When LogRocket is connected to your headless CMS, session data can include the structured content context behind the page, not just the URL that happened to render it.

For Monitoring & Observability teams, this solves a common gap. Frontend tools capture what happened in the browser, while content systems know what the user was actually reading, buying, comparing, or trying to submit. With structured content in Sanity's Content Lake, you can pass LogRocket exact fields like `_id`, `_type`, `slug`, `locale`, `campaignId`, `author`, and `releaseId`. GROQ selects only the fields LogRocket needs, and webhooks or Functions react when content changes so your app isn't relying on stale lookup tables.

The disconnected version is messy. Engineers inspect a replay, copy the URL, search the content system manually, ask an editor whether the page changed that day, and then guess which version the user saw. That can turn a 10-minute bug report into a 2-hour investigation. The trade-off is that LogRocket's custom event capture runs in the client SDK, so most teams use Sanity webhooks or Functions to prepare content context, then send it to LogRocket from the browser when the user views or interacts with that content.


03 โ€” Architecture

Architecture overview

A typical Sanity and LogRocket integration starts with structured content in the Content Lake. You model pages, products, campaigns, help articles, or other content types in Sanity Studio, including fields that matter for observability, such as slug, locale, campaign ID, experiment key, release ID, and owner team. When an editor publishes or updates content, a Sanity webhook fires. You can filter the webhook with GROQ so it only runs for types LogRocket should know about, for example `_type in ["page", "product", "article"]`. The webhook can call a Sanity Function, or the Function can handle the mutation directly. Inside that server-side step, `@sanity/client` fetches the full content context with GROQ, including referenced data like author, category, or campaign. From there, the Function writes a small content-context payload to your app, cache, or API route. When the end user loads the page, your frontend initializes the LogRocket browser SDK with `LogRocket.init("org/app")`, then calls `LogRocket.track("Sanity content viewed", payload)` and, when appropriate, `LogRocket.identify(userId, traits)`. LogRocket attaches those custom events and traits to the user's replay, so engineers can filter sessions by content ID, content type, locale, campaign, or release. Functions keep the server-side processing close to the content event, with no separate queue or cron job to run. Webhooks are a good fit when you already have middleware or an existing observability service. Either way, GROQ keeps the payload small and specific, instead of sending full documents or rendered HTML.


04 โ€” Use cases

Common use cases

๐ŸŽฅ

Replay bugs by content ID

Attach Sanity document IDs and slugs to LogRocket sessions so engineers can filter replays for one article, product page, or campaign.

๐Ÿšจ

Connect frontend errors to publish events

When JavaScript errors spike after a content release, compare LogRocket sessions against the Sanity release ID, locale, and content type.

๐Ÿงช

Debug content-driven experiments

Track variant keys from Sanity in LogRocket so product teams can replay sessions for variant A, variant B, or a specific campaign audience.

๐Ÿ’ฌ

Give support better session context

Let support teams see the exact help article, onboarding step, or pricing page a customer viewed before opening a ticket.


05 โ€” Implementation

Step-by-step integration

  1. 1

    Set up LogRocket

    Create a LogRocket app, copy the app ID in the `org/app` format, and install the browser SDK with `npm install logrocket`. If you use React, add `@logrocket/react` for component tracking. LogRocket's browser app ID is public client config, not a secret. Create an API token only if your plan and workflow require reporting or export access.

  2. 2

    Initialize LogRocket in your frontend

    Call `LogRocket.init(process.env.NEXT_PUBLIC_LOGROCKET_APP_ID)` once in your client app. If users sign in, call `LogRocket.identify(user.id, { email, plan })` after authentication so sessions can be connected to account-level issues.

  3. 3

    Model observability fields in Sanity Studio

    Add fields that help investigations, such as `slug`, `locale`, `campaignId`, `experimentKey`, `ownerTeam`, and `supportTier`. Keep these as typed fields in your schema so they're queryable with GROQ and safe to pass into LogRocket events.

  4. 4

    Create the content-change trigger

    Add a Sanity webhook or Function for publish and update events. Use a GROQ filter like `_type in ["page", "product", "article"]` so you don't process unrelated documents such as internal notes or reusable labels.

  5. 5

    Fetch the exact payload with GROQ

    In your webhook handler or Function, use `@sanity/client` to fetch the changed document and any referenced fields LogRocket should receive. Avoid sending full Portable Text bodies, draft-only fields, or PII. A 10-field payload is easier to search than a 200-field document.

  6. 6

    Send content context to LogRocket and test

    Render the content context into the page or fetch it from your app API, then call `LogRocket.track("Sanity content viewed", payload)` in the browser. Test by publishing a page in Sanity Studio, opening it in a browser, triggering a session in LogRocket, and filtering sessions by the Sanity `_id` or slug.


06 โ€” Code

Code example

typescriptsanity-to-logrocket.ts
import {createClient} from '@sanity/client'

const sanity = createClient({
  projectId: process.env.SANITY_PROJECT_ID!,
  dataset: process.env.SANITY_DATASET!,
  apiVersion: '2025-02-19',
  token: process.env.SANITY_READ_TOKEN,
  useCdn: false,
})

export async function POST(req: Request) {
  const body = await req.json()
  const id = body._id || body.ids?.updated?.[0] || body.ids?.created?.[0]

  const content = await sanity.fetch(
    `*[_id == $id][0]{
      _id, _type, title, "slug": slug.current,
      locale, campaignId, experimentKey,
      "author": author->name
    }`,
    {id}
  )

  await fetch(`${process.env.SITE_URL}/api/content-context`, {
    method: 'POST',
    headers: {
      'content-type': 'application/json',
      authorization: `Bearer ${process.env.INTERNAL_TOKEN}`,
    },
    body: JSON.stringify(content),
  })

  return Response.json({ok: true})
}

// Client component on the rendered page
'use client'
import {useEffect} from 'react'
import LogRocket from 'logrocket'

LogRocket.init(process.env.NEXT_PUBLIC_LOGROCKET_APP_ID!)

export function TrackContentView({content}: {content: Record<string, unknown>}) {
  useEffect(() => {
    LogRocket.track('Sanity content viewed', content)
  }, [content])

  return null
}

07 โ€” Why Sanity

How Sanity + LogRocket works

Build your LogRocket integration on Sanity

Sanity gives you the structured content foundation, real-time event system, and flexible APIs to connect LogRocket sessions to the exact content your users saw.

Start building free โ†’

08 โ€” Comparison

CMS approaches to LogRocket

CapabilityTraditional CMSSanity
Session context by content objectOften limited to URL, page title, or rendered HTML, which makes it harder to identify the exact source field behind a replay.Content Lake documents are structured JSON, and GROQ can return the exact content ID, slug, locale, campaign, and referenced fields for LogRocket.
Publish-aware observabilityTeams often compare LogRocket timelines with editorial calendars by hand after an error spike.Webhooks and Functions can react to publish, update, and delete events, then prepare LogRocket-ready context without separate infrastructure.
Payload controlRendered pages can include too much markup and too little structured meaning for useful LogRocket filters.GROQ projections return small, purpose-built payloads, including joins across references in one query.
Experiment and campaign debuggingVariant data may live in templates, plugins, or analytics tools, so LogRocket sessions don't always show which content variant rendered.Experiment keys, campaign IDs, and release data can be modeled in schema and sent to LogRocket as typed session events.
Trade-offs and setup effortFast to start if the site already exists, but content-level observability usually needs custom theme code.You still need to design the event payload and add client-side LogRocket tracking, but Functions, webhooks, and GROQ reduce the moving parts.

09 โ€” Next steps

Keep building

Explore related integrations to complete your content stack.

Ready to try Sanity?

See how Sanity's Content Operating System powers integrations with LogRocket and 200+ other tools.