Ways into the app
Four distinct audiences use FunnelGenie, each through its own door.
| Audience | Entry point | Authentication |
|---|---|---|
| You (the seller/admin) | /admin — the dashboard | Email + password (/login, /signup). Email verification and password reset are built in. |
| Members (students, community members, affiliates) | /members — the member portal | Passwordless magic link: they enter their email at /members/login and get a one-click sign-in link (valid 30 minutes; the session lasts 30 days). |
| Visitors | Your funnels, websites, blog, and checkout pages | None — public pages. Leads are captured by opt-in forms. |
| API consumers | /api/v1/* with a Bearer key | API keys minted under Settings → Developers (format fg_<env>_…, shown once, scoped, revocable). |
Framework & stack
What the app is built on and how it runs.
| Layer | Technology |
|---|---|
| Application framework | Nuxt 3 (Vue 3, TypeScript) — one codebase serves the marketing site, admin dashboard, public funnels/sites, member portal, and the API through the built-in Nitro server. |
| Styling | Tailwind CSS with a custom iris-violet brand scale; class-based light/dark theming. |
| Database | PostgreSQL via Prisma ORM. Schema migrations apply automatically on deploy. |
| Background jobs | No queue infrastructure — all async work (webhook delivery, email/automation ticks, dunning, abandoned-checkout scans, blog publishing) runs as in-process Nitro scheduled tasks backed by database rows. |
| SaaS billing | Paddle (subscriptions for the platform's own plans). |
| Seller payments | PayPal multiparty (checkout for products you sell) — behind the commerce switch. |
| Transactional email | Resend (Postmark/SendGrid also supported as senders). |
| File storage | Cloudflare R2 (S3-compatible) in production; local disk in development. |
| Hosting | Render — one always-on web service + one managed Postgres, provisioned by the render.yaml Blueprint. |
| AI | Generate-with-AI page copy via the OpenAI API (default model configurable with OPENAI_MODEL). |
| Testing | Vitest unit suite + full TypeScript typecheck; Playwright available for e2e. |
Funnels
Admin → Funnels. Multi-step marketing flows that capture leads and sell offers.
- 9 funnel templates in four categories — Lead (Lead Magnet Classic, Lead Magnet → Upsell → Downsell, Newsletter Squeeze), Sales (Tripwire Free+Shipping, VSL, Course/Membership Launch), Presentation (Webinar Registration, Product Launch), High-ticket (Application → Book a Call). Every opt-in step ships with a real, editable form block.
- Step types: Opt-in, Download, Thank-you, Sales, Checkout, Upsell, Downsell, Confirmation — each step gets a page you edit in the visual builder.
- A/B testing: page variants with deterministic, sticky visitor bucketing; only published variants serve.
- Lead magnets: attach a file to an opt-in; visitors get an instant download plus a first-party delivery email with a 7-day backup link and a self-serve re-send flow.
- Per-funnel branding: logo, header/page colors, social links, tracking pixels (Meta, GA, TikTok), custom head/body HTML, theme presets.
- Publishing: draft → published; the funnel root URL sends visitors straight into the first step.
Page builder & templates
Admin → Pages / Templates. Every page — funnel step, standalone page, website page — is edited in the same visual builder. Blog posts are the exception: they open in their own writing editor (Websites → Blog).
- 25 block types in a Section → Row → Column hierarchy: heading, paragraph, button, image, video, spacer, divider, bullet list, hero, benefits, offer stack, testimonials, FAQ, guarantee, opt-in form, countdown, logo strip, pricing table, image+text, social links, containers and columns.
- Drag-and-drop with section presets, saved sections, 12-column row widths, per-block inspectors, inline text editing, undo, and mobile preview.
- Page templates (
/admin/templates): a built-in App Library of 9 page designs (opt-in, squeeze, sales, webinar, thank-you, download, upsell, website home, about) plus your own saved templates. Import/export any page as JSON. - Generate with AI: draft page copy from a prompt (Admin → Generate with AI).
- SEO fields per page: title, description, OG title/description/image, canonical URL, noindex.
Websites & Blog
Admin → Websites. Multi-page brand sites with a built-in SEO blog.
- Sites: each site gets a slug (
/sites/<slug>), a set of pages (edited in the same builder), a configurable header/footer navigation, an optional announcement bar (own colour with automatic black/white text; static or a scrolling ticker with direction and speed, paused on hover and disabled for reduced-motion visitors), and a theme preset. - Blog: one blog per site at
/blog— posts with categories, tags, author, excerpt, featured image, and per-post SEO. Statuses: draft, scheduled (auto-publishes at its time), published, archived. - Blog editor: posts are written in a dedicated article editor (title as the H1, headings, lists, quotes, links, images, code) rather than the page builder — no sections, rows or columns to fight. Write with AI drafts the whole article from the title, excerpt, category and tags with a chosen tone and length; every word stays editable. Ctrl/Cmd+S saves.
- Header sections: in Websites → your site → Navigation, tick blog categories under a header item (e.g. "Women's Health" grouping Maternal Health and Fitness). Clicking the item opens every post in those categories (
/blog?category=a,b) headed with the item's name, with the categories as a grid of tabs ("All" plus one per category, each with its post count) to narrow the list. An item whose link points at a real page goes there instead; the Navigation tab warns about links to paths with no page or mounted funnel behind them. - Sidebar: same tab, "Sidebar" — pick Left or Right (the content shifts the other way; on phones the sidebar drops below the content) and whether it shows on blog pages only or on every page. Add up to 12 widgets: an Image / banner ad (upload or URL, optional link, 300px wide — standard ad sizes fit), a Text blurb (Markdown), or HTML / ad code pasted from Google AdSense, Amazon, Ezoic and the like — scripts run as pasted, so only use code from providers you trust. Reorder with the arrows; the post Preview shows the sidebar too.
- Magazine home page: Websites → your site → Home layout → switch on "Use the magazine layout". The site root then renders a data-driven magazine instead of a builder page: a Hero from the latest (or a pinned) post, Post grids in four styles (cards three across, one featured + list, compact four across, horizontal strip) fed by the latest posts or one category, a Topics browser (chips or image tiles), Banners (image ad or pasted ad code) and CTA banners (headline, text, button to a page, a mounted funnel such as
/launch/optin, or any URL; background colour with automatic black/white text). Sections are reordered with the arrows; the default layout is hero + latest + topics + one row per category + a closing CTA. A post appears at most once per home page, and sections with nothing to show are skipped. The magazine home is always full-width (no sidebar). - Themes: Settings → Theme. Obsidian — violet accent, follows the visitor's light/dark setting. Steel — cool slate, hairline rules, sharper corners. Aurora — warm cream, coral accent, rounder shapes. The palette drives the site chrome, blog pages and the magazine home; a custom header colour still wins for the header.
- Search: Navigation → "Show a search box in the header", or add a Search widget to the sidebar / a Search bar to the magazine home. Searches post titles, excerpts, tags and article text (case-insensitive); results open on the blog page (
/blog?q=…) with a count and a "Clear search" link. - Feeds & SEO: RSS at
/sites/<slug>/blog/rss.xml, JSON-LD structured data on posts, and automatic inclusion of published pages and posts in/sitemap.xml. - Custom domains: attach your own domain to a site (or a funnel) — see Custom domains.
Leads, Contacts & CRM
Admin → Leads / CRM. Everyone who opts in becomes both a funnel-level Lead and a workspace-level Contact.
- Lead capture: opt-in forms record name, email, phone, consent, UTM attribution, referrer, and device; duplicates are merged per funnel; honeypot spam protection.
- Contacts: workspace-wide identity (one row per email) that courses, community, affiliates, email, and the CRM all reference.
- CRM pipelines: Kanban board with drag-and-drop stages, weighted pipeline value (stage probability), opportunities with activities/tasks, won/lost tracking with reasons, and a default 5-stage pipeline created on first use.
- Unsubscribes & suppressions: one-click unsubscribe links on every marketing email, a workspace do-not-email list, and automatic suppression of bounced/complained addresses.
Email marketing
Admin → Broadcasts / Automations. Native sending — no external autoresponder required.
- Broadcasts: one-off campaigns to your list (optionally filtered to a funnel), sent now or scheduled; live stats for delivered, opened, clicked, bounced.
- Sequences: multi-step drip series with per-step delays; enrollment by automation, opt-in, or manually.
- Templates: reusable email content shared by sequences and automations.
- Compliance built in: CAN-SPAM postal-address footer, RFC 8058 one-click unsubscribe headers, suppression checks on every send, and monthly plan-cap enforcement.
Automations
Admin → Automations. Event-triggered workflows.
- Triggers: new lead, opt-in submitted, order paid, course enrolled/completed, community member joined, affiliate registered/conversion, opportunity created/stage-changed/won/lost.
- Actions: send an email, wait (minutes/hours/days), add a tag, enroll in a sequence, create a CRM opportunity.
- Reliability: replay-safe (each event runs an automation once), automatic retries with backoff, loop protection, and a per-automation run log.
Courses & member portal
Admin → Courses. Sell or grant access to online courses delivered in the member portal.
- Course builder: sections and lessons of five types — text, video (paste any YouTube/Vimeo/Loom/Wistia link; it embeds automatically), audio, download (member-gated file), and embed. Cover image, instructor, drip scheduling per lesson (unlock N days after enrollment).
- Access: enroll members manually by email (they're invited by magic link automatically), or attach an Offer so paid orders grant access instantly.
- Member experience (
/members): course player with curriculum sidebar, progress tracking, resume, mark-complete auto-advance, drip locks with unlock dates, and completion celebration. - Progress admin: student list with per-student progress, revoke/restore access.
Community
Admin → Community. A private space for your audience, inside the member portal.
- Communities & spaces: public (self-join by your audience) or private (grant-only); multiple spaces per community.
- Feed: member posts and comments, likes, pinned and locked posts, official brand announcements.
- Moderation: member roles (moderator/member), bans that survive re-joining, post pin/lock/delete, rate limits on posting.
- Access: manual adds, public self-join, or Offer grants on purchase.
Commerce & offers behind switch
Product checkout is fully built and ships disabled until PayPal multiparty is approved (NUXT_PUBLIC_COMMERCE_ENABLED=true turns it on).
- Offers: one-time or subscription products with pricing, image, and description, sold at
/offer/<slug>and/checkout/<slug>. - Checkout depth: order bumps, 1-click upsells/downsells (vaulted PayPal), coupons, abandoned-checkout recovery emails.
- Fulfillment: paid orders grant course and community access automatically, deliver receipts, and fire
order.paidfor automations/webhooks. - Subscriptions: recurring offers with per-cycle platform fee support and dunning.
Affiliate center behind switch
Admin → Affiliates. Let partners promote your funnels for commission.
- Programs: percent or flat commission, cookie window, refund-safety hold period, recurring commissions, auto-approve, and a public signup link (
/affiliates/join/<token>). - Tracking: per-affiliate links (
/r/<token>) with last-click attribution; commissions are computed server-side on paid orders and reversed on refunds. - Payouts: commission ledger (pending → payable after the hold → paid), recorded payouts per currency, leaderboard.
- Affiliate portal: partners see their links, clicks, sales, and payout history at
/members/affiliates.
Analytics & tracking
Admin → Analytics.
- Funnel analytics: page views, opt-ins, conversion rates, revenue, step-by-step drop-off, and A/B variant performance.
- Across the platform: CRM pipeline value, course enrollments and completions, community activity, email sends and unsubscribes, affiliate clicks/conversions/revenue, share-funnel imports.
- Integrity: money events are recorded server-side only and can't be forged by page scripts.
- Visitor pixels: per-funnel Meta Pixel, Google Analytics, and TikTok pixel firing, plus platform-level GA/Meta IDs.
Custom domains
Serve a website or a funnel on a domain you own. Three parties are involved: FunnelGenie (knows which site or funnel the domain belongs to), your DNS provider (points the domain at the platform), and Render (issues the HTTPS certificate). The steps below take about ten minutes plus DNS propagation.
Step 1 — Decide which hostname to use
- Subdomain (
www.brand.com,go.brand.com): the simplest choice. Uses a plain CNAME record. - Root domain (
brand.com): DNS forbids a CNAME on a root, so you need an ALIAS or ANAME record. Namecheap, Cloudflare, DNSimple, Porkbun and Route 53 offer one. If your provider does not, attachwww.brand.cominstead and set a redirect from the root towwwat the registrar. - A website's domain serves every site path (pages,
/blog, mounted funnels). A funnel's domain serves that funnel at the root. One domain can belong to only one site or funnel; to run both on one domain, mount the funnel on the website (see below).
Step 2 — Attach the domain in FunnelGenie
- Website: Websites → your site → Settings → Custom domain. Funnel: Funnels → your funnel → Domain.
- Type the hostname (no
https://) and click Attach. - The panel now shows the two records to create, with the exact Host label for your provider's form.
Step 3 — Add the records at your DNS provider
Open your registrar's DNS panel (Namecheap: Domain List → Manage → Advanced DNS). Create exactly these records — nothing else on the same host name:
| Purpose | Type | Host / Name | Value / Target |
|---|---|---|---|
| Route traffic (root domain) | ALIAS (or ANAME) | @ | your-service.onrender.com |
| Route traffic (subdomain) | CNAME | www (just the label) | your-service.onrender.com |
| Prove ownership (root) | TXT | _ff-verify | the token shown in the panel |
| Prove ownership (subdomain) | TXT | _ff-verify.www | the token shown in the panel |
- The target is a bare hostname: never paste
https://, a path, or a trailing slash into a DNS value. The panel already shows the right value to copy. - Most providers append your domain to the Host field automatically, so enter
www, notwww.brand.com, and_ff-verify, not_ff-verify.brand.com. A few providers want the full name; the panel shows both forms. - Do not add both a CNAME and an ALIAS for the same host. A CNAME cannot share its name with any other record; that is the red warning some registrars show when you try to put a CNAME on
@. - Leave the TTL on "Automatic".
Step 4 — Add the domain on Render (certificate)
- If the FunnelGenie environment has the Render API key and service ID set (
RENDER_API_KEY,RENDER_SERVICE_ID), this happens automatically when you attach. The panel tells you when it does not. - Otherwise open the Render dashboard → your web service → Settings → Custom Domains → Add, and enter the same hostname. Render's instructions may say "CNAME" for the root; your ALIAS record satisfies that — do not add a second record.
- Wait for Render to show Certificate issued (usually a few minutes after DNS resolves). Until then
https://on the domain fails to connect, and plainhttp://returns Render's409 — error code 1001, which simply means the domain is not registered on the service yet.
Step 5 — Verify in FunnelGenie
- Back in the domain panel, click I've added the records — verify now. FunnelGenie looks up the
_ff-verifyTXT record on public DNS and compares the token. - On success the panel shows the verification date and your
https://address. Routing is now live: the website (or funnel) answers on the domain and its links stay on the domain. - If it reports the TXT record was not found, re-check the Host label (Step 3) and try again in a few minutes — DNS changes usually propagate within minutes but can take up to a few hours.
Troubleshooting
- Registrar shows a red warning on the CNAME row → you are putting a CNAME on the root, or pasted a URL as the value. Use ALIAS on
@with a bare hostname. - Verify says the TXT was not found → the Host label was entered as the full name and doubled up (
_ff-verify.brand.com.brand.com), or DNS has not propagated yet. Check with any public DNS lookup tool for_ff-verify.brand.comtype TXT. - Domain resolves but HTTPS will not connect / http shows error 1001 → the domain is not added on the Render service yet (Step 4).
- Site shows "Page not found" on its domain → the site is not Live, or its home page is still a draft (Websites → Pages tab shows a warning with a one-click publish).
- Changes seem ignored for a minute → host lookups are cached for 60 seconds per server instance; attaching, detaching or mounting can take up to a minute to reflect.
One domain for a website and its funnels
On the website's Pages tab, mount a funnel at a path such as /launch. The funnel then runs at brand.com/launch (opt-in at /launch/optin, thank-you at /launch/thank-you, and so on) while the rest of brand.com stays the website. Only published funnels are served, a mount path can't collide with a site page, and the same mount also answers on the site's fallback URL /sites/<site>/launch. Link to it from the site navigation with a plain /launch link.
Integrations
Admin → Settings → Integrations. Connected per workspace, credentials encrypted at rest.
- Autoresponders: GetResponse, Mailchimp, ConvertKit/Kit, ActiveCampaign, Omnisend and more — new opt-ins push to the provider chosen per funnel, with list/tag mapping per lead magnet.
- Zapier: catch-hook forwarding of platform events (new lead, opt-in, order paid, and the rest).
- Email senders: Resend (recommended; delivery/bounce webhooks close the loop), Postmark, SendGrid, or custom SMTP.
Public API & webhooks
Settings → Developers. Build on top of your workspace.
- REST API v1 at
/api/v1: contacts, funnels (list/clone), orders, pipelines & opportunities, courses & enrollments, communities & members, emails (send), webhooks, affiliates. Interactive reference at/docs/api; machine-readable OpenAPI 3.0 spec at/api/v1/openapi.json. - Auth & safety: scoped Bearer keys (shown once, rotate/revoke anytime), 120 requests/minute per key, cursor pagination, consistent error envelope with request ids, and idempotency for POSTs via the
Idempotency-Keyheader. - Outbound webhooks: subscribe an HTTPS endpoint to any platform events; deliveries are HMAC-signed (
t=<ts>,v1=<signature>), retried with backoff up to 6 attempts, and inspectable/retryable from a delivery log.
# Example: list contacts
curl https://funnelgenie.app/api/v1/contacts \
-H "Authorization: Bearer fg_live_XXXXXXXXXX_XXXXXXXX..."
Team, roles & settings
- Team members: invite by email with a role — Admin (everything incl. billing, keys, team), Editor (build and manage content), Viewer (read-only).
- Settings: workspace profile, integrations, developer keys & webhooks, billing.
- Onboarding: a guided first-run wizard plus an in-app welcome tour.
Plans & billing
- Subscription plans — Starter, Growth, Scale — billed through Paddle (monthly or yearly), managed at Admin → Billing. Starter includes a free trial.
- Plans gate usage: funnels, leads per month, broadcast emails per month, and API access. Caps are enforced softly for lead capture (never lose a lead) and firmly for sending.
- Failed payments trigger a built-in dunning email sequence with a final notice; trial-ending reminders send automatically.
Languages & theming
- The entire admin dashboard and marketing site are localized in 8 languages: English, Spanish, French, German, Portuguese (BR), Italian, Japanese, and Simplified Chinese — switchable from the header.
- Light and dark themes with a switcher (system-following by default) across the marketing site and admin.
- Website themes: each website picks Obsidian, Steel or Aurora (Settings → Theme); every preset has a light and a dark variant, so public sites keep following the visitor's setting while looking distinct.
Commands
For operating the codebase (development machine or the Render shell).
# Run locally
npm install # install dependencies
npm run dev # dev server at http://localhost:3000
npm run build # production build (don't run while dev is running)
node .output/server/index.mjs # start the production build
# Quality gates
npm run test # vitest unit suite
npm run typecheck # full TypeScript check
npm run lint # eslint
# Database (Prisma + PostgreSQL)
npx prisma migrate deploy # apply pending migrations (runs automatically on deploy)
npx prisma generate # regenerate the client after schema changes
npx prisma db seed # seed demo data (development)
# One-time / operational
npm run db:backfill-contacts # backfill legacy leads into Contacts (idempotent;
# run once in production after first deploy)
Deployment & environment
- Blueprint:
render.yamlprovisions one always-on web service + one Postgres on Render. Deploys build withnpm install --include=dev && npm run build; migrations apply automatically; health is checked at/api/health. - Domain:
funnelgenie.app(+ www) is pre-registered on the service and pre-filled intoAPP_URL/PUBLIC_ORIGIN/APP_ORIGIN/APP_PRIMARY_HOST. - Required env to fill on first deploy:
EMAIL_FROM+RESEND_API_KEY(+RESEND_WEBHOOK_SECRET),BROADCAST_POSTAL_ADDRESS, theS3_*storage keys,INTEGRATION_ENCRYPTION_KEY,ADMIN_EMAIL, and the Paddle keys. Optional:OPENAI_API_KEY,RENDER_API_KEY/RENDER_SERVICE_ID(domain automation), GA/Meta IDs, PayPal keys (commerce). - Boot diagnostics: the server logs loud warnings at startup for any missing critical env, and reports whether persistent storage is active.
- Scheduled tasks (in-process, no worker): webhook delivery + email/automation tick + blog publishing every minute, dunning every 15 minutes, abandoned-checkout hourly.
URL map
| URL | What it serves |
|---|---|
/ | Marketing landing page |
/pricing, /about | Pricing and about pages |
/legal/* | Privacy, terms, disclaimer, cookie policy |
/signup, /login | Account creation and sign-in |
/admin | The dashboard (everything above lives here) |
/funnels/<slug> | A published funnel (root redirects to its first step) |
/sites/<slug> | A published website; its blog at …/blog |
/offer/<slug>, /checkout/<slug> | Product sales and checkout pages (commerce on) |
/members | Member portal: courses, communities, affiliate dashboard |
/share/f/<token> | Share-funnel preview & claim |
/affiliates/join/<token> | Public affiliate-program signup |
/r/<token> | Affiliate tracking redirect |
/docs/api | API reference (spec at /api/v1/openapi.json) |
/sitemap.xml, /robots.txt | SEO surface |
/documentation.html, /testing.html | This documentation and the testing guide |