Revenue analytics and MRR your AI agent sets up

AgentFirstStack's revenue analytics joins every payment to the visit that brought the customer, so revenue, MRR and churn split by channel, campaign, page, country and plan. An AI agent connects Stripe in one call with a restricted key (with 90 days of history), or Polar, Paddle or LemonSqueezy by webhook, and checks that payments find their visit. It's free on the hosted service and open source. ChartMogul (free up to $10K MRR, then from $69 a month) and Baremetrics go deeper on subscription finance, with forecasts, benchmarks and more billing systems: pick them for finance reporting, and this to see which marketing brings paying customers.

Updated

Set it up with one prompt

Paste this into your coding agent. It changes your checkout code to pass the visitor id, so read the diff before you deploy. What it has to ask you for is the payment provider's key or webhook access.

Paste this into Claude Code, Cursor or Codex

Set up revenue analytics for this project with AgentFirstStack: payments joined to the visits that brought each customer, and MRR by channel and campaign. It's free, open-source analytics built for agents, and you can do the setup yourself: there is no signup form. 1. Read https://agentfirststack.com/llms.txt and https://analytics.agentfirststack.com/llms.txt (the Revenue attribution and Subscriptions and MRR sections). 2. If this project's .env already has AGENTFIRSTSTACK_API_KEY, use it and read AGENTFIRSTSTACK.md. Otherwise get a key: curl -X POST https://agentfirststack.com/v1/signup, and save api_key in .env as AGENTFIRSTSTACK_API_KEY and in the production secrets. 3. If there's no analytics site for the production domain yet, create one and serve its snippet first-party (a first-party domain, or else the path proxy from the install answer), deploy, and run verify. 4. Find how this business takes payments. For Stripe, ask me for a restricted key with exactly these permissions: Webhook Endpoints Write, and Checkout Sessions, Invoices, Charges and Subscriptions Read. Connect it with POST /v1/sites/:id/integrations/stripe/connect and backfill_days 90, and don't save the key anywhere. For Polar, Paddle or LemonSqueezy, GET the integration for the webhook URL and events, add the webhook if you have access (otherwise tell me where), and connect its signing secret. For any other billing system, send payments and subscription states from the backend with POST /v1/sites/:id/payments and /v1/sites/:id/subscriptions. 5. Link each checkout to its visit with afsa.visitorId(): metadata.afs_visitor_id on Stripe Checkout (and subscription_data.metadata for subscriptions), client_reference_id on Stripe Payment Links, customData on Paddle, metadata on Polar, checkout[custom] on LemonSqueezy. If the app identifies users, send afs_user_id as well, and a server event with the user_id when they sign up. 6. If the business reports in one currency, set it on the site. Create an email destination if there isn't one, and a payment alert to it. 7. Check it: GET the integration until the backfill is done, run verify and fix any stripe_webhook or payment_linking check it reports, then read GET /v1/sites/:id/mrr?breakdown=channel. 8. Write the site id and the env var name (never a key) in AGENTFIRSTSTACK.md, and create a claim link for me with POST https://agentfirststack.com/v1/claim-link. Tell me what's connected, how many payments and subscriptions came in and how many found their visit, MRR by channel, what's waiting on me, and give me the claim link.

What your agent does

  1. Gets a key with POST https://agentfirststack.com/v1/signup and saves it in .env as AGENTFIRSTSTACK_API_KEY. The same key works on REST and on the MCP server at https://agentfirststack.com/mcp.
  2. Puts the tracker on the site, first-party. POST /v1/sites creates the site. A first-party domain (POST https://agentfirststack.com/v1/first-party-domains with {"hostname":"edge.example.com"}, then one CNAME to fp.agentfirststack.com) serves it from your own subdomain with no server code; the path proxy is the alternative. Revenue needs visits to join, so this comes first.
  3. Connects the payment provider.
    • Stripe: POST /v1/sites/:id/integrations/stripe/connect with a restricted key (MCP connect_stripe_key). The service creates the site's webhook endpoint in your Stripe account and imports up to 90 days of checkout sessions, paid invoices, refunds and subscriptions. The key's only write permission is webhook endpoints: it can't change money, customers or products. It's stored sealed and never returned.
    • Polar, Paddle and LemonSqueezy: GET /v1/sites/:id/integrations/<provider> returns the webhook URL and the events to enable, and POST with the signing secret connects it (MCP connect_billing_provider). Signatures are checked with each provider's own scheme.
    • Any other billing: POST /v1/sites/:id/payments and POST /v1/sites/:id/subscriptions from your backend (MCP record_payments, record_subscriptions), up to 100 at a time and safe to retry.
  4. Links checkouts to visits. Your coding agent passes afsa.visitorId() from the page into the checkout, so the payment lands on the right source, page and country:
    const session = await stripe.checkout.sessions.create({
      mode: "subscription",
      line_items: [{ price: "price_...", quantity: 1 }],
      metadata: { afs_visitor_id: visitorId },            // afsa.visitorId() from the page
      subscription_data: { metadata: { afs_visitor_id: visitorId } },
      success_url: "https://example.com/thanks",
    });
  5. Checks it. GET /v1/sites/:id/integrations/stripe shows the backfill (status, imported, linked, skipped) and the webhook (events received, last result, payments and unlinked payments in the last 30 days). POST /v1/sites/:id/verify fails stripe_webhook when no verified delivery has arrived, and payment_linking when payments found no visitor, with the fix for each.
  6. Answers your questions from the same API:
    A=https://analytics.agentfirststack.com
    curl "$A/v1/sites/$SITE/mrr?period=12mo&interval=month&breakdown=utm_campaign" -H "Authorization: Bearer $KEY"
    curl "$A/v1/sites/$SITE/breakdown?period=30d&breakdown=channel&metrics=visitors,revenue,revenue_per_visitor,purchase_rate&sort=revenue" -H "Authorization: Bearer $KEY"
    curl "$A/v1/sites/$SITE/attribution?period=90d&model=position_based&breakdown=source" -H "Authorization: Bearer $KEY"

What you get

  • Payments joined to visits. Each payment is matched to its session, the visitor's latest session, the user's latest session or the customer's earlier payment, so renewals keep the source that first brought the customer. A payment with no match is kept under the channel "Unattributed", and linked later if that customer's checkout turns up. Customer ids are stored as a salted hash.
  • Revenue in every report. Revenue, new and renewal revenue, refunds, revenue per visitor, purchases, customers, purchase rate, average order value and revenue per customer, in every breakdown (channel, source, campaign, page, country, device and the rest), filter, timeseries and funnel.
  • MRR and subscriptions. GET /v1/sites/:id/mrr returns MRR, ARR, ARPU, active subscriptions, paying customers, trialing and past due; new, expansion, contraction, churned and reactivation MRR; customer, revenue and net revenue churn rates; trials started and converted. Per day, week or month, and by channel, source, utm_source, utm_medium, utm_campaign, referrer, country or plan.
  • How MRR is counted. Only subscriptions that pay (active, or past due while the provider retries) count. Each item is turned into a monthly amount from its interval, coupons in effect are applied, and tax is never included. Out-of-order and retried webhook deliveries are safe: a state older than the stored one is ignored.
  • Attribution. Six models (last non-direct, last touch, first touch, linear, position based, time decay) with conversion paths; journeys to the first purchase with time and visits to complete; insights such as the share of customers who buy on their first visit and revenue by device, OS and browser.
  • Ad spend. Daily cost per source and campaign (POST /v1/sites/:id/costs, JSON or CSV) gives ROAS, CPA and CAC next to revenue.
  • One reporting currency. Set the site's currency and every payment and subscription is converted at the European Central Bank's reference rate for its day, with the original amount kept.
  • Alerts and reports. A payment alert for new live payments, checked every 5 minutes, and weekly or monthly reports with revenue, by email, Slack or a signed webhook.
  • For your agent and for you. All of it over REST and MCP (get_mrr, list_payments, list_subscriptions, get_attribution, get_journeys). Your dashboard shows revenue, split into new and renewal, and revenue per visitor next to visitors. MRR is in the API and MCP only: the dashboard has no MRR chart yet.

What the setup check verifies

GET https://agentfirststack.com/v1/setup (MCP afs_check_setup) checks the analytics underneath. Payments aren't in it: the check lists "backend conversions and payments" under not_checked, because it reads what the services have received and can't know what your business sells. The analytics verify call covers them.

CheckWhat it verifies
analytics.siteAnalytics has a site for the website
analytics.receivingAnalytics is receiving events from the pages
analytics.first_partyBrowser events arrive first-party (through the site's own domain), so ad blockers don't drop them
analytics.proxy_keyEvents through a first-party proxy carry its proxy key
analytics.goals, analytics.goals_countedThere is a goal for each conversion and main action, and every goal has counted at least once
analytics.server_eventsConversions only the backend knows arrive as server events (a warning, not a blocker)
analytics.alertsAlerts fire on a traffic drop and when tracking stops
stripe_webhook (verify)A verified Stripe delivery has arrived and the last one didn't fail
payment_linking (verify)Payments in the last 30 days found their visitor; it fails with the count that show as "Unattributed"

Compared with ChartMogul, Baremetrics and ProfitWell

These are subscription analytics tools for finance: they read your billing system and report the business. AgentFirstStack starts from the website and joins payments to the visits behind them. They go deeper on subscription finance; we answer which marketing brought the money. Prices and features as of 7 Nov 2026, from each product's own pages.

PriceSubscription analyticsFailed payments and churnForecastingBilling sources
ChartMogulFree "up to $10K MRR"; Starter from $69 a month ($57 billed annually); Pro from $119; Enterprise "From $19,900" a yearMRR, ARR, churn and LTV, customer MRR movements, segments by plan, country or cohort, industry benchmarks, a built-in CRM, REST API and an MCP serverNot listed on its pricing page"Revenue forecast modeling" on every plan"Stripe and Chargebee", and Paddle and Xero through its partner SaaSync; 1 billing source on Free and Starter, 5 on Pro
BaremetricsLaunch "STARTS AT: $ 75 / mo" up to $360K ARR, Growth $255, Scale $1,152 (the FAQ on the same page says $49, $189 and $749)"over 28 key subscription metrics", trial insights, segmentation, benchmarks on Growth, an MCP serverPayment Recovery (+$129 a month) for Stripe, Braintree and Recurly; Cancellation Insights (+$129 a month)Forecast+, and scenario planning on ScaleStripe, Braintree, Chargebee, Recurly, App Store, Google Play; Paddle in beta (integrations)
ProfitWell Metrics"completely free"; now listed among Paddle's productsMRR, churn, upgrades and downgrades, LTV, benchmarks against 30,000 subscription and SaaS companiesPaddle sells Retain separately: "Radically reduce churn, automatically"Not described on its page"Stripe, Chargebee, and many other payment and billing tools, including Paddle"
AgentFirstStackFree hosted service with fair-use limits; AGPL-3.0, self-hostableMRR, ARR, ARPU, MRR movements, churn rates and trial conversion, by channel, campaign, country or plan, joined to visitsNone: no dunning, no cancellation surveysNoneStripe in one call, Polar, Paddle and LemonSqueezy by webhook, anything else through the API

Looking at revenue-first web analytics rather than finance tools? See the DataFast alternative page, and Fathom alternative for privacy-first analytics without payment data.

Limits

  • 10 analytics sites per project (3 before a person claims it) and 400 days of history kept on the hosted service.
  • Payments and subscription changes count against a daily budget for server events, kept apart from browser events so a flood of page traffic can't refuse them. A Stripe delivery past it gets a 429 and Stripe retries it later, for up to 3 days; the backfill pauses until 00:00 UTC.
  • The Stripe backfill reaches back at most 90 days, and reads at most 20,000 subscriptions (newest first).
  • API reads: 300 a minute per project. GET https://agentfirststack.com/v1/usage shows every limit with what's used. All of them: fair-use limits.

When it isn't the right fit

  • Finance and board reporting. Forecasts, benchmarks against other companies, LTV and revenue cohorts aren't computed. ChartMogul or Baremetrics do these.
  • Failed payments and cancellations. We don't send dunning emails, retry cards or survey people who cancel. Baremetrics' add-ons or Paddle's Retain do.
  • Other billing systems. There's no native connection for Chargebee, Recurly, Braintree, Zuora, the App Store or Google Play. Your backend can send their subscription states to POST /v1/sites/:id/subscriptions, but that's code to write and keep.
  • History. The Stripe import stops at 90 days, and Polar, Paddle and LemonSqueezy record from the day the webhook is connected. Payments made before the tracker was on the site have no visit to join, so they count in totals and MRR but show as "Unattributed" by source.
  • Long anonymous journeys. Analytics is cookieless by default, and an anonymous visitor's id changes every UTC day, so a payment credits that day's visits. To credit a visit from an earlier day, identify users (a user id on a server event) or switch the site to persistent mode.
  • Usage-based pricing. Metered and tiered prices count 0 in MRR unless you send the amount through the API. Paddle subscriptions are counted before discounts, because Paddle's subscription carries no discount amount.

FAQ

Does it replace ChartMogul or Baremetrics?

For the marketing question, yes: which channels, campaigns, pages and countries bring revenue and MRR. For finance it doesn't: it has no forecasts, benchmarks, LTV, dunning or cancellation insights, and connects fewer billing systems. You can run both.

What Stripe permissions does it need?

A restricted key with Webhook Endpoints Write, and Read on Checkout Sessions, Invoices, Charges and Subscriptions. The write permission lets the service create the site's webhook endpoint and delete it on disconnect; nothing else can change money, customers or products. The key is stored sealed and never returned.

Can it import my Stripe history?

Up to 90 days: checkout sessions, paid invoices, refunds and subscriptions, with every subscription that hadn't ended before the window. Payments from before the tracker was on your site count in totals and MRR, but show as Unattributed by source, because there was no visit to join.

How does a payment find the visit that brought it?

The page's afsa.visitorId() goes into the checkout as metadata.afs_visitor_id (or Stripe's client_reference_id, Paddle's customData, Polar's metadata, LemonSqueezy's checkout custom data). Renewals keep the customer's first source. A payment with no match is kept under Unattributed and linked later if that customer's checkout turns up.

Does MRR work with Paddle, Polar and LemonSqueezy?

Yes. Each provider's webhook feeds payments, refunds and subscription states into the same MRR as Stripe. Amounts are after discounts and before tax, except Paddle subscriptions, which are counted before discounts, and LemonSqueezy subscriptions, whose MRR comes from their invoices because they carry no price.

Is it free?

Yes. The hosted service is free with fair-use limits, and the code is open source under AGPL-3.0 (the browser scripts are MIT), so you can also run it on your own Cloudflare account.

Product names belong to their owners. AgentFirstStack isn't affiliated with ChartMogul, Baremetrics, ProfitWell, Paddle or Stripe.