Analytics & Data8 min read

How to Integrate Heap with Your Headless CMS

Connect Heap to your headless CMS so every page view, click, funnel step, and content publish event carries structured content context.

Published April 29, 2026
01 โ€” Overview

What is Heap?

Heap is a digital insights and product analytics platform that captures user interactions on web and mobile apps, then helps teams analyze funnels, journeys, retention, and friction points. Product, growth, marketing, and data teams use Heap when they want retroactive analysis of user behavior without defining every click event before launch. It sits in the analytics and data category alongside tools like Amplitude and Mixpanel, with a focus on autocaptured behavioral data.


02 โ€” The case for integration

Why integrate Heap with a headless CMS?

Heap tells you what users do. Your headless CMS tells you what content they saw when they did it. Connecting the two lets you answer questions like, "Do buying guides with expert review blocks convert better?", "Which author drives the most trial signups?", and "Did the new onboarding copy reduce drop-off between step 2 and step 3?" Without the integration, Heap may show that a button was clicked 4,312 times, but not whether those clicks came from a product page, campaign landing page, article template, or experiment variant.,A structured content back end makes this much easier. With Sanity, content in the Content Lake is typed JSON, so you can send clean properties into Heap, such as content_id, content_type, slug, author, topic, locale, campaign, and release_id. GROQ selects exactly those fields, including referenced documents like authors or categories. Webhooks fire when content is published, updated, or deleted, and Functions can run the sync logic without a separate queue, cron job, or small server you have to maintain.,The disconnected alternative is messy. Teams often copy campaign names into spreadsheets, hardcode tracking properties in frontend components, or wait for a data engineer to join Heap exports to content tables later in BigQuery or Snowflake. That works for a while, but it breaks when slugs change, content is localized, or a campaign ships in 12 markets. The trade-off is that you still need clear tracking conventions. Heap autocapture gives you a lot, but content metadata needs intentional field names and a shared event plan.


03 โ€” Architecture

Architecture overview

A typical Heap integration starts when an editor publishes content in Sanity Studio. A Sanity webhook fires on the publish mutation and sends the document ID to a webhook handler, or the same logic runs inside a Sanity Function. The handler uses @sanity/client and a GROQ query to fetch the published document from the Content Lake, including only the fields Heap needs, such as _id, _type, slug.current, title, author->name, topics[]->title, locale, and experimentKey. The handler then calls Heap's server-side Track API at https://heapanalytics.com/api/track with app_id, identity, event, and properties to record a content lifecycle event like "Content Published". On the frontend, you also install Heap's web SDK snippet, call heap.identify() for signed-in users, and call heap.track("Content Viewed", properties) when a Sanity-powered page renders. The end user just sees the page or app. Heap receives user behavior and content context keyed by the same content_id, which makes funnels, segments, paths, and retention reports more useful.


04 โ€” Use cases

Common use cases

๐Ÿ“ˆ

Content performance funnels

Send Sanity fields like content type, topic, author, and campaign into Heap so teams can compare signup, trial, or purchase funnels by content attributes.

๐Ÿงช

Experiment analysis

Track Sanity experiment keys or variant names in Heap events to see how different headlines, CTAs, or page modules affect user behavior.

๐Ÿงญ

Journey analysis by content

Use Heap paths and journeys to see whether users move from articles to product pages, docs, pricing, checkout, or support flows.

๐Ÿšฆ

Release impact tracking

Send publish events from Sanity to Heap so teams can correlate content releases with activation, drop-off, and conversion changes.


05 โ€” Implementation

Step-by-step integration

  1. 1

    Set up Heap

    Create a Heap account and project, choose your web or mobile environment, and copy the Heap environment ID, also called app ID in older server-side API docs. Install Heap's web SDK snippet on your site, then verify that page views and autocaptured events appear in Live View.

  2. 2

    Define your tracking plan

    Pick 6 to 10 content properties you want on Heap events, such as content_id, content_type, slug, title, author, topic, locale, campaign, release_id, and experiment_key. Keep names lowercase and stable so Heap charts don't split the same idea across multiple properties.

  3. 3

    Model content in Sanity Studio

    Add schema fields that support analytics questions, not just rendering. For example, include slug, author reference, topic references, campaign code, locale, publish date, and an optional experiment key. Because Sanity Studio uses schema-as-code, these fields can be reviewed in Git before they affect tracking.

  4. 4

    Create the sync mechanism

    Create a Sanity webhook that fires on publish events and sends the document ID to a Next.js route, serverless function, or Sanity Function. Use a GROQ filter so the webhook only runs for tracked types, such as article, landingPage, productPage, or docsPage.

  5. 5

    Call Heap's API

    In the handler, fetch the published document from the Content Lake with @sanity/client, map it to Heap event properties, and POST to Heap's server-side Track API. Store the Heap app ID and Sanity token in environment variables, not in client-side code.

  6. 6

    Test the frontend experience

    Render the same content_id and metadata on the page, then call heap.track("Content Viewed", properties) when the route loads. Test one published page, one updated page, and one localized page. In Heap, confirm that content lifecycle events and user behavior events share the same content_id.


06 โ€” Code

Code example

typescriptapp/api/sanity-to-heap/route.ts
import {createClient} from '@sanity/client'
import {NextRequest, NextResponse} from 'next/server'

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: NextRequest) {
  const body = await req.json()
  const id = body._id?.replace('drafts.', '')

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

  if (!content) return NextResponse.json({skipped: true})

  const heapRes = await fetch('https://heapanalytics.com/api/track', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({
      app_id: process.env.HEAP_APP_ID,
      identity: 'sanity-content-pipeline',
      event: 'Content Published',
      properties: {
        content_id: content._id,
        content_type: content._type,
        slug: content.slug,
        title: content.title,
        author: content.author,
        topics: content.topics || [],
        published_at: content.publishedAt,
      },
    }),
  })

  if (!heapRes.ok) {
    return NextResponse.json({error: await heapRes.text()}, {status: 502})
  }

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

07 โ€” Why Sanity

How Sanity + Heap works

Build your Heap integration on Sanity

Sanity's AI Content Operating System gives you structured content, real-time events, and flexible APIs to connect Heap behavior data with the content that shaped it.

Start building free โ†’

08 โ€” Comparison

CMS approaches to Heap

CapabilityTraditional CMSSanity
Content metadata on analytics eventsUses GROQ to fetch the exact content properties Heap needs, including referenced authors, topics, and campaign data in one query.
Publish-triggered Heap eventsUses GROQ-powered webhooks or Functions to trigger Heap syncs only for the content types and mutations you choose.
Experiment and variant trackingModels experiment keys, variants, releases, and scheduled publishing in Sanity Studio, then sends those fields to Heap as event properties.
Frontend tracking consistencyFeeds the same content_id, slug, type, and taxonomy values to web, mobile, Heap, and AI agents from the Content Lake.
Operational effortFunctions can run server-side sync logic on content changes without separate infrastructure, though high-volume teams should still plan retries and monitoring.

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 Heap and 200+ other tools.