Skip to Content
CampaignsCampaigns — Dashboard UI

Campaigns — Dashboard UI

Related: Workflow & Permissions | API Routes | Dashboard pages


Page Map

/campaigns → Campaigns Hub (list) /campaigns/new → Creation Wizard /campaigns/[id] → Campaign Detail /campaigns/[id]?tab=content → Content tab /campaigns/[id]?tab=audience → Audience tab /campaigns/[id]?tab=performance → Performance tab /campaigns/[id]?tab=keywords → Keywords tab (Google Ads only) /campaigns/[id]?tab=ads → Ads tab (Meta Ads + LinkedIn Ads) /campaigns/[id]?tab=optimizations → Optimizations tab (paid_ads, seo_outreach, review_generation) /campaigns/[id]?tab=sequence → Sequence tab (email/review only) /campaigns/[id]?tab=settings → Settings tab /campaigns/analytics → Cross-campaign Analytics

1. Campaigns Hub (/campaigns)

The entry point for the Campaigns section.

Layout:

  • Quick stats header (4 cards):

    • Active campaigns (count)
    • Total ad spend (paid_ads campaigns, current month)
    • Avg email open rate (email_marketing campaigns)
    • Top performing campaign (by primary metric)
  • Filter bar: type, channel, status, goal, date range, linked deliverable period

  • Campaign list: Cards or table rows, each showing:

    • Type icon + channel badges
    • Campaign name + goal label
    • Date range
    • Status badge (colour-coded to workflow stage)
    • Primary metric for the type (CTR for paid ads, open rate for email, engagement rate for social)
    • Quick-action: “View” / “Continue setup”
  • “New Campaign” button — opens the creation wizard

  • “Import from Platform” button — opens the import flow (see below)

Import from Platform flow

Triggered when the DM team has campaigns already running on Google Ads / Meta Ads / LinkedIn Ads and wants to bring them into Leadmetrics.

  1. Select connected channel (dropdown listing connected ad accounts, e.g. “Google Ads — Acme Corp”)
  2. Leadmetrics calls GET /campaigns/import?channel=google_ads&connectedChannelId=... and shows the list of campaigns from the platform
  3. Each row: campaign name, platform status (enabled / paused), budget, date range, “Already imported” badge if applicable
  4. DM selects one or more campaigns and clicks “Import Selected”
  5. Calls POST /campaigns/import — creates Campaign + CampaignExternalMapping records and triggers initial metrics sync
  6. Imported campaigns appear in the hub list immediately with source: imported badge

2. Campaign Creation Wizard (/campaigns/new)

A multi-step wizard. State is persisted so the user can navigate back between steps.

Step 1 — Type & Goal

  • Select campaign type (radio cards with icon and description for each of the 5 types)
  • Select goal (radio cards: awareness, traffic, leads, sales, retention, reviews)
  • Select channels (multi-select checkboxes, filtered to channels connected for the tenant)
  • For paid_ads type: show a secondary option — “Link to existing platform campaign” — which lets the DM enter or look up the externalCampaignId after creation (via POST /:id/link-external)

Step 2 — Details

  • Campaign name
  • Budget (optional; shown for paid_ads, hidden for seo_outreach)
  • Currency selector (shown when budget is entered)
  • Start date / end date (date range picker)
  • Link to Deliverable Period (optional dropdown — “Standalone” or select from active periods)

Step 3 — Campaign Brief

  • “Generate Brief” button → calls POST /:id/generate-brief
  • Loading state while campaign-brief-writer runs
  • Editable rich-text output displaying:
    • Objectives + KPI targets
    • Messaging pillars
    • Audience breakdown
    • Recommended formats per channel
    • Budget allocation (if budget provided)
  • DM can edit before proceeding

Step 4 — Audience

  • “Generate Audience Suggestions” button → calls POST /:id/generate-audience
  • Displays AI-suggested segments as cards (name, rationale, estimated size, recommended budget split)
  • DM can accept, reject, or manually add segments
  • Platform audience sync status per segment (if platformAudienceId is set)

Step 5 — Content

  • List of content pieces to generate for this campaign (based on type + channels):
    • e.g. for paid_ads on Google: “Generate RSA Ad Copy” → triggers google-ads-writer
    • e.g. for email_marketing: “Generate Email Sequence” → triggers email-writer
  • Each item shows: deliverable type, agent to run, status (not started / queued / done)
  • DM can trigger each piece independently or “Generate All”
  • Can also link existing Activities from the deliverables plan

Step 6 — Review & Launch

  • Summary of all setup: type, goal, channels, brief excerpt, audience count, content count
  • Status timeline widget (current: draft)
  • “Submit for DM Review” button → transitions to dm_review
  • Option: “Send for Client Approval” (skips internal review, transitions directly to client_review) — admin-only

3. Campaign Detail Page (/campaigns/[id])

Tabbed layout. Tabs visible to DM team. Client reviewer sees a restricted view (see below).

Overview Tab

  • Status timeline (horizontal stepper showing current stage in the lifecycle)
  • Campaign brief (collapsible)
  • Goal progress widget (target KPI vs current metric)
  • Quick stats: impressions, clicks, conversions, spend (last 7 days vs previous period)
  • Recent AI insights callout (latest recommendation from ads-analyst or meta-ads-insights)

Content Tab

  • List of all Activity records where Activity.campaignId === id
  • Columns: type, status, created date, agent used, quick preview of output
  • For each item: “Edit”, “Approve”, “Regenerate” actions
  • “Add Content” button → triggers new activity creation (calls POST /:id/content)
  • Filter by status (pending / awaiting_approval / approved / done)

Audience Tab

  • Segment cards: name, type badge, estimated size, filters summary, platform sync status
  • “Sync to Platform” button per segment (pushes to Google / Meta audience manager via connected channel)
  • “Generate Audience Suggestions” button (re-runs audience-analyst)
  • “Add Segment” manual form

Performance Tab

  • Date range picker (last 7 / 30 / 90 days, custom)
  • Channel selector (if campaign spans multiple channels, each shown separately)
  • Sync status bar: shows CampaignExternalMapping.lastSyncedAt per platform + “Sync Now” button (calls POST /:id/metrics/sync). If no mapping exists, shows a “Link to platform campaign” prompt instead of charts.
  • Line charts: impressions, clicks, conversions over time (sourced from CampaignMetrics structured rows)
  • Cost metrics (paid ads): spend, CPC, ROAS
  • Email metrics: open rate, CTR, unsubscribes per sequence step
  • Social metrics: reach, engagement rate
  • AI Insights panel (right sidebar or collapsible section):
    • Latest recommendations from insights workers
    • Each recommendation: description, suggested action, confidence level
    • “Apply” button → queues the optimisation for double-approval workflow

For seo_outreach campaigns, the Performance tab additionally shows:

  • Backlink health summary: live count, dead count, nofollow count — colour-coded status bar
  • Backlink table: domain, URL, DA score, status badge, anchor text, acquired date, last checked date — with a “Re-check” button per row that triggers a fresh HTTP health check
  • Outreach funnel per sequence step: sent → opened → clicked — bar chart showing drop-off
  • Reply rate tracker (manual entry or email provider webhook): prospects contacted → replied → agreed to publish → live

For review_generation campaigns, the Performance tab additionally shows:

  • Review velocity chart: ReviewMetrics.newReviewCount week-over-week per platform — line chart
  • Rating trend: average star rating over time per platform
  • Platform distribution: donut chart showing review count split across Google, Trustpilot, G2, etc.
  • Drip funnel: enrolled contacts → step 1 sent → step 2 sent → review link clicked — showing conversion drop-off per step
  • Negative theme alerts: if ReviewMetrics.keyThemes contains flagged negative themes, shown as a warning banner with the extracted theme text

Keywords Tab (Google Ads paid_ads campaigns only)

Shown only when CampaignExternalMapping.platform === "google_ads" exists for the campaign.

Three sub-views via segmented control:

Keywords

  • Table: keyword text, match type badge (Broad / Phrase / Exact), status, bid (editable inline), quality score (colour-coded 1–10), impressions, clicks, CTR, avg CPC, conversions
  • Filter by: ad group, status, match type
  • Inline bid edit: click a bid cell, enter new value, saves on blur → calls PATCH /:id/keywords/:keywordId
  • Inline status toggle: pause / enable per keyword
  • “Sync Keywords” button → calls POST /:id/keywords/sync
  • Ad group selector dropdown (filters the table to a specific ad group)

Search Terms

  • Table: search term, match type, impressions, clicks, spend, conversions, CTR, avg CPC, classification badge (colour-coded: green = add as keyword, red = negative, amber = watch, grey = irrelevant, white = unclassified)
  • Filter by: classification, date range, ad group
  • “Sync Search Terms” button with date range picker → calls POST /:id/search-terms/sync
  • “Classify with AI” button → calls POST /:id/search-terms/classify — shown when unclassified terms exist
  • Per-row: DM can click the classification badge to override → dropdown to select decision → calls PATCH /:id/search-terms/:id/classification
  • Bulk selection: select multiple terms → “Mark as Negative” / “Add as Keyword” bulk action
  • “Push Negatives to Google Ads” button (sticky bottom bar, appears when dm_reviewed negative terms exist) → match type selector → calls POST /:id/search-terms/push-negatives

Negative Keywords

  • Table: keyword, match type, level (Campaign / Ad Group), source badge (manual or from search terms), status, date added
  • ”+ Add Negative Keyword” button → inline form (keyword text, match type, campaign/ad group level) → calls POST /:id/negative-keywords
  • Per-row delete icon → confirmation modal → calls DELETE /:id/negative-keywords/:id
  • “Sync from Google Ads” button → calls POST /:id/keywords/sync (also syncs negatives)

Ads Tab (Meta Ads and/or LinkedIn Ads paid_ads campaigns only)

Shown when a CampaignExternalMapping with platform === "meta_ads" or "linkedin_ads" exists for the campaign. If both platforms are linked, a platform switcher (tab or dropdown) toggles between Meta view and LinkedIn view.

Meta Ads View

  • Sync status barMetaAdSet.lastSyncedAt + “Sync Ads” button → calls POST /:id/metrics/sync?scope=ads
  • Ad Sets panel (top section):
    • Table of MetaAdSet records: name, status badge, daily budget, reach, frequency, CTR, ROAS
    • Frequency shown with colour coding: green < 3.0, amber 3–5, red > 5 (cold audience thresholds)
    • Inline: expand an ad set row to see placement breakdown and targeting summary
    • “Pause” / “Resume” toggle per ad set (calls PATCH /:id/optimizations/:id/apply after DM approval flow)
  • Ads grid (bottom section, filters by selected ad set):
    • Card grid view: creativePreviewUrl thumbnail, ad name, format badge, status badge
    • Per card footer: impressions, CTR, ROAS, frequency
    • Fatigue flag banner on fatigued cards (red border + “Refresh Creative” button)
    • “Refresh Creative” → enqueues meta-ads-writer and creates a creative_refresh CampaignOptimizationRecommendation
    • Click a card to see full metrics breakdown + headline copy

LinkedIn Ads View

  • Sync status barLinkedInAd.lastSyncedAt + “Sync Ads” button
  • Ads table:
    • Columns: creative name, format badge, status, impressions, clicks, CTR, CPC, conversions, frequency, Lead Gen Form completions (if applicable)
    • Frequency colour-coded: green < 2.0, amber 2–3, red > 3 (B2B audience threshold)
    • Fatigue flag icon (⚠) inline on rows where fatigueFlag = true
    • Row action: “Refresh Creative” (creates creative_refresh recommendation)
  • Demographic Breakdown panel (collapsible, below the table):
    • Dimension selector: Job Function | Seniority | Industry | Company Size | Job Title | Company
    • Bar chart showing CTR and conversion rate per dimension value, sorted descending
    • Top-performing segments highlighted green; lowest-performing highlighted amber
    • “Tighten Audience” button next to top-performing segment → creates an audience_tighten CampaignOptimizationRecommendation with the selected segment as context
    • Sync date shown; “Sync Demographics” button calls the demographic breakdown endpoint

Optimizations Tab (paid_ads, seo_outreach, and review_generation campaigns)

Shown for paid_ads, seo_outreach, and review_generation campaigns. This is the HITL hub for the weekly automated optimization scan and any manually triggered recommendations.

Layout:

  • Platform filter (all / Meta Ads / LinkedIn Ads / Google Ads)
  • Status filter (pending / dm_reviewing / client_review / applied / skipped)
  • “Run Optimization Scan” button → calls POST /:id/optimizations/trigger — triggers a fresh threshold check and enqueues optimizer workers

Recommendation cards (ordered by priority: high → medium → low):

Each card shows:

  • Priority badge (🔴 High / 🟡 Medium / ⚪ Low)
  • Platform badge (Meta Ads / LinkedIn Ads)
  • Recommendation type label (e.g. “Creative Refresh”, “Budget Shift”, “Audience Tighten”)
  • Title (AI-generated, e.g. “Refresh fatigued ad — Summer Promo V1”)
  • Rationale (AI explanation, expandable)
  • Estimated impact (e.g. “~15% CTR recovery expected”)
  • Suggested action summary (e.g. “Pause ad ID 123456 and request new creative variant”)
  • Status badge
  • Created date

Actions per card (role-gated):

StatusDM actionsClient actions
pending”Approve” → dm_approved | “Skip” → skipped
dm_approved (client approval needed)View only”Approve” → client_approved | “Reject” → dm_reviewing
dm_approved (DM can apply directly)“Apply Now” → applied
client_approved”Push to Platform” → appliedView only
appliedView only (shows applied date)View only
skipped”Reopen” → pending
  • “Approve” / “Skip” open a confirmation drawer with optional note field
  • For creative_refresh type: the card also links to the draft creative Activity generated by the writer worker — DM can review and edit the new ad copy before approving

Sequence Tab (email_marketing + review_generation only)

  • List of sequences for this campaign
  • Each sequence: name, trigger type, status, step count
  • Expand a sequence to see step list:
    • Step order, delay, subject, body preview
    • Per-step metrics: sent count, open rate, click rate
    • “Edit Step” inline
    • “Pause / Resume” step
  • “Create Sequence” button (for email campaigns)
  • “Generate Review Drip” button (for review_generation campaigns — calls POST /:id/review-sequence)

Settings Tab

  • Campaign name (editable)
  • Budget + currency (editable)
  • Start / end dates
  • Connected channels (shows which tenant channels are linked)
  • Deliverable period link (dropdown to change or unlink)
  • Auto-pilot toggle (paid_ads only; shows confirmation modal explaining double-approval requirement)
  • Danger zone: “Archive Campaign”

4. Cross-Campaign Analytics (/campaigns/analytics)

Aggregate view across all campaigns.

  • Summary cards: total campaigns, total spend, total leads generated, avg ROAS
  • Campaign comparison table: sortable by any metric column
  • Channel breakdown chart: spend / conversions grouped by channel
  • Funnel view: impressions → clicks → leads → conversions (stacked bar or sankey)
  • Time series: compare multiple campaigns on the same chart
  • Date range filter + campaign type filter

5. Client Approval View

When the campaign status === "client_review", client users (role: reviewer) see a read-only campaign review page:

  • Campaign name, type, goal, channels, date range
  • Budget (if applicable)
  • Campaign brief (full text)
  • Content list (previews of ad copy, emails, social posts — read-only)
  • Audience segments (name + estimated size only — no filter detail)
  • “Approve” button → calls POST /:id/approve with { approved: true }
  • “Request Changes” button → calls POST /:id/approve with { approved: false, note } — opens a text field for feedback before submitting

This reuses the same approval pattern as blog and social post client reviews.


Files to Create

FilePurpose
apps/dashboard/src/app/(dashboard)/campaigns/page.tsxCampaigns Hub
apps/dashboard/src/app/(dashboard)/campaigns/new/page.tsxCreation Wizard
apps/dashboard/src/app/(dashboard)/campaigns/[id]/page.tsxCampaign Detail (tabbed)
apps/dashboard/src/app/(dashboard)/campaigns/analytics/page.tsxCross-campaign Analytics

© 2026 Leadmetrics — Internal use only