Promotions & Sponsors
Recurring monetisation beyond one-time premium listings — promotion placements, sponsor slots, bundling and pricing strategy.
Why this matters
One-time premium listings get you to first revenue, but they cap out fast — every project owner pays once and then stops giving you money. Promotions and sponsors are the two recurring-revenue layers that turn a directory into a sustainable business: project owners renew month after month for visibility, and unrelated brands pay to reach your audience without owning a listing.
Sustainable directory businesses split revenue roughly 30/40/30 across one-time premium, recurring promotions and recurring sponsorships. This page documents both recurring layers — when each works, how to price them, and the Stripe wiring that makes them run unattended.
The two systems
| System | Who buys | Billing |
|---|---|---|
| Promotions | Project owners wanting extra visibility | Monthly subscription |
| Sponsors | Companies/brands wanting a permanent slot | Monthly subscription |
Both live in the admin panel. Pricing comes from advertising.config.ts.
Promotions
Three placement types, each independent:
| Placement | Where it appears | Default price |
|---|---|---|
| Banner | Horizontal ad below the site header, every page | $69/mo |
| Catalog Card | Promoted card mixed into the project grid | $39/mo |
| Detail Card | Sidebar card on project detail pages | $19/mo |
Buyers at /promote can pick one, two, or all three. Picking all three triggers a 30% discount (via a Stripe coupon — see Advertising Config).
Promotion admin
Admins can:
- Approve new purchases (if manual review is required)
- Edit start / end dates
- Revoke a placement
- See which projects are currently running ads
Sponsors
Sponsors get logo placement in a sponsor section (sidebar, footer, or dedicated partners page — depending on your layout). Recurring monthly subscription.
maxSponsors: 8 in advertising.config.ts caps how many run simultaneously. Excess buyers go on a waitlist.
Stripe setup
Each placement and the sponsor plan needs a recurring monthly Price in Stripe:
STRIPE_PRICE_ID_PROMO_BANNER=price_...
STRIPE_PRICE_ID_PROMO_CATALOG=price_...
STRIPE_PRICE_ID_PROMO_DETAIL=price_...
STRIPE_PRICE_ID_PARTNER_SUBSCRIPTION=price_...
STRIPE_COUPON_ID_PROMO_ALL_THREE= # optional 30% off bundleSee Payments for full Stripe flow.
Feature flags
Turn the whole system off with:
promotions: false, // /promote page → 404, admin section gone
partners: false, // sponsor slots → hiddenWhen to use which
- Premium listings — the starter revenue stream. User pays once, gets upgrade for one listing.
- Promotions — recurring revenue for projects that already paid premium and want more visibility.
- Sponsors — unrelated-to-directory brands who want to reach your audience (e.g. an IDE sponsoring a "developer tools" directory).
A real-world walkthrough: pricing for a 5,000-pageviews/month directory
Suppose your directory does 5,000 monthly pageviews, evenly split across 200 listings. A "banner" promotion appears on every page → 5,000 impressions/month. At a CPM of $5–10 (typical for niche audiences), that's $25–50 of pure ad value per month — so $69/month is fair for a project owner who cares about visibility (they're getting their listing seen plus implicit category authority).
Catalog placements ($39/mo) appear ~40% of the time the user is browsing the catalog. Detail-page placements ($19/mo) appear only on co-located project pages. Stack them and the project owner gets blanket coverage; offer the "all three" bundle at 30% off ($89/mo) to make the upgrade obvious.
Sponsors are different: they pay for brand association, not pageview math. A boutique productivity-tool brand sponsoring a "tools for designers" directory cares about being seen in the right room, not raw impressions. Price sponsorships at $200–500/month for a small directory — you'll have 3–8 slots maximum, all sold with personal outreach. Don't open a public "buy a sponsorship" page until you have 50,000+ monthly pageviews.
Common pitfalls
- Setting promotion prices based on cost instead of value. Stripe takes 2.9% + $0.30. A $19/month promotion nets you ~$18, but the ad is worth $40+ to the buyer. Don't underprice — promotion buyers care about ROI, not your margins.
- Forgetting to invalidate the homepage cache when promotions change. If your homepage ISR cache doesn't include "active promotions" as a tag, a paid banner can take an hour to appear. Use
revalidateTag('promotions')in the Stripe webhook handler. - Selling unlimited sponsor slots. Sponsors lose value when there are 20 of them on a page. Hard-cap with
maxSponsorsand run a waitlist; scarcity drives renewals. - Ignoring failed renewals. Stripe's
customer.subscription.updatedevent fires when a card declines. The webhook handler should mark the placementinactiveand email the buyer — otherwise their banner keeps running for free. - Mixing promotion and premium pricing in one Stripe Price. Each placement type needs its own Stripe
Price. Reusing a Price across types makes upgrades and refunds messy. Set up explicitSTRIPE_PRICE_ID_*env vars per type.
FAQ
Should I offer a yearly discount on promotions?
Yes — a "save 2 months by paying yearly" deal converts cash flow and reduces churn. Add a yearly Stripe Price alongside the monthly one and surface both at /promote. Most operators see ~20% of buyers choose yearly when offered.
Can I let project owners self-serve cancel their promotion?
Yes — link to the Stripe Customer Portal from your dashboard. Stripe handles cancellation, the webhook handler revokes the placement on customer.subscription.deleted. No custom code beyond a portal link.
How many active promotions can a directory run before it looks sponsored?
Empirically, more than 1 banner + 5 catalog placements + 10 detail-page placements starts to feel ad-heavy at small scale. The catalog ratio matters most: keep promoted-to-organic at 1:5 or better. Above 1:3, users notice and bounce.