Files
theater-ziefen-website/.agents/skills/content-experimentation-best-practices/references/cms-integration.md
T
johannes.gasser 57af0b8386
Build and Deploy / build-and-deploy (push) Successful in 2m53s
add skills
2026-05-18 08:39:42 +02:00

5.4 KiB

CMS Integration Patterns

Integrating experimentation with your CMS enables content teams to run tests without developer intervention.

Architecture Options

1. CMS-Managed Variants

Store experiment variants as content in the CMS.

Pros: Content team autonomy, version controlled Cons: More complex queries, potential publish coordination

// Experiment document
defineType({
  name: 'experiment',
  type: 'document',
  fields: [
    defineField({ name: 'name', type: 'string' }),
    defineField({ name: 'status', type: 'string', options: { 
      list: ['draft', 'running', 'paused', 'concluded'] 
    }}),
    defineField({ 
      name: 'variants', 
      type: 'array',
      of: [{
        type: 'object',
        fields: [
          defineField({ name: 'name', type: 'string' }),
          defineField({ name: 'weight', type: 'number' }),
          defineField({ name: 'content', type: 'reference', to: [{ type: 'page' }] }),
        ]
      }]
    }),
    defineField({ name: 'startDate', type: 'datetime' }),
    defineField({ name: 'endDate', type: 'datetime' }),
  ]
})

2. Field-Level Variants

Store variants as fields on the content document.

Pros: Simpler queries, content stays together Cons: Less flexible, schema complexity

defineType({
  name: 'landingPage',
  fields: [
    defineField({ name: 'headline', type: 'string' }),
    defineField({ 
      name: 'headlineVariantB', 
      type: 'string',
      description: 'A/B test variant (leave empty if not testing)'
    }),
    defineField({ name: 'activeExperiment', type: 'string' }),
  ]
})

3. External Experimentation Platform

Use dedicated tools (Optimizely, LaunchDarkly, VWO) with CMS content.

Pros: Robust analytics, proven platforms Cons: Additional cost, integration complexity

// CMS stores experiment IDs, platform handles assignment
defineField({
  name: 'experimentId',
  type: 'string',
  description: 'Optimizely experiment ID'
})

Implementation Pattern (CMS-Managed)

1. Experiment Schema

defineType({
  name: 'experiment',
  type: 'document',
  fields: [
    defineField({ name: 'name', type: 'string', validation: r => r.required() }),
    defineField({ name: 'hypothesis', type: 'text' }),
    defineField({ 
      name: 'status', 
      type: 'string', 
      options: { list: ['draft', 'running', 'concluded'] },
      initialValue: 'draft'
    }),
    defineField({
      name: 'variants',
      type: 'array',
      of: [{
        type: 'object',
        name: 'variant',
        fields: [
          defineField({ name: 'id', type: 'string' }),
          defineField({ name: 'name', type: 'string' }),
          defineField({ name: 'weight', type: 'number', initialValue: 50 }),
        ]
      }],
      validation: r => r.min(2).error('Need at least 2 variants')
    }),
    defineField({ name: 'targetPage', type: 'reference', to: [{ type: 'page' }] }),
    defineField({ name: 'targetField', type: 'string' }),
  ]
})

2. Variant Content

// On the page being tested
defineField({
  name: 'experimentVariants',
  type: 'array',
  of: [{
    type: 'object',
    fields: [
      defineField({ name: 'experimentId', type: 'reference', to: [{ type: 'experiment' }] }),
      defineField({ name: 'variantId', type: 'string' }),
      defineField({ name: 'headline', type: 'string' }),
      // Other variant-specific fields
    ]
  }]
})

3. Frontend Assignment

// Middleware or server-side
function assignVariant(experimentId: string, variants: Variant[]): string {
  // Check for existing assignment in cookie
  const cookieKey = `exp_${experimentId}`
  const existing = getCookie(cookieKey)
  if (existing) return existing
  
  // Random assignment based on weights
  const rand = Math.random() * 100
  let cumulative = 0
  for (const variant of variants) {
    cumulative += variant.weight
    if (rand <= cumulative) {
      setCookie(cookieKey, variant.id, { maxAge: 30 * 24 * 60 * 60 })
      return variant.id
    }
  }
  return variants[0].id
}

4. Query with Variant

*[_type == "page" && slug.current == $slug][0]{
  ...,
  "experiment": experimentVariants[experimentId->status == "running"][0]{
    experimentId->{name, _id},
    variantId,
    headline
  }
}

Analytics Integration

Event Tracking

// Track experiment exposure
function trackExposure(experimentId: string, variantId: string) {
  analytics.track('Experiment Viewed', {
    experimentId,
    variantId,
    timestamp: new Date().toISOString()
  })
}

// Track conversion
function trackConversion(experimentId: string, variantId: string, metric: string) {
  analytics.track('Experiment Conversion', {
    experimentId,
    variantId,
    metric,
    timestamp: new Date().toISOString()
  })
}

Data Layer

// Push to data layer for analytics tools
window.dataLayer.push({
  event: 'experiment_assignment',
  experiment_id: experimentId,
  variant_id: variantId
})

Best Practices

Content Team Workflow

  1. Create experiment document with hypothesis
  2. Create variant content
  3. Set status to "running"
  4. Monitor results
  5. Set status to "concluded" and record winner

Avoid Flicker

  • Assign variants server-side when possible
  • Use CSS to hide content until variant determined
  • Pre-render both variants, show based on assignment

Clean Up

  • Archive concluded experiments
  • Remove losing variant content
  • Implement winner as default