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.
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.
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
- Gets a key with
POST https://agentfirststack.com/v1/signupand saves it in.envasAGENTFIRSTSTACK_API_KEY. The same key works on REST and on the MCP server athttps://agentfirststack.com/mcp. - Puts the tracker on the site, first-party.
POST /v1/sitescreates the site. A first-party domain (POST https://agentfirststack.com/v1/first-party-domainswith{"hostname":"edge.example.com"}, then one CNAME tofp.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. - Connects the payment provider.
- Stripe:
POST /v1/sites/:id/integrations/stripe/connectwith a restricted key (MCPconnect_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, andPOSTwith the signing secret connects it (MCPconnect_billing_provider). Signatures are checked with each provider's own scheme. - Any other billing:
POST /v1/sites/:id/paymentsandPOST /v1/sites/:id/subscriptionsfrom your backend (MCPrecord_payments,record_subscriptions), up to 100 at a time and safe to retry.
- Stripe:
- 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", }); - Checks it.
GET /v1/sites/:id/integrations/stripeshows 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/verifyfailsstripe_webhookwhen no verified delivery has arrived, andpayment_linkingwhen payments found no visitor, with the fix for each. - 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/mrrreturns 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.
| Check | What it verifies |
|---|---|
analytics.site | Analytics has a site for the website |
analytics.receiving | Analytics is receiving events from the pages |
analytics.first_party | Browser events arrive first-party (through the site's own domain), so ad blockers don't drop them |
analytics.proxy_key | Events through a first-party proxy carry its proxy key |
analytics.goals, analytics.goals_counted | There is a goal for each conversion and main action, and every goal has counted at least once |
analytics.server_events | Conversions only the backend knows arrive as server events (a warning, not a blocker) |
analytics.alerts | Alerts 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.
| Price | Subscription analytics | Failed payments and churn | Forecasting | Billing sources | |
|---|---|---|---|---|---|
| ChartMogul | Free "up to $10K MRR"; Starter from $69 a month ($57 billed annually); Pro from $119; Enterprise "From $19,900" a year | MRR, ARR, churn and LTV, customer MRR movements, segments by plan, country or cohort, industry benchmarks, a built-in CRM, REST API and an MCP server | Not 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 |
| Baremetrics | Launch "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 server | Payment Recovery (+$129 a month) for Stripe, Braintree and Recurly; Cancellation Insights (+$129 a month) | Forecast+, and scenario planning on Scale | Stripe, Braintree, Chargebee, Recurly, App Store, Google Play; Paddle in beta (integrations) |
| ProfitWell Metrics | "completely free"; now listed among Paddle's products | MRR, churn, upgrades and downgrades, LTV, benchmarks against 30,000 subscription and SaaS companies | Paddle sells Retain separately: "Radically reduce churn, automatically" | Not described on its page | "Stripe, Chargebee, and many other payment and billing tools, including Paddle" |
| AgentFirstStack | Free hosted service with fair-use limits; AGPL-3.0, self-hostable | MRR, ARR, ARPU, MRR movements, churn rates and trial conversion, by channel, campaign, country or plan, joined to visits | None: no dunning, no cancellation surveys | None | Stripe 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/usageshows 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.
Related
- AnalyticsWeb analytics your AI agent sets upThe analytics the revenue joins to.
- AnalyticsDataFast alternativeRevenue-first web analytics, compared.
- AnalyticsAdd analytics with Claude CodeOne prompt, revenue included.
- Conversion trackingSend the same purchases to Google Ads, Meta and TikTok.
- AnalyticsShopify analyticsOrders from the webhook, joined to the visit.
- All servicesOne MCP server for every serviceAnalytics, tags, mail and replay tools on one key.