- Pull read-cost by operation and by customer (the cross-match), not just a total bill.
- Join read-cost to revenue to see margin per paying customer.
- Same secret-key gate as revenue and errors, so the layers stay joined.
Definitions used in this guide
A single document, row, or query result your database counts toward usage and bills you for.
Connecting each read back to the feature or code path that caused it, instead of seeing one undivided total.
Where a read ran — your server, your web app, your dashboard, or a mobile build. The same query can fire from several, and the bill hides which.
What should be true before you start?
Before you pull read-cost, decide what you want to govern: a runaway operation, a heavy customer, or thin margin. A bill total cannot answer the third question; only cost joined to revenue can. That join is the cross-match. If you are still measuring cost by hand, start with measuring read-cost without a tool that costs you reads.
Teams that do this well make the data model boring before they make the UI impressive. They decide what the product trusts, how the customer is identified, and which events prove that a premium flow worked. That upfront discipline prevents pricing changes, support escalations, or platform additions from turning into a rewrite later.
- Decide the unit: per operation, per customer, or margin (cost vs revenue).
- Pick a threshold that means 'investigate', not just 'noticed'.
- Keep the secret key server-side; pull the joined attribution.
How should you implement this step by step?
Call /v1/buckets for read-cost by operation, and /v1/crossmatch for a customer's read-cost beside their revenue. Because cost and revenue share one identity, you can render cost per paying customer — margin — instead of a scary total. Attributing reads to features is the same idea as attributing read-cost to features in a serverless app, now joined to who pays.
Implementation should move from trust to explanation. First make the purchase and access state reliable. Then add the events and context that explain whether the path is working for real customers. That order matters because a beautiful funnel built on unreliable access logic will still mislead the team.
- Call
/v1/bucketsfor read-cost by operation, with thecd_sk_live_secret key. - Call
/v1/crossmatch?userId=...to read a customer'sreadCostbeside theirrevenue. - Compute margin: revenue per customer against read-cost per customer.
- Alert when a paying customer's cost outruns what they pay, or an operation blows its budget.
| Question | Endpoint | The join |
|---|---|---|
| Which operation is expensive? | /v1/buckets | Find the read monster. |
| What does this customer cost? | /v1/crossmatch | Read-cost beside revenue. |
| Is the margin thin? | crossmatch revenue × readCost | Cost vs what they pay. |
const r = await fetch("https://api.cross-deck.com/v1/crossmatch?userId=" + id, {
headers: { Authorization: "Bearer " + process.env.CROSSDECK_SECRET_KEY }
});
const { data } = await r.json();
// the join: read-cost next to revenue, per customer
flagThinMargin(data.readCost.reads, data.revenue.monthlyCents);
Where do teams make mistakes?
The mistake is watching a bill total with no idea of cost per customer or margin.
Most production problems here are not caused by missing one API call; they are caused by model mistakes. Teams mix catalog structure with access logic, treat frontend success states as final truth, or log events without preserving identity. Those shortcuts often feel fine during integration and expensive during the first real support incident.
- Tracking spend with no attribution, so you cut blindly.
- Measuring cost without revenue, so you optimise a profitable customer away.
- Polling so aggressively that the monitoring itself adds meaningful reads.
How does Crossdeck operationalize the workflow?
Crossdeck attributes every read to an actor and an operation, then joins it to revenue through the same identity behind the cross-match. Pulling that into your dashboard turns a database bill into margin per customer — cost and revenue on the same row, which a standalone cost meter can never show.
The operating win is margin visibility: the expensive customer and the expensive query are both obvious, and you can tell which expensive customers earn their keep. That is read-cost as the moat sees it — joined, not standalone.
The operating win is not just cleaner instrumentation. It is that product, support, and engineering can all look at the same customer and reason from the same truth. That shortens the loop between insight, bug fixing, and revenue recovery.
What should a healthy rollout let your team do?
After rollout, the team should be able to inspect one customer and answer four basic questions quickly: what they bought, what access they should have, what they did before the key moment, and whether an error or product break interrupted the path. If those answers still live in different systems, the rollout is not finished yet.
A healthy setup should also make pricing, platform, and lifecycle changes cheaper. New SKUs, trial structures, payment rails, or premium features should mostly be mapping and instrumentation updates, not excuses to rewrite the access model from scratch.
- Trace one premium journey from paywall view to verified access.
- Confirm support can explain a paid-user issue without engineering stitching exports together.
- Review whether new products can be attached without changing feature checks.
What should you review after launch?
The first review cycle should happen with real production questions, not a checklist alone. Look at a new conversion, a failed payment or retry, a support ticket, and a customer who used a premium feature successfully. If the workflow is sound, those stories should be easy to reconstruct.
From there, keep reviewing the signal as an operating surface. The point is not only to collect data. It is to make the next pricing change, onboarding improvement, or incident response faster because the evidence is already joined.
- Review the earliest events that predict retained value.
- Check the gap between entitlement state and what the UI showed.
- Use the next support conversation as a live test of the model.
How should the whole team use the workflow?
A workflow like this becomes more valuable when it is not trapped inside engineering. Support should be able to confirm access and recent failure context. Product should be able to connect the path to adoption or conversion quality. Engineering should be able to see which state or step broke first.
When those three views line up, the system starts compounding. Each incident teaches the team something about pricing, onboarding, premium UX, or instrumentation instead of dying as a one-off ticket.
- Support: confirm entitlement state and the last premium action quickly.
- Product: review which steps correlate with value or friction.
- Engineering: prioritize breaks by customer and revenue impact.
Frequently asked questions
What is a database read-cost API?
It is an endpoint that returns read-cost attributed to who and what caused it. Crossdeck's /v1/buckets and /v1/crossmatch let your backend budget and alert on database cost, joined to revenue.
Can I see cost and revenue per customer together?
Yes. /v1/crossmatch returns a customer's readCost beside their revenue, so you can compute margin per paying customer instead of staring at a bill total.
What is the cross-match for read-cost?
The cross-match attributes reads to the actor and operation that caused them, joined to revenue and entitlements — so read-cost is a margin question, not just a meter.
Does Crossdeck work across iOS, Android, and web?
Yes. Crossdeck is designed around one customer timeline across Apple, Google Play, Stripe, and web or mobile product events, so the same entitlement and revenue model can travel across surfaces.
What should I do after reading this guide?
Use the CTA in this article to start free or go straight into browse the reporting api reference so you can turn the concept into a verified implementation.
Take this into the product
Open the Reporting API reference, pull /v1/buckets, and put cost-per-paying-customer in your own dashboard.