We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
From the blog
Introducing Aurora Meter: Usage-Based Billing and Metering for Phoenix
By Liam Killingback ·
Introducing Aurora Meter: Usage-Based Billing and Metering for Phoenix
Every SaaS eventually has to answer the same three questions about every customer: how much have they used, what is their plan allowed to do, and what do we bill them for it? On most stacks you reach for a library. On Phoenix, until now, you hand-rolled all three — a counter here, a plan check there, a Stripe webhook somewhere else — and hoped they stayed consistent as the app grew.
Today we’re releasing Aurora Meter: real-time usage metering, plan entitlements, and Stripe billing for Phoenix and Elixir. Think Laravel Cashier + OpenMeter, for the BEAM — a free, MIT-licensed core that counts and gates usage on an in-memory hot path, plus a commercial Aurora Meter Pro tier that closes the loop to revenue with Stripe.
If you’ve been putting off usage-based pricing because the plumbing looked like a month of work, this is for you.
Usage-based billing is the new default
Per-seat pricing is quietly giving way to usage-based pricing. The reason is the AI era: when every feature call has a real marginal cost — tokens, GPU time, a third-party API bill — charging a flat monthly fee means you either overcharge light users or lose money on heavy ones. So the modern SaaS meters what customers actually do (AI generations, API calls, documents processed, minutes transcribed) and bills for it, often with an included allowance plus overage.
That pattern shows up in three places in your codebase, and they have to agree:
- Metering — counting each unit of usage, fast enough that it never becomes a bottleneck on your hot path.
- Entitlements — deciding, on every request, whether a customer’s plan allows the action and whether they’re within their allowance.
- Billing — turning the metered usage into an invoice, reliably, via your payment provider.
Get them out of sync and you either bill customers for usage you didn’t gate, or gate usage you’re not billing for. Ecosystems like Node, Python and Go have OpenMeter, Lago, and friends for exactly this. Elixir had nothing — no metering library, and no Laravel-Cashier equivalent. Aurora Meter fills that gap.
Count, gate, bill
Aurora Meter does three jobs behind one small API.
1. Meter — count usage without touching your database
Recording usage is a single call:
AuroraMeter.track(org, :ai_generations)
Under the hood that’s an atomic :ets.update_counter/3 — lock-free, concurrency-safe, and measured in microseconds. There is no database round-trip on the write path. A background flusher persists snapshots to Postgres on an interval, and a broadcaster fans live values out over Phoenix.PubSub, so your dashboards update in real time. In our benchmarks the counter sustains ~8 million increments per second on a single node — you are not going to out-grow it.
Reading usage is just as cheap:
AuroraMeter.usage(org, :ai_generations)
# => 7_420
2. Entitle — gate features by plan
Plans are declared in a small compile-time DSL, so your pricing lives in one place and is validated when your app compiles:
defmodule MyApp.Plans do
use AuroraMeter.Plans
plan :free do
limit :ai_generations, 100, :hard
feature :priority_support, false
end
plan :pro do
metered :ai_generations, included: 10_000, unit_price: 1
feature :priority_support, true
end
end
A :hard limit blocks at its cap. A :metered feature is always allowed and the overage is what gets billed. A boolean feature is a plain capability flag. To gate, run, and meter an action in one atomic step, wrap it in with_quota/4:
case AuroraMeter.with_quota(org, :ai_generations, fn -> generate_report() end) do
{:ok, report} -> render(report)
{:error, :limit_exceeded} -> prompt_upgrade()
end
The important word there is atomic. with_quota/4 reserves the usage before running your function and rolls the reservation back if the function raises, so hard limits stay correct even under heavy concurrency — no race where two requests both slip past a cap of one. That single guarantee is the thing most hand-rolled metering gets subtly wrong.
You also get the obvious helpers — allowed?/2, entitled?/2, remaining/2 — plus drop-in LiveView components that render live usage meters straight from the ETS counters, so an admin dashboard is a few lines of markup.
3. Bill — report usage to Stripe
The free core ships a billing seam: a clean boundary where a provider plugs in. Aurora Meter Pro implements it against Stripe and closes the loop to revenue:
- Stripe Checkout + webhook sync keep local subscriptions in lockstep with Stripe, idempotently, via a self-contained HMAC webhook verifier.
- A background usage reporter (Oban) reports metered deltas to Stripe Billing Meters exactly once, so usage-based invoices are correct.
- Subscription-aligned billing periods, historical rollups with CSV export for finance, hosted real-time dashboards, and quota alerts with reconciliation round it out.
So the free core lets you count and gate today; Pro is what you add when Stripe should start charging for it.
Why the BEAM is the right place for metering
Metering is a real-time, high-write, concurrent problem — which is exactly what the BEAM is good at. ETS gives you lock-free atomic counters with no external dependency. PubSub gives you live dashboards for free. OTP supervision keeps the flusher and broadcaster healthy without a cron job or a separate service. On other stacks, real-time metering usually means bolting on Redis and a queue; on Phoenix it’s just your app. That’s the moat, and it’s why a metering primitive belongs in the Elixir ecosystem rather than as yet another SaaS you pay per-event to call.
Getting started
Add the free core from Hex:
def deps do
[
{:aurora_meter, "~> 0.1"}
]
end
Add it to your supervision tree — one child that validates its config at boot and starts the metering runtime:
children = [
MyApp.Repo,
{Phoenix.PubSub, name: MyApp.PubSub},
AuroraMeter,
MyAppWeb.Endpoint
]
Point it at your plans module and repo in config, run the generated migration, and you’re metering:
# count usage on your hot path
AuroraMeter.track(org, :ai_generations)
# gate + run + meter in one atomic step
AuroraMeter.with_quota(org, :ai_generations, fn ->
generate_report()
end)
That’s the whole loop. Full setup, the plan DSL reference, and a live showcase are on the Aurora Meter product page, and the source lives on GitHub.
Free core vs Aurora Meter Pro
The free MIT core is genuinely useful on its own: ETS-backed real-time counters, the plan DSL and entitlement gate, LiveView usage components, Postgres persistence, and telemetry. Everything you need to count and gate.
Aurora Meter Pro adds the revenue half: Stripe Checkout and webhook sync, metered usage reported to Stripe Billing Meters, subscription-aligned periods, historical rollups with CSV export, hosted dashboards, and quota alerts. It’s licensed per app at a flat monthly price — the same model as Oban Pro — so it scales with your business, not your usage.
Where it fits
If you’re building AI features, this closes an obvious gap. Say you’re streaming OpenAI responses in Phoenix LiveView or chatting with your data through pdfai — every one of those calls costs you real money. Metering is how you turn that cost into a priced product: Aurora Meter counts the call, checks the customer’s plan, and (with Pro) reports it to Stripe for invoicing. You get to charge for your AI features instead of eating their cost.
It’s just as at home metering API calls, seats, exports, transcription minutes, or anything else you sell by the unit.
Try it today
Aurora Meter is the newest piece of the PhxTemplates family — the AI-native, use-case-specific Phoenix toolkit, at honest prices.
- Free core: github.com/liamkillingback/aurora-meter (MIT)
- Product page + guide: phxtemplates.com/aurora-meter
- Aurora Meter Pro: Stripe billing, dashboards and rollups, from the product page
And if you’re standing up a whole SaaS — auth, billing, admin, AI and now metering — our production-ready Phoenix templates and the lifetime Builder Pass wire the rest in for you, so you can start ahead. Count, gate, bill — and ship.