OpenAnalyst Product Docs
Create campaigns, associate links, track conversions through the funnel, and measure performance.
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
↑ ↓
└────────────────┘
- Prepare
- Launch + Verify
- Pause + Resume
| Status | Meaning |
|---|---|
DRAFT | Campaign created but not yet tracking. Default state. |
ACTIVE | Campaign is live and tracking clicks and conversions. |
PAUSED | Campaign is paused. Existing data preserved, no new tracking. |
Goal types
Each campaign has a goal type that sets default tracking behavior:
| Goal type | Default tracking preset | Default event type |
|---|---|---|
PRODUCT_SALE | ga4_purchase | purchase |
LEAD_CAPTURE | ga4_lead | lead |
NEWSLETTER | ga4_sign_up | newsletter_signup |
AFFILIATE_CLICKOUT | custom_webhook | affiliate_click |
APP_INSTALL | ga4_app_install | app_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 withFREE_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_getcampaign_structure_upsertcampaign_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:
- Click events are recorded and attributed to the campaign.
- Campaign rollups are updated in real-time (clicks, bot clicks, conversions, revenue).
- 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.
- Trend health
- Funnel quality
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
- Open
https://app.openanalyst.com. - Navigate to your handle and open Campaigns.
- Create a new campaign with a goal type.
- Associate links to the campaign.
- Run the health check to verify readiness.
- Activate the campaign and share links.
- Monitor funnel metrics under Analytics.
Required auth
- CREATOR-level
JWTor above to create and manage campaigns. - CREATOR-level
JWTor above to query campaign analytics. PATwithanalytics.read(or wildcardanalytics.*) scope for automated funnel queries.PATwithpages.read/pages.writefor campaign site-structure automation.
API fallback
POST /v2/handles/{handle}/campaigns— Create campaignGET /v2/handles/{handle}/campaigns— List campaignsPUT /v2/handles/{handle}/site-structure/campaigns/{campaignId}— Upsert campaign detail structureGET /v2/handles/{handle}/site-structure/campaigns/{campaignId}— Fetch campaign detail structurePOST /v2/handles/{handle}/site-structure/campaigns/{campaignId}/publish— Publish campaign detail structure pageGET /v2/handles/{handle}/campaigns/{campaignId}/health— Campaign health checkPOST /v2/handles/{handle}/campaigns/{campaignId}/test-conversion— Test conversionGET /v2/handles/{handle}/analytics?funnel=true&campaignId={id}— Funnel metricsGET /v2/handles/{handle}/analytics?groupBy=segment&campaignId={id}— Segment breakdown
Common errors
| Code | Error | Cause |
|---|---|---|
| 400 | invalid_campaign_id | Campaign ID does not match required pattern |
| 404 | campaign_not_found | Campaign does not exist |
| 409 | campaign_conflict | Campaign ID already exists |
Related: