Skip to content

feat: api-first Plus landing experiment (featurePlusApiLanding)#5888

Merged
nimrodkra merged 8 commits intomainfrom
feat/plus-api-landing-experiment
Apr 21, 2026
Merged

feat: api-first Plus landing experiment (featurePlusApiLanding)#5888
nimrodkra merged 8 commits intomainfrom
feat/plus-api-landing-experiment

Conversation

@nimrodkra
Copy link
Copy Markdown
Member

@nimrodkra nimrodkra commented Apr 20, 2026

Summary

New A/B experiment targeting developers who clicked "Get API Access" but dropped off on a generic /plus page. When featurePlusApiLanding is enabled, the Plus page is reframed around the public API:

  • Hero + feature list lead with API access, integrations, and developer use cases
  • New PlusApiShowcase block with three API use cases (coding agents, internal tools, personal automations)
  • FAQ gains four API-specific entries at the top, gated on the flag so the control arm stays untouched
  • All Plus CTAs (UpgradeToPlus, PlusMobileEntryBanner, PlusGrid, CustomFeedEmptyScreen, PlusUserBadge, tablet sidebar, main sidebar) swap from avocado green to Plus pink (text-action-plus-default / ButtonColor.Bacon) when the flag is on. Themed for light and dark.
  • Migrates CTA copy read sites off the legacy featurePlusCtaCopy onto the new flag so both scopes (CTA copy + /plus content) share one flag
  • Plus public API docs URL moved from inline string to lib/constants.ts (plusPublicApiDocs)

featurePlusApiLanding is a boolean flag (default false), evaluated via useConditionalFeature with shouldEvaluate: !isPlus across all consumers.

Control behavior is fully preserved.

Test plan

  • Flag off: /plus renders existing hero, features, FAQ, and green CTAs
  • Flag on: hero, features, showcase block, and extended FAQ render; CTAs (sidebar, tablet sidebar, mobile banner, feed grid card, UpgradeToPlus, CustomFeedEmptyScreen, PlusUserBadge) show in Plus pink on both light and dark themes
  • "Public API access" feature row still renders correctly (bold, pink icon)
  • Quick pass on mobile + tablet viewports

Made with Cursor

Preview domain

https://feat-plus-api-landing-experiment.preview.app.daily.dev

Adds a new A/B experiment gated by `featurePlusApiLanding` (control | api)
targeting developers who clicked "Get API Access" but bounced on a generic
/plus page. The api variant reframes the Plus page around the public API:

- Hero + feature list emphasize API access, integrations, and dev use cases
- New PlusApiShowcase block with 3 API use cases (coding agents, internal
  tools, personal automations)
- Plus FAQ reordered with API-specific entries at the top
- All Plus CTAs (UpgradeToPlus, PlusMobileEntryBanner, PlusGrid, tablet and
  main sidebars) switch from avocado green to Plus pink (bacon) when the
  variant is api, using `text-action-plus-default` + ButtonColor.Bacon
- Migrates read sites from the legacy `featurePlusCtaCopy` flag to
  `featurePlusApiLanding` so both scope (CTA copy + /plus content) share
  one flag

Made-with: Cursor
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 20, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
daily-webapp Ready Ready Preview Apr 20, 2026 6:44pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
storybook Ignored Ignored Apr 20, 2026 6:44pm

Request Review

@nimrodkra
Copy link
Copy Markdown
Member Author

@claude please review this pr

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 20, 2026

Claude finished @nimrodkra's task in 3m 53s —— View job


PR Review: feat: api-first Plus landing experiment (featurePlusApiLanding)

  • Gathering context and reading changed files
  • Reviewing feature flag and experiment setup
  • Reviewing new PlusApiShowcase component
  • Reviewing CTA color theming changes
  • Reviewing Plus page content changes (PlusInfo, PlusList)
  • Reviewing sidebar changes
  • Final review summary

Overview

Good experiment setup overall — clean feature flag, well-structured showcase component, and the CTA theming changes are consistent across all 5 touchpoints. There are a few issues worth fixing before shipping, one of which is a bug that affects the control variant.


🚨 Bug: API FAQ items appear in the control variant too

File: packages/shared/src/components/plus/common.tsx

plusFAQItems is a shared static array consumed directly by PlusFAQ:

// PlusFAQ.tsx
{plusFAQItems.map((item) => (...))}

The new API-specific questions ("What can I build with the API?", "What endpoints does the API have?", "How does authentication work?", "Are there usage limits?") are prepended to this shared array unconditionally. Both the control and api variants will show these questions. This breaks the A/B experiment's control arm.

Fix: create variant-specific FAQ arrays and pass them as a prop, or filter in PlusFAQ based on the feature flag.

// Option A — separate arrays
export const plusFAQItemsControl: FAQItem[] = [...];
export const plusFAQItemsApi: FAQItem[] = [...apiItems, ...plusFAQItemsControl];

// PlusFAQ.tsx accepts items prop, or reads the flag itself

Fix this →


⚠️ "OpenClaw" is not a real product

File: packages/shared/src/components/plus/PlusApiShowcase.tsx, line 25

body: `...Pre-built integrations for Claude Code, Cursor, Codex, and OpenClaw.`,

"OpenClaw" doesn't exist. This is likely an AI hallucination. The mention of "Codex" may also be outdated (OpenAI Codex was deprecated). Verify the actual supported integrations and remove or replace this.

Fix this →


⚠️ Hardcoded API docs URL

File: packages/shared/src/components/plus/PlusApiShowcase.tsx, line 95

href="https://docs.daily.dev/docs/plus/public-api"

This URL is hardcoded directly in the component instead of using a constant from lib/constants. If the docs URL ever changes, it'll need to be tracked down manually. Move it to lib/constants.ts.


⚠️ useFeature used directly in PlusInfo — inconsistent with the established pattern

File: packages/shared/src/components/plus/PlusInfo.tsx, line 157

const apiLandingVariant = useFeature(featurePlusApiLanding);

The CLAUDE.md guidelines (and every other component in this PR) use useConditionalFeature with shouldEvaluate to avoid unnecessary GrowthBook evaluations. PlusInfo is only shown to non-Plus users, but the pattern should be consistent:

const { value: apiLandingVariant } = useConditionalFeature({
  feature: featurePlusApiLanding,
  shouldEvaluate: !isPlus, // or whatever the appropriate condition is
});

⚠️ CTA copy strings duplicated across 5+ components

The strings 'Get API Access' / 'Level Up with Plus' / 'Upgrade' and the isApiVariant = apiLandingVariant === 'api' pattern are repeated in:

  • UpgradeToPlus.tsx
  • SidebarTablet.tsx
  • MainSection.tsx
  • CustomFeedEmptyScreen.tsx
  • PlusUserBadge.tsx

This makes copy changes fragile. Consider extracting a small shared hook:

// hooks/usePlusApiLanding.ts
export const usePlusApiLanding = (shouldEvaluate = true) => {
  const { value } = useConditionalFeature({ feature: featurePlusApiLanding, shouldEvaluate });
  return { isApiVariant: value === 'api' };
};

Or at minimum, export the copy constants from one place.


✅ Good things worth noting

  • reframeControlItem fails fast (throw new Error(...)) when an ID isn't found — matches the codebase's invariant philosophy.
  • giftToUser && giftOneYear null-guard in PlusInfo.tsx is a real correctness fix.
  • productOptions ?? [] and openCheckout?.() defensive guards in PlusDesktop / PlusMobile are clean.
  • PlusApiShowcase accessibilityuseId() + aria-labelledby on the <section> is correct.
  • MainSection useMemo dep fix — switching from ctaCopy object reference to ctaCopy.full, isApiVariant is more precise.
  • ref typed correctly as useRef<HTMLDivElement>(null) in PlusDesktop.

Summary

The experiment structure is solid. The one blocking bug is the shared plusFAQItems array being modified unconditionally — the control /plus page will render API-specific FAQ items. The "OpenClaw" copy issue is a user-facing problem that should also be fixed before this ships to any traffic. The duplication concerns are lower priority but worth a follow-up.

- Shorten labels in `plusFeatureListApiFirst` now that the page context
  makes "via API" redundant
- Apply Prettier formatting to `PlusInfo` and `PlusList`
- Guard `squads?.length` and `user` access in `SidebarTablet` to pass the
  strict-changed typecheck (pre-existing, surfaced by flag swap)

Made-with: Cursor
- Split plusFAQItems into control + api arrays so the new API FAQ items
  only render in the api variant (previously leaked into control via
  shared static array).
- PlusFAQ reads featurePlusApiLanding (gated on !isPlus) to pick the
  correct list.
- PlusInfo switches from useFeature to useConditionalFeature with
  shouldEvaluate: !isPlus, consistent with other CTA sites.
- Move the Plus public API docs URL to lib/constants.ts.

Made-with: Cursor
Comment thread packages/shared/src/lib/featureManagement.ts Outdated
Per review, flip the flag from a 'control' | 'api' string variant to a
plain boolean (default false). Rename local variables from
apiLandingVariant / isApiVariant to isApiLanding and drop the now
unnecessary === 'api' comparisons across all call sites.

Made-with: Cursor
Archived GrowthBook keys stay reserved, so the original plus_api_landing
key could not be reused for the refactored boolean flag.

Made-with: Cursor
@nimrodkra nimrodkra merged commit 1efced8 into main Apr 21, 2026
13 checks passed
@nimrodkra nimrodkra deleted the feat/plus-api-landing-experiment branch April 21, 2026 05:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants