Campaign Studio — Improvement & Growth Plan
Package: capell-app/campaign-studio · Kind: package · Tier: premium · Product group: Capell Growth · Bundle: growth · Status: Complete
1. Snapshot
Section titled “1. Snapshot”Campaign Studio is a schema-owning growth package (surfaces admin + frontend) that adds campaign groups, landing-page variants, UTM attribution, CTA/hero/lead-form widgets, conversion goals, and funnel/overview reporting on top of Capell. It owns five tables (campaign_groups, campaign_landing_pages, campaign_cta_widgets, campaign_conversion_goals, campaign_conversions) and five models, drives four Filament resources plus three dashboard contributions, and exposes 19 Actions (recording, attribution, variant resolution, URL building, stats, experiment sync/results, public conversion capture, tracker script loading). It hard-requires admin, core, form-builder, frontend, insights, layout-builder and softly supports experiments + seo-suite/site-discovery. Conversion capture flows through the FormBuilder FormSubmitted listener (src/Listeners/RecordFormSubmissionConversion.php) plus the public Campaign Studio beacon for CTA-click and page-view goals.
Marketplace and Composer copy now use buyer-facing campaign/outcome positioning. Screenshots in capell.json marketplace block now include the extension card plus six committed product screenshots for campaign groups, landing-page variants, conversion goals, CTA widgets, dashboard widgets, and the frontend landing page.
Completed Improvement Slices
Section titled “Completed Improvement Slices”- 2026-06-03: Rewrote marketplace/Composer copy, promoted real product screenshots into the manifest, removed the dead
AttributionModelenum, and hardened the overview conversion-rate join against blankutm_campaignvalues. - 2026-06-04: Added UTM fields to the campaign hero widget configurator and routed hero primary/secondary button URLs through
BuildCampaignUrlAction, with render coverage proving decorated public URLs do not leak numeric campaign identifiers. - 2026-06-04: Added the public campaign conversion beacon, post-load tracker script, typed capture Action/Data boundary, full-page public-output safety tests, and frontend cache contribution metadata proving Campaign Studio output is non-cacheable and varies by UTM targeting dimensions.
- 2026-06-04: Filtered landing-page variant resolution to linked Capell pages that pass the public
publishedDate()scope, with Action tests proving expired or scheduled pages are skipped for targeted, primary, and fallback selection. - 2026-06-04: Closed the remaining Now reporting/attribution rows by counting distinct Insights visits for duplicate campaign UTMs, adding a configurable conversion attribution lookback window, and exposing typed Campaign Studio experiment result readouts with per-variant conversion rates and lift.
- 2026-06-06: Added
SyncCampaignStatusesAction, thecapell:campaign-studio-sync-statusescommand, and an every-five-minutes package schedule so campaign windows transitionScheduledtoActiveandActivetoEnded. - 2026-06-08: Connected campaign page-view and CTA-click goals into Insights conversion events through
RecordConversionAction, preserving campaign, goal, URL, value, and source-package metadata while retaining the existing Campaign Studio dedupe policy.
2. Improvements (existing functionality)
Section titled “2. Improvements (existing functionality)”- Shipped 2026-06-04: Wire CTA-click conversions to a real capture path.
POST /capell/campaigns/conversionsnow accepts same-origin page-view and CTA-click beacon posts, resolves Insights visits, landing pages, CTA widgets, and conversion goals throughCaptureCampaignConversionAction, and records conversions through the existing campaign conversion Actions. — restores advertised capability —src/Actions/CaptureCampaignConversionAction.php,src/Http/Controllers/CampaignConversionBeaconController.php,src/Support/RenderHooks/RegisterCampaignTrackerHook.php— L - Shipped 2026-06-03: Resolve or remove the
AttributionModelenum.AttributionModelwas removed after review confirmed it had no production consumers andBuildConversionAttributionActionrecords both first- and last-touch fields. — removes misleading API + clarifies attribution semantics —src/Actions/BuildConversionAttributionAction.php— M - Shipped 2026-06-04: Make
BuildCampaignOverviewStatsActionconversion-rate join robust. The overview visit denominator now excludes null/blank campaign UTMs and counts distinct Insights visit ids, so duplicate campaign groups sharing autm_campaignno longer double-count the same visit in the headline conversion-rate KPI. — correctness of a headline KPI —src/Actions/BuildCampaignOverviewStatsAction.php— M - Shipped 2026-06-04: Variant resolution ignores active/published state of the target page.
ResolveCampaignLandingPageVariantActionnow filters all targeted, primary, and first-available candidates through the linked page’s publicpublishedDate()scope, so scheduled or expired pages are skipped instead of being selected as campaign variants. — prevents serving unpublished content —src/Actions/ResolveCampaignLandingPageVariantAction.php— M - Eager-load to avoid N+1 in funnel + landing-page queries.
BuildCampaignConversionFunnelActionis clean (withCount), butCampaignLandingPagePublicUrlContributor::publicUrls()loads all landing pages with nestedpage.pageUrls.*and thenunique()s in PHP — fine for sitemaps but unbounded as campaigns grow. Add chunking/pagination for large sites. — sitemap-build scalability —src/Support/PublicUrls/CampaignLandingPagePublicUrlContributor.php— S - Shipped 2026-06-04: Hero button URLs bypass
BuildCampaignUrlAction. Hero primary/secondary CTAs now use configured widget UTM metadata andBuildCampaignUrlActionto append missing UTM parameters while preserving existing query strings and fragments. The current lead-form widget has no button URL; its capture path remains Form Builder submission attribution. — consistent attribution across hero and CTA widget links —resources/views/components/widget/campaign-hero.blade.php— S - Shipped 2026-06-03: Surface the committed screenshots in the manifest. The marketplace manifest now references six committed product screenshots in addition to the extension card. — marketplace listing quality —
capell.json— S - Populate the changelog.
CHANGELOG.mdhas a single placeholder line (“Prepared package metadata…”). For a premium first-party package this should track schema/Action changes. — release hygiene / buyer trust —CHANGELOG.md— S
3. Missing Features (gaps)
Section titled “3. Missing Features (gaps)”Mapped against declared capabilities[] (campaign-audience-targeting, campaign-conversion-funnel-reporting, landing-page-variant-experiments, campaign-experiment-sync, …) and standard campaign-marketing norms.
- Shipped 2026-06-04: Client-side conversion capture (table stakes). Campaign Studio now injects a post-load tracker through the frontend
BodyEndrender hook and records page-view plus CTA-click conversions through the same-origin Campaign Studio beacon. — table stakes. - Audience targeting beyond UTM (differentiator vs gap).
AudienceTargetDataandResolveCampaignLandingPageVariantActiononly matchutm_content/utm_term. The capability is namedcampaign-audience-targeting, but there is no geo, device, referrer, returning-vs-new, or time-window targeting — despitecoredepending ontorann/geoip. Adding GeoIP/device rules (and feeding them into the Experiments audience rules already modelled inSyncCampaignExperimentAction) would be a real differentiator. - Shipped 2026-06-04: A/B test result readout in-package (table stakes for “variant-experiments”).
BuildCampaignExperimentResultsActionnow reads the synced campaign-scoped Experiments winner report back through typed Campaign Studio data, including per-variant conversion rates, winning variant key, and lift over the control variant. — table stakes. - Shipped 2026-06-06: Scheduling automation.
SyncCampaignStatusesActiontransitions campaign windows fromScheduledtoActiveoncestarts_atopens and fromActivetoEndedonceends_atcloses. The package registerscapell:campaign-studio-sync-statusesand schedules it every five minutes when installed. — table stakes for “campaign scheduling”. - Shipped 2026-06-08: Insights conversion loop. New campaign conversions now also create first-party Insights conversion events named
campaign.{campaign_slug}.{goal_key}when an Insights visit is present, so Campaign Studio funnels can be reconciled with the broader growth dashboard without adding a public tracking surface. — table stakes for the Growth bundle. - Multichannel / channel taxonomy. Attribution is UTM-only. There is no first-class channel model (email, paid-social, organic) or per-channel rollup in
BuildTopCampaignStudioWidget. Marketing buyers expect channel breakdowns. — differentiator. - Revenue / value attribution.
value_amountexists on goals andbudget_amounton groups, but no Action computes ROAS, cost-per-conversion, or revenue per campaign. The funnel only counts conversions. Surfacing value-weighted conversions would turn reporting from “counts” into “money”. — differentiator. - Shipped 2026-06-04: Configurable attribution lookback window.
RecordCampaignConversionActionnow honorscapell-campaign-studio.attribution.lookback_days(default 30) and drops stale Insights visit identity/UTM attribution outside the window before recording the conversion. — table stakes. - Anonymous/no-identity conversion dedup policy. Conversions with no visit/event/source still skip dedup (
hasIdentity()returns false → plaincreate). A future row should decide whether anonymous conversions need a bounded dedupe policy by goal, landing page, and time window without collapsing separate anonymous visitors into one conversion. — table stakes. - Public landing-page route ownership. The package contributes URLs to Site Discovery but renders through
core’scapell.pages.show. There is no campaign-native short URL / vanity slug (/go/{campaign}) that auto-applies UTMs and redirects — a common campaign-tool feature. — differentiator.
4. Issues / Risks
Section titled “4. Issues / Risks”- Shipped 2026-06-04: Cache-vs-personalization contradiction. Campaign Studio now records a non-cacheable frontend render contribution with UTM variance metadata whenever its tracker is injected, and docs clarify that conversion capture is post-load/cache-compatible while UTM-targeted variant selection remains dynamic frontend output. Tests assert the tracker contribution is non-cacheable and carries
utm_campaign,utm_content, andutm_term. —capell.json(performance block),src/Support/RenderHooks/RegisterCampaignTrackerHook.php— High. - Shipped 2026-06-03: Dead enum shipped in a premium API.
AttributionModelwas removed after review confirmed it had no production consumers andBuildConversionAttributionActionalways records both first- and last-touch fields. — Medium. - Shipped 2026-06-04: CTA/page-view Actions are untested in integration and unreachable in production. Feature tests now cover route registration, page-view capture, CTA-click capture, invalid-origin rejection, and deduping through Insights visit identity/source context. — Medium.
- Shipped 2026-06-04: No frontend render/feature test. Feature coverage now renders a full public campaign page fragment with widget output plus the tracker hook and asserts no authoring markers, model fields, numeric campaign id attributes, or signed editor URLs leak. — Medium.
- Public-output safety: currently OK, keep it that way.
tracking/attributes.blade.phpandcampaign-cta-widget.blade.phpexpose onlycampaignGroup->slugand goal/ctakey— no numeric IDs, field paths, or model names — and a test guards this. The hero/lead-form widgets renderdata-campaign-goalfromgetMeta('goal_key')(admin-authored string), which is acceptable. Risk is regression if a future change emits IDs; lock with a render-level (not just component-level) assertion. —resources/views/components/**— Low (but easy to regress). SyncCampaignExperimentActionusesforceFill(...)->save()and direct relation writes. It bypasses the Experiments package’s own create Action on the update path (only the create path callsCreateExperimentAction). If Experiments adds validation/events to variant/goal writes, this drifts. Cross-package write coupling is a maintenance risk. —src/Actions/SyncCampaignExperimentAction.phpL48-65, L199-250 — Medium.- Shipped 2026-06-04:
utm_campaignjoin double-counted duplicate campaigns. Multiple campaign groups can still share autm_campaign(onlyslugis unique), but the overview/visit join now counts distinct Insights visits so duplicate groups do not inflate the denominator. Shared UTM values remain analytically ambiguous and should be avoided for precise campaign attribution. —src/Actions/BuildCampaignOverviewStatsAction.php— Medium. - i18n completeness. Enum labels and Filament strings are translated via
__()(good). Verify all five lang files (form,generic,navigation,package,widgets) carry every key the code references (e.g.generic.landing_page_variant,widgets.active_campaign-studio); the oddactive_campaign-studioarray key (hyphen in an array key/translation slug) is fragile. —resources/lang/en/*,src/Actions/BuildCampaignOverviewStatsAction.php— Low. - Performance budget unverified.
adminQueryBudget: 40andfrontendRenderBudgetMs: 20are declared but no test or benchmark asserts them; the CTA hydrate batch (CampaignCtaWidget::hydrateWidgets) is well-designed for it, but unmeasured. —capell.json— Low.
5. Marketplace & Selling
Section titled “5. Marketplace & Selling”The manifest and Composer description now use this buyer-facing one-sentence summary:
Launch, target, and measure marketing campaigns inside Capell — build landing-page variants, drop in CTA and lead-capture widgets, and track UTM-attributed conversions and funnels without bolting on a separate analytics tool.
The package should continue toward this fuller buyer-facing product story as the remaining conversion-capture gaps land:
Campaign Studio turns Capell into a campaign command centre for marketing and growth teams. Group your landing pages, CTAs, and lead forms under a campaign, target visitors with UTM-driven page variants, and let conversions flow in automatically from form submissions and on-page goals. Built-in funnel and overview reporting show which campaigns and pages actually convert — and how that rate trends week over week — without exporting to a third-party tool. When the Experiments add-on is installed, your landing-page variants and conversion goals sync straight into a running A/B test.
Screenshot / media gaps. Manifest now exposes the extension card plus six real product screenshots. Missing entirely: a hero showing the funnel/overview stats, and an animated GIF of variant selection or the experiment sync. Dark captures exist in docs/screenshots/ but are not yet promoted into marketplace media; decide whether to add them or keep the listing focused on the light captures.
Pricing / tier / bundle positioning. Premium tier in the growth bundle is right — this is a paid, first-party, priority-support package. It is the natural anchor of the Capell Growth bundle: it hard-requires insights (analytics), form-builder (lead capture), and layout-builder (widgets), so selling Campaign Studio pulls those in. Cross-sell levers: (1) experiments add-on as an upsell unlocked by the existing SyncCampaignExperimentAction; (2) seo-suite / site-discovery for sitemap + AI-discovery of landing pages (already wired via CampaignLandingPagePublicUrlContributor); (3) bundle with a future “Automation Studio” that listens to the already-dispatched CampaignConverted event. Position as the Extension Suite centrepiece: “Campaign Studio + Experiments + SEO Suite = the Capell Growth Suite.”
Differentiators / value props / target buyer. Target buyer: the in-house marketer or agency running campaigns on a Capell-built site who today stitches together GA + a form tool + spreadsheets. Value props: campaigns, variants, widgets, and conversion reporting native to the CMS (no tag-manager glue); UTM attribution captured server-side and deduped; one-click sync to real A/B experiments; landing pages that automatically enter the sitemap and AI-discovery feeds. Differentiator to lean into: closed-loop — the same campaign that builds the page also reports its conversions and feeds the experiment.
Keywords / tags (8–12): campaign management, landing pages, conversion tracking, UTM attribution, A/B testing, lead capture, marketing CMS, CTA widgets, conversion funnel, growth marketing, audience targeting, Filament.
Completion Review
Section titled “Completion Review”Completed 2026-06-08. The current manifest-backed plan is closed: Campaign Studio ships campaign/landing-page/goal admin surfaces, safe UTM-decorated widgets, a public beacon for page-view and CTA-click conversions, scheduled campaign status automation, experiment result readouts, public-output/cache-safety tests, and a first-party Insights conversion bridge. Revenue/ROAS, deeper audience targeting, anonymous dedupe policy, campaign vanity URLs, and looser Experiments write coupling remain future product-depth candidates rather than active completion blockers.
6. Prioritized Roadmap
Section titled “6. Prioritized Roadmap”| Item | Bucket | Effort | Impact | Section ref |
|---|---|---|---|---|
| Shipped 2026-06-04: Wire CTA-click + page-view conversion capture (beacon) | Done | L | High | §2, §3 |
| Shipped 2026-06-04: Add frontend render/feature tests proving widgets render + no ID/marker leak in full page | Done | M | High | §4 |
| Shipped 2026-06-04: Resolve the cacheable=false vs static-HTML-cache personalization contradiction (tracker contribution + doc) | Done | M | High | §4 |
| Shipped 2026-06-04: Filter variant resolution to published pages | Done | M | Medium | §2 |
Shipped 2026-06-04: Harden overview conversion-rate join (null/duplicate utm_campaign) | Done | M | Medium | §2, §4 |
| Shipped 2026-06-06: Add campaign scheduling command (Scheduled→Active→Ended transitions) | Done | M | Medium | §3 |
| Shipped 2026-06-04: In-package A/B variant results readout (lift per variant) | Done | L | High | §3 |
| Shipped 2026-06-08: Feed Campaign Studio conversions into Insights conversion events | Done | M | High | §3, §5 |
Revenue/ROAS reporting using existing value_amount + budget_amount | Future | M | High | §3 |
Geo/device/referrer audience targeting (use torann/geoip) | Future | L | High | §3 |
| Shipped 2026-06-04: Configurable attribution lookback window | Done | M | Medium | §3, §4 |
| Anonymous/no-identity conversion dedup policy | Future | M | Medium | §3, §4 |
Decouple SyncCampaignExperimentAction update path from direct relation writes | Future | M | Low | §4 |
| Populate CHANGELOG + benchmark perf budgets (20ms render / 40 query) | Future | S | Low | §2, §4 |