Marketing & Advertising8 min read

How to Integrate Ortto with Your Headless CMS

Send campaign content, lead source data, and signup context from your headless CMS to Ortto so email, SMS, and ad journeys can react to what people actually read and request.

Published April 29, 2026
01 โ€” Overview

What is Ortto?

Ortto is a customer data and marketing automation platform used to collect customer profiles, track behavioral events, build segments, and send email, SMS, in-app, and ad audience campaigns. Marketing, growth, SaaS, and ecommerce teams use Ortto when they need a customer data platform and journey builder in one place. Its core strength is connecting profile data with activity data so teams can trigger campaigns from real customer behavior.


02 โ€” The case for integration

Why integrate Ortto with a headless CMS?

Ortto works best when it gets clean context, not just an email address. If someone downloads a pricing guide, registers for a webinar, or signs up from a localized landing page, your marketing team needs to know the asset, campaign, topic, language, consent state, and source URL. Without an integration, that context usually lives in hidden form fields, spreadsheet imports, or one-off Zapier-style mappings that break when a field name changes.


03 โ€” Architecture

Architecture overview

A typical Sanity and Ortto integration starts with structured content in the Content Lake. For example, a newsletterSignup document references a campaign document and a gatedAsset document. A Sanity webhook fires when that signup is created, or when a campaign page is published. The webhook calls a server endpoint or Sanity Function with the changed document ID. That server-side code uses @sanity/client and GROQ to fetch exactly the fields Ortto needs, such as email, first name, consent state, campaign code, asset title, locale, persona, and source URL. The handler then calls Ortto's REST API, usually POST https://api.ap3api.com/v1/person/merge with the X-Api-Key header, to create or update the person record. If you've defined custom activities in Ortto, the same handler can send a conversion event to Ortto after the person is merged. From there, Ortto can add the person to segments, trigger email or SMS journeys, sync ad audiences, and show the activity in the person timeline.


04 โ€” Use cases

Common use cases

๐Ÿ“ฉ

Gated content follow-up

When someone requests a Sanity-modeled guide or report, send the asset title, topic, campaign code, and locale to Ortto for a targeted nurture journey.

๐ŸŽฏ

Campaign source enrichment

Attach Sanity campaign metadata to Ortto people so segments can use content type, persona, journey stage, and source page instead of only UTM values.

๐Ÿงช

Landing page test reporting

Sync variant IDs and content references from Sanity to Ortto so marketers can compare conversions by headline, offer, audience, and region.

๐Ÿ”

Lifecycle reactivation

Use Sanity topics and product content tags to update Ortto fields that trigger reactivation emails, SMS reminders, or ad audience changes.


05 โ€” Implementation

Step-by-step integration

  1. 1

    Set up Ortto access

    Create or sign in to your Ortto account, then create a private API key in Ortto settings. Give it access to people and activities if you plan to merge profiles and record content conversions. In Ortto, create any custom fields you need, such as campaign code, source asset, persona, or journey stage, and copy their field IDs.

  2. 2

    Model marketing data in Sanity Studio

    Create schemas for campaign, gatedAsset, landingPage, and newsletterSignup. Include fields such as title, slug, campaignCode, persona, journeyStage, locale, consentText, orttoFieldValue, and references between signups and the content that caused them.

  3. 3

    Create a Sanity webhook

    Add a webhook that fires on create or publish events. For lead capture, use a filter like _type == 'newsletterSignup' && optIn == true. For campaign metadata sync, use a filter like _type in ['campaign', 'gatedAsset'] and only trigger on published documents.

  4. 4

    Fetch the full document with GROQ

    In a Sanity Function, webhook listener, or middleware route, use @sanity/client to fetch the changed document. Use GROQ projections to join referenced campaign and asset data so Ortto receives one clean payload instead of partial IDs.

  5. 5

    Send the mapped data to Ortto

    Call Ortto's REST API from server-side code. Use POST /v1/person/merge to create or update people by email, map Sanity fields to Ortto system and custom field IDs, and only send people who have valid consent.

  6. 6

    Test the end-to-end path

    Create a test signup in Sanity Studio, confirm the webhook ran, check your server logs, and verify the person in Ortto under People. Then submit the real frontend form and confirm that the Ortto profile contains the expected campaign and content fields.


06 โ€” Code

Code example

typescriptapp/api/sanity-to-ortto/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,
})

const query = `*[_id == $id][0]{
  email, firstName, lastName, optIn,
  "assetTitle": sourceAsset->title,
  "campaignCode": campaign->campaignCode,
  "persona": campaign->persona
}`

export async function POST(req: NextRequest) {
  const body = await req.json()
  const id = body._id || body.ids?.created?.[0] || body.ids?.updated?.[0]
  if (!id) return NextResponse.json({skipped: 'No document id'}, {status: 202})

  const lead = await sanity.fetch(query, {id})
  if (!lead?.optIn || !lead.email) {
    return NextResponse.json({skipped: 'No consent or email'}, {status: 202})
  }

  const orttoRes = await fetch('https://api.ap3api.com/v1/person/merge', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Api-Key': process.env.ORTTO_API_KEY!,
    },
    body: JSON.stringify({
      people: [{
        fields: {
          'str::email': lead.email,
          'str::first': lead.firstName,
          'str::last': lead.lastName,
          'str:cm:source-asset': lead.assetTitle,
          'str:cm:campaign-code': lead.campaignCode,
          'str:cm:persona': lead.persona,
        },
      }],
      merge_by: ['str::email'],
    }),
  })

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

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

07 โ€” Why Sanity

How Sanity + Ortto works

Build your Ortto integration on Sanity

Sanity gives you the structured content foundation, real-time event system, and flexible APIs you need to connect Ortto with your marketing journeys.

Start building free โ†’

08 โ€” Comparison

CMS approaches to Ortto

CapabilityTraditional CMSSanity
Lead capture contextForm data often lands in plugins or tables with limited campaign context, so marketers export CSV files to enrich Ortto later.A signup document can reference the exact campaign, asset, persona, and locale, then a webhook or Function sends that context to Ortto.
Real-time marketing triggersPublish and form events may require plugin-specific hooks, and retries vary by plugin.Webhooks fire on content mutations, and Functions can run server-side sync logic without separate infrastructure.
Field-level control for Ortto payloadsContent is often stored as pages or blocks, so extracting only the fields Ortto needs can be messy.GROQ can fetch a compact payload with joined references, such as signup email, asset title, campaign code, persona, and language.
Consent and compliance handlingConsent may be tied to a form plugin, making it harder to reuse across campaigns and channels.Consent state, consent copy, timestamp, and source page can be modeled directly and checked before sending data to Ortto.
Multi-channel campaign contentEmail copy, landing page copy, and ad copy are often duplicated across tools.One structured back end can feed web pages, mobile screens, Ortto journeys, ad tools, and AI agents with the same approved content.

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