Paid acquisition — action items & what to watch (2026-06-11)
TL;DR: The funnel is fixed and verified. Direct/organic visitors engage normally;
paid clicks (YouTube + FB) do not consume — consumed% ≈ 0 even now that the
paywall is gone. The bottleneck is ad quality/intent, not the site. Everything
below is what's left — almost all of it is in Ads Manager, not the code.
North-star metric: consumed% by source on the Paid acquisition dashboard.
It is the % of sessions that actually pressed play / listen / read. Today it's ~0 on
paid. The whole game now is getting that number off zero.
🔴 DO NOW — Ads Manager (highest leverage first)
- Fix the Meta Pixel ID mismatch (the real reason it shows "no activity").
The site code fires pixel
1421912249452225(NEXT_PUBLIC_FB_PIXEL_ID), but your ads + Events Manager dataset use976627715239476. Different pixels, so the dataset never sees the site's events. The pixel base code IS installed (FacebookPixel.tsx, mounted inlayout.tsx) — it's just pointed at the wrong ID. Don't use the "Set up Web Events" dialog or Conversions API; this is config, not installation.- Fix (Vercel → frontend env, then redeploy):
TheNEXT_PUBLIC_FB_PIXEL_ID=976627715239476 NEXT_PUBLIC_FB_PIXEL_HOSTNAME=graphene.fmHOSTNAMEgate fires the Graphene pixel only on graphene.fm (graphene.fm + hivejournal.com share one Vercel deploy), so Meta's lookalike is built from real Graphene listeners, not mixed HiveJournal traffic. - ⚠️ Confirm first: if hivejournal.com runs its own FB ads on
1421…, this change stops HJ's pixel (one deploy = one pixel env). If so, ask for per-host pixel mapping in code instead. - Verify: Events Manager → Test Events → enter
https://www.graphene.fm→ browse → confirmPageViewfires for pixel976…. - Why it matters: without the right pixel firing, Meta optimizes for the cheapest
click (your 3-second-bounce traffic). This is the single biggest FB lever on
consumed%.
- Fix (Vercel → frontend env, then redeploy):
- Switch YouTube objective from views/awareness to Traffic → "Landing page views" (or Conversions) so Google buys people who actually land and stay, not cheap impressions/clicks. Right now: 222 YouTube sessions → 0 consumed.
- Exclude Audience Network placements on Meta (junk / accidental clicks).
- Point ALL ads at the season page, not
/listenor the homepage. Destination format (per show):https://www.graphene.fm/seasons/<SEASON_ID>- NYFB:
https://www.graphene.fm/seasons/0f80c02a-1855-42bc-bd9b-6ee2d55a6b0e - The Offline ("Blackout Logs"):
https://www.graphene.fm/seasons/40c7d47b-4102-4a21-95e1-7ae73aa61d26
- NYFB:
- Re-scrape the FB destination so the share-image fix (robots.txt, shipped) takes: Facebook Sharing Debugger → paste the season URL → Scrape Again → then re-publish the stuck ad (clears the "Image Wasn't Downloaded" error).
- Watch 3–5 Session Replays of YouTube/FB landers (PostHog → Session replay). Confirm whether it's accidental clicks, an in-app-browser issue, or a creative→landing mismatch. Do this — it's the fastest "what's really happening" check.
UTM tagging for new/edited ads
Put this in Meta's ad-level "URL parameters" field (auto-fills per ad):
utm_source=fb&utm_medium=paid&utm_campaign={{campaign.name}}&utm_content={{ad.name}}&utm_term={{placement}}
YouTube equivalent: utm_source=youtube&utm_medium=paid&utm_campaign=...&utm_content=...
Don't double-tag — UTMs go in either the URL params field or the destination URL, never both.
✅ DONE — verify still true
-
POSTHOG_KEYset on Railway backend — confirmed working (server-sidesignin_completedviaoauth_callbackis firing). Server-side conversions (subscription_active,episode_tip_paid) will now register when they happen.- Value:
POSTHOG_KEY=phc_kntvSXmtrgmE2FgWfTiYqRBVV7sVZPQqhUJgtdidKZkU POSTHOG_HOST=https://us.i.posthog.com
- Value:
- Spot-check actual paid revenue in Stripe / the
subscriptionstable — the earlier "0 subs" was a tracking blind spot; confirm whether real subs/tips exist that PostHog couldn't see before the key was set.
📊 WATCH — your scoreboard (PostHog project 378637)
- Paid acquisition dashboard
- Median dwell + consumed%/paywalled% by source ← the key tile
- Funnel: Paywall → Subscription
- Funnel: Cold-ad → Listen → Paywall
How to read it / what "working" looks like:
consumed%on paid sources lifts off 0 → the ad changes are buying real listeners. ✅paywalled%stays near 0 → the 3-free-chapters fix is holding (cold visitors not walled).median_dwell_secclimbs above 0 → fewer instant bounces.- If
consumed%stays ~0 after the pixel + objective changes → the creative or audience is the problem, not placement; iterate on hooks/targeting.
🎨 Brand assets for ad creative (CapCut / overlays)
Reusable hosted assets — drop straight into a video editor:
- Logo lockup (hex + GRAPHENE + .fm), transparent PNG — the one to use for
ad end-cards / watermarks:
https://www.graphene.fm/api/brand/graphene-logo(1400×360, white wordmark + purple.fm, transparent bg — sits cleanly over dark footage. Route:api/brand/graphene-logo.) - Hex mark only — transparent SVG:
https://www.graphene.fm/favicons/graphene.svg(or opaque 180×180 PNG app-tile at/api/icons/graphene— has a background box, so prefer the lockup or SVG for overlays). - Wordmark spec (if typing it in CapCut instead):
GRAPHENEin Inter Bold, all caps, white, letter-spacing ~0.15em, with a smaller purple (#a78bfa).fm.
🚢 SHIPPED THIS SESSION (code — already live, no action needed)
The whole downstream funnel was rebuilt and deployed. For the record:
| PR | Fix |
|---|---|
| #531 | Cold-ad homepage hero no longer dead-ends + warns on dropped server events |
| #532 | First 3 chapters always free (cold visitors get a real taste before any wall) |
| #533 | Top Graphene+ perks surfaced on the locked-chapter card |
| #534 | /listen paid LP: poster is now a giant tap-to-play button |
| #535 | robots.txt allows /api/og/ so Meta/social can fetch share + ad images |
Verified live: paywall stopped firing for cold traffic after deploy; direct/organic visitors consume normally on the same pages. The machine works — it needs better fuel.
🔮 LATER / optional
- New trailer for the paused YouTube ad (or run it pointed at
/seasons/<id>— the cold-ad hero falls back to the first free chapter's audio, so it doesn't strictly need a trailer). - If short paid seasons ever ship, add a "keep the last chapter walled" guard (today the 3-free pilot makes any ≤3-chapter season fully free).
- Tune the free-pilot width (
ALWAYS_FREE_THROUGH_EPISODE, currently3) once there's real conversion data.
Generated from the 2026-06-11 funnel + PostHog analysis session. Re-pull anytime by asking to "re-pull PostHog" — the queries live in this session's history.