links.arjun.tv/docs/end-user/campaign-funnel-workflow

Campaign Funnel Workflow

Use this guide to create campaigns, associate links, track conversions through the funnel, and measure campaign performance.

For a platform-wide, runnable lab that combines schema setup, analytics, and function-binding flows, use Platform-Wide Feature Exploration Lab.

When to use

  • You want to track clicks-to-conversions for a marketing initiative.
  • You need funnel metrics across multiple links in a campaign.
  • You want to test conversions before going live.
  • You need campaign-level analytics broken down by segment, country, or device.

What is a campaign?

A campaign is a container that groups links and conversion events under a shared goal. Campaigns enable:

  • Goal-based tracking (product sale, lead capture, newsletter signup, affiliate clickout, app install).
  • Funnel metrics: clicks → qualified clicks → conversions → revenue.
  • Cross-link attribution when multiple links feed the same campaign.
  • Campaign-scoped personalization rules.

Campaign lifecycle

DRAFT → ACTIVE → PAUSED
  ↑                ↓
  └────────────────┘
Select a lifecycle stage to view API actions and readiness checkpoints before activation.
StatusMeaning
DRAFTCampaign created but not yet tracking. Default state.
ACTIVECampaign is live and tracking clicks and conversions.
PAUSEDCampaign is paused. Existing data preserved, no new tracking.

Goal types

Each campaign has a goal type that sets default tracking behavior:

Goal typeDefault tracking presetDefault event type
PRODUCT_SALEga4_purchasepurchase
LEAD_CAPTUREga4_leadlead
NEWSLETTERga4_sign_upnewsletter_signup
AFFILIATE_CLICKOUTcustom_webhookaffiliate_click
APP_INSTALLga4_app_installapp_install

Defaults can be overridden at campaign creation time.

End-to-end workflow

1. Create a campaign

POST /v2/handles/{handle}/campaigns

{
  "campaignId": "spring-launch",
  "goalType": "PRODUCT_SALE",
  "status": "ACTIVE",
  "primarySlug": "spring-promo"
}

The campaignId must match ^[a-z0-9][a-z0-9_-]{2,63}$. If omitted, one is auto-generated as cmp_{hex}.

The response includes a quickStart array with activation steps:

{
  "campaign": { ... },
  "quickStart": [
    "Share the short URL in your campaign channel.",
    "Click once to validate click/context tracking.",
    "Post one conversion event to complete activation."
  ]
}

2. Associate links

Set the campaignId field when creating or updating a link:

PUT /v2/handles/{handle}/links/{slug}

{
  "destinationUrl": "https://shop.example.com/spring",
  "campaignId": "spring-launch",
  "trackingPolicy": {
    "mode": "DIRECT",
    "appendContextParam": true
  }
}

Multiple links can reference the same campaign. This is useful for A/B testing different creatives or channels.

2.5 Configure campaign detail structure page

Use campaign site-structure routes when each campaign needs its own detail page schema and login-gated content.

JWT control-plane routes:

  • PUT /v2/handles/{handle}/site-structure/campaigns/{campaignId} (upsert page + schema JSON)
  • GET /v2/handles/{handle}/site-structure/campaigns/{campaignId} (fetch page + schema JSON)
  • POST /v2/handles/{handle}/site-structure/campaigns/{campaignId}/publish (publish with FREE_WITH_LOGIN)

PAT automation routes:

  • PUT /v2/public/handles/{handle}/site-structure/campaigns/{campaignId}
  • GET /v2/public/handles/{handle}/site-structure/campaigns/{campaignId}
  • POST /v2/public/handles/{handle}/site-structure/campaigns/{campaignId}/publish

MCP tool equivalents:

  • campaign_structure_get
  • campaign_structure_upsert
  • campaign_structure_publish

Schema is stored under deterministic S3 keys: site-structure/{handle}/campaigns/{campaignId}/v{version}.json

Campaign records store a detailsPageSlug backreference for O(1) lookup.

Hands-on track with step-by-step commands:

3. Verify campaign health

GET /v2/handles/{handle}/campaigns/{campaignId}/health

Returns readiness checks:

{
  "campaignId": "spring-launch",
  "checks": [
    { "name": "tracking_preset", "status": "PASS", "detail": "Using tracking preset 'ga4_purchase'." },
    { "name": "conversion_event_type", "status": "PASS", "detail": "Using event type 'purchase'." },
    { "name": "primary_link", "status": "PASS", "detail": "Primary link configured: spring-promo" }
  ],
  "readiness": "READY"
}

4. Test a conversion

POST /v2/handles/{handle}/campaigns/{campaignId}/test-conversion

{
  "eventType": "purchase",
  "value": 99.99,
  "currency": "USD",
  "metadata": {
    "orderId": "12345",
    "items": 3
  }
}

Test conversions are marked with test: true in metadata and emit a conversion.tested webhook event.

5. Go live

Share the campaign's primary link. As visitors click and convert:

  1. Click events are recorded and attributed to the campaign.
  2. Campaign rollups are updated in real-time (clicks, bot clicks, conversions, revenue).
  3. Funnel metrics become available in the analytics API.

6. Monitor the funnel

GET /v2/handles/{handle}/analytics?funnel=true&campaignId=spring-launch

Returns the campaign funnel:

{
  "funnel": [
    {
      "campaignId": "spring-launch",
      "clicks": 1250,
      "qualifiedClicks": 1200,
      "conversions": 47,
      "revenue": 5234.50,
      "confidence": 87,
      "breakdown": {
        "source": [
          { "source": "email", "count": 800 },
          { "source": "social", "count": 400 }
        ],
        "country": [
          { "country": "US", "count": 900 },
          { "country": "GB", "count": 300 }
        ],
        "device": [
          { "device": "mobile", "count": 700 },
          { "device": "desktop", "count": 500 }
        ]
      },
      "lastSeenAt": "2026-02-25T12:34:56.000Z"
    }
  ]
}

When campaignId is omitted, the response includes an aggregate funnel across all campaigns plus individual funnels for up to 50 campaigns.

Screenshot-style reference for the monitor phase: chart trends, funnel counts, and confidence signals.

Campaign-level segment analytics

Query segment breakdowns scoped to a campaign:

GET /v2/handles/{handle}/analytics?groupBy=segment&campaignId=spring-launch

Returns clicks, conversions, and revenue per visitor segment for the specified campaign.

Personalization rules with campaigns

Personalization rules can target specific campaigns using the campaignIn condition:

{
  "ruleId": "spring-mobile-variant",
  "enabled": true,
  "priority": 100,
  "when": {
    "campaignIn": ["spring-launch"],
    "deviceIn": ["MOBILE"]
  },
  "variant": {
    "id": "mobile-optimized",
    "destinationUrl": "https://m.shop.example.com/spring"
  }
}

When a click arrives with a matching campaignId, the personalization engine evaluates the campaign condition alongside device, country, and source conditions.

UI path

  1. Open https://app.{PUBLIC_DOMAIN}.
  2. Navigate to your handle and open Campaigns.
  3. Create a new campaign with a goal type.
  4. Associate links to the campaign.
  5. Run the health check to verify readiness.
  6. Activate the campaign and share links.
  7. Monitor funnel metrics under Analytics.

Required auth

  • CREATOR-level JWT or above to create and manage campaigns.
  • CREATOR-level JWT or above to query campaign analytics.
  • PAT with analytics.read (or wildcard analytics.*) scope for automated funnel queries.
  • PAT with pages.read/pages.write for campaign site-structure automation.

API fallback

  • POST /v2/handles/{handle}/campaigns — Create campaign
  • GET /v2/handles/{handle}/campaigns — List campaigns
  • PUT /v2/handles/{handle}/site-structure/campaigns/{campaignId} — Upsert campaign detail structure
  • GET /v2/handles/{handle}/site-structure/campaigns/{campaignId} — Fetch campaign detail structure
  • POST /v2/handles/{handle}/site-structure/campaigns/{campaignId}/publish — Publish campaign detail structure page
  • GET /v2/handles/{handle}/campaigns/{campaignId}/health — Campaign health check
  • POST /v2/handles/{handle}/campaigns/{campaignId}/test-conversion — Test conversion
  • GET /v2/handles/{handle}/analytics?funnel=true&campaignId={id} — Funnel metrics
  • GET /v2/handles/{handle}/analytics?groupBy=segment&campaignId={id} — Segment breakdown

Common errors

CodeErrorCause
400invalid_campaign_idCampaign ID does not match required pattern
404campaign_not_foundCampaign does not exist
409campaign_conflictCampaign ID already exists

Related: