smithery.ai

promo-banner

Set up promotional banners with optional countdown timers. Use when creating seasonal sales, limited-time offers, or marketing campaigns that need dismissible banners with localized copy and theme customization.

First seen Apr 14, 2026

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 4,951 B
  • docs SUMMARY.md 229 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

Promo banner setup

Configure a promotional banner through the shared banner registry. Existing placements already resolve and render the highest-priority active banner.

Configure the campaign

Set the active registry entry in apps/web/.env.local or the deployment environment:

# Required
NEXT_PUBLIC_PROMO_ENABLED=true
NEXT_PUBLIC_ACTIVE_PROMO_BANNER=winterSaleBanner

# Optional presentation
NEXT_PUBLIC_PROMO_THEME=pink
NEXT_PUBLIC_PROMO_COUNTDOWN_END_DATE=2026-01-31T23:59:59Z

# Only for Stripe metadata and bonus-credit campaigns
NEXT_PUBLIC_PROMO_ID=winter_sale_2026
NEXT_PUBLIC_PROMO_BONUS_STARTER=2000
NEXT_PUBLIC_PROMO_BONUS_STANDARD=7500
NEXT_PUBLIC_PROMO_BONUS_PRO=105000

Use NEXTPUBLICACTIVEPROMOBANNER for new banners. NEXTPUBLICPROMOTRANSLATIONS remains a legacy selection fallback. NEXTPUBLICPROMOID does not select the banner or name its dismissal cookie.

Register the banner

Add the banner to apps/web/lib/banners/registry.ts. The id must match the active environment value and the translation key. Give each banner a stable, unique dismissal cookie.

yourPromoBanner: {
  countdown: {
    endDateEnvVar: 'NEXT_PUBLIC_PROMO_COUNTDOWN_END_DATE',
  },
  cta: {
    loggedInHref: creditsHref,
    loggedOutHref: signupHref,
  },
  dismiss: {
    cookieKey: 'banner-your-promo-dismissed',
    days: 30,
  },
  id: 'yourPromoBanner',
  kind: 'promo',
  placements: ['landing', 'dashboard', 'blog'],
  priority: 100,
},

Omit countdown when the banner has no deadline. Choose only the placements where the banner belongs.

Add localized copy

Add the banner under promos in every apps/web/messages/*.json file. The supported locales are en, es, de, da, it, and fr.

{
  "promos": {
    "yourPromoBanner": {
      "text": "Your promotion text",
      "ctaLoggedIn": "Claim offer",
      "ctaLoggedOut": "Sign up now",
      "ariaLabelDismiss": "Dismiss promotion",
      "countdown": {
        "prefix": "Ends in:",
        "days": "Days",
        "hours": "Hours",
        "minutes": "Min",
        "seconds": "Sec"
      },
      "pricing": {
        "bannerText": "Your promotion"
      }
    }
  }
}

Omit countdown copy when the registry entry has no countdown.

Rendering and priority

apps/web/lib/banners/resolve-banner.ts selects one active banner for each placement. Promo banners use priority 100, ahead of ordinary announcements. Pages pass the resolved value to apps/web/components/banner.tsx, so adding a registry entry does not require another banner component.

Add page wiring only when introducing a new placement. Resolve the banner on the server and render the shared Banner component.

The landing, voice-cloning, and voice-call pages omit request cookies to keep their static caching. On those pages, the client can hide a dismissed banner, but it cannot replace it with the next eligible banner because the server sent only the highest-priority banner. If a promo and announcement are active together, dismissing the promo leaves the banner slot empty on those pages. Blog and dashboard pages pass dismissal cookies to the resolver, so they can fall back to the announcement.

Theme colors

Set NEXTPUBLICPROMO_THEME to pink, orange, or blue. Theme variables live in apps/web/app/globals.css under [data-promo-theme] selectors.

When adding a theme, extend BannerTheme in apps/web/lib/banners/types.ts, add its CSS variables, and update the example environment values.

Dismissal behavior

The registry entry owns the dismissal cookieKey and retention period in days. apps/web/components/banner.tsx hides the banner immediately and writes that cookie through setCookie in apps/web/lib/cookies.ts. The resolver reads the same cookie on later requests.

Dismissal is entirely client-side. Do not add a Server Action or derive the cookie name from NEXTPUBLICPROMO_ID.

Checklist

  1. Add a registry entry with a unique id, dismiss.cookieKey, and

dismiss.days.

  1. Choose the CTA targets, placements, countdown behavior, and priority.
  2. Add matching copy to all six apps/web/messages/*.json files.
  3. Set NEXTPUBLICPROMO_ENABLED=true and

NEXTPUBLICACTIVEPROMOBANNER to the registry id.

  1. Set theme, countdown, Stripe metadata, and bonus-credit variables only when

the campaign needs them.

  1. Run pnpm check-translations, pnpm fixall, and the focused banner tests.
  2. Verify dismissal, logged-in and logged-out CTAs, supported placements, and

countdown expiry before deployment. When a promo and announcement overlap, verify the dismissal result on both cacheable and cookie-aware pages.