All skills
sanity-io avatar

/content-experimentation-best-practices

@ad50ea4 official
by Sanitysanity-io/agent-toolkit187 stars
30

Content experimentation and A/B testing guidance covering experiment design, hypotheses, metrics, sample size, statistical foundations, CMS-managed variants, and common analysis pitfalls. Use this skill when planning experiments, setting up variants, choosing success metrics, interpreting statistical results, or building experimentation workflows in a CMS or frontend stack.

Use this Skill: https://skilld.dev/gh/sanity-io/agent-toolkit/content-experimentation-best-practices

This session only. Nothing lands on disk.

referencescms-integration.md

≈1.8k tokens on demand. Your agent reads this file only when SKILL.md points to it.

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. Returns the assigned variant id, or null when the
// experiment has no variants to assign.
function assignVariant(experimentId: string, variants: Variant[]): string | null {
  if (variants.length === 0) return null

  // Reuse an existing assignment, but only if it's still a valid variant.
  // After variants are renamed or removed, drop the stale cookie and reassign,
  // otherwise users stay bucketed to IDs that no longer exist.
  const cookieKey = `exp_${experimentId}`
  const existing = getCookie(cookieKey)
  if (existing && variants.some(v => v.id === existing)) return existing

  // Random assignment based on weights. Normalize against the total weight so
  // splits work even when weights don't sum to 100 (otherwise draws above the
  // sum skew to the fallback).
  const totalWeight = variants.reduce((sum, v) => sum + v.weight, 0)
  if (totalWeight <= 0) {
    const fallback = variants[0]
    setCookie(cookieKey, fallback.id, { maxAge: 30 * 24 * 60 * 60 })
    return fallback.id
  }
  const rand = Math.random() * totalWeight
  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
    }
  }
  // Fall back to the last variant to absorb any floating-point remainder, and
  // persist it like any other assignment so the visitor stays bucketed.
  const fallback = variants[variants.length - 1]
  setCookie(cookieKey, fallback.id, { maxAge: 30 * 24 * 60 * 60 })
  return fallback.id
}

4. Query with Variant

Resolve one experiment's assignment at a time, passing both its experimentId and the variantId returned by assignVariant. Match on both: variant IDs like control repeat across experiments, so filtering on variantId alone could pick a different running experiment's row. For a page running several experiments, resolve each one separately and merge the results.

*[_type == "page" && slug.current == $slug][0]{
  ...,
  "experiment": experimentVariants[
    experimentId->_id == $experimentId &&
    experimentId->status == "running" &&
    variantId == $variantId
  ][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

Source: SKILL.md on GitHub

No alerts16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    The skill provides comprehensive guidelines and best practices for content experimentation and A/B testing. It includes illustrative code snippets for CMS integration and statistical calculation. No security risks were identified.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer6mo

    5 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at ad50ea4. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 weeks ago.

Activeupdated 6 months ago
  • a-b-testing
  • content-experimentation
  • statistical-analysis
  • cms
  • conversion-optimization
  • multivariate-testing
  • metrics
  • hypothesis-testing

README badge

README badge for sanity-io/agent-toolkit/content-experimentation-best-practices

Provides guidance on A/B testing, multivariate testing, and statistical analysis for content experiments, including experiment design, metrics selection, sample sizing, CMS integration patterns, and common pitfalls. Use when setting up experimentation infrastructure, designing content variants, or interpreting test results in a headless CMS or frontend stack.

Generated from the current SKILL.md.

Does this skill cover statistical rigor for A/B tests?
Yes. The skill includes statistical foundations covering p-values, confidence intervals, power analysis, and Bayesian methods to help interpret results correctly.
Can I use this skill to set up experiments in a headless CMS?
Yes. The skill includes guidance on CMS-managed variants and field-level variants, with patterns for integrating experimentation into CMS workflows.
What common mistakes does this skill help avoid?
The skill documents 17 common pitfalls across statistics, design, execution, and interpretation to help teams avoid typical experimentation errors.
Does this cover multivariate testing or just A/B tests?
Both. The skill covers A/B testing, multivariate testing, and how to design experiments that test multiple variables simultaneously.

Generated from the current SKILL.md. These answers refresh after source changes.