{
  "license": "CC BY 4.0",
  "licenseUrl": "https://creativecommons.org/licenses/by/4.0/",
  "recipe": {
    "slug": "signup-activation-funnel",
    "title": "Build a Signup-to-Activation Funnel in SQL",
    "testedWith": "Apache DataFusion 45.2.0",
    "lastReviewed": "2026-07-27"
  },
  "contract": {
    "tableName": "product_events",
    "schema": [
      {
        "name": "timestamp_utc",
        "type": "Timestamp",
        "description": "When the product event occurred."
      },
      {
        "name": "user_id",
        "type": "Utf8",
        "description": "Stable user identifier."
      },
      {
        "name": "event_name",
        "type": "Utf8",
        "description": "Stable snake_case milestone name."
      },
      {
        "name": "source",
        "type": "Utf8",
        "description": "Acquisition or campaign source."
      }
    ]
  },
  "query": "WITH user_funnel AS (\n  SELECT\n    user_id,\n    MIN(CASE WHEN event_name = 'signup_completed'\n      THEN timestamp_utc END) AS signed_up_at,\n    MIN(CASE WHEN event_name = 'onboarding_completed'\n      THEN timestamp_utc END) AS onboarded_at,\n    MIN(CASE WHEN event_name = 'integration_connected'\n      THEN timestamp_utc END) AS integrated_at,\n    MIN(CASE WHEN event_name = 'first_value_completed'\n      THEN timestamp_utc END) AS activated_at\n  FROM product_events\n  WHERE timestamp_utc >= now() - INTERVAL '30 days'\n  GROUP BY user_id\n),\nstage_counts AS (\n  SELECT 1 AS step_order, 'Signed up' AS step, COUNT(*) AS users\n  FROM user_funnel\n  WHERE signed_up_at IS NOT NULL\n  UNION ALL\n  SELECT 2, 'Onboarded', COUNT(*)\n  FROM user_funnel\n  WHERE onboarded_at >= signed_up_at\n  UNION ALL\n  SELECT 3, 'Integrated', COUNT(*)\n  FROM user_funnel\n  WHERE integrated_at >= onboarded_at\n  UNION ALL\n  SELECT 4, 'Activated', COUNT(*)\n  FROM user_funnel\n  WHERE activated_at >= integrated_at\n)\nSELECT\n  step_order,\n  step,\n  users,\n  100.0 * users\n    / NULLIF(MAX(CASE WHEN step_order = 1 THEN users END) OVER (), 0)\n    AS conversion_from_signup_pct,\n  100.0 * users\n    / NULLIF(LAG(users) OVER (ORDER BY step_order), 0)\n    AS conversion_from_previous_pct\nFROM stage_counts\nORDER BY step_order;",
  "fixtureKind": "reproducible",
  "inputRows": [
    {
      "timestamp_utc": "2026-07-28T13:00:00.000Z",
      "user_id": "user-1",
      "event_name": "signup_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T13:01:00.000Z",
      "user_id": "user-1",
      "event_name": "onboarding_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T13:02:00.000Z",
      "user_id": "user-1",
      "event_name": "integration_connected",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T13:03:00.000Z",
      "user_id": "user-1",
      "event_name": "first_value_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:50:00.000Z",
      "user_id": "user-2",
      "event_name": "signup_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:51:00.000Z",
      "user_id": "user-2",
      "event_name": "onboarding_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:52:00.000Z",
      "user_id": "user-2",
      "event_name": "integration_connected",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:53:00.000Z",
      "user_id": "user-2",
      "event_name": "first_value_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:40:00.000Z",
      "user_id": "user-3",
      "event_name": "signup_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:41:00.000Z",
      "user_id": "user-3",
      "event_name": "onboarding_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:42:00.000Z",
      "user_id": "user-3",
      "event_name": "integration_connected",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:43:00.000Z",
      "user_id": "user-3",
      "event_name": "first_value_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:30:00.000Z",
      "user_id": "user-4",
      "event_name": "signup_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:31:00.000Z",
      "user_id": "user-4",
      "event_name": "onboarding_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:32:00.000Z",
      "user_id": "user-4",
      "event_name": "integration_connected",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:20:00.000Z",
      "user_id": "user-5",
      "event_name": "signup_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:21:00.000Z",
      "user_id": "user-5",
      "event_name": "onboarding_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:10:00.000Z",
      "user_id": "user-6",
      "event_name": "signup_completed",
      "source": "organic"
    },
    {
      "timestamp_utc": "2026-07-28T12:11:00.000Z",
      "user_id": "user-6",
      "event_name": "onboarding_completed",
      "source": "organic"
    },
    {
      "timestamp_utc": "2026-07-28T12:00:00.000Z",
      "user_id": "user-7",
      "event_name": "signup_completed",
      "source": "organic"
    },
    {
      "timestamp_utc": "2026-07-28T11:50:00.000Z",
      "user_id": "user-8",
      "event_name": "signup_completed",
      "source": "organic"
    }
  ],
  "illustrativeInputRows": [
    {
      "timestamp_utc": "2026-07-28T13:00:00.000Z",
      "user_id": "user-1",
      "event_name": "signup_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T13:01:00.000Z",
      "user_id": "user-1",
      "event_name": "onboarding_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T13:02:00.000Z",
      "user_id": "user-1",
      "event_name": "integration_connected",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T13:03:00.000Z",
      "user_id": "user-1",
      "event_name": "first_value_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:50:00.000Z",
      "user_id": "user-2",
      "event_name": "signup_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:51:00.000Z",
      "user_id": "user-2",
      "event_name": "onboarding_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:52:00.000Z",
      "user_id": "user-2",
      "event_name": "integration_connected",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:53:00.000Z",
      "user_id": "user-2",
      "event_name": "first_value_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:40:00.000Z",
      "user_id": "user-3",
      "event_name": "signup_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:41:00.000Z",
      "user_id": "user-3",
      "event_name": "onboarding_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:42:00.000Z",
      "user_id": "user-3",
      "event_name": "integration_connected",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:43:00.000Z",
      "user_id": "user-3",
      "event_name": "first_value_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:30:00.000Z",
      "user_id": "user-4",
      "event_name": "signup_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:31:00.000Z",
      "user_id": "user-4",
      "event_name": "onboarding_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:32:00.000Z",
      "user_id": "user-4",
      "event_name": "integration_connected",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:20:00.000Z",
      "user_id": "user-5",
      "event_name": "signup_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:21:00.000Z",
      "user_id": "user-5",
      "event_name": "onboarding_completed",
      "source": "docs"
    },
    {
      "timestamp_utc": "2026-07-28T12:10:00.000Z",
      "user_id": "user-6",
      "event_name": "signup_completed",
      "source": "organic"
    },
    {
      "timestamp_utc": "2026-07-28T12:11:00.000Z",
      "user_id": "user-6",
      "event_name": "onboarding_completed",
      "source": "organic"
    },
    {
      "timestamp_utc": "2026-07-28T12:00:00.000Z",
      "user_id": "user-7",
      "event_name": "signup_completed",
      "source": "organic"
    },
    {
      "timestamp_utc": "2026-07-28T11:50:00.000Z",
      "user_id": "user-8",
      "event_name": "signup_completed",
      "source": "organic"
    }
  ],
  "expectedOutput": {
    "columns": [
      "step_order",
      "step",
      "users",
      "conversion_from_signup_pct",
      "conversion_from_previous_pct"
    ],
    "rows": [
      {
        "step_order": 1,
        "step": "Signed up",
        "users": 8,
        "conversion_from_signup_pct": 100,
        "conversion_from_previous_pct": null
      },
      {
        "step_order": 2,
        "step": "Onboarded",
        "users": 6,
        "conversion_from_signup_pct": 75,
        "conversion_from_previous_pct": 75
      },
      {
        "step_order": 3,
        "step": "Integrated",
        "users": 4,
        "conversion_from_signup_pct": 50,
        "conversion_from_previous_pct": 66.66666667
      },
      {
        "step_order": 4,
        "step": "Activated",
        "users": 3,
        "conversion_from_signup_pct": 37.5,
        "conversion_from_previous_pct": 75
      }
    ]
  },
  "notes": [
    "The included synthetic input rows generate the expected output when timestamps are shifted into the documented query window.",
    "Run this fixture in the public browser SQL playground; the selected query executes locally with DuckDB-Wasm.",
    "Adapt time windows, thresholds, identities, and business definitions before operational use."
  ]
}