# FunnelFizz Agent Skill

> Self-contained instructions for an AI agent (Claude, Cursor, ChatGPT, Copilot, etc.) to set up
> FunnelFizz end-to-end for the user. Paste this file's URL into your agent and say
> "follow this." Your agent should work through the steps in order, asking the user for
> anything it needs.

**Skill name:** `funnelfizz-setup`
**Version:** 2026-04-23
**Canonical URL:** https://docs.funnelfizz.com/skill.md
**Product docs:** https://docs.funnelfizz.com
**LLM-ready full docs:** https://docs.funnelfizz.com/llms-full.txt

---

## What FunnelFizz is

FunnelFizz is a marketing funnel builder for small SaaS teams. It maps the customer journey
across four fixed stages:

```
AWARENESS → CONSIDERATION → TRIAL → CUSTOMER
```

It connects to the user's tracking script, Stripe account, and social providers (X, YouTube,
LinkedIn, Instagram, TikTok, Reddit, Google Search Console, Google Ads). It sends email
campaigns and runs stage-triggered automations (drip sequences built as DAGs).

There are three plan tiers: **FREE**, **HOBBY**, **PRO**. There is no TEAM plan.

Product domain: **funnelfizz.com**. Brand name (in copy): **FunnelFizz** (PascalCase).

## Your job as the agent

Take the user from "I just heard of FunnelFizz" to "my funnel is tracking traffic and Stripe
events." Do as much as possible without bothering the user. Specifically:

1. [Sign the user up or confirm they're signed in](#step-1-sign-up).
2. [Install the tracking snippet in their codebase](#step-2-install-tracking).
3. [Help them create a Stripe restricted key with the 7 required scopes](#step-3-connect-stripe).
4. [Connect the user's providers](#step-4-connect-providers) (X, YouTube, GSC, whatever they use).
5. [Set up a custom sending domain if they want email](#step-5-email-sending-domain) (PRO only).
6. [Fire `identify` events from their app's auth layer](#step-6-identity-and-events).
7. [Instrument key custom events](#step-7-custom-events) from their codebase.
8. [Build a starter automation](#step-8-starter-automation) — at minimum a trial welcome drip.

At each step, tell the user what you're about to do. Don't take destructive actions without
confirmation.

## Inputs you'll need

Before starting, ask the user for:

1. **FunnelFizz account** — email + password or "I need to sign up."
2. **Their product's domain** — e.g., `example.com`. Also note if app and marketing are on
   different subdomains.
3. **Their codebase** — you should have read/write access to it (this is the normal agent
   setup).
4. **Stripe access** — either the user pastes an `rk_live_...` key they've created, or they
   grant you temporary access to their Stripe dashboard to create it (the second is usually
   easier; guide them step-by-step).
5. **Social provider accounts** — which platforms do they use? X? YouTube? LinkedIn?
6. **Framework** — Next.js, Astro, Remix, WordPress, Shopify, plain HTML, etc.

If the user hasn't decided on these yet, help them pick defaults instead of blocking.

## Security & trust rules

**MUST DO:**

- Store keys ONLY in the user's environment (`.env`, `.env.local`) and FunnelFizz's settings.
- Use the user's own Stripe account. Never create Stripe accounts on behalf of the user.
- Confirm before writing secrets to a shared file. `.env` must already be gitignored.
- Tell the user which file you're modifying before you modify it.

**MUST NOT DO:**

- Do NOT paste a `sk_live_...` Stripe secret key into FunnelFizz. Only restricted
  (`rk_live_...`) or test (`rk_test_...`) keys.
- Do NOT commit `.env` or any file containing keys. Check `.gitignore` first.
- Do NOT transmit the user's Stripe key, FunnelFizz session cookies, or OAuth tokens to any
  third party, including your model provider's logs where possible.
- Do NOT skip the `identify` call setup — the funnel is broken without it, and the user won't
  know why until it's too late.

## Step 1: Sign up

If the user doesn't have an account:

- Direct them to `https://funnelfizz.com/signup`.
- Wait for them to finish and confirm they're logged in.
- Ask them what they want to name their first funnel. Default suggestion: `"[Product name]
  — Main Acquisition"`.
- Complete the onboarding wizard with them (it's only a couple steps).

## Step 2: Install tracking

### 2a. Grab the snippet

Ask the user for their tracking snippet. They'll see it in FunnelFizz's onboarding (step 2)
or at **Settings → Tracking → Install code**. It looks like:

```html
<meta name="funnelfizz-verify" content="YOUR_TOKEN" />
<script>
(function(w,d,t){
  w._fn = w._fn || [];
  w.funnelfizz = function(){ w._fn.push(arguments) };
  var s = d.createElement('script');
  s.async = 1;
  s.src = 'https://funnelfizz.com/track.js?t=' + t;
  d.head.appendChild(s);
})(window, document, 'YOUR_TOKEN');
</script>
```

### 2b. Install based on framework

**Next.js (App Router):** In `app/layout.tsx`, add the meta tag inside `<head>` and use
`next/script` with `strategy="afterInteractive"` to load the script.

**Next.js (Pages Router):** In `pages/_document.tsx`, add both tags inside `<Head>`.

**Astro:** In your root layout, add both tags inside `<head>` with `is:inline` on the script.

**Remix:** In `app/root.tsx`, add both tags inside `<Links>`/`<Meta>` sections and inject the
script with `dangerouslySetInnerHTML`.

**WordPress:** Install "Insert Headers and Footers" plugin, paste into **Scripts in Header**.

**Webflow / Framer / Squarespace:** Site-wide **Custom Code → Head**.

**Shopify:** `layout/theme.liquid`, inside `<head>`.

**Plain HTML:** Paste into every page's `<head>` (or into the shared header include).

### 2c. If the product has separate subdomains

If `app.example.com` and `www.example.com` are the same product, install on BOTH, AND add
`cookieDomain: '.example.com'` to the tracking config so the `_fn_vid` cookie is shared.

### 2d. Verify

After installing:

1. Ask the user to visit their live site once in a new tab.
2. Wait ~10 seconds.
3. Verify in FunnelFizz (onboarding will auto-advance, or refresh **Settings → Tracking**).

If verification fails after 30 seconds, check: snippet actually in `<head>`, domain matches,
no ad-blocker in user's test browser.

## Step 3: Connect Stripe

### 3a. Create a restricted key in Stripe

Guide the user through (have them do this — you should NOT log into Stripe on their behalf):

1. Open `https://dashboard.stripe.com/apikeys`.
2. Click **Create restricted key**.
3. Name: `FunnelFizz (read-only)`.
4. Set these 7 permissions to **Read**:
   - Customers
   - Charges and Refunds
   - Events
   - Products and Prices
   - Invoices
   - Subscriptions
   - Balance
5. Leave everything else as **None**.
6. Click **Create key** → **Reveal key** → copy the `rk_live_...` (or `rk_test_...`) value.

### 3b. Paste into FunnelFizz

1. Have the user open FunnelFizz → **Settings → Integrations → Stripe → Connect**.
2. Paste the restricted key.
3. Click **Validate**.

If FunnelFizz returns a "missing scopes" error, the user missed one of the seven. Have them go
back to Stripe → edit the key → add the missing scope → save → re-paste.

### 3c. Map products

FunnelFizz auto-detects Stripe products. In the conversion config:

- **Position 1 (CONSIDERATION → TRIAL):** pick the trial product/price.
- **Position 2 (TRIAL → CUSTOMER):** pick the paid product(s).

Ask the user which of their Stripe products represents the trial and which represents paid
subscription. Default to the primary/only paid product if there's ambiguity.

## Step 4: Connect providers

Ask which platforms they use. For each, walk them through OAuth:

- **X (Twitter)**: **Settings → Integrations → X → Connect**. Sign in, approve read-only.
- **YouTube**: same flow, Google OAuth.
- **LinkedIn**: same.
- **Instagram**: requires a Business or Creator account; standard OAuth.
- **TikTok**: OAuth.
- **Reddit** (HOBBY+): OAuth.
- **Google Search Console** (HOBBY+): OAuth — the user must have already verified the site
  in GSC at `search.google.com/search-console`.
- **Google Ads** (HOBBY+): OAuth — if they have an MCC, they'll pick which sub-account.

If the user is on FREE and wants a HOBBY+ provider (Reddit, GSC, Google Ads), upgrade them at
`https://funnelfizz.com/pricing` before the connect step.

## Step 5: Email sending domain

**Skip this step if the user is on FREE.** FREE plans have no email sending. HOBBY sends from
`funnelfizz.com`; this section is for PRO users who want a custom domain.

### 5a. Add domain

FunnelFizz → **Settings → Email → Domains → Add domain**.

Use a **subdomain** (e.g., `mail.example.com`), not the apex — it keeps your main domain's
reputation separate.

### 5b. Add DNS records

FunnelFizz will show three records. The user needs to add them at their DNS registrar
(Cloudflare, Namecheap, Route 53, GoDaddy, etc.).

- **MX** on the subdomain → Resend's MX.
- **TXT (SPF)** on the subdomain → `v=spf1 include:amazonses.com ~all` (or whatever FunnelFizz
  specifies — copy exactly).
- **TXT (DKIM)** on `<selector>._domainkey.mail.example.com` → the DKIM public key.
- *(Optional but recommended)* **TXT (DMARC)** on `_dmarc.example.com` → `v=DMARC1; p=none; ...`.

Ask the user which registrar they use and walk them through that registrar's UI. Cloudflare
is usually the easiest.

### 5c. Verify

Back in FunnelFizz, click **Verify**. We poll DNS every 30s and mark verified when all records
resolve. DNS propagation can take up to an hour; usually done within 5 min.

## Step 6: Identity and events

### 6a. Fire `identify` after login

In the user's app, wherever the login/signup success handler lives, add:

```javascript
funnelfizz('identify', {
  userId: user.id,        // their internal user ID
  email: user.email,      // strongly recommended
  createdAt: user.created_at,  // optional, helps cohort analysis
});
```

**React / Next.js pattern:** put this in a client-side `useEffect` tied to auth state, so it
fires on every login and every page-load-after-login.

```tsx
'use client';
import { useEffect } from 'react';
import { useSession } from 'next-auth/react';

export function FunnelFizzIdentify() {
  const { data: session } = useSession();
  useEffect(() => {
    if (session?.user?.id) {
      // @ts-expect-error funnelfizz global
      window.funnelfizz?.('identify', {
        userId: session.user.id,
        email: session.user.email,
      });
    }
  }, [session?.user?.id, session?.user?.email]);
  return null;
}
```

Mount `<FunnelFizzIdentify />` in the app's root layout.

**Vanilla / SSR-first apps:** Emit an inline `<script>` after login that calls `funnelfizz`
directly once the user object is available.

### 6b. Call `identify` defensively

The tracking script queues calls before it loads — calling `funnelfizz('identify', ...)` is
safe even if `track.js` hasn't finished loading. No `if (window.funnelfizz)` check needed
unless you're extremely performance-paranoid.

## Step 7: Custom events

Instrument the key funnel moments. Scan the user's codebase for these conventional signals
and add events:

| Event name | When to fire |
|---|---|
| `signup` | After account creation succeeds |
| `pricing_viewed` | On pricing page load |
| `trial_started` | After Stripe trial creation (redundant with webhook but useful) |
| `activation` | When the user completes "the key action" — ask them what activation means for their product |
| `upgrade_clicked` | When they click an upgrade CTA |
| `cancel_clicked` | When they open the cancel flow |

Fire each with:

```javascript
funnelfizz('event', 'signup', { plan: 'hobby', source: 'pricing_page' });
```

Keep properties simple: 3-5 keys max, primitive values only (string/number/boolean).

## Step 8: Starter automation

Build the simplest useful automation first — a trial welcome drip. In FunnelFizz:

1. **Main Funnel → TRIAL stage → Automations → Create.**
2. **Trigger:** `subscription_trial`.
3. **Steps:**
   - **SEND_EMAIL:** "Welcome to [Product] — here's the 60-second quickstart" (Day 0).
   - **WAIT:** 2 days.
   - **SEND_EMAIL:** "3 things Pro users do first."
   - **WAIT:** 5 days.
   - **CONDITIONAL_SPLIT:** `profile.subscriptionStatus == "active"` → yes = END, no = send
     "Trial ends in 2 days."
4. **Activate.**

Offer to draft the email copy for the user if they don't have it ready.

## When you're done

Confirm with the user:

- [ ] Tracking snippet installed and verified.
- [ ] Stripe connected and validating.
- [ ] At least one provider connected (if relevant).
- [ ] `identify` call installed and firing after login.
- [ ] At least one custom event firing from the codebase.
- [ ] One automation activated.

Then link the user to the relevant docs:

- Quickstart: https://docs.funnelfizz.com/quickstart/overview
- Concepts: https://docs.funnelfizz.com/concepts/stages
- Features: https://docs.funnelfizz.com/features/providers
- Tutorials: https://docs.funnelfizz.com/tutorials/building-a-basic-saas-funnel

## If you get stuck

Tell the user which step failed and what specifically didn't work. Common traps:

- **Tracking snippet not verifying**: usually caused by the meta tag being outside `<head>`,
  or a subdomain mismatch, or a content-security-policy blocking the script. Ask the user to
  open their live site and inspect the `<head>` for the `funnelfizz-verify` meta tag.
- **Stripe key rejected**: missing one of the seven scopes. FunnelFizz tells you exactly which
  one; go back to Stripe and add it.
- **`identify` doesn't fire**: the tracking script isn't loaded on the authenticated pages.
  Either it wasn't installed in the shared layout, or a CSP/route is stripping it.

For anything else, have the user email `hello@funnelfizz.com` with:
- Their account email
- What they were trying to do
- What they tried already
- The error message (screenshot if possible)

## Plan tiers cheat-sheet

| Feature | FREE | HOBBY ($9/mo) | PRO |
|---|---|---|---|
| Funnels | 1 | 3 | Unlimited |
| Tracking events | Unlimited | Unlimited | Unlimited |
| Email campaigns | — | 3,000 / mo | 20,000 / mo |
| Automations/stage | 0 | 1 | 5 |
| Custom sending domain | — | — | Yes |
| A/B testing | — | — | Yes |
| Mentions monitoring | — | — | Yes (1 brand) |
| Reddit / GSC / Google Ads | — | Yes | Yes |

Full current pricing at https://funnelfizz.com/pricing.

## Glossary for your context

- **Stage** — one of AWARENESS / CONSIDERATION / TRIAL / CUSTOMER. Fixed order.
- **Conversion** — the transition from one stage to the next. There are 3 of them (positions 0, 1, 2).
- **Split** — filter between two stages. 8 conditions: traffic_source, utm, channel, device_type, geography, custom_event, ab, stripe_product.
- **Extension** — post-CUSTOMER upsell pipeline. Ext Consideration / Ext Trial / Ext Customer.
- **Journey event** — a row in the journeyEvents table marking stage entry/conversion/churn for a given profile in a given funnel.
- **Profile** — a person, identified by `visitorId` (cookie), optionally stitched to `userId` (via `identify`) and `stripe_customer_id`.
- **Workspace** — top-level tenancy unit. Holds funnels, integrations, email quota, team members.

## Versioning

This file is updated when the product changes. Check the `Version:` line at the top. If a
user reports behavior that contradicts this file, fetch the latest at
`https://docs.funnelfizz.com/skill.md` and compare.
